[clang-tools-extra] ce286ec - [IncludeCleaner] Add public API
Kadir Cetinkaya via cfe-commits
cfe-commits at lists.llvm.org
Mon Oct 24 08:06:21 PDT 2022
Author: Kadir Cetinkaya
Date: 2022-10-24T17:06:15+02:00
New Revision: ce286eccacd660f2b71cba15d9b83fe2217e36b8
URL: https://github.com/llvm/llvm-project/commit/ce286eccacd660f2b71cba15d9b83fe2217e36b8
DIFF: https://github.com/llvm/llvm-project/commit/ce286eccacd660f2b71cba15d9b83fe2217e36b8.diff
LOG: [IncludeCleaner] Add public API
Introduces walkUsed, a very simple version of the public API to enable
incremental development on rest of the pieces.
Differential Revision: https://reviews.llvm.org/D136293
Added:
clang-tools-extra/include-cleaner/include/clang-include-cleaner/Analysis.h
clang-tools-extra/include-cleaner/lib/Analysis.cpp
clang-tools-extra/include-cleaner/unittests/AnalysisTest.cpp
Modified:
clang-tools-extra/include-cleaner/lib/CMakeLists.txt
clang-tools-extra/include-cleaner/lib/WalkAST.cpp
clang-tools-extra/include-cleaner/unittests/CMakeLists.txt
clang-tools-extra/include-cleaner/unittests/WalkASTTest.cpp
Removed:
################################################################################
diff --git a/clang-tools-extra/include-cleaner/include/clang-include-cleaner/Analysis.h b/clang-tools-extra/include-cleaner/include/clang-include-cleaner/Analysis.h
new file mode 100644
index 0000000000000..0c28119831988
--- /dev/null
+++ b/clang-tools-extra/include-cleaner/include/clang-include-cleaner/Analysis.h
@@ -0,0 +1,75 @@
+//===--- Analysis.h - Analyze symbol references in AST ------------- 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
+//
+//===----------------------------------------------------------------------===//
+/// A library that provides usage analysis for symbols based on AST analysis.
+//===----------------------------------------------------------------------===//
+
+#ifndef CLANG_INCLUDE_CLEANER_ANALYSIS_H
+#define CLANG_INCLUDE_CLEANER_ANALYSIS_H
+
+#include "clang/Tooling/Inclusions/StandardLibrary.h"
+#include "llvm/ADT/STLFunctionalExtras.h"
+#include <variant>
+
+namespace clang {
+class SourceLocation;
+class Decl;
+class FileEntry;
+namespace include_cleaner {
+
+/// An entity that can be referenced in the code.
+struct Symbol {
+ Symbol(Decl &D) : Storage(&D) {}
+ Symbol(tooling::stdlib::Symbol S) : Storage(S) {}
+
+private:
+ // FIXME: Add support for macros.
+ std::variant<const Decl *, tooling::stdlib::Symbol> Storage;
+};
+
+/// Represents a file that provides some symbol. Might not be includeable, e.g.
+/// built-in or main-file itself.
+struct Header {
+ /// A physical (or logical, in case of a builtin) file.
+ Header(const FileEntry *FE) : Storage(FE) {}
+ /// A logical file representing a stdlib header.
+ Header(tooling::stdlib::Header H) : Storage(H) {}
+
+ bool operator==(const Header &RHS) const { return Storage == RHS.Storage; }
+
+private:
+ // FIXME: Handle verbatim spellings.
+ std::variant<const FileEntry *, tooling::stdlib::Header> Storage;
+};
+/// A UsedSymbolCB is a callback invoked for each symbol reference seen.
+///
+/// References occur at a particular location, refer to a single symbol, and
+/// that symbol may be provided by several headers.
+/// FIXME: Provide signals about the reference type and providing headers so the
+/// caller can filter and rank the results.
+using UsedSymbolCB = llvm::function_ref<void(
+ SourceLocation RefLoc, Symbol Target, llvm::ArrayRef<Header> Providers)>;
+
+/// Find and report all references to symbols in a region of code.
+///
+/// The AST traversal is rooted at ASTRoots - typically top-level declarations
+/// of a single source file.
+/// FIXME: Handle macro uses.
+///
+/// This is the main entrypoint of the include-cleaner library, and can be used:
+/// - to diagnose missing includes: a referenced symbol is provided by
+/// headers which don't match any #include in the main file
+/// - to diagnose unused includes: an #include in the main file does not match
+/// the headers for any referenced symbol
+/// FIXME: Take in an include structure to improve location to header mappings
+/// (e.g. IWYU pragmas).
+void walkUsed(llvm::ArrayRef<Decl *> ASTRoots, UsedSymbolCB CB);
+
+} // namespace include_cleaner
+} // namespace clang
+
+#endif
diff --git a/clang-tools-extra/include-cleaner/lib/Analysis.cpp b/clang-tools-extra/include-cleaner/lib/Analysis.cpp
new file mode 100644
index 0000000000000..72fac3c9c0084
--- /dev/null
+++ b/clang-tools-extra/include-cleaner/lib/Analysis.cpp
@@ -0,0 +1,50 @@
+//===--- Analysis.cpp -----------------------------------------------------===//
+//
+// 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 "clang-include-cleaner/Analysis.h"
+#include "AnalysisInternal.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/Tooling/Inclusions/StandardLibrary.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/SmallVector.h"
+
+namespace clang::include_cleaner {
+namespace {
+llvm::SmallVector<Header>
+toHeader(llvm::ArrayRef<tooling::stdlib::Header> Headers) {
+ llvm::SmallVector<Header> Result;
+ llvm::for_each(Headers, [&](tooling::stdlib::Header H) {
+ Result.emplace_back(Header(H));
+ });
+ return Result;
+}
+
+} // namespace
+void walkUsed(llvm::ArrayRef<Decl *> ASTRoots, UsedSymbolCB CB) {
+ tooling::stdlib::Recognizer Recognizer;
+ for (auto *Root : ASTRoots) {
+ auto &SM = Root->getASTContext().getSourceManager();
+ walkAST(*Root, [&](SourceLocation Loc, NamedDecl &ND) {
+ if (auto SS = Recognizer(&ND)) {
+ // FIXME: Also report forward decls from main-file, so that the caller
+ // can decide to insert/ignore a header.
+ return CB(Loc, Symbol(*SS), toHeader(SS->headers()));
+ }
+ // FIXME: Extract locations from redecls.
+ // FIXME: Handle IWYU pragmas, non self-contained files.
+ // FIXME: Handle macro locations.
+ if (auto *FE = SM.getFileEntryForID(SM.getFileID(ND.getLocation())))
+ return CB(Loc, Symbol(ND), {Header(FE)});
+ });
+ }
+ // FIXME: Handle references of macros.
+}
+
+} // namespace clang::include_cleaner
diff --git a/clang-tools-extra/include-cleaner/lib/CMakeLists.txt b/clang-tools-extra/include-cleaner/lib/CMakeLists.txt
index b255abca7499d..759261e90499a 100644
--- a/clang-tools-extra/include-cleaner/lib/CMakeLists.txt
+++ b/clang-tools-extra/include-cleaner/lib/CMakeLists.txt
@@ -1,6 +1,7 @@
set(LLVM_LINK_COMPONENTS Support)
add_clang_library(clangIncludeCleaner
+ Analysis.cpp
HTMLReport.cpp
Record.cpp
WalkAST.cpp
@@ -9,5 +10,6 @@ add_clang_library(clangIncludeCleaner
clangAST
clangBasic
clangLex
+ clangToolingInclusionsStdlib
)
diff --git a/clang-tools-extra/include-cleaner/lib/WalkAST.cpp b/clang-tools-extra/include-cleaner/lib/WalkAST.cpp
index b7354fe300e04..a86534337c273 100644
--- a/clang-tools-extra/include-cleaner/lib/WalkAST.cpp
+++ b/clang-tools-extra/include-cleaner/lib/WalkAST.cpp
@@ -9,8 +9,7 @@
#include "AnalysisInternal.h"
#include "clang/AST/RecursiveASTVisitor.h"
-namespace clang {
-namespace include_cleaner {
+namespace clang::include_cleaner {
namespace {
using DeclCallback = llvm::function_ref<void(SourceLocation, NamedDecl &)>;
@@ -43,5 +42,4 @@ void walkAST(Decl &Root, DeclCallback Callback) {
ASTWalker(Callback).TraverseDecl(&Root);
}
-} // namespace include_cleaner
-} // namespace clang
+} // namespace clang::include_cleaner
diff --git a/clang-tools-extra/include-cleaner/unittests/AnalysisTest.cpp b/clang-tools-extra/include-cleaner/unittests/AnalysisTest.cpp
new file mode 100644
index 0000000000000..c7bb12f34b972
--- /dev/null
+++ b/clang-tools-extra/include-cleaner/unittests/AnalysisTest.cpp
@@ -0,0 +1,69 @@
+//===--- AnalysisTest.cpp -------------------------------------------------===//
+//
+// 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 "clang-include-cleaner/Analysis.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/Basic/FileManager.h"
+#include "clang/Basic/SourceLocation.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/Testing/TestAST.h"
+#include "clang/Tooling/Inclusions/StandardLibrary.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/Testing/Support/Annotations.h"
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+#include <cstddef>
+
+namespace clang::include_cleaner {
+namespace {
+using testing::Pair;
+using testing::UnorderedElementsAre;
+
+TEST(WalkUsed, Basic) {
+ // FIXME: Have a fixture for setting up tests.
+ llvm::Annotations HeaderCode(R"cpp(
+ void foo();
+ namespace std { class vector {}; })cpp");
+ llvm::Annotations Code(R"cpp(
+ void bar() {
+ $foo^foo();
+ std::$vector^vector v;
+ }
+ )cpp");
+ TestInputs Inputs(Code.code());
+ Inputs.ExtraFiles["header.h"] = HeaderCode.code().str();
+ Inputs.ExtraArgs.push_back("-include");
+ Inputs.ExtraArgs.push_back("header.h");
+ TestAST AST(Inputs);
+
+ llvm::SmallVector<Decl *> TopLevelDecls;
+ for (Decl *D : AST.context().getTranslationUnitDecl()->decls()) {
+ TopLevelDecls.emplace_back(D);
+ }
+
+ auto &SM = AST.sourceManager();
+ llvm::DenseMap<size_t, std::vector<Header>> OffsetToProviders;
+ walkUsed(TopLevelDecls, [&](SourceLocation RefLoc, Symbol S,
+ llvm::ArrayRef<Header> Providers) {
+ auto [FID, Offset] = SM.getDecomposedLoc(RefLoc);
+ EXPECT_EQ(FID, SM.getMainFileID());
+ OffsetToProviders.try_emplace(Offset, Providers.vec());
+ });
+ auto HeaderFile = AST.fileManager().getFile("header.h").get();
+ EXPECT_THAT(
+ OffsetToProviders,
+ UnorderedElementsAre(
+ Pair(Code.point("foo"), UnorderedElementsAre(Header(HeaderFile))),
+ Pair(Code.point("vector"),
+ UnorderedElementsAre(Header(
+ tooling::stdlib::Header::named("<vector>").value())))));
+}
+
+} // namespace
+} // 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 7167d9214427d..ba9fc6419f388 100644
--- a/clang-tools-extra/include-cleaner/unittests/CMakeLists.txt
+++ b/clang-tools-extra/include-cleaner/unittests/CMakeLists.txt
@@ -5,6 +5,7 @@ set(LLVM_LINK_COMPONENTS
add_custom_target(ClangIncludeCleanerUnitTests)
add_unittest(ClangIncludeCleanerUnitTests ClangIncludeCleanerTests
+ AnalysisTest.cpp
RecordTest.cpp
WalkASTTest.cpp
)
@@ -18,6 +19,7 @@ clang_target_link_libraries(ClangIncludeCleanerTests
clangAST
clangBasic
clangFrontend
+ clangToolingInclusionsStdlib
)
target_link_libraries(ClangIncludeCleanerTests
diff --git a/clang-tools-extra/include-cleaner/unittests/WalkASTTest.cpp b/clang-tools-extra/include-cleaner/unittests/WalkASTTest.cpp
index 3e4fd42bf9cc5..f53aa4e37dc3c 100644
--- a/clang-tools-extra/include-cleaner/unittests/WalkASTTest.cpp
+++ b/clang-tools-extra/include-cleaner/unittests/WalkASTTest.cpp
@@ -1,15 +1,28 @@
+//===--- WalkASTTest.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/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/Support/Error.h"
#include "llvm/Testing/Support/Annotations.h"
+#include "gmock/gmock.h"
#include "gtest/gtest.h"
+#include <cstddef>
+#include <vector>
-namespace clang {
-namespace include_cleaner {
+namespace clang::include_cleaner {
namespace {
+using testing::Pair;
+using testing::UnorderedElementsAre;
// Specifies a test of which symbols are referenced by a piece of code.
//
@@ -106,5 +119,4 @@ TEST(WalkAST, Alias) {
}
} // namespace
-} // namespace include_cleaner
-} // namespace clang
+} // namespace clang::include_cleaner
More information about the cfe-commits
mailing list