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 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits