summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBolshakov <bolsh.andrey@yandex.ru>2023-03-26 21:28:23 +0300
committerKim Gräsman <kim.grasman@gmail.com>2023-04-16 16:13:39 +0200
commit5957e2fb928d97446a3905d09e6c317960c4622e (patch)
treefdbc7a255d43f6fcac176881cde2398baf3b2530
parent5317d11d3eefe99254d2d41c165e8402c3fb2aba (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.cc10
-rw-r--r--iwyu_output.cc23
-rw-r--r--iwyu_output.h13
-rw-r--r--tests/cxx/elaborated_type.cc17
4 files changed, 59 insertions, 4 deletions
diff --git a/iwyu.cc b/iwyu.cc
index bbb6ac3..5ee5da7 100644
--- a/iwyu.cc
+++ b/iwyu.cc
@@ -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; }