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