[clang-tools-extra] f82f5b0 - [include-cleaner] Introduce symbol to location mapping

Kadir Cetinkaya via cfe-commits cfe-commits at lists.llvm.org
Thu Dec 1 00:46:14 PST 2022


Author: Kadir Cetinkaya
Date: 2022-12-01T09:46:05+01:00
New Revision: f82f5b0507a25cbef1cf44fa5ef481c786a40473

URL: https://github.com/llvm/llvm-project/commit/f82f5b0507a25cbef1cf44fa5ef481c786a40473
DIFF: https://github.com/llvm/llvm-project/commit/f82f5b0507a25cbef1cf44fa5ef481c786a40473.diff

LOG: [include-cleaner] Introduce symbol to location mapping

Creates a one to many mapping, by returning all the possible locations
providing a symbol. Also includes an "is definition" signal for the
location, that can be used for ranking afterwards.

This also takes care of stdlib symbols by having a variant of locations.

Depends on D135859.

Differential Revision: https://reviews.llvm.org/D135953

Added: 
    clang-tools-extra/include-cleaner/unittests/LocateSymbolTest.cpp

Modified: 
    clang-tools-extra/include-cleaner/lib/AnalysisInternal.h
    clang-tools-extra/include-cleaner/lib/LocateSymbol.cpp
    clang-tools-extra/include-cleaner/unittests/CMakeLists.txt

Removed: 
    


################################################################################
diff  --git a/clang-tools-extra/include-cleaner/lib/AnalysisInternal.h b/clang-tools-extra/include-cleaner/lib/AnalysisInternal.h
index 29dbd58886abf..026bb8dd20501 100644
--- a/clang-tools-extra/include-cleaner/lib/AnalysisInternal.h
+++ b/clang-tools-extra/include-cleaner/lib/AnalysisInternal.h
@@ -24,7 +24,10 @@
 #include "clang-include-cleaner/Record.h"
 #include "clang-include-cleaner/Types.h"
 #include "clang/Basic/SourceLocation.h"
+#include "clang/Tooling/Inclusions/StandardLibrary.h"
 #include "llvm/ADT/STLFunctionalExtras.h"
+#include <variant>
+#include <vector>
 
 namespace clang {
 class ASTContext;
@@ -66,7 +69,6 @@ struct SymbolLocation {
   bool operator==(const SymbolLocation &RHS) const {
     return Storage == RHS.Storage;
   }
-
   SourceLocation physical() const { return std::get<Physical>(Storage); }
   tooling::stdlib::Symbol standard() const {
     return std::get<Standard>(Storage);
@@ -91,6 +93,9 @@ void writeHTMLReport(FileID File, const Includes &,
                      HeaderSearch &HS, PragmaIncludes *PI,
                      llvm::raw_ostream &OS);
 
+/// A set of locations that provides the declaration.
+std::vector<SymbolLocation> locateSymbol(const Symbol &S);
+
 } // namespace include_cleaner
 } // namespace clang
 

diff  --git a/clang-tools-extra/include-cleaner/lib/LocateSymbol.cpp b/clang-tools-extra/include-cleaner/lib/LocateSymbol.cpp
index 03c32e656ee49..cdfe5fda5e95f 100644
--- a/clang-tools-extra/include-cleaner/lib/LocateSymbol.cpp
+++ b/clang-tools-extra/include-cleaner/lib/LocateSymbol.cpp
@@ -1,4 +1,4 @@
-//===--- LocateSymbol.cpp -------------------------------------------------===//
+//===--- LocateSymbol.cpp - Find locations providing a symbol -------------===//
 //
 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 // See https://llvm.org/LICENSE.txt for license information.
@@ -7,10 +7,28 @@
 //===----------------------------------------------------------------------===//
 
 #include "AnalysisInternal.h"
+#include "clang/AST/DeclBase.h"
+#include "clang/Basic/SourceLocation.h"
+#include "clang/Tooling/Inclusions/StandardLibrary.h"
 #include "llvm/ADT/StringExtras.h"
 #include "llvm/Support/raw_ostream.h"
+#include <utility>
+#include <vector>
 
 namespace clang::include_cleaner {
+namespace {
+
+std::vector<SymbolLocation> locateDecl(const Decl &D) {
+  std::vector<SymbolLocation> Result;
+  // FIXME: Should we also provide physical locations?
+  if (auto SS = tooling::stdlib::Recognizer()(&D))
+    return {SymbolLocation(*SS)};
+  for (auto *Redecl : D.redecls())
+    Result.push_back(Redecl->getLocation());
+  return Result;
+}
+
+} // namespace
 
 llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const SymbolLocation &S) {
   switch (S.kind()) {
@@ -28,4 +46,13 @@ llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const SymbolLocation &S) {
   llvm_unreachable("Unhandled Symbol kind");
 }
 
-} // namespace clang::include_cleaner
\ No newline at end of file
+std::vector<SymbolLocation> locateSymbol(const Symbol &S) {
+  switch (S.kind()) {
+  case Symbol::Declaration:
+    return locateDecl(S.declaration());
+  case Symbol::Macro:
+    return {SymbolLocation(S.macro().Definition)};
+  }
+}
+
+} // namespace clang::include_cleaner

diff  --git a/clang-tools-extra/include-cleaner/unittests/CMakeLists.txt b/clang-tools-extra/include-cleaner/unittests/CMakeLists.txt
index 94640c3c2fc1f..d911b5df70c50 100644
--- a/clang-tools-extra/include-cleaner/unittests/CMakeLists.txt
+++ b/clang-tools-extra/include-cleaner/unittests/CMakeLists.txt
@@ -7,6 +7,7 @@ add_custom_target(ClangIncludeCleanerUnitTests)
 add_unittest(ClangIncludeCleanerUnitTests ClangIncludeCleanerTests
   AnalysisTest.cpp
   FindHeadersTest.cpp
+  LocateSymbolTest.cpp
   RecordTest.cpp
   TypesTest.cpp
   WalkASTTest.cpp

diff  --git a/clang-tools-extra/include-cleaner/unittests/LocateSymbolTest.cpp b/clang-tools-extra/include-cleaner/unittests/LocateSymbolTest.cpp
new file mode 100644
index 0000000000000..f347db927e27d
--- /dev/null
+++ b/clang-tools-extra/include-cleaner/unittests/LocateSymbolTest.cpp
@@ -0,0 +1,133 @@
+//===--- LocateSymbolTest.cpp -------------------------------------- C++-*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+#include "AnalysisInternal.h"
+#include "clang-include-cleaner/Types.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclBase.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/ASTMatchers/ASTMatchers.h"
+#include "clang/Basic/SourceLocation.h"
+#include "clang/Lex/Preprocessor.h"
+#include "clang/Testing/TestAST.h"
+#include "clang/Tooling/Inclusions/StandardLibrary.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/Casting.h"
+#include "llvm/Testing/Support/Annotations.h"
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+#include <cstddef>
+#include <memory>
+#include <unordered_map>
+#include <utility>
+#include <variant>
+#include <vector>
+
+namespace clang::include_cleaner {
+namespace {
+using testing::ElementsAre;
+using testing::ElementsAreArray;
+using testing::Pair;
+using testing::UnorderedElementsAre;
+
+// A helper for building ASTs and getting decls out of it by name. Example usage
+// looks like:
+//   LocateExample X("void ^foo();");
+//   Decl &Foo = X.findDecl("foo");
+//   X.points(); // returns all the points in annotated test input.
+struct LocateExample {
+private:
+  llvm::Annotations Target;
+  TestAST AST;
+
+public:
+  LocateExample(llvm::StringRef AnnotatedCode)
+      : Target(AnnotatedCode), AST([this] {
+          TestInputs Inputs(Target.code());
+          Inputs.ExtraArgs.push_back("-std=c++17");
+          return Inputs;
+        }()) {}
+
+  const Decl &findDecl(llvm::StringRef SymbolName) {
+    const NamedDecl *DeclToLocate;
+    struct MatchCB : public ast_matchers::MatchFinder::MatchCallback {
+      MatchCB(const NamedDecl *&Out) : Out(Out) {}
+      void run(const ast_matchers::MatchFinder::MatchResult &Result) override {
+        Out = Result.Nodes.getNodeAs<NamedDecl>("id");
+        assert(Out);
+        Out = llvm::cast<NamedDecl>(Out->getCanonicalDecl());
+      }
+      const NamedDecl *&Out;
+    } CB(DeclToLocate);
+    ast_matchers::MatchFinder Finder;
+    Finder.addMatcher(ast_matchers::namedDecl(
+                          ast_matchers::unless(ast_matchers::isImplicit()),
+                          ast_matchers::hasName(SymbolName))
+                          .bind("id"),
+                      &CB);
+    Finder.matchAST(AST.context());
+    if (!DeclToLocate)
+      ADD_FAILURE() << "Couldn't find any decls with name: " << SymbolName;
+    assert(DeclToLocate);
+    return *DeclToLocate;
+  }
+
+  Macro findMacro(llvm::StringRef Name) {
+    auto &PP = AST.preprocessor();
+    auto *II = PP.getIdentifierInfo(Name);
+    if (!II || !II->hasMacroDefinition()) {
+      ADD_FAILURE() << "Couldn't find any macros with name: " << Name;
+      return {};
+    }
+    auto MD = PP.getMacroDefinition(II);
+    assert(MD.getMacroInfo());
+    return {II, MD.getMacroInfo()->getDefinitionLoc()};
+  }
+
+  std::vector<SymbolLocation> points() {
+    auto &SM = AST.sourceManager();
+    auto FID = SM.getMainFileID();
+    auto Offsets = Target.points();
+    std::vector<SymbolLocation> Results;
+    for (auto &Offset : Offsets)
+      Results.emplace_back(SM.getComposedLoc(FID, Offset));
+    return Results;
+  }
+};
+
+TEST(LocateSymbol, Decl) {
+  // Looks for decl with name 'foo' and performs locateSymbol on it.
+  // Expects all the locations in the case to be returned as a location.
+  const llvm::StringLiteral Cases[] = {
+      "struct ^foo; struct ^foo {};",
+      "namespace ns { void ^foo(); void ^foo() {} }",
+      "enum class ^foo; enum class ^foo {};",
+  };
+
+  for (auto &Case : Cases) {
+    SCOPED_TRACE(Case);
+    LocateExample Test(Case);
+    EXPECT_THAT(locateSymbol(Test.findDecl("foo")),
+                ElementsAreArray(Test.points()));
+  }
+}
+
+TEST(LocateSymbol, Stdlib) {
+  LocateExample Test("namespace std { struct vector; }");
+  EXPECT_THAT(locateSymbol(Test.findDecl("vector")),
+              ElementsAre(*tooling::stdlib::Symbol::named("std::", "vector")));
+}
+
+TEST(LocateSymbol, Macros) {
+  // Make sure we preserve the last one.
+  LocateExample Test("#define FOO\n#undef FOO\n#define ^FOO");
+  EXPECT_THAT(locateSymbol(Test.findMacro("FOO")),
+              ElementsAreArray(Test.points()));
+}
+
+} // namespace
+} // namespace clang::include_cleaner


        


More information about the cfe-commits mailing list