kadircet updated this revision to Diff 476091.
kadircet added a comment.

- Rebase
- Move to new file
- Handle macros
- Change from boolean output to enum for signalling


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D135953/new/

https://reviews.llvm.org/D135953

Files:
  clang-tools-extra/include-cleaner/include/clang-include-cleaner/Types.h
  clang-tools-extra/include-cleaner/lib/AnalysisInternal.h
  clang-tools-extra/include-cleaner/lib/LocateSymbol.cpp
  clang-tools-extra/include-cleaner/lib/WalkAST.cpp
  clang-tools-extra/include-cleaner/unittests/CMakeLists.txt
  clang-tools-extra/include-cleaner/unittests/LocateSymbolTest.cpp
  clang-tools-extra/include-cleaner/unittests/WalkASTTest.cpp

Index: clang-tools-extra/include-cleaner/unittests/WalkASTTest.cpp
===================================================================
--- clang-tools-extra/include-cleaner/unittests/WalkASTTest.cpp
+++ clang-tools-extra/include-cleaner/unittests/WalkASTTest.cpp
@@ -7,12 +7,14 @@
 //===----------------------------------------------------------------------===//
 #include "AnalysisInternal.h"
 #include "clang/AST/ASTContext.h"
+#include "clang/AST/Decl.h"
 #include "clang/Basic/FileManager.h"
 #include "clang/Basic/SourceLocation.h"
 #include "clang/Frontend/TextDiagnostic.h"
 #include "clang/Testing/TestAST.h"
 #include "llvm/ADT/ArrayRef.h"
 #include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/Twine.h"
 #include "llvm/Support/Error.h"
 #include "llvm/Support/ScopedPrinter.h"
 #include "llvm/Testing/Support/Annotations.h"
@@ -20,6 +22,7 @@
 #include <cstddef>
 #include <unordered_map>
 #include <utility>
+#include <variant>
 #include <vector>
 
 namespace clang::include_cleaner {
Index: clang-tools-extra/include-cleaner/unittests/LocateSymbolTest.cpp
===================================================================
--- /dev/null
+++ clang-tools-extra/include-cleaner/unittests/LocateSymbolTest.cpp
@@ -0,0 +1,96 @@
+//===--- 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/AST/ASTContext.h"
+#include "clang/AST/Decl.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 "llvm/ADT/StringRef.h"
+#include "llvm/ADT/Twine.h"
+#include "llvm/Support/Casting.h"
+#include "llvm/Testing/Support/Annotations.h"
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+#include <cstddef>
+#include <unordered_map>
+#include <utility>
+#include <variant>
+#include <vector>
+
+namespace clang::include_cleaner {
+namespace {
+using testing::Pair;
+using testing::UnorderedElementsAre;
+
+// Looks for decl with name \p SymbolName and performs locateSymbol on it.
+// Expects all the locations marked in `Code` with the right annotation to be
+// generated.
+void testLocate(llvm::StringRef Code, llvm::StringRef SymbolName = "foo") {
+  llvm::Annotations Target(Code);
+
+  TestInputs Inputs(Target.code());
+  Inputs.ExtraArgs.push_back("-std=c++17");
+  TestAST AST(Inputs);
+  const auto &SM = AST.sourceManager();
+
+  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());
+  ASSERT_TRUE(DeclToLocate);
+  std::vector<std::pair<size_t, llvm::StringRef>> ReferencedOffsets;
+  for (auto Loc : locateSymbol(*DeclToLocate)) {
+    switch (Loc.first.kind()) {
+    case SymbolLocation::Physical: {
+      auto [FID, Offset] =
+          SM.getDecomposedLoc(SM.getFileLoc(Loc.first.physical()));
+      ASSERT_EQ(FID, SM.getMainFileID());
+      ReferencedOffsets.push_back(
+          {Offset,
+           llvm::StringRef(bool(Loc.second & Hint::Complete) ? "$def" : "")});
+      break;
+    }
+    case SymbolLocation::Standard:
+      EXPECT_TRUE(bool(Loc.second & Hint::Complete));
+      EXPECT_EQ(Loc.first.standard().name(), SymbolName);
+      break;
+    }
+  }
+  llvm::sort(ReferencedOffsets);
+  auto AnnotatedCode = Target.code().str();
+  for (auto [Offset, Annotation] : llvm::reverse(ReferencedOffsets))
+    AnnotatedCode.insert(Offset, (Annotation + "^").str());
+  EXPECT_EQ(Code, AnnotatedCode);
+}
+
+TEST(LocateDecl, General) {
+  testLocate("struct ^foo; struct $def^foo {};");
+  testLocate("namespace ns { void ^foo(); void $def^foo() {} }");
+  testLocate("enum class ^foo; enum class $def^foo {};");
+  // Check for stdlib matching.
+  testLocate("namespace std { struct vector; }", "vector");
+}
+
+} // namespace
+} // namespace clang::include_cleaner
Index: clang-tools-extra/include-cleaner/unittests/CMakeLists.txt
===================================================================
--- clang-tools-extra/include-cleaner/unittests/CMakeLists.txt
+++ clang-tools-extra/include-cleaner/unittests/CMakeLists.txt
@@ -7,6 +7,7 @@
 add_unittest(ClangIncludeCleanerUnitTests ClangIncludeCleanerTests
   AnalysisTest.cpp
   FindHeadersTest.cpp
+  LocateSymbolTest.cpp
   RecordTest.cpp
   WalkASTTest.cpp
 )
Index: clang-tools-extra/include-cleaner/lib/WalkAST.cpp
===================================================================
--- clang-tools-extra/include-cleaner/lib/WalkAST.cpp
+++ clang-tools-extra/include-cleaner/lib/WalkAST.cpp
@@ -17,8 +17,11 @@
 #include "clang/AST/TypeLoc.h"
 #include "clang/Basic/SourceLocation.h"
 #include "clang/Basic/SourceManager.h"
+#include "clang/Tooling/Inclusions/StandardLibrary.h"
 #include "llvm/ADT/STLExtras.h"
 #include "llvm/Support/Casting.h"
+#include <utility>
+#include <vector>
 
 namespace clang::include_cleaner {
 namespace {
Index: clang-tools-extra/include-cleaner/lib/LocateSymbol.cpp
===================================================================
--- clang-tools-extra/include-cleaner/lib/LocateSymbol.cpp
+++ 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,55 @@
 //===----------------------------------------------------------------------===//
 
 #include "AnalysisInternal.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclCXX.h"
+#include "clang/AST/DeclTemplate.h"
+#include "clang/Basic/SourceLocation.h"
+#include "clang/Tooling/Inclusions/StandardLibrary.h"
 #include "llvm/ADT/StringExtras.h"
+#include "llvm/Support/Casting.h"
 #include "llvm/Support/raw_ostream.h"
+#include <utility>
+#include <vector>
 
 namespace clang::include_cleaner {
+namespace {
+// Looks for a visible definition of \p D. Returns nullptr if none is available,
+// or there are possibly multiple definitions (e.g. namespaces).
+const Decl *getDefinition(const Decl *D) {
+  if (const auto *TD = dyn_cast<TagDecl>(D))
+    return TD->getDefinition();
+  if (const auto *VD = dyn_cast<VarDecl>(D))
+    return VD->getDefinition();
+  if (const auto *FD = dyn_cast<FunctionDecl>(D))
+    return FD->getDefinition();
+  if (const auto *CTD = dyn_cast<ClassTemplateDecl>(D))
+    if (const auto *RD = CTD->getTemplatedDecl())
+      return RD->getDefinition();
+  if (isa<ValueDecl>(D) || isa<TemplateTypeParmDecl>(D) ||
+      isa<TemplateTemplateParmDecl>(D))
+    return D;
+  return nullptr;
+}
+
+std::vector<HintedLocation> locateDecl(const Decl &D) {
+  std::vector<HintedLocation> Result;
+  // FIXME: Should we also provide physical locations?
+  if (auto SS = tooling::stdlib::Recognizer()(&D))
+    return {{*SS, Hint::Complete}};
+  SourceLocation DefLoc;
+  if (auto *Def = getDefinition(&D)) {
+    DefLoc = Def->getLocation();
+    Result.push_back({DefLoc, Hint::Complete});
+  }
+  for (auto *Redecl : D.redecls()) {
+    if (Redecl->getLocation() != DefLoc)
+      Result.push_back({Redecl->getLocation(), Hint::Declaration});
+  }
+  return Result;
+}
+
+} // namespace
 
 llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const SymbolLocation &S) {
   switch (S.kind()) {
@@ -28,4 +73,13 @@
   llvm_unreachable("Unhandled Symbol kind");
 }
 
-} // namespace clang::include_cleaner
\ No newline at end of file
+std::vector<HintedLocation> locateSymbol(const Symbol &S) {
+  switch (S.kind()) {
+  case Symbol::Declaration:
+    return locateDecl(S.declaration());
+  case Symbol::Macro:
+    return {{S.macro().Definition, Hint::Complete}};
+  }
+}
+
+} // namespace clang::include_cleaner
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
@@ -24,7 +24,13 @@
 #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/BitmaskEnum.h"
 #include "llvm/ADT/STLFunctionalExtras.h"
+#include <cstdint>
+#include <utility>
+#include <variant>
+#include <vector>
 
 namespace clang {
 class ASTContext;
@@ -65,7 +71,6 @@
   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);
@@ -77,6 +82,18 @@
 };
 llvm::raw_ostream &operator<<(llvm::raw_ostream &, const Header &);
 
+/// Represents properties of a symbol provider.
+/// FIXME: Expose in public API for decision making (ranking, ignoring, etc.).
+enum class Hint : uint8_t {
+  /// Declaration for the symbol, which is provided by all locations.
+  Declaration = 0,
+  /// Complete definition for the symbol.
+  Complete = 1,
+  // FIXME: Add header based hints, e.g. IWYU mappings, header-symbol name.
+  LLVM_MARK_AS_BITMASK_ENUM(Complete),
+};
+LLVM_ENABLE_BITMASK_ENUMS_IN_NAMESPACE();
+
 /// Finds the headers that provide the symbol location.
 // FIXME: expose signals
 llvm::SmallVector<Header> findHeaders(const SymbolLocation &Loc,
@@ -88,6 +105,10 @@
 void writeHTMLReport(FileID File, llvm::ArrayRef<Decl *> Roots, ASTContext &Ctx,
                      llvm::raw_ostream &OS);
 
+using HintedLocation = std::pair<SymbolLocation, Hint>;
+/// A set of locations that provides the declaration.
+std::vector<HintedLocation> locateSymbol(const Symbol &S);
+
 } // namespace include_cleaner
 } // namespace clang
 
Index: clang-tools-extra/include-cleaner/include/clang-include-cleaner/Types.h
===================================================================
--- clang-tools-extra/include-cleaner/include/clang-include-cleaner/Types.h
+++ clang-tools-extra/include-cleaner/include/clang-include-cleaner/Types.h
@@ -64,7 +64,6 @@
   struct Macro macro() const { return std::get<Macro>(Storage); }
 
 private:
-  // FIXME: Add support for macros.
   // Order must match Kind enum!
   std::variant<const Decl *, struct Macro> Storage;
 };
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to