diff options
author | Bolshakov <bolsh.andrey@yandex.ru> | 2023-03-26 21:28:23 +0300 |
---|---|---|
committer | Kim Gräsman <kim.grasman@gmail.com> | 2023-04-16 16:13:39 +0200 |
commit | 5957e2fb928d97446a3905d09e6c317960c4622e (patch) | |
tree | fdbc7a255d43f6fcac176881cde2398baf3b2530 | |
parent | 5317d11d3eefe99254d2d41c165e8402c3fb2aba (diff) |
Handle elaborated keywords as fwd-decls
C++ doesn't require any forward-declaration after the declaration name
occured in an elaborated type with corresponding tag
(class/struct/union).
Initial support. Only those elaborated types are treated
as fwd-declarations which occur before any other declaration
of the underlying type ("owning" elaborated types).
TypeLoc is intercepted and handled instead of just the type because only
explicitly written elaborated types matter. Moreover, location
information could be used in the future for full support of treating
elaborated types as fwd-declarations, even in the "non-owning" case.
Besides, it is the more correct fix of #1065.
-rw-r--r-- | iwyu.cc | 10 | ||||
-rw-r--r-- | iwyu_output.cc | 23 | ||||
-rw-r--r-- | iwyu_output.h | 13 | ||||
-rw-r--r-- | tests/cxx/elaborated_type.cc | 17 |
4 files changed, 59 insertions, 4 deletions
@@ -167,6 +167,7 @@ using clang::Decl; using clang::DeclContext; using clang::DeclRefExpr; using clang::DeducedTemplateSpecializationType; +using clang::ElaboratedTypeLoc; using clang::EnumConstantDecl; using clang::EnumDecl; using clang::EnumType; @@ -4207,6 +4208,15 @@ class IwyuAstConsumer return Base::VisitTemplateSpecializationType(type); } + bool VisitElaboratedTypeLoc(ElaboratedTypeLoc type_loc) { + if (type_loc.getTypePtr()->getKeyword() != clang::ETK_None) { + preprocessor_info() + .FileInfoFor(CurrentFileEntry()) + ->AddElaboratedType(type_loc); + } + return Base::VisitElaboratedTypeLoc(type_loc); + } + // --- Visitors defined by BaseASTVisitor (not RecursiveASTVisitor). bool VisitTemplateName(TemplateName template_name) { diff --git a/iwyu_output.cc b/iwyu_output.cc index 1834618..309f91a 100644 --- a/iwyu_output.cc +++ b/iwyu_output.cc @@ -42,6 +42,7 @@ using clang::CXXMethodDecl; using clang::CXXRecordDecl; using clang::Decl; using clang::DeclContext; +using clang::ElaboratedTypeLoc; using clang::EnumDecl; using clang::FileEntry; using clang::FunctionDecl; @@ -502,6 +503,17 @@ OneIncludeOrForwardDeclareLine::OneIncludeOrForwardDeclareLine( } OneIncludeOrForwardDeclareLine::OneIncludeOrForwardDeclareLine( + ElaboratedTypeLoc type_loc) + : is_desired_(true), + is_present_(true), + is_elaborated_type_(true), + fwd_decl_(type_loc.getTypePtr()->getOwnedTagDecl()) { + const SourceRange decl_lines = type_loc.getLocalSourceRange(); + start_linenum_ = GetLineNumber(GetInstantiationLoc(decl_lines.getBegin())); + end_linenum_ = GetLineNumber(GetInstantiationLoc(decl_lines.getEnd())); +} + +OneIncludeOrForwardDeclareLine::OneIncludeOrForwardDeclareLine( const FileEntry* included_file, const string& quoted_include, int linenum) : line_("#include " + quoted_include), start_linenum_(linenum), @@ -592,6 +604,15 @@ void IwyuFileInfo::AddForwardDeclare(const clang::NamedDecl* fwd_decl, << internal::GetQualifiedNameAsString(fwd_decl) << "\n"; } +void IwyuFileInfo::AddElaboratedType(ElaboratedTypeLoc type_loc) { + if (!type_loc.getTypePtr()->getOwnedTagDecl()) + return; + lines_.push_back(OneIncludeOrForwardDeclareLine(type_loc)); + VERRS(6) << "Found owning elaborated type: " << GetFilePath(file_) << ":" + << lines_.back().LineNumberString() << ": " + << PrintableTypeLoc(type_loc) << "\n"; +} + void IwyuFileInfo::AddUsingDecl(const UsingDecl* using_decl) { CHECK_(using_decl && "using_decl unexpectedly nullptr"); using_decl_referenced_.insert(std::make_pair(using_decl, false)); @@ -2084,7 +2105,7 @@ size_t PrintableDiffs(const string& filename, OutputLine("\nThe full include-list for " + filename + ":")); for (const auto& key_line : sorted_lines) { const OneIncludeOrForwardDeclareLine* line = key_line.second; - if (line->is_desired()) { + if (line->is_desired() && !line->is_elaborated_type()) { output_lines.push_back( PrintableIncludeOrForwardDeclareLine(*line, aqi)); } diff --git a/iwyu_output.h b/iwyu_output.h index a0f09cc..6d0b344 100644 --- a/iwyu_output.h +++ b/iwyu_output.h @@ -30,6 +30,7 @@ namespace clang { class FileEntry; class UsingDecl; +class ElaboratedTypeLoc; } // namespace clang namespace include_what_you_use { @@ -144,6 +145,7 @@ class OneUse { class OneIncludeOrForwardDeclareLine { public: explicit OneIncludeOrForwardDeclareLine(const clang::NamedDecl* fwd_decl); + explicit OneIncludeOrForwardDeclareLine(clang::ElaboratedTypeLoc); OneIncludeOrForwardDeclareLine(const clang::FileEntry* included_file, const string& quoted_include, int linenum); @@ -158,6 +160,9 @@ class OneIncludeOrForwardDeclareLine { bool is_present() const { return is_present_; } + bool is_elaborated_type() const { + return is_elaborated_type_; + } const map<string, int>& symbol_counts() const { return symbol_counts_; } @@ -206,9 +211,10 @@ class OneIncludeOrForwardDeclareLine { string line_; // '#include XXX' or 'class YYY;' int start_linenum_ = -1; int end_linenum_ = -1; - bool is_desired_ = false; // IWYU will recommend this line - bool is_present_ = false; // line was present before the IWYU run - map<string, int> symbol_counts_; // how many times we referenced each symbol + bool is_desired_ = false; // IWYU will recommend this line + bool is_present_ = false; // line was present before the IWYU run + bool is_elaborated_type_ = false; // Fwd-decl introduced by elaborated type + map<string, int> symbol_counts_; // how many times we referenced each symbol // Only either two following members are set for includes string quoted_include_; // quoted file name we're including const clang::FileEntry* included_file_ = nullptr; // the file we're including @@ -258,6 +264,7 @@ class IwyuFileInfo { // the fwd-decl be removed, even if we don't see any uses of it. void AddForwardDeclare(const clang::NamedDecl* fwd_decl, bool definitely_keep_fwd_decl); + void AddElaboratedType(clang::ElaboratedTypeLoc); void AddUsingDecl(const clang::UsingDecl* using_decl); diff --git a/tests/cxx/elaborated_type.cc b/tests/cxx/elaborated_type.cc index a2ec2b3..fcbedab 100644 --- a/tests/cxx/elaborated_type.cc +++ b/tests/cxx/elaborated_type.cc @@ -60,6 +60,21 @@ void global_qualified_elab(class ::GlobalClass* c); // they must also be forward-declared. Elaboration::Template<int, float>* namespace_qualified_template; +// Elaborated types can be treated as forward-declarations, hence no fwd-decl is +// needed if a declaration is introduced by elaborated type. Implicit +// declaration introduction occurs at least when there isn't any previous +// declaration of the type in a translation unit. +void elaborated_first_elaborated(class FirstElaborated*); +void bare_first_elaborated(FirstElaborated*); +class FirstElaborated; +void previously_introduced(FirstElaborated*); + +// But if an elaborated type appears after the first fwd-decl use of the type, a +// true forward declaration is still needed. +class FirstForwardDeclared; +void bare_first_forward_declared(FirstForwardDeclared*); +void elaborated_first_forward_declared(class FirstForwardDeclared*); + /**** IWYU_SUMMARY tests/cxx/elaborated_type.cc should add these lines: @@ -74,11 +89,13 @@ tests/cxx/elaborated_type.cc should remove these lines: - #include "tests/cxx/elaborated_type_namespace.h" // lines XX-XX - #include "tests/cxx/elaborated_type_struct.h" // lines XX-XX - #include "tests/cxx/elaborated_type_union.h" // lines XX-XX +- class FirstElaborated; // lines XX-XX The full include-list for tests/cxx/elaborated_type.cc: #include "tests/cxx/elaborated_type_enum1.h" // for ElaborationEnum1 #include "tests/cxx/elaborated_type_enum2.h" // for ElaborationEnum2 class ElaborationClass; +class FirstForwardDeclared; // lines XX-XX class GlobalClass; // lines XX-XX namespace Elaboration { class Class; } namespace Elaboration { template <typename T, typename U> struct Template; } |