kadircet created this revision.
kadircet added reviewers: hokein, sammccall.
Herald added a project: All.
kadircet requested review of this revision.
Herald added a project: clang-tools-extra.
Herald added a subscriber: cfe-commits.

Introduces walkUsed, a very simple version of the public API to enable
incremental development on rest of the pieces.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D136293

Files:
  clang-tools-extra/include-cleaner/include/clang-include-cleaner/Analysis.h
  clang-tools-extra/include-cleaner/lib/WalkAST.cpp
  clang-tools-extra/include-cleaner/unittests/CMakeLists.txt
  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
@@ -1,15 +1,32 @@
+//===--- 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-include-cleaner/Analysis.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 "clang/Tooling/Inclusions/StandardLibrary.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/SmallVector.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.
 //
@@ -105,6 +122,44 @@
            "^S *x;");
 }
 
+TEST(WalkUsed, Basic) {
+  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 include_cleaner
-} // namespace clang
+} // 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
@@ -18,6 +18,7 @@
   clangAST
   clangBasic
   clangFrontend
+  clangToolingInclusionsStdlib
   )
 
 target_link_libraries(ClangIncludeCleanerTests
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
@@ -7,10 +7,15 @@
 //===----------------------------------------------------------------------===//
 
 #include "AnalysisInternal.h"
+#include "clang-include-cleaner/Analysis.h"
 #include "clang/AST/RecursiveASTVisitor.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 {
-namespace include_cleaner {
+namespace clang::include_cleaner {
 namespace {
 using DeclCallback = llvm::function_ref<void(SourceLocation, NamedDecl &)>;
 
@@ -37,11 +42,38 @@
   }
 };
 
+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 walkAST(Decl &Root, DeclCallback Callback) {
   ASTWalker(Callback).TraverseDecl(&Root);
 }
 
-} // namespace include_cleaner
-} // namespace clang
+void walkUsed(llvm::ArrayRef<Decl *> ASTRoots, UsedSymbolVisitor 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)) {
+        llvm::errs() << "returning stdlib\n";
+        return CB(Loc, Symbol(*SS), toHeader(SS->headers()));
+      }
+      // FIXME: Extract locations from redecls.
+      // FIXME: Handle IWYU pragmas, non self-contained files.
+      llvm::errs() << "Returning fileentry\n";
+      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
Index: clang-tools-extra/include-cleaner/include/clang-include-cleaner/Analysis.h
===================================================================
--- /dev/null
+++ clang-tools-extra/include-cleaner/include/clang-include-cleaner/Analysis.h
@@ -0,0 +1,69 @@
+//===--- 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
+//
+//===----------------------------------------------------------------------===//
+
+#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<Decl *, tooling::stdlib::Symbol> Storage;
+};
+
+/// Represents a file that's providing some symbol. Might not be includeable.
+struct Header {
+  Header(const FileEntry *FE) : Storage(FE) {}
+  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 UsedSymbolVisitor 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.
+using UsedSymbolVisitor = 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, UsedSymbolVisitor CB);
+
+} // namespace include_cleaner
+} // namespace clang
+
+#endif
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to