[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