hokein updated this revision to Diff 489959.
hokein added a comment.

rebase and update


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D140875/new/

https://reviews.llvm.org/D140875

Files:
  clang-tools-extra/clangd/CMakeLists.txt
  clang-tools-extra/clangd/Config.h
  clang-tools-extra/clangd/ConfigCompile.cpp
  clang-tools-extra/clangd/IncludeCleaner.cpp
  clang-tools-extra/clangd/ParsedAST.cpp
  clang-tools-extra/clangd/ParsedAST.h
  clang-tools-extra/clangd/Preamble.cpp
  clang-tools-extra/clangd/Preamble.h
  clang-tools-extra/include-cleaner/include/clang-include-cleaner/Record.h
  clang-tools-extra/include-cleaner/lib/Record.cpp

Index: clang-tools-extra/include-cleaner/lib/Record.cpp
===================================================================
--- clang-tools-extra/include-cleaner/lib/Record.cpp
+++ clang-tools-extra/include-cleaner/lib/Record.cpp
@@ -150,7 +150,7 @@
   RecordPragma(const CompilerInstance &CI, PragmaIncludes *Out)
       : SM(CI.getSourceManager()),
         HeaderInfo(CI.getPreprocessor().getHeaderSearchInfo()), Out(Out),
-        UniqueStrings(Arena) {}
+        UniqueStrings(Out->Arena) {}
 
   void FileChanged(SourceLocation Loc, FileChangeReason Reason,
                    SrcMgr::CharacteristicKind FileType,
@@ -176,7 +176,6 @@
           std::unique(It.getSecond().begin(), It.getSecond().end()),
           It.getSecond().end());
     }
-    Out->Arena = std::move(Arena);
   }
 
   void InclusionDirective(SourceLocation HashLoc, const Token &IncludeTok,
@@ -307,7 +306,6 @@
   const SourceManager &SM;
   HeaderSearch &HeaderInfo;
   PragmaIncludes *Out;
-  llvm::BumpPtrAllocator Arena;
   /// Intern table for strings. Contents are on the arena.
   llvm::StringSaver UniqueStrings;
 
@@ -336,6 +334,27 @@
   std::vector<KeepPragma> KeepStack;
 };
 
+PragmaIncludes::PragmaIncludes(const PragmaIncludes & In) {
+  *this = In;
+}
+
+PragmaIncludes &PragmaIncludes::operator=(const PragmaIncludes &In) {
+  ShouldKeep = In.ShouldKeep;
+  NonSelfContainedFiles = In.NonSelfContainedFiles;
+  Arena.Reset();
+  llvm::UniqueStringSaver Strings(Arena);
+  IWYUPublic.clear();
+  for (const auto& It : In.IWYUPublic)
+    IWYUPublic.try_emplace(It.first, Strings.save(It.second));
+  IWYUExportBy.clear();
+  for (const auto& UIDAndExporters : In.IWYUExportBy) {
+    const auto& [UID, Exporters] = UIDAndExporters;
+    for (StringRef ExporterHeader : Exporters)
+       IWYUExportBy.try_emplace(UID).first->second.push_back(ExporterHeader);
+  }
+  return *this;
+ }
+
 void PragmaIncludes::record(const CompilerInstance &CI) {
   auto Record = std::make_unique<RecordPragma>(CI, this);
   CI.getPreprocessor().addCommentHandler(Record.get());
Index: clang-tools-extra/include-cleaner/include/clang-include-cleaner/Record.h
===================================================================
--- clang-tools-extra/include-cleaner/include/clang-include-cleaner/Record.h
+++ clang-tools-extra/include-cleaner/include/clang-include-cleaner/Record.h
@@ -48,6 +48,13 @@
 /// defines the symbol.
 class PragmaIncludes {
 public:
+  PragmaIncludes() = default;
+  PragmaIncludes(PragmaIncludes &&) = default;
+  PragmaIncludes &operator=(PragmaIncludes &&) = default;
+
+  PragmaIncludes(const PragmaIncludes &);
+  PragmaIncludes &operator=(const PragmaIncludes &);
+
   /// Installs an analysing PPCallback and CommentHandler and populates results
   /// to the structure.
   void record(const CompilerInstance &CI);
Index: clang-tools-extra/clangd/Preamble.h
===================================================================
--- clang-tools-extra/clangd/Preamble.h
+++ clang-tools-extra/clangd/Preamble.h
@@ -27,6 +27,7 @@
 #include "Diagnostics.h"
 #include "FS.h"
 #include "Headers.h"
+#include "clang-include-cleaner/Record.h"
 #include "index/CanonicalIncludes.h"
 #include "support/Path.h"
 #include "clang/Frontend/CompilerInvocation.h"
@@ -57,6 +58,8 @@
   // Processes like code completions and go-to-definitions will need #include
   // information, and their compile action skips preamble range.
   IncludeStructure Includes;
+
+  include_cleaner::PragmaIncludes Pragmas;
   // Macros defined in the preamble section of the main file.
   // Users care about headers vs main-file, not preamble vs non-preamble.
   // These should be treated as main-file entities e.g. for code completion.
Index: clang-tools-extra/clangd/Preamble.cpp
===================================================================
--- clang-tools-extra/clangd/Preamble.cpp
+++ clang-tools-extra/clangd/Preamble.cpp
@@ -11,6 +11,7 @@
 #include "Config.h"
 #include "Headers.h"
 #include "SourceCode.h"
+#include "clang-include-cleaner/Record.h"
 #include "support/Logger.h"
 #include "support/ThreadsafeFS.h"
 #include "support/Trace.h"
@@ -77,6 +78,9 @@
 
   std::vector<PragmaMark> takeMarks() { return std::move(Marks); }
 
+  include_cleaner::PragmaIncludes takePragmaIncludes() {
+    return std::move(Pragmas);
+  }
   CanonicalIncludes takeCanonicalIncludes() { return std::move(CanonIncludes); }
 
   bool isMainFileIncludeGuarded() const { return IsMainFileIncludeGuarded; }
@@ -118,6 +122,9 @@
     LangOpts = &CI.getLangOpts();
     SourceMgr = &CI.getSourceManager();
     Includes.collect(CI);
+    if (Config::current().Diagnostics.UnusedIncludes ==
+        Config::UnusedIncludesPolicy::Experiment)
+      Pragmas.record(CI);
     if (BeforeExecuteCallback)
       BeforeExecuteCallback(CI);
   }
@@ -187,6 +194,7 @@
   PreambleParsedCallback ParsedCallback;
   IncludeStructure Includes;
   CanonicalIncludes CanonIncludes;
+  include_cleaner::PragmaIncludes Pragmas;
   MainFileMacros Macros;
   std::vector<PragmaMark> Marks;
   bool IsMainFileIncludeGuarded = false;
@@ -560,6 +568,7 @@
     Result->CompileCommand = Inputs.CompileCommand;
     Result->Diags = std::move(Diags);
     Result->Includes = CapturedInfo.takeIncludes();
+    Result->Pragmas = CapturedInfo.takePragmaIncludes();
     Result->Macros = CapturedInfo.takeMacros();
     Result->Marks = CapturedInfo.takeMarks();
     Result->CanonIncludes = CapturedInfo.takeCanonicalIncludes();
Index: clang-tools-extra/clangd/ParsedAST.h
===================================================================
--- clang-tools-extra/clangd/ParsedAST.h
+++ clang-tools-extra/clangd/ParsedAST.h
@@ -25,6 +25,7 @@
 #include "Diagnostics.h"
 #include "Headers.h"
 #include "Preamble.h"
+#include "clang-include-cleaner/Record.h"
 #include "index/CanonicalIncludes.h"
 #include "support/Path.h"
 #include "clang/Frontend/FrontendAction.h"
@@ -107,6 +108,10 @@
   /// (!) does not have tokens from the preamble.
   const syntax::TokenBuffer &getTokens() const { return Tokens; }
 
+  const include_cleaner::PragmaIncludes &getPragmaIncludes() const {
+    return Pragmas;
+  }
+
   /// Returns the version of the ParseInputs this AST was built from.
   llvm::StringRef version() const { return Version; }
 
@@ -129,7 +134,8 @@
             MainFileMacros Macros, std::vector<PragmaMark> Marks,
             std::vector<Decl *> LocalTopLevelDecls,
             std::optional<std::vector<Diag>> Diags, IncludeStructure Includes,
-            CanonicalIncludes CanonIncludes);
+            CanonicalIncludes CanonIncludes,
+            include_cleaner::PragmaIncludes Pragmas);
 
   Path TUPath;
   std::string Version;
@@ -161,6 +167,7 @@
   std::vector<Decl *> LocalTopLevelDecls;
   IncludeStructure Includes;
   CanonicalIncludes CanonIncludes;
+  include_cleaner::PragmaIncludes Pragmas;
   std::unique_ptr<HeuristicResolver> Resolver;
 };
 
Index: clang-tools-extra/clangd/ParsedAST.cpp
===================================================================
--- clang-tools-extra/clangd/ParsedAST.cpp
+++ clang-tools-extra/clangd/ParsedAST.cpp
@@ -23,6 +23,7 @@
 #include "Preamble.h"
 #include "SourceCode.h"
 #include "TidyProvider.h"
+#include "clang-include-cleaner/Record.h"
 #include "index/CanonicalIncludes.h"
 #include "index/Index.h"
 #include "index/Symbol.h"
@@ -589,9 +590,11 @@
   }
 
   IncludeStructure Includes;
+  include_cleaner::PragmaIncludes Pragmas;
   // If we are using a preamble, copy existing includes.
   if (Preamble) {
     Includes = Preamble->Includes;
+    Pragmas = Preamble->Pragmas;
     Includes.MainFileIncludes = Patch->preambleIncludes();
     // Replay the preamble includes so that clang-tidy checks can see them.
     ReplayPreamble::attach(Patch->preambleIncludes(), *Clang,
@@ -601,6 +604,9 @@
   // Otherwise we would collect the replayed includes again...
   // (We can't *just* use the replayed includes, they don't have Resolved path).
   Includes.collect(*Clang);
+  if (Config::current().Diagnostics.UnusedIncludes ==
+      Config::UnusedIncludesPolicy::Experiment)
+    Pragmas.record(*Clang);
   // Copy over the macros in the preamble region of the main file, and combine
   // with non-preamble macros below.
   MainFileMacros Macros;
@@ -686,7 +692,7 @@
                    std::move(Clang), std::move(Action), std::move(Tokens),
                    std::move(Macros), std::move(Marks), std::move(ParsedDecls),
                    std::move(Diags), std::move(Includes),
-                   std::move(CanonIncludes));
+                   std::move(CanonIncludes), std::move(Pragmas));
   if (Result.Diags) {
     auto UnusedHeadersDiags =
         issueUnusedIncludesDiagnostics(Result, Inputs.Contents);
@@ -789,13 +795,15 @@
                      std::vector<PragmaMark> Marks,
                      std::vector<Decl *> LocalTopLevelDecls,
                      std::optional<std::vector<Diag>> Diags,
-                     IncludeStructure Includes, CanonicalIncludes CanonIncludes)
+                     IncludeStructure Includes, CanonicalIncludes CanonIncludes,
+                     include_cleaner::PragmaIncludes Pragmas)
     : TUPath(TUPath), Version(Version), Preamble(std::move(Preamble)),
       Clang(std::move(Clang)), Action(std::move(Action)),
       Tokens(std::move(Tokens)), Macros(std::move(Macros)),
       Marks(std::move(Marks)), Diags(std::move(Diags)),
       LocalTopLevelDecls(std::move(LocalTopLevelDecls)),
-      Includes(std::move(Includes)), CanonIncludes(std::move(CanonIncludes)) {
+      Includes(std::move(Includes)), CanonIncludes(std::move(CanonIncludes)),
+      Pragmas(std::move(Pragmas)) {
   Resolver = std::make_unique<HeuristicResolver>(getASTContext());
   assert(this->Clang);
   assert(this->Action);
Index: clang-tools-extra/clangd/IncludeCleaner.cpp
===================================================================
--- clang-tools-extra/clangd/IncludeCleaner.cpp
+++ clang-tools-extra/clangd/IncludeCleaner.cpp
@@ -12,6 +12,8 @@
 #include "ParsedAST.h"
 #include "Protocol.h"
 #include "SourceCode.h"
+#include "clang-include-cleaner/Analysis.h"
+#include "clang-include-cleaner/Types.h"
 #include "index/CanonicalIncludes.h"
 #include "support/Logger.h"
 #include "support/Trace.h"
@@ -460,20 +462,81 @@
 
 std::vector<const Inclusion *> computeUnusedIncludes(ParsedAST &AST) {
   const auto &SM = AST.getSourceManager();
+  const auto &Includes = AST.getIncludeStructure();
+  const Config &Cfg = Config::current();
+  if (Cfg.Diagnostics.UnusedIncludes ==
+      Config::UnusedIncludesPolicy::Experiment) {
+    llvm::DenseSet<IncludeStructure::HeaderID> Used;
+
+    // FIXME: this map should probably be in IncludeStructure.
+    llvm::StringMap<llvm::SmallVector<IncludeStructure::HeaderID>> BySpelling;
+    for (const auto &Inc : Includes.MainFileIncludes) {
+      if (Inc.HeaderID)
+        BySpelling.try_emplace(Inc.Written)
+            .first->second.push_back(
+                static_cast<IncludeStructure::HeaderID>(*Inc.HeaderID));
+    }
+    // FIXME: !!this is a hacky way to collect macro references.
+    std::vector<include_cleaner::SymbolReference> Macros;
+    for (const syntax::Token &Tok : AST.getTokens().spelledTokens(SM.getMainFileID())) {
+      auto Macro = locateMacroAt(Tok, AST.getPreprocessor());
+      if (!Macro)
+        continue;
+      if (auto DefLoc = Macro->Info->getDefinitionLoc(); DefLoc.isValid())
+        Macros.push_back({Tok.location(),
+                          include_cleaner::Macro{/*Name=*/nullptr, DefLoc},
+                          include_cleaner::RefType::Explicit});
+    }
+    include_cleaner::walkUsed(
+        AST.getLocalTopLevelDecls(), /*MacroRefs=*/Macros, &AST.getPragmaIncludes(),
+        SM,
+        [&](const include_cleaner::SymbolReference &Ref,
+            llvm::ArrayRef<include_cleaner::Header> Providers) {
+          for (const auto &H : Providers) {
+            switch (H.kind()) {
+            case include_cleaner::Header::Physical:
+              if (auto HeaderID = Includes.getID(H.physical()))
+                Used.insert(*HeaderID);
+              break;
+            case include_cleaner::Header::Standard:
+              for (auto HeaderID : Includes.StdlibHeaders.lookup(H.standard()))
+                Used.insert(HeaderID);
+              break;
+            case include_cleaner::Header::Verbatim:
+              for (auto HeaderID : BySpelling.lookup(H.verbatim()))
+                Used.insert(HeaderID);
+              break;
+            }
+          }
+        });
+    std::vector<const Inclusion *> Unused;
+    for (const auto &I : Includes.MainFileIncludes) {
+      // non-existing headers may not have header ID!
+      if (!I.HeaderID)
+        continue;
+      auto HID = static_cast<IncludeStructure::HeaderID>(*I.HeaderID);
+      // FIXME: use mayConsiderUnused to respect the AnalyzeStdlib and
+      // IgnoreHeader options, but it also does extra IWYU-related filterings
+      // which we don't need.
+      if (!Used.contains(HID) &&
+          !AST.getPragmaIncludes().shouldKeep(I.HashLine + 1) &&
+          mayConsiderUnused(I, AST, Cfg))
+        Unused.push_back(&I);
+    }
+    return Unused;
+  }
 
   auto Refs = findReferencedLocations(AST);
   auto ReferencedFiles =
-      findReferencedFiles(Refs, AST.getIncludeStructure(),
-                          AST.getCanonicalIncludes(), AST.getSourceManager());
-  auto ReferencedHeaders =
-      translateToHeaderIDs(ReferencedFiles, AST.getIncludeStructure(), SM);
+      findReferencedFiles(Refs, Includes, AST.getCanonicalIncludes(), SM);
+  auto ReferencedHeaders = translateToHeaderIDs(ReferencedFiles, Includes, SM);
   return getUnused(AST, ReferencedHeaders, ReferencedFiles.SpelledUmbrellas);
 }
 
 std::vector<Diag> issueUnusedIncludesDiagnostics(ParsedAST &AST,
                                                  llvm::StringRef Code) {
   const Config &Cfg = Config::current();
-  if (Cfg.Diagnostics.UnusedIncludes != Config::UnusedIncludesPolicy::Strict ||
+  if (Cfg.Diagnostics.UnusedIncludes == Config::UnusedIncludesPolicy::None ||
       Cfg.Diagnostics.SuppressAll ||
       Cfg.Diagnostics.Suppress.contains("unused-includes"))
     return {};
Index: clang-tools-extra/clangd/ConfigCompile.cpp
===================================================================
--- clang-tools-extra/clangd/ConfigCompile.cpp
+++ clang-tools-extra/clangd/ConfigCompile.cpp
@@ -431,11 +431,13 @@
           });
 
     if (F.UnusedIncludes)
-      if (auto Val = compileEnum<Config::UnusedIncludesPolicy>(
-                         "UnusedIncludes", **F.UnusedIncludes)
-                         .map("Strict", Config::UnusedIncludesPolicy::Strict)
-                         .map("None", Config::UnusedIncludesPolicy::None)
-                         .value())
+      if (auto Val =
+              compileEnum<Config::UnusedIncludesPolicy>("UnusedIncludes",
+                                                        **F.UnusedIncludes)
+                  .map("Strict", Config::UnusedIncludesPolicy::Strict)
+                  .map("Experiment", Config::UnusedIncludesPolicy::Experiment)
+                  .map("None", Config::UnusedIncludesPolicy::None)
+                  .value())
         Out.Apply.push_back([Val](const Params &, Config &C) {
           C.Diagnostics.UnusedIncludes = *Val;
         });
Index: clang-tools-extra/clangd/Config.h
===================================================================
--- clang-tools-extra/clangd/Config.h
+++ clang-tools-extra/clangd/Config.h
@@ -88,7 +88,7 @@
     bool StandardLibrary = true;
   } Index;
 
-  enum UnusedIncludesPolicy { Strict, None };
+  enum UnusedIncludesPolicy { Strict, None, Experiment };
   /// Controls warnings and errors when parsing code.
   struct {
     bool SuppressAll = false;
Index: clang-tools-extra/clangd/CMakeLists.txt
===================================================================
--- clang-tools-extra/clangd/CMakeLists.txt
+++ clang-tools-extra/clangd/CMakeLists.txt
@@ -2,6 +2,8 @@
 include_directories(${CMAKE_CURRENT_SOURCE_DIR})
 include_directories(${CMAKE_CURRENT_BINARY_DIR})
 
+include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../include-cleaner/include)
+
 add_subdirectory(support)
 
 # Configure the Features.inc file.
@@ -162,6 +164,7 @@
   clangDriver
   clangFormat
   clangFrontend
+  clangIncludeCleaner
   clangIndex
   clangLex
   clangSema
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to