llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT--> @llvm/pr-subscribers-clang-tools-extra Author: wieDasDing (dingxiangfei2009) <details> <summary>Changes</summary> Use of initializer should constitute the use of the base type. It appears that we have not been recording such use sites which potentially go indirectly through incomplete forward declarations. --- Full diff: https://github.com/llvm/llvm-project/pull/230070.diff 3 Files Affected: - (modified) clang-tools-extra/include-cleaner/lib/WalkAST.cpp (+29-4) - (modified) clang-tools-extra/include-cleaner/unittests/AnalysisTest.cpp (+18) - (modified) clang-tools-extra/include-cleaner/unittests/WalkASTTest.cpp (+41) ``````````diff diff --git a/clang-tools-extra/include-cleaner/lib/WalkAST.cpp b/clang-tools-extra/include-cleaner/lib/WalkAST.cpp index 5449411371e60..be385a5411762 100644 --- a/clang-tools-extra/include-cleaner/lib/WalkAST.cpp +++ b/clang-tools-extra/include-cleaner/lib/WalkAST.cpp @@ -101,10 +101,14 @@ class ASTWalker : public RecursiveASTVisitor<ASTWalker> { NamedDecl *getMemberProvider(QualType Base) { if (Base->isPointerType()) return getMemberProvider(Base->getPointeeType()); - if (const auto *TT = dyn_cast<TypedefType>(Base)) - return TT->getDecl(); - if (const auto *UT = dyn_cast<UsingType>(Base)) - return UT->getDecl(); + // An alias of an incomplete record does not provide the record definition. + if (const auto *RT = Base->getAs<RecordType>(); + !RT || RT->getDecl()->isCompleteDefinition()) { + if (const auto *TT = dyn_cast<TypedefType>(Base)) + return TT->getDecl(); + if (const auto *UT = dyn_cast<UsingType>(Base)) + return UT->getDecl(); + } // A heuristic: to resolve a template type to **only** its template name. // We're only using this method for the base type of MemberExpr, in general // the template provides the member, and the critical case `unique_ptr<Foo>` @@ -248,6 +252,27 @@ class ASTWalker : public RecursiveASTVisitor<ASTWalker> { return true; } + bool VisitInitListExpr(InitListExpr *E) { + const InitListExpr *Sem = E->isSemanticForm() ? E : E->getSemanticForm(); + QualType Type = Sem ? Sem->getType() : E->getType(); + report(E->getBeginLoc(), getMemberProvider(Type), RefType::Implicit); + return true; + } + + bool VisitCXXParenListInitExpr(CXXParenListInitExpr *E) { + report(E->getBeginLoc(), getMemberProvider(E->getType()), + RefType::Implicit); + return true; + } + + bool VisitDesignatedInitExpr(DesignatedInitExpr *E) { + for (const DesignatedInitExpr::Designator &D : E->designators()) { + if (D.isFieldDesignator()) + report(D.getFieldLoc(), D.getFieldDecl(), RefType::Implicit); + } + return true; + } + bool VisitOverloadExpr(OverloadExpr *E) { // Since we can't prove which overloads are used, report all of them. for (NamedDecl *D : E->decls()) diff --git a/clang-tools-extra/include-cleaner/unittests/AnalysisTest.cpp b/clang-tools-extra/include-cleaner/unittests/AnalysisTest.cpp index 5df8792c93b2e..22cb9c5abdb24 100644 --- a/clang-tools-extra/include-cleaner/unittests/AnalysisTest.cpp +++ b/clang-tools-extra/include-cleaner/unittests/AnalysisTest.cpp @@ -445,6 +445,24 @@ TEST_F(AnalyzeTest, ImplicitOperatorNewDeleteNotUnused) { EXPECT_THAT(Results.Unused, testing::IsEmpty()); } +TEST_F(AnalyzeTest, ForwardDeclaredTypedefAggregateInit) { + Inputs.Code = R"cpp( +#include "fwd.h" +#include "def.h" + +static const Bar b = { 1 }; +)cpp"; + Inputs.ExtraFiles["fwd.h"] = guard("typedef struct Foo Bar;"); + Inputs.ExtraFiles["def.h"] = guard("struct Foo { int a; };"); + TestAST AST(Inputs); + auto Decls = AST.context().getTranslationUnitDecl()->decls(); + auto Results = + analyze(std::vector<Decl *>{Decls.begin(), Decls.end()}, + PP.MacroReferences, PP.Includes, &PI, AST.preprocessor()); + EXPECT_THAT(Results.Unused, testing::IsEmpty()); + EXPECT_THAT(Results.Missing, testing::IsEmpty()); +} + TEST(FixIncludes, Basic) { llvm::StringRef Code = R"cpp(#include "d.h" #include "a.h" diff --git a/clang-tools-extra/include-cleaner/unittests/WalkASTTest.cpp b/clang-tools-extra/include-cleaner/unittests/WalkASTTest.cpp index c9519c2e91b68..519368b23ddac 100644 --- a/clang-tools-extra/include-cleaner/unittests/WalkASTTest.cpp +++ b/clang-tools-extra/include-cleaner/unittests/WalkASTTest.cpp @@ -472,6 +472,22 @@ TEST(WalkAST, MemberExprs) { namespace ns { template<typename> struct Foo { int a; }; } using ns::$implicit^Foo;)cpp", "void k(Foo<int> b) { b.^a; }"); + // If the alias points to an incomplete forward declaration, look through to + // the underlying record declaration. + testWalk(R"cpp( + typedef struct $implicit^Foo Bar; + struct Foo { int a; };)cpp", + "void test(Bar b) { b.^a; }"); + testWalk(R"cpp( + typedef struct $implicit^Foo Bar; + typedef Bar Baz; + struct Foo { int a; };)cpp", + "void test(Baz b) { b.^a; }"); + testWalk(R"cpp( + namespace ns { struct $implicit^Foo; } + using Bar = ns::Foo; + namespace ns { struct Foo { int a; }; })cpp", + "void test(Bar b) { b.^a; }"); // Test the dependent-type case (CXXDependentScopeMemberExpr) testWalk("template<typename T> struct $implicit^Base { void method(); };", "template<typename T> void k(Base<T> t) { t.^method(); }"); @@ -487,6 +503,31 @@ TEST(WalkAST, ConstructExprs) { testWalk("struct $implicit^S { S(int); };", "S ^t(42);"); testWalk("struct $implicit^S { S(int); };", "S t = ^42;"); testWalk("namespace ns { struct S{}; } using ns::$implicit^S;", "S ^t;"); + testWalk("typedef struct $implicit^S T; struct S {};", "T ^t;"); +} + +TEST(WalkAST, InitListExprs) { + testWalk("struct $implicit^S { int a; };", "S s = ^{1};"); + testWalk("struct $implicit^S { int a; };", "S s^(1);"); + testWalk("struct S { int $implicit^a; };", "S s = {.^a = 1};"); + testWalk("struct S { int a; }; using $implicit^T = S;", "T s = ^{1};"); + testWalk(R"cpp( + typedef struct $implicit^Foo Bar; + struct Foo { int a; };)cpp", + "Bar b = ^{1};"); + testWalk(R"cpp( + typedef struct $implicit^Foo Bar; + using Baz = Bar; + struct Foo { int a; };)cpp", + "Baz b = ^{1};"); + testWalk(R"cpp( + typedef struct $implicit^Foo Bar; + struct Foo { int a; };)cpp", + "Bar b = ^{.a = 1};"); + testWalk(R"cpp( + typedef struct Foo Bar; + struct Foo { int $implicit^a; };)cpp", + "Bar b = {.^a = 1};"); } TEST(WalkAST, Operator) { `````````` </details> https://github.com/llvm/llvm-project/pull/230070 _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
