hokein created this revision.
hokein added reviewers: kadircet, sammccall.
Herald added a project: All.
hokein requested review of this revision.
Herald added a project: clang-tools-extra.

A HTML report of gtest after this patch:
https://gist.githubusercontent.com/hokein/73eee6f65a803e5702d8388c187524a6/raw/cf05a503519703a2fb87840bb0b270fe11a7a9fd/RecordTest.html


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D138779

Files:
  clang-tools-extra/include-cleaner/lib/Analysis.cpp
  clang-tools-extra/include-cleaner/lib/AnalysisInternal.h
  clang-tools-extra/include-cleaner/lib/FindHeaders.cpp
  clang-tools-extra/include-cleaner/lib/HTMLReport.cpp
  clang-tools-extra/include-cleaner/unittests/AnalysisTest.cpp

Index: clang-tools-extra/include-cleaner/unittests/AnalysisTest.cpp
===================================================================
--- clang-tools-extra/include-cleaner/unittests/AnalysisTest.cpp
+++ clang-tools-extra/include-cleaner/unittests/AnalysisTest.cpp
@@ -25,6 +25,8 @@
 
 namespace clang::include_cleaner {
 namespace {
+using testing::AllOf;
+using testing::Not;
 using testing::Pair;
 using testing::UnorderedElementsAre;
 
@@ -134,6 +136,118 @@
       UnorderedElementsAre(Pair(Main.point(), UnorderedElementsAre(HdrFile))));
 }
 
+MATCHER(isMacroLoc, "") { return arg.isMacroID(); }
+MATCHER_P3(expandedAt, FileID, Offset, SM, "") {
+  auto [ExpanedFileID, ExpandedOffset] = SM->getDecomposedExpansionLoc(arg);
+  return ExpanedFileID == FileID && ExpandedOffset == Offset;
+}
+MATCHER_P3(spelledAt, FileID, Offset, SM, "") {
+  auto [SpelledFileID, SpelledOffset] = SM->getDecomposedSpellingLoc(arg);
+  return SpelledFileID == FileID && SpelledOffset == Offset;
+}
+TEST(WalkUsed, FilterRefsNotSpelledInMainFile) {
+  llvm::Annotations Main(R"cpp(
+    #include "header.h"
+
+    // Macros defined in main file.
+    #define PLUS_ONE(X) X+1;
+    #define CALL_FUN $func_spelled^func()
+
+    #define M 1
+    #define USE_M $M1^$M2_spelled^M
+
+    void test(int a) {
+      // Tests for decl refs.
+      // The ref of `func()` is spelled in the main-file macro body.
+      $func_expanded^CALL_FUN;
+
+      // Refs of `a` are spelled in the main file (via macro arg).
+      $a1_expanded^PLUS_ONE($a1_spelled^a);
+      $a2_expanded^HDR_PLUS_ONE($a2_spelled^a);
+
+      // Refs of `func()` and `a` are from macro body which are spelled outside
+      // the main file, thus filtered out.
+      HDR_CALL_FUN;
+      HDR_A_PLUS_ONE;
+
+      // Tests for macro refs.
+      // 2 macro refs of `M`:
+      //   - M1 is a file loc, spelled in the macro body of USE_M
+      //   - M2 is a macro loc, expanded by the macro USE_M usage.
+      $M2_expanded^USE_M;
+      // Macro refs of `HDR_M` not spelled in main file, thus filtered out.
+      HDR_USE_M;
+    }
+  )cpp");
+  TestInputs Inputs(Main.code());
+  Inputs.ExtraFiles["header.h"] = guard(R"cpp(
+    #define HDR_PLUS_ONE(X) X + 1
+    #define HDR_A_PLUS_ONE a + 1
+    #define HDR_CALL_FUN func()
+
+    void func();
+
+    #define HDR_M 1
+    #define HDR_USE_M HDR_M
+  )cpp");
+  RecordedPP Recorded;
+  Inputs.MakeAction = [&]() {
+    struct RecordAction : public SyntaxOnlyAction {
+      RecordedPP &Out;
+      RecordAction(RecordedPP &Out) : Out(Out) {}
+      bool BeginSourceFileAction(clang::CompilerInstance &CI) override {
+        auto &PP = CI.getPreprocessor();
+        PP.addPPCallbacks(Out.record(PP));
+        return true;
+      }
+    };
+    return std::make_unique<RecordAction>(Recorded);
+  };
+  TestAST AST(Inputs);
+
+  llvm::SmallVector<Decl *> TopLevelDecls;
+  for (Decl *D : AST.context().getTranslationUnitDecl()->decls())
+    TopLevelDecls.emplace_back(D);
+  auto &SM = AST.sourceManager();
+  FileID MainFID = SM.getMainFileID();
+  llvm::StringMap<std::vector<SourceLocation>> SymbolRefs;
+  walkUsed(
+      TopLevelDecls, Recorded.MacroReferences, /*PragmaIncludes=*/nullptr, SM,
+      [&](const SymbolReference &Ref, llvm::ArrayRef<Header>) {
+        switch (Ref.Target.kind()) {
+        case Symbol::Declaration:
+          SymbolRefs[dyn_cast<NamedDecl>(&Ref.Target.declaration())->getName()]
+              .push_back(Ref.RefLocation);
+          break;
+        case Symbol::Macro:
+          SymbolRefs[Ref.Target.macro().Name->getName()].push_back(
+              Ref.RefLocation);
+          break;
+        }
+      });
+  EXPECT_THAT(SymbolRefs.lookup("func"),
+              UnorderedElementsAre(
+                  AllOf(isMacroLoc(),
+                        expandedAt(MainFID, Main.point("func_expanded"), &SM),
+                        spelledAt(MainFID, Main.point("func_spelled"), &SM))));
+  EXPECT_THAT(SymbolRefs.lookup("a"),
+              UnorderedElementsAre(
+                  AllOf(isMacroLoc(),
+                        expandedAt(MainFID, Main.point("a1_expanded"), &SM),
+                        spelledAt(MainFID, Main.point("a1_spelled"), &SM)),
+                  AllOf(isMacroLoc(),
+                        expandedAt(MainFID, Main.point("a2_expanded"), &SM),
+                        spelledAt(MainFID, Main.point("a2_spelled"), &SM))));
+
+  EXPECT_THAT(
+      SymbolRefs.lookup("M"),
+      UnorderedElementsAre(
+          AllOf(Not(isMacroLoc()), spelledAt(MainFID, Main.point("M1"), &SM)),
+          AllOf(isMacroLoc(),
+                expandedAt(MainFID, Main.point("M2_expanded"), &SM),
+                spelledAt(MainFID, Main.point("M2_spelled"), &SM))));
+  EXPECT_THAT(SymbolRefs.lookup("HDR_M"), testing::IsEmpty());
+}
 
 } // namespace
 } // namespace clang::include_cleaner
Index: clang-tools-extra/include-cleaner/lib/HTMLReport.cpp
===================================================================
--- clang-tools-extra/include-cleaner/lib/HTMLReport.cpp
+++ clang-tools-extra/include-cleaner/lib/HTMLReport.cpp
@@ -529,10 +529,15 @@
   Reporter R(OS, Ctx, HS, Includes, PI, File);
   for (Decl *Root : Roots)
     walkAST(*Root, [&](SourceLocation Loc, const NamedDecl &D, RefType T) {
+      if (!isSpelledInMainFile(Loc, Ctx.getSourceManager()))
+        return;
       R.addRef(SymbolReference{Loc, D, T});
     });
-  for (const SymbolReference &Ref : MacroRefs)
+  for (const SymbolReference &Ref : MacroRefs) {
+    if (!isSpelledInMainFile(Ref.RefLocation, Ctx.getSourceManager()))
+      continue;
     R.addRef(Ref);
+  }
   R.write();
 }
 
Index: clang-tools-extra/include-cleaner/lib/FindHeaders.cpp
===================================================================
--- clang-tools-extra/include-cleaner/lib/FindHeaders.cpp
+++ clang-tools-extra/include-cleaner/lib/FindHeaders.cpp
@@ -54,4 +54,8 @@
   llvm_unreachable("unhandled SymbolLocation kind!");
 }
 
+bool isSpelledInMainFile(SourceLocation Loc, const SourceManager &SM) {
+  return SM.isWrittenInMainFile(Loc.isMacroID() ? SM.getSpellingLoc(Loc) : Loc);
+}
+
 } // namespace clang::include_cleaner
\ No newline at end of file
Index: clang-tools-extra/include-cleaner/lib/AnalysisInternal.h
===================================================================
--- clang-tools-extra/include-cleaner/lib/AnalysisInternal.h
+++ clang-tools-extra/include-cleaner/lib/AnalysisInternal.h
@@ -84,6 +84,9 @@
                                       const SourceManager &SM,
                                       const PragmaIncludes *PI);
 
+/// Returns true if the given source location is spelled in the main file.
+bool isSpelledInMainFile(SourceLocation Loc, const SourceManager &SM);
+
 /// Write an HTML summary of the analysis to the given stream.
 void writeHTMLReport(FileID File, const RecordedPP::RecordedIncludes &Includes,
                      llvm::ArrayRef<Decl *> Roots,
Index: clang-tools-extra/include-cleaner/lib/Analysis.cpp
===================================================================
--- clang-tools-extra/include-cleaner/lib/Analysis.cpp
+++ clang-tools-extra/include-cleaner/lib/Analysis.cpp
@@ -26,6 +26,8 @@
   for (auto *Root : ASTRoots) {
     auto &SM = Root->getASTContext().getSourceManager();
     walkAST(*Root, [&](SourceLocation Loc, NamedDecl &ND, RefType RT) {
+      if (!isSpelledInMainFile(Loc, SM))
+        return;
       SymbolReference SymRef{Loc, ND, RT};
       if (auto SS = Recognizer(&ND)) {
         // FIXME: Also report forward decls from main-file, so that the caller
@@ -38,6 +40,8 @@
   }
   for (const SymbolReference &MacroRef : MacroRefs) {
     assert(MacroRef.Target.kind() == Symbol::Macro);
+    if (!isSpelledInMainFile(MacroRef.RefLocation, SM))
+      continue;
     CB(MacroRef, findHeaders(MacroRef.Target.macro().Definition, SM, PI));
   }
 }
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to