[clang-tools-extra] 1f7c7d4 - [clangd] Update symbol collector to use include-cleaner.

Viktoriia Bakalova via cfe-commits cfe-commits at lists.llvm.org
Wed Jul 19 06:47:11 PDT 2023


Author: Viktoriia Bakalova
Date: 2023-07-19T13:47:02Z
New Revision: 1f7c7d4bdd7b847d82b19bcd097029fabb449b90

URL: https://github.com/llvm/llvm-project/commit/1f7c7d4bdd7b847d82b19bcd097029fabb449b90
DIFF: https://github.com/llvm/llvm-project/commit/1f7c7d4bdd7b847d82b19bcd097029fabb449b90.diff

LOG: [clangd] Update symbol collector to use include-cleaner.

Differential Revision: https://reviews.llvm.org/D152900

Added: 
    

Modified: 
    clang-tools-extra/clangd/ClangdServer.cpp
    clang-tools-extra/clangd/Hover.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/clangd/TUScheduler.cpp
    clang-tools-extra/clangd/TUScheduler.h
    clang-tools-extra/clangd/XRefs.cpp
    clang-tools-extra/clangd/index/CanonicalIncludes.cpp
    clang-tools-extra/clangd/index/CanonicalIncludes.h
    clang-tools-extra/clangd/index/FileIndex.cpp
    clang-tools-extra/clangd/index/FileIndex.h
    clang-tools-extra/clangd/index/IndexAction.cpp
    clang-tools-extra/clangd/index/SymbolCollector.cpp
    clang-tools-extra/clangd/index/SymbolCollector.h
    clang-tools-extra/clangd/tool/Check.cpp
    clang-tools-extra/clangd/unittests/CanonicalIncludesTests.cpp
    clang-tools-extra/clangd/unittests/FileIndexTests.cpp
    clang-tools-extra/clangd/unittests/SymbolCollectorTests.cpp
    clang-tools-extra/clangd/unittests/TUSchedulerTests.cpp
    clang-tools-extra/clangd/unittests/TestTU.cpp
    clang-tools-extra/clangd/unittests/TestWorkspace.cpp
    clang-tools-extra/include-cleaner/include/clang-include-cleaner/Types.h

Removed: 
    


################################################################################
diff  --git a/clang-tools-extra/clangd/ClangdServer.cpp b/clang-tools-extra/clangd/ClangdServer.cpp
index 1451adcbf4d4fe..af002e0cb2d689 100644
--- a/clang-tools-extra/clangd/ClangdServer.cpp
+++ b/clang-tools-extra/clangd/ClangdServer.cpp
@@ -23,7 +23,7 @@
 #include "SourceCode.h"
 #include "TUScheduler.h"
 #include "XRefs.h"
-#include "index/CanonicalIncludes.h"
+#include "clang-include-cleaner/Record.h"
 #include "index/FileIndex.h"
 #include "index/Merge.h"
 #include "index/StdLib.h"
@@ -53,6 +53,7 @@
 #include <string>
 #include <type_traits>
 #include <vector>
+#include <utility>
 
 namespace clang {
 namespace clangd {
@@ -69,13 +70,13 @@ struct UpdateIndexCallbacks : public ParsingCallbacks {
                        const ThreadsafeFS &TFS, AsyncTaskRunner *Tasks,
                        bool CollectInactiveRegions,
                        const ClangdServer::Options &Opts)
-      : FIndex(FIndex), ServerCallbacks(ServerCallbacks),
-        TFS(TFS), Stdlib{std::make_shared<StdLibSet>()}, Tasks(Tasks),
+      : FIndex(FIndex), ServerCallbacks(ServerCallbacks), TFS(TFS),
+        Stdlib{std::make_shared<StdLibSet>()}, Tasks(Tasks),
         CollectInactiveRegions(CollectInactiveRegions), Opts(Opts) {}
 
   void onPreambleAST(
       PathRef Path, llvm::StringRef Version, CapturedASTCtx ASTCtx,
-      const std::shared_ptr<const CanonicalIncludes> CanonIncludes) override {
+      std::shared_ptr<const include_cleaner::PragmaIncludes> PI) override {
 
     if (!FIndex)
       return;
@@ -87,11 +88,10 @@ struct UpdateIndexCallbacks : public ParsingCallbacks {
 
     // FIndex outlives the UpdateIndexCallbacks.
     auto Task = [FIndex(FIndex), Path(Path.str()), Version(Version.str()),
-                 ASTCtx(std::move(ASTCtx)),
-                 CanonIncludes(CanonIncludes)]() mutable {
+                 ASTCtx(std::move(ASTCtx)), PI(std::move(PI))]() mutable {
       trace::Span Tracer("PreambleIndexing");
       FIndex->updatePreamble(Path, Version, ASTCtx.getASTContext(),
-                             ASTCtx.getPreprocessor(), *CanonIncludes);
+                             ASTCtx.getPreprocessor(), *PI);
     };
 
     if (Opts.AsyncPreambleIndexing && Tasks) {

diff  --git a/clang-tools-extra/clangd/Hover.cpp b/clang-tools-extra/clangd/Hover.cpp
index fbd0be07961651..ceae563131c13f 100644
--- a/clang-tools-extra/clangd/Hover.cpp
+++ b/clang-tools-extra/clangd/Hover.cpp
@@ -21,7 +21,6 @@
 #include "clang-include-cleaner/IncludeSpeller.h"
 #include "clang-include-cleaner/Types.h"
 #include "index/SymbolCollector.h"
-#include "support/Logger.h"
 #include "support/Markup.h"
 #include "support/Trace.h"
 #include "clang/AST/ASTContext.h"
@@ -1190,7 +1189,7 @@ void maybeAddSymbolProviders(ParsedAST &AST, HoverInfo &HI,
 
   const SourceManager &SM = AST.getSourceManager();
   llvm::SmallVector<include_cleaner::Header> RankedProviders =
-      include_cleaner::headersForSymbol(Sym, SM, AST.getPragmaIncludes());
+      include_cleaner::headersForSymbol(Sym, SM, AST.getPragmaIncludes().get());
   if (RankedProviders.empty())
     return;
 
@@ -1254,7 +1253,7 @@ void maybeAddUsedSymbols(ParsedAST &AST, HoverInfo &HI, const Inclusion &Inc) {
   llvm::DenseSet<include_cleaner::Symbol> UsedSymbols;
   include_cleaner::walkUsed(
       AST.getLocalTopLevelDecls(), collectMacroReferences(AST),
-      AST.getPragmaIncludes(), SM,
+      AST.getPragmaIncludes().get(), SM,
       [&](const include_cleaner::SymbolReference &Ref,
           llvm::ArrayRef<include_cleaner::Header> Providers) {
         if (Ref.RT != include_cleaner::RefType::Explicit ||

diff  --git a/clang-tools-extra/clangd/IncludeCleaner.cpp b/clang-tools-extra/clangd/IncludeCleaner.cpp
index 9a910e5850a9f1..6c33fd3588ffff 100644
--- a/clang-tools-extra/clangd/IncludeCleaner.cpp
+++ b/clang-tools-extra/clangd/IncludeCleaner.cpp
@@ -48,6 +48,7 @@
 #include "llvm/Support/Regex.h"
 #include <cassert>
 #include <iterator>
+#include <memory>
 #include <optional>
 #include <string>
 #include <utility>
@@ -71,8 +72,9 @@ bool isIgnored(llvm::StringRef HeaderPath, HeaderFilter IgnoreHeaders) {
   return false;
 }
 
-bool mayConsiderUnused(const Inclusion &Inc, ParsedAST &AST,
-                       const include_cleaner::PragmaIncludes *PI) {
+bool mayConsiderUnused(
+    const Inclusion &Inc, ParsedAST &AST,
+    const include_cleaner::PragmaIncludes *PI) {
   // FIXME(kirillbobyrev): We currently do not support the umbrella headers.
   // System headers are likely to be standard library headers.
   // Until we have good support for umbrella headers, don't warn about them.
@@ -312,7 +314,7 @@ getUnused(ParsedAST &AST,
     auto IncludeID = static_cast<IncludeStructure::HeaderID>(*MFI.HeaderID);
     if (ReferencedFiles.contains(IncludeID))
       continue;
-    if (!mayConsiderUnused(MFI, AST, AST.getPragmaIncludes())) {
+    if (!mayConsiderUnused(MFI, AST, AST.getPragmaIncludes().get())) {
       dlog("{0} was not used, but is not eligible to be diagnosed as unused",
            MFI.Written);
       continue;
@@ -395,7 +397,7 @@ IncludeCleanerFindings computeIncludeCleanerFindings(ParsedAST &AST) {
   trace::Span Tracer("include_cleaner::walkUsed");
   include_cleaner::walkUsed(
       AST.getLocalTopLevelDecls(), /*MacroRefs=*/Macros,
-      AST.getPragmaIncludes(), SM,
+      AST.getPragmaIncludes().get(), SM,
       [&](const include_cleaner::SymbolReference &Ref,
           llvm::ArrayRef<include_cleaner::Header> Providers) {
         bool Satisfied = false;

diff  --git a/clang-tools-extra/clangd/ParsedAST.cpp b/clang-tools-extra/clangd/ParsedAST.cpp
index 02c8597c79613d..81cfe8bb60b3e0 100644
--- a/clang-tools-extra/clangd/ParsedAST.cpp
+++ b/clang-tools-extra/clangd/ParsedAST.cpp
@@ -27,7 +27,6 @@
 #include "SourceCode.h"
 #include "TidyProvider.h"
 #include "clang-include-cleaner/Record.h"
-#include "index/CanonicalIncludes.h"
 #include "index/Symbol.h"
 #include "support/Logger.h"
 #include "support/Path.h"
@@ -655,16 +654,8 @@ ParsedAST::build(llvm::StringRef Filename, const ParseInputs &Inputs,
   PP.addPPCallbacks(
       collectPragmaMarksCallback(Clang->getSourceManager(), Marks));
 
-  // Copy over the includes from the preamble, then combine with the
-  // non-preamble includes below.
-  CanonicalIncludes CanonIncludes;
-  if (Preamble)
-    CanonIncludes = *Preamble->CanonIncludes;
-  else
-    CanonIncludes.addSystemHeadersMapping(Clang->getLangOpts());
-  std::unique_ptr<CommentHandler> IWYUHandler =
-      collectIWYUHeaderMaps(&CanonIncludes);
-  PP.addCommentHandler(IWYUHandler.get());
+  // FIXME: Attach a comment handler to take care of
+  // keep/export/no_include etc. IWYU pragmas.
 
   // Collect tokens of the main file.
   syntax::TokenCollector CollectTokens(PP);
@@ -719,8 +710,7 @@ ParsedAST::build(llvm::StringRef Filename, const ParseInputs &Inputs,
   ParsedAST Result(Filename, Inputs.Version, std::move(Preamble),
                    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(Diags), std::move(Includes));
   llvm::move(getIncludeCleanerDiags(Result, Inputs.Contents),
              std::back_inserter(Result.Diags));
   return std::move(Result);
@@ -806,10 +796,6 @@ const IncludeStructure &ParsedAST::getIncludeStructure() const {
   return Includes;
 }
 
-const CanonicalIncludes &ParsedAST::getCanonicalIncludes() const {
-  return CanonIncludes;
-}
-
 ParsedAST::ParsedAST(PathRef TUPath, llvm::StringRef Version,
                      std::shared_ptr<const PreambleData> Preamble,
                      std::unique_ptr<CompilerInstance> Clang,
@@ -817,23 +803,23 @@ ParsedAST::ParsedAST(PathRef TUPath, llvm::StringRef Version,
                      syntax::TokenBuffer Tokens, MainFileMacros Macros,
                      std::vector<PragmaMark> Marks,
                      std::vector<Decl *> LocalTopLevelDecls,
-                     std::vector<Diag> Diags, IncludeStructure Includes,
-                     CanonicalIncludes CanonIncludes)
+                     std::vector<Diag> Diags, IncludeStructure Includes)
     : 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)) {
   Resolver = std::make_unique<HeuristicResolver>(getASTContext());
   assert(this->Clang);
   assert(this->Action);
 }
 
-const include_cleaner::PragmaIncludes *ParsedAST::getPragmaIncludes() const {
+std::shared_ptr<const include_cleaner::PragmaIncludes>
+ParsedAST::getPragmaIncludes() const {
   if (!Preamble)
     return nullptr;
-  return &Preamble->Pragmas;
+  return Preamble->Pragmas;
 }
 
 std::optional<llvm::StringRef> ParsedAST::preambleVersion() const {

diff  --git a/clang-tools-extra/clangd/ParsedAST.h b/clang-tools-extra/clangd/ParsedAST.h
index 307100ae0fc494..c68fdba6bd26cd 100644
--- a/clang-tools-extra/clangd/ParsedAST.h
+++ b/clang-tools-extra/clangd/ParsedAST.h
@@ -26,7 +26,6 @@
 #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"
 #include "clang/Lex/Preprocessor.h"
@@ -95,7 +94,6 @@ class ParsedAST {
   /// bytes. Does not include the size of the preamble.
   std::size_t getUsedBytes() const;
   const IncludeStructure &getIncludeStructure() const;
-  const CanonicalIncludes &getCanonicalIncludes() const;
 
   /// Gets all macro references (definition, expansions) present in the main
   /// file, including those in the preamble region.
@@ -107,7 +105,8 @@ class ParsedAST {
   const syntax::TokenBuffer &getTokens() const { return Tokens; }
   /// Returns the PramaIncludes from the preamble.
   /// Might be null if AST is built without a preamble.
-  const include_cleaner::PragmaIncludes *getPragmaIncludes() const;
+  std::shared_ptr<const include_cleaner::PragmaIncludes>
+  getPragmaIncludes() const;
 
   /// Returns the version of the ParseInputs this AST was built from.
   llvm::StringRef version() const { return Version; }
@@ -130,8 +129,7 @@ class ParsedAST {
             std::unique_ptr<FrontendAction> Action, syntax::TokenBuffer Tokens,
             MainFileMacros Macros, std::vector<PragmaMark> Marks,
             std::vector<Decl *> LocalTopLevelDecls, std::vector<Diag> Diags,
-            IncludeStructure Includes, CanonicalIncludes CanonIncludes);
-
+            IncludeStructure Includes);
   Path TUPath;
   std::string Version;
   // In-memory preambles must outlive the AST, it is important that this member
@@ -161,7 +159,6 @@ class ParsedAST {
   // top-level decls from the preamble.
   std::vector<Decl *> LocalTopLevelDecls;
   IncludeStructure Includes;
-  CanonicalIncludes CanonIncludes;
   std::unique_ptr<HeuristicResolver> Resolver;
 };
 

diff  --git a/clang-tools-extra/clangd/Preamble.cpp b/clang-tools-extra/clangd/Preamble.cpp
index 212f882d313ce1..f4547a5babf081 100644
--- a/clang-tools-extra/clangd/Preamble.cpp
+++ b/clang-tools-extra/clangd/Preamble.cpp
@@ -15,7 +15,6 @@
 #include "Protocol.h"
 #include "SourceCode.h"
 #include "clang-include-cleaner/Record.h"
-#include "index/CanonicalIncludes.h"
 #include "support/Logger.h"
 #include "support/Path.h"
 #include "support/ThreadsafeFS.h"
@@ -95,7 +94,6 @@ class CppFilePreambleCallbacks : public PreambleCallbacks {
   include_cleaner::PragmaIncludes takePragmaIncludes() {
     return std::move(Pragmas);
   }
-  CanonicalIncludes takeCanonicalIncludes() { return std::move(CanonIncludes); }
 
   std::optional<CapturedASTCtx> takeLife() { return std::move(CapturedCtx); }
 
@@ -141,7 +139,6 @@ class CppFilePreambleCallbacks : public PreambleCallbacks {
   }
 
   void BeforeExecute(CompilerInstance &CI) override {
-    CanonIncludes.addSystemHeadersMapping(CI.getLangOpts());
     LangOpts = &CI.getLangOpts();
     SourceMgr = &CI.getSourceManager();
     PP = &CI.getPreprocessor();
@@ -160,11 +157,6 @@ class CppFilePreambleCallbacks : public PreambleCallbacks {
         collectPragmaMarksCallback(*SourceMgr, Marks));
   }
 
-  CommentHandler *getCommentHandler() override {
-    IWYUHandler = collectIWYUHeaderMaps(&CanonIncludes);
-    return IWYUHandler.get();
-  }
-
   static bool isLikelyForwardingFunction(FunctionTemplateDecl *FT) {
     const auto *FD = FT->getTemplatedDecl();
     const auto NumParams = FD->getNumParams();
@@ -214,12 +206,10 @@ class CppFilePreambleCallbacks : public PreambleCallbacks {
 private:
   PathRef File;
   IncludeStructure Includes;
-  CanonicalIncludes CanonIncludes;
   include_cleaner::PragmaIncludes Pragmas;
   MainFileMacros Macros;
   std::vector<PragmaMark> Marks;
   bool IsMainFileIncludeGuarded = false;
-  std::unique_ptr<CommentHandler> IWYUHandler = nullptr;
   const clang::LangOptions *LangOpts = nullptr;
   const SourceManager *SourceMgr = nullptr;
   const Preprocessor *PP = nullptr;
@@ -686,11 +676,10 @@ buildPreamble(PathRef FileName, CompilerInvocation CI,
     Result->CompileCommand = Inputs.CompileCommand;
     Result->Diags = std::move(Diags);
     Result->Includes = CapturedInfo.takeIncludes();
-    Result->Pragmas = CapturedInfo.takePragmaIncludes();
+    Result->Pragmas = std::make_shared<const include_cleaner::PragmaIncludes>(
+        CapturedInfo.takePragmaIncludes());
     Result->Macros = CapturedInfo.takeMacros();
     Result->Marks = CapturedInfo.takeMarks();
-    Result->CanonIncludes = std::make_shared<const CanonicalIncludes>(
-        (CapturedInfo.takeCanonicalIncludes()));
     Result->StatCache = StatCache;
     Result->MainIsIncludeGuarded = CapturedInfo.isMainFileIncludeGuarded();
     if (PreambleCallback) {
@@ -703,7 +692,7 @@ buildPreamble(PathRef FileName, CompilerInvocation CI,
       // While extending the life of FileMgr and VFS, StatCache should also be
       // extended.
       Ctx->setStatCache(Result->StatCache);
-      PreambleCallback(std::move(*Ctx), Result->CanonIncludes);
+      PreambleCallback(std::move(*Ctx), Result->Pragmas);
     }
     return Result;
   }

diff  --git a/clang-tools-extra/clangd/Preamble.h b/clang-tools-extra/clangd/Preamble.h
index cbadae31dd02ea..21a281aac0cce9 100644
--- a/clang-tools-extra/clangd/Preamble.h
+++ b/clang-tools-extra/clangd/Preamble.h
@@ -28,7 +28,6 @@
 #include "FS.h"
 #include "Headers.h"
 #include "clang-include-cleaner/Record.h"
-#include "index/CanonicalIncludes.h"
 #include "support/Path.h"
 #include "clang/Basic/SourceManager.h"
 #include "clang/Frontend/CompilerInvocation.h"
@@ -104,7 +103,7 @@ struct PreambleData {
   // information, and their compile action skips preamble range.
   IncludeStructure Includes;
   // Captures #include-mapping information in #included headers.
-  include_cleaner::PragmaIncludes Pragmas;
+  std::shared_ptr<const 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.
@@ -114,7 +113,6 @@ struct PreambleData {
   // Cache of FS operations performed when building the preamble.
   // When reusing a preamble, this cache can be consumed to save IO.
   std::shared_ptr<PreambleFileStatusCache> StatCache;
-  std::shared_ptr<const CanonicalIncludes> CanonIncludes;
   // Whether there was a (possibly-incomplete) include-guard on the main file.
   // We need to propagate this information "by hand" to subsequent parses.
   bool MainIsIncludeGuarded = false;
@@ -122,7 +120,7 @@ struct PreambleData {
 
 using PreambleParsedCallback =
     std::function<void(CapturedASTCtx ASTCtx,
-                       std::shared_ptr<const CanonicalIncludes> CanonIncludes)>;
+                       std::shared_ptr<const include_cleaner::PragmaIncludes>)>;
 
 /// Timings and statistics from the premble build. Unlike PreambleData, these
 /// do not need to be stored for later, but can be useful for logging, metrics,

diff  --git a/clang-tools-extra/clangd/TUScheduler.cpp b/clang-tools-extra/clangd/TUScheduler.cpp
index 46c469ff3f4117..dd2ce16147a5dd 100644
--- a/clang-tools-extra/clangd/TUScheduler.cpp
+++ b/clang-tools-extra/clangd/TUScheduler.cpp
@@ -54,7 +54,7 @@
 #include "GlobalCompilationDatabase.h"
 #include "ParsedAST.h"
 #include "Preamble.h"
-#include "index/CanonicalIncludes.h"
+#include "clang-include-cleaner/Record.h"
 #include "support/Cancellation.h"
 #include "support/Context.h"
 #include "support/Logger.h"
@@ -1080,9 +1080,9 @@ void PreambleThread::build(Request Req) {
   LatestBuild = clang::clangd::buildPreamble(
       FileName, *Req.CI, Inputs, StoreInMemory,
       [&](CapturedASTCtx ASTCtx,
-          std::shared_ptr<const CanonicalIncludes> CanonIncludes) {
+          std::shared_ptr<const include_cleaner::PragmaIncludes> PI) {
         Callbacks.onPreambleAST(FileName, Inputs.Version, std::move(ASTCtx),
-                                CanonIncludes);
+                                std::move(PI));
       },
       &Stats);
   if (!LatestBuild)

diff  --git a/clang-tools-extra/clangd/TUScheduler.h b/clang-tools-extra/clangd/TUScheduler.h
index 03417e1bd978ff..fb936d46bbcf7e 100644
--- a/clang-tools-extra/clangd/TUScheduler.h
+++ b/clang-tools-extra/clangd/TUScheduler.h
@@ -13,7 +13,7 @@
 #include "Compiler.h"
 #include "Diagnostics.h"
 #include "GlobalCompilationDatabase.h"
-#include "index/CanonicalIncludes.h"
+#include "clang-include-cleaner/Record.h"
 #include "support/Function.h"
 #include "support/MemoryTree.h"
 #include "support/Path.h"
@@ -21,6 +21,7 @@
 #include "llvm/ADT/StringMap.h"
 #include "llvm/ADT/StringRef.h"
 #include <chrono>
+#include <memory>
 #include <optional>
 #include <string>
 
@@ -161,10 +162,9 @@ class ParsingCallbacks {
   /// Called on the AST that was built for emitting the preamble. The built AST
   /// contains only AST nodes from the #include directives at the start of the
   /// file. AST node in the current file should be observed on onMainAST call.
-  virtual void onPreambleAST(PathRef Path, llvm::StringRef Version,
-                             CapturedASTCtx Ctx,
-                             const std::shared_ptr<const CanonicalIncludes>) {}
-
+  virtual void
+  onPreambleAST(PathRef Path, llvm::StringRef Version, CapturedASTCtx Ctx,
+                std::shared_ptr<const include_cleaner::PragmaIncludes>) {}
   /// The argument function is run under the critical section guarding against
   /// races when closing the files.
   using PublishFn = llvm::function_ref<void(llvm::function_ref<void()>)>;

diff  --git a/clang-tools-extra/clangd/XRefs.cpp b/clang-tools-extra/clangd/XRefs.cpp
index 80a7d028ddf902..5853870db77918 100644
--- a/clang-tools-extra/clangd/XRefs.cpp
+++ b/clang-tools-extra/clangd/XRefs.cpp
@@ -1334,7 +1334,7 @@ maybeFindIncludeReferences(ParsedAST &AST, Position Pos,
   auto ReferencedInclude = convertIncludes(SM, Inc);
   include_cleaner::walkUsed(
       AST.getLocalTopLevelDecls(), collectMacroReferences(AST),
-      AST.getPragmaIncludes(), SM,
+      AST.getPragmaIncludes().get(), SM,
       [&](const include_cleaner::SymbolReference &Ref,
           llvm::ArrayRef<include_cleaner::Header> Providers) {
         if (Ref.RT != include_cleaner::RefType::Explicit)

diff  --git a/clang-tools-extra/clangd/index/CanonicalIncludes.cpp b/clang-tools-extra/clangd/index/CanonicalIncludes.cpp
index 4311eb9f481f8e..3e3ba4d9f2b58d 100644
--- a/clang-tools-extra/clangd/index/CanonicalIncludes.cpp
+++ b/clang-tools-extra/clangd/index/CanonicalIncludes.cpp
@@ -7,14 +7,10 @@
 //===----------------------------------------------------------------------===//
 
 #include "CanonicalIncludes.h"
-#include "Headers.h"
 #include "clang/Basic/FileEntry.h"
-#include "clang/Tooling/Inclusions/HeaderAnalysis.h"
-#include "clang/Tooling/Inclusions/StandardLibrary.h"
+#include "clang/Basic/LangOptions.h"
 #include "llvm/ADT/StringRef.h"
-#include "llvm/Support/FileSystem/UniqueID.h"
 #include "llvm/Support/Path.h"
-#include <algorithm>
 
 namespace clang {
 namespace clangd {
@@ -669,31 +665,21 @@ const std::pair<llvm::StringRef, llvm::StringRef> IncludeMappings[] = {
 
 } // namespace
 
-void CanonicalIncludes::addMapping(FileEntryRef Header,
-                                   llvm::StringRef CanonicalPath) {
-  FullPathMapping[Header.getUniqueID()] = std::string(CanonicalPath);
-}
-
 /// The maximum number of path components in a key from StdSuffixHeaderMapping.
 /// Used to minimize the number of lookups in suffix path mappings.
 constexpr int MaxSuffixComponents = 3;
 
-llvm::StringRef CanonicalIncludes::mapHeader(FileEntryRef Header) const {
-  auto MapIt = FullPathMapping.find(Header.getUniqueID());
-  if (MapIt != FullPathMapping.end())
-    return MapIt->second;
-
+llvm::StringRef CanonicalIncludes::mapHeader(llvm::StringRef HeaderPath) const {
   if (!StdSuffixHeaderMapping)
     return "";
 
   int Components = 1;
 
   // FIXME: check that this works on Windows and add tests.
-  auto Filename = Header.getName();
-  for (auto It = llvm::sys::path::rbegin(Filename),
-            End = llvm::sys::path::rend(Filename);
+  for (auto It = llvm::sys::path::rbegin(HeaderPath),
+            End = llvm::sys::path::rend(HeaderPath);
        It != End && Components <= MaxSuffixComponents; ++It, ++Components) {
-    auto SubPath = Filename.substr(It->data() - Filename.begin());
+    auto SubPath = HeaderPath.substr(It->data() - HeaderPath.begin());
     auto MappingIt = StdSuffixHeaderMapping->find(SubPath);
     if (MappingIt != StdSuffixHeaderMapping->end())
       return MappingIt->second;
@@ -701,54 +687,6 @@ llvm::StringRef CanonicalIncludes::mapHeader(FileEntryRef Header) const {
   return "";
 }
 
-llvm::StringRef CanonicalIncludes::mapSymbol(llvm::StringRef Scope,
-                                             llvm::StringRef Name,
-                                             const LangOptions &L) const {
-  tooling::stdlib::Lang Lang;
-  if (L.CPlusPlus)
-    Lang = tooling::stdlib::Lang::CXX;
-  else if (L.C11)
-    Lang = tooling::stdlib::Lang::C;
-  else
-    return "";
-  // FIXME: remove the following special cases when the tooling stdlib supports
-  // them.
-  // There are two std::move()s, this is by far the most common.
-  if (Scope == "std::" && Name == "move")
-    return "<utility>";
-  if (auto StdSym = tooling::stdlib::Symbol::named(Scope, Name, Lang))
-    if (auto Header = StdSym->header())
-      return Header->name();
-  return "";
-}
-
-std::unique_ptr<CommentHandler>
-collectIWYUHeaderMaps(CanonicalIncludes *Includes) {
-  class PragmaCommentHandler : public clang::CommentHandler {
-  public:
-    PragmaCommentHandler(CanonicalIncludes *Includes) : Includes(Includes) {}
-
-    bool HandleComment(Preprocessor &PP, SourceRange Range) override {
-      auto Pragma = tooling::parseIWYUPragma(
-          PP.getSourceManager().getCharacterData(Range.getBegin()));
-      if (!Pragma || !Pragma->consume_front("private, include "))
-        return false;
-      auto &SM = PP.getSourceManager();
-      // We always insert using the spelling from the pragma.
-      if (auto *FE = SM.getFileEntryForID(SM.getFileID(Range.getBegin())))
-        Includes->addMapping(FE->getLastRef(),
-                             isLiteralInclude(*Pragma)
-                                 ? Pragma->str()
-                                 : ("\"" + *Pragma + "\"").str());
-      return false;
-    }
-
-  private:
-    CanonicalIncludes *const Includes;
-  };
-  return std::make_unique<PragmaCommentHandler>(Includes);
-}
-
 void CanonicalIncludes::addSystemHeadersMapping(const LangOptions &Language) {
   // FIXME: remove the std header mapping once we support ambiguous symbols, now
   // it serves as a fallback to disambiguate:

diff  --git a/clang-tools-extra/clangd/index/CanonicalIncludes.h b/clang-tools-extra/clangd/index/CanonicalIncludes.h
index f1464885018e95..551a437b3dfe72 100644
--- a/clang-tools-extra/clangd/index/CanonicalIncludes.h
+++ b/clang-tools-extra/clangd/index/CanonicalIncludes.h
@@ -20,13 +20,9 @@
 #define LLVM_CLANG_TOOLS_EXTRA_CLANGD_INDEX_CANONICALINCLUDES_H
 
 #include "clang/Basic/FileEntry.h"
-#include "clang/Lex/Preprocessor.h"
+#include "clang/Basic/LangOptions.h"
 #include "llvm/ADT/StringMap.h"
 #include "llvm/ADT/StringRef.h"
-#include "llvm/Support/FileSystem/UniqueID.h"
-#include <mutex>
-#include <string>
-#include <vector>
 
 namespace clang {
 namespace clangd {
@@ -36,18 +32,10 @@ namespace clangd {
 /// Only const methods (i.e. mapHeader) in this class are thread safe.
 class CanonicalIncludes {
 public:
-  /// Adds a file-to-string mapping from \p ID to \p CanonicalPath.
-  void addMapping(FileEntryRef Header, llvm::StringRef CanonicalPath);
-
-  /// Returns the overridden include for a qualified symbol with, or "".
-  /// \p Scope and \p Name concatenation forms the fully qualified name.
-  /// \p Scope is the qualifier with the trailing "::" (e.g. "std::") or empty
-  /// (for global namespace).
-  llvm::StringRef mapSymbol(llvm::StringRef Scope, llvm::StringRef Name,
-                            const LangOptions &L) const;
-
-  /// Returns the overridden include for files in \p Header, or "".
-  llvm::StringRef mapHeader(FileEntryRef Header) const;
+  /// Returns the overridden verbatim spelling for files in \p Header that can
+  /// be directly included (i.e., contains quotes "" or angled brackets <>), or
+  /// "" if the spelling could not be found.
+  llvm::StringRef mapHeader(llvm::StringRef HeaderPath) const;
 
   /// Adds mapping for system headers and some special symbols (e.g. STL symbols
   /// in <iosfwd> need to be mapped individually). Approximately, the following
@@ -60,37 +48,10 @@ class CanonicalIncludes {
   void addSystemHeadersMapping(const LangOptions &Language);
 
 private:
-  /// A map from the private header to a canonical include path.
-  llvm::DenseMap<llvm::sys::fs::UniqueID, std::string> FullPathMapping;
   /// A map from a suffix (one or components of a path) to a canonical path.
   /// Used only for mapping standard headers.
   const llvm::StringMap<llvm::StringRef> *StdSuffixHeaderMapping = nullptr;
 };
-
-/// Returns a CommentHandler that parses pragma comment on include files to
-/// determine when we should include a 
diff erent header from the header that
-/// directly defines a symbol. Mappinps are registered with \p Includes.
-///
-/// Currently it only supports IWYU private pragma:
-/// https://github.com/include-what-you-use/include-what-you-use/blob/master/docs/IWYUPragmas.md#iwyu-pragma-private
-///
-/// We ignore other pragmas:
-/// - keep: this is common but irrelevant: we do not currently remove includes
-/// - export: this is common and potentially interesting, there are three cases:
-///    * Points to a public header (common): we can suppress include2 if you
-///      already have include1. Only marginally useful.
-///    * Points to a private header annotated with `private` (somewhat common):
-///      Not incrementally useful as we support private.
-///    * Points to a private header without pragmas (rare). This is a reversed
-///      private pragma, and is valuable but too rare to be worthwhile.
-/// - no_include: this is about as common as private, but only affects the
-///   current file, so the value is smaller. We could add support.
-/// - friend: this is less common than private, has implementation 
diff iculties,
-///   and affects behavior in a limited scope.
-/// - associated: extremely rare
-std::unique_ptr<CommentHandler>
-collectIWYUHeaderMaps(CanonicalIncludes *Includes);
-
 } // namespace clangd
 } // namespace clang
 

diff  --git a/clang-tools-extra/clangd/index/FileIndex.cpp b/clang-tools-extra/clangd/index/FileIndex.cpp
index dc5c83433ffddc..5052c661cfc5ef 100644
--- a/clang-tools-extra/clangd/index/FileIndex.cpp
+++ b/clang-tools-extra/clangd/index/FileIndex.cpp
@@ -9,7 +9,7 @@
 #include "FileIndex.h"
 #include "CollectMacros.h"
 #include "ParsedAST.h"
-#include "index/CanonicalIncludes.h"
+#include "clang-include-cleaner/Record.h"
 #include "index/Index.h"
 #include "index/MemIndex.h"
 #include "index/Merge.h"
@@ -46,11 +46,12 @@ namespace {
 SlabTuple indexSymbols(ASTContext &AST, Preprocessor &PP,
                        llvm::ArrayRef<Decl *> DeclsToIndex,
                        const MainFileMacros *MacroRefsToIndex,
-                       const CanonicalIncludes &Includes, bool IsIndexMainAST,
-                       llvm::StringRef Version, bool CollectMainFileRefs) {
+                       const include_cleaner::PragmaIncludes &PI,
+                       bool IsIndexMainAST, llvm::StringRef Version,
+                       bool CollectMainFileRefs) {
   SymbolCollector::Options CollectorOpts;
   CollectorOpts.CollectIncludePath = true;
-  CollectorOpts.Includes = &Includes;
+  CollectorOpts.PragmaIncludes = &PI;
   CollectorOpts.CountReferences = false;
   CollectorOpts.Origin =
       IsIndexMainAST ? SymbolOrigin::Open : SymbolOrigin::Preamble;
@@ -222,18 +223,18 @@ FileShardedIndex::getShard(llvm::StringRef Uri) const {
 SlabTuple indexMainDecls(ParsedAST &AST) {
   return indexSymbols(
       AST.getASTContext(), AST.getPreprocessor(), AST.getLocalTopLevelDecls(),
-      &AST.getMacros(), AST.getCanonicalIncludes(),
+      &AST.getMacros(), *AST.getPragmaIncludes(),
       /*IsIndexMainAST=*/true, AST.version(), /*CollectMainFileRefs=*/true);
 }
 
 SlabTuple indexHeaderSymbols(llvm::StringRef Version, ASTContext &AST,
                              Preprocessor &PP,
-                             const CanonicalIncludes &Includes) {
+                             const include_cleaner::PragmaIncludes &PI) {
   std::vector<Decl *> DeclsToIndex(
       AST.getTranslationUnitDecl()->decls().begin(),
       AST.getTranslationUnitDecl()->decls().end());
   return indexSymbols(AST, PP, DeclsToIndex,
-                      /*MainFileMacros=*/nullptr, Includes,
+                      /*MainFileMacros=*/nullptr, PI,
                       /*IsIndexMainAST=*/false, Version,
                       /*CollectMainFileRefs=*/false);
 }
@@ -458,10 +459,10 @@ void FileIndex::updatePreamble(IndexFileIn IF) {
 
 void FileIndex::updatePreamble(PathRef Path, llvm::StringRef Version,
                                ASTContext &AST, Preprocessor &PP,
-                               const CanonicalIncludes &Includes) {
+                               const include_cleaner::PragmaIncludes &PI) {
   IndexFileIn IF;
   std::tie(IF.Symbols, std::ignore, IF.Relations) =
-      indexHeaderSymbols(Version, AST, PP, Includes);
+      indexHeaderSymbols(Version, AST, PP, PI);
   updatePreamble(std::move(IF));
 }
 

diff  --git a/clang-tools-extra/clangd/index/FileIndex.h b/clang-tools-extra/clangd/index/FileIndex.h
index a9072d64ef152e..44f33e8fbcd51e 100644
--- a/clang-tools-extra/clangd/index/FileIndex.h
+++ b/clang-tools-extra/clangd/index/FileIndex.h
@@ -16,7 +16,7 @@
 #define LLVM_CLANG_TOOLS_EXTRA_CLANGD_INDEX_FILEINDEX_H
 
 #include "Headers.h"
-#include "index/CanonicalIncludes.h"
+#include "clang-include-cleaner/Record.h"
 #include "index/Index.h"
 #include "index/Merge.h"
 #include "index/Ref.h"
@@ -113,7 +113,8 @@ class FileIndex : public MergedIndex {
   /// Update preamble symbols of file \p Path with all declarations in \p AST
   /// and macros in \p PP.
   void updatePreamble(PathRef Path, llvm::StringRef Version, ASTContext &AST,
-                      Preprocessor &PP, const CanonicalIncludes &Includes);
+                      Preprocessor &PP,
+                      const include_cleaner::PragmaIncludes &PI);
   void updatePreamble(IndexFileIn);
 
   /// Update symbols and references from main file \p Path with
@@ -162,7 +163,7 @@ SlabTuple indexMainDecls(ParsedAST &AST);
 /// included headers.
 SlabTuple indexHeaderSymbols(llvm::StringRef Version, ASTContext &AST,
                              Preprocessor &PP,
-                             const CanonicalIncludes &Includes);
+                             const include_cleaner::PragmaIncludes &PI);
 
 /// Takes slabs coming from a TU (multiple files) and shards them per
 /// declaration location.

diff  --git a/clang-tools-extra/clangd/index/IndexAction.cpp b/clang-tools-extra/clangd/index/IndexAction.cpp
index 6588f4d513232f..5d56285a839614 100644
--- a/clang-tools-extra/clangd/index/IndexAction.cpp
+++ b/clang-tools-extra/clangd/index/IndexAction.cpp
@@ -9,7 +9,9 @@
 #include "IndexAction.h"
 #include "AST.h"
 #include "Headers.h"
+#include "clang-include-cleaner/Record.h"
 #include "index/Relation.h"
+#include "index/SymbolCollector.h"
 #include "index/SymbolOrigin.h"
 #include "clang/AST/ASTConsumer.h"
 #include "clang/AST/ASTContext.h"
@@ -126,7 +128,7 @@ struct IncludeGraphCollector : public PPCallbacks {
 class IndexAction : public ASTFrontendAction {
 public:
   IndexAction(std::shared_ptr<SymbolCollector> C,
-              std::unique_ptr<CanonicalIncludes> Includes,
+              std::unique_ptr<include_cleaner::PragmaIncludes> PI,
               const index::IndexingOptions &Opts,
               std::function<void(SymbolSlab)> SymbolsCallback,
               std::function<void(RefSlab)> RefsCallback,
@@ -135,8 +137,7 @@ class IndexAction : public ASTFrontendAction {
       : SymbolsCallback(SymbolsCallback), RefsCallback(RefsCallback),
         RelationsCallback(RelationsCallback),
         IncludeGraphCallback(IncludeGraphCallback), Collector(C),
-        Includes(std::move(Includes)), Opts(Opts),
-        PragmaHandler(collectIWYUHeaderMaps(this->Includes.get())) {
+        PI(std::move(PI)), Opts(Opts) {
     this->Opts.ShouldTraverseDecl = [this](const Decl *D) {
       // Many operations performed during indexing is linear in terms of depth
       // of the decl (USR generation, name lookups, figuring out role of a
@@ -154,8 +155,7 @@ class IndexAction : public ASTFrontendAction {
 
   std::unique_ptr<ASTConsumer>
   CreateASTConsumer(CompilerInstance &CI, llvm::StringRef InFile) override {
-    CI.getPreprocessor().addCommentHandler(PragmaHandler.get());
-    Includes->addSystemHeadersMapping(CI.getLangOpts());
+    PI->record(CI.getPreprocessor());
     if (IncludeGraphCallback != nullptr)
       CI.getPreprocessor().addPPCallbacks(
           std::make_unique<IncludeGraphCollector>(CI.getSourceManager(), IG));
@@ -201,9 +201,8 @@ class IndexAction : public ASTFrontendAction {
   std::function<void(RelationSlab)> RelationsCallback;
   std::function<void(IncludeGraph)> IncludeGraphCallback;
   std::shared_ptr<SymbolCollector> Collector;
-  std::unique_ptr<CanonicalIncludes> Includes;
+  std::unique_ptr<include_cleaner::PragmaIncludes> PI;
   index::IndexingOptions Opts;
-  std::unique_ptr<CommentHandler> PragmaHandler;
   IncludeGraph IG;
 };
 
@@ -228,12 +227,12 @@ std::unique_ptr<FrontendAction> createStaticIndexingAction(
     Opts.RefFilter = RefKind::All;
     Opts.RefsInHeaders = true;
   }
-  auto Includes = std::make_unique<CanonicalIncludes>();
-  Opts.Includes = Includes.get();
-  return std::make_unique<IndexAction>(
-      std::make_shared<SymbolCollector>(std::move(Opts)), std::move(Includes),
-      IndexOpts, SymbolsCallback, RefsCallback, RelationsCallback,
-      IncludeGraphCallback);
+  auto PragmaIncludes = std::make_unique<include_cleaner::PragmaIncludes>();
+  Opts.PragmaIncludes = PragmaIncludes.get();
+  return std::make_unique<IndexAction>(std::make_shared<SymbolCollector>(Opts),
+                                       std::move(PragmaIncludes), IndexOpts,
+                                       SymbolsCallback, RefsCallback,
+                                       RelationsCallback, IncludeGraphCallback);
 }
 
 } // namespace clangd

diff  --git a/clang-tools-extra/clangd/index/SymbolCollector.cpp b/clang-tools-extra/clangd/index/SymbolCollector.cpp
index 5e19f1b56ff8ff..5389a0e31b81bb 100644
--- a/clang-tools-extra/clangd/index/SymbolCollector.cpp
+++ b/clang-tools-extra/clangd/index/SymbolCollector.cpp
@@ -13,8 +13,13 @@
 #include "ExpectedTypes.h"
 #include "SourceCode.h"
 #include "URI.h"
+#include "clang-include-cleaner/Analysis.h"
+#include "clang-include-cleaner/IncludeSpeller.h"
+#include "clang-include-cleaner/Record.h"
+#include "clang-include-cleaner/Types.h"
 #include "index/CanonicalIncludes.h"
 #include "index/Relation.h"
+#include "index/Symbol.h"
 #include "index/SymbolID.h"
 #include "index/SymbolLocation.h"
 #include "clang/AST/Decl.h"
@@ -22,6 +27,8 @@
 #include "clang/AST/DeclObjC.h"
 #include "clang/AST/DeclTemplate.h"
 #include "clang/AST/DeclarationName.h"
+#include "clang/AST/Expr.h"
+#include "clang/Basic/FileEntry.h"
 #include "clang/Basic/LangOptions.h"
 #include "clang/Basic/SourceLocation.h"
 #include "clang/Basic/SourceManager.h"
@@ -30,10 +37,17 @@
 #include "clang/Lex/Token.h"
 #include "clang/Tooling/Inclusions/HeaderAnalysis.h"
 #include "llvm/ADT/ArrayRef.h"
-#include "llvm/Support/Casting.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/ErrorHandling.h"
 #include "llvm/Support/FileSystem.h"
 #include "llvm/Support/Path.h"
+#include <cassert>
+#include <memory>
 #include <optional>
+#include <string>
+#include <utility>
 
 namespace clang {
 namespace clangd {
@@ -188,7 +202,7 @@ class SymbolCollector::HeaderFileURICache {
   // (IndexDataConsumer::setPreprocessor can happen before or after initialize)
   Preprocessor *&PP;
   const SourceManager &SM;
-  const CanonicalIncludes *Includes;
+  const include_cleaner::PragmaIncludes *PI;
   llvm::StringRef FallbackDir;
   llvm::DenseMap<const FileEntry *, const std::string *> CacheFEToURI;
   llvm::StringMap<std::string> CachePathToURI;
@@ -200,7 +214,7 @@ class SymbolCollector::HeaderFileURICache {
 public:
   HeaderFileURICache(Preprocessor *&PP, const SourceManager &SM,
                      const SymbolCollector::Options &Opts)
-      : PP(PP), SM(SM), Includes(Opts.Includes), FallbackDir(Opts.FallbackDir) {
+      : PP(PP), SM(SM), PI(Opts.PragmaIncludes), FallbackDir(Opts.FallbackDir) {
   }
 
   // Returns a canonical URI for the file \p FE.
@@ -234,6 +248,23 @@ class SymbolCollector::HeaderFileURICache {
     return R.first->second;
   }
 
+  // If a file is mapped by canonical headers, use that mapping, regardless
+  // of whether it's an otherwise-good header (header guards etc).
+  llvm::StringRef mapCanonical(llvm::StringRef HeaderPath) {
+    if (!PP)
+      return "";
+    // Populate the system header mapping as late as possible to
+    // ensure the preprocessor has been set already.
+    CanonicalIncludes SysHeaderMapping;
+    SysHeaderMapping.addSystemHeadersMapping(PP->getLangOpts());
+    auto Canonical = SysHeaderMapping.mapHeader(HeaderPath);
+    if (Canonical.empty())
+      return "";
+    // If we had a mapping, always use it.
+    assert(Canonical.startswith("<") || Canonical.startswith("\""));
+    return Canonical;
+  }
+
 private:
   // This takes care of making paths absolute and path->URI caching, but no
   // FileManager-based canonicalization.
@@ -376,19 +407,14 @@ class SymbolCollector::HeaderFileURICache {
     const auto FE = SM.getFileEntryRefForID(FID);
     if (!FE || FE->getName().empty())
       return "";
+
+    if (auto Verbatim = PI->getPublic(*FE); !Verbatim.empty())
+      return Verbatim;
+
     llvm::StringRef Filename = FE->getName();
-    // If a file is mapped by canonical headers, use that mapping, regardless
-    // of whether it's an otherwise-good header (header guards etc).
-    if (Includes) {
-      llvm::StringRef Canonical =
-          Includes->mapHeader(*SM.getFileEntryRefForID(FID));
-      if (!Canonical.empty()) {
-        // If we had a mapping, always use it.
-        if (Canonical.startswith("<") || Canonical.startswith("\""))
-          return Canonical;
-        return toURI(Canonical);
-      }
-    }
+    if (auto Canonical = mapCanonical(Filename); !Canonical.empty())
+      return Canonical;
+
     // Framework headers are spelled as <FrameworkName/Foo.h>, not
     // "path/FrameworkName.framework/Headers/Foo.h".
     auto &HS = PP->getHeaderSearchInfo();
@@ -764,7 +790,8 @@ bool SymbolCollector::handleMacroOccurrence(const IdentifierInfo *Name,
   S.CompletionSnippetSuffix = SnippetSuffix;
 
   IndexedMacros.insert(Name);
-  setIncludeLocation(S, DefLoc);
+
+  setIncludeLocation(S, DefLoc, include_cleaner::Macro{Name, DefLoc});
   Symbols.insert(S);
   return true;
 }
@@ -798,13 +825,24 @@ void SymbolCollector::processRelations(
   }
 }
 
-void SymbolCollector::setIncludeLocation(const Symbol &S, SourceLocation Loc) {
-  if (Opts.CollectIncludePath &&
-      shouldCollectIncludePath(S.SymInfo.Kind) != Symbol::Invalid)
-    // Use the expansion location to get the #include header since this is
-    // where the symbol is exposed.
-    IncludeFiles[S.ID] =
-        PP->getSourceManager().getDecomposedExpansionLoc(Loc).first;
+void SymbolCollector::setIncludeLocation(const Symbol &S, SourceLocation DefLoc,
+                                         const include_cleaner::Symbol &Sym) {
+  const auto &SM = PP->getSourceManager();
+  if (!Opts.CollectIncludePath ||
+      shouldCollectIncludePath(S.SymInfo.Kind) == Symbol::Invalid)
+    return;
+
+  // Use the expansion location to get the #include header since this is
+  // where the symbol is exposed.
+  IncludeFiles[S.ID] = SM.getDecomposedExpansionLoc(DefLoc).first;
+
+  auto [It, Inserted] = SymbolProviders.try_emplace(S.ID);
+  if (Inserted) {
+    auto Headers =
+        include_cleaner::headersForSymbol(Sym, SM, Opts.PragmaIncludes);
+    if (!Headers.empty())
+      It->second = Headers.front();
+  }
 }
 
 void SymbolCollector::finish() {
@@ -830,54 +868,84 @@ void SymbolCollector::finish() {
     }
   }
   llvm::DenseMap<FileID, bool> FileToContainsImportsOrObjC;
+  llvm::DenseMap<include_cleaner::Header, std::string> HeaderSpelling;
   // Fill in IncludeHeaders.
   // We delay this until end of TU so header guards are all resolved.
-  for (const auto &[SID, FID] : IncludeFiles) {
-    if (const Symbol *S = Symbols.find(SID)) {
-      llvm::StringRef IncludeHeader;
-      // Look for an overridden include header for this symbol specifically.
-      if (Opts.Includes) {
-        IncludeHeader =
-            Opts.Includes->mapSymbol(S->Scope, S->Name, ASTCtx->getLangOpts());
-        if (!IncludeHeader.empty()) {
-          if (IncludeHeader.front() != '"' && IncludeHeader.front() != '<')
-            IncludeHeader = HeaderFileURIs->toURI(IncludeHeader);
-          else if (IncludeHeader == "<utility>" && S->Scope == "std::" &&
-                   S->Name == "move" && S->Signature.contains(','))
-            IncludeHeader = "<algorithm>";
-        }
+  for (const auto &[SID, OptionalProvider] : SymbolProviders) {
+    const Symbol *S = Symbols.find(SID);
+    if (!S)
+      continue;
+    const auto FIDIt = IncludeFiles.find(SID);
+    assert(FIDIt != IncludeFiles.end());
+
+    const auto FID = IncludeFiles.at(SID);
+    // Determine if the FID is #include'd or #import'ed.
+    Symbol::IncludeDirective Directives = Symbol::Invalid;
+    auto CollectDirectives = shouldCollectIncludePath(S->SymInfo.Kind);
+    if ((CollectDirectives & Symbol::Include) != 0)
+      Directives |= Symbol::Include;
+    // Only allow #import for symbols from ObjC-like files.
+    if ((CollectDirectives & Symbol::Import) != 0) {
+      auto [It, Inserted] = FileToContainsImportsOrObjC.try_emplace(FID);
+      if (Inserted)
+        It->second = FilesWithObjCConstructs.contains(FID) ||
+                     tooling::codeContainsImports(
+                         ASTCtx->getSourceManager().getBufferData(FID));
+      if (It->second)
+        Directives |= Symbol::Import;
+    }
+
+    if (Directives == Symbol::Invalid)
+      continue;
+
+    // Use the include location-based logic for Objective-C symbols.
+    if (Directives & Symbol::Import) {
+      if (auto IncludeHeader = HeaderFileURIs->getIncludeHeader(FID);
+          !IncludeHeader.empty()) {
+        auto NewSym = *S;
+        NewSym.IncludeHeaders.push_back({IncludeHeader, 1, Directives});
+        Symbols.insert(NewSym);
       }
-      // Otherwise find the approprate include header for the defining file.
-      if (IncludeHeader.empty())
-        IncludeHeader = HeaderFileURIs->getIncludeHeader(FID);
-
-      // Symbols in slabs aren't mutable, insert() has to walk all the strings
-      if (!IncludeHeader.empty()) {
-        Symbol::IncludeDirective Directives = Symbol::Invalid;
-        auto CollectDirectives = shouldCollectIncludePath(S->SymInfo.Kind);
-        if ((CollectDirectives & Symbol::Include) != 0)
-          Directives |= Symbol::Include;
-        // Only allow #import for symbols from ObjC-like files.
-        if ((CollectDirectives & Symbol::Import) != 0) {
-          auto [It, Inserted] = FileToContainsImportsOrObjC.try_emplace(FID);
-          if (Inserted)
-            It->second = FilesWithObjCConstructs.contains(FID) ||
-                         tooling::codeContainsImports(
-                             ASTCtx->getSourceManager().getBufferData(FID));
-          if (It->second)
-            Directives |= Symbol::Import;
-        }
-        if (Directives != Symbol::Invalid) {
-          Symbol NewSym = *S;
-          NewSym.IncludeHeaders.push_back({IncludeHeader, 1, Directives});
-          Symbols.insert(NewSym);
-        }
+      // FIXME: use providers from include-cleaner library once it's polished
+      // for Objective-C.
+      continue;
+    }
+
+    assert(Directives == Symbol::Include);
+    // For #include's, use the providers computed by the include-cleaner
+    // library.
+    if (!OptionalProvider)
+      continue;
+    const auto &H = *OptionalProvider;
+    const auto [SpellingIt, Inserted] = HeaderSpelling.try_emplace(H);
+    if (Inserted) {
+      auto &SM = ASTCtx->getSourceManager();
+      if (H.kind() == include_cleaner::Header::Kind::Physical) {
+        if (auto Canonical =
+                HeaderFileURIs->mapCanonical(H.physical()->getName());
+            !Canonical.empty())
+          SpellingIt->second = Canonical;
+        else if (tooling::isSelfContainedHeader(H.physical(), SM,
+                                                PP->getHeaderSearchInfo()))
+          SpellingIt->second =
+              HeaderFileURIs->toURI(H.physical()->getLastRef());
+      } else {
+        SpellingIt->second = include_cleaner::spellHeader(
+            {H, PP->getHeaderSearchInfo(),
+             SM.getFileEntryForID(SM.getMainFileID())});
       }
     }
+
+    if (!SpellingIt->second.empty()) {
+      auto NewSym = *S;
+      NewSym.IncludeHeaders.push_back({SpellingIt->second, 1, Directives});
+      Symbols.insert(NewSym);
+    }
   }
 
   ReferencedSymbols.clear();
   IncludeFiles.clear();
+  SymbolProviders.clear();
   FilesWithObjCConstructs.clear();
 }
 
@@ -951,7 +1019,7 @@ const Symbol *SymbolCollector::addDeclaration(const NamedDecl &ND, SymbolID ID,
   }
 
   Symbols.insert(S);
-  setIncludeLocation(S, ND.getLocation());
+  setIncludeLocation(S, ND.getLocation(), include_cleaner::Symbol{ND});
   if (S.SymInfo.Lang == index::SymbolLanguage::ObjC)
     FilesWithObjCConstructs.insert(FID);
   return Symbols.find(S.ID);

diff  --git a/clang-tools-extra/clangd/index/SymbolCollector.h b/clang-tools-extra/clangd/index/SymbolCollector.h
index 265554429a2da5..0a890c4d5760a6 100644
--- a/clang-tools-extra/clangd/index/SymbolCollector.h
+++ b/clang-tools-extra/clangd/index/SymbolCollector.h
@@ -9,7 +9,8 @@
 #define LLVM_CLANG_TOOLS_EXTRA_CLANGD_INDEX_SYMBOLCOLLECTOR_H
 
 #include "CollectMacros.h"
-#include "index/CanonicalIncludes.h"
+#include "clang-include-cleaner/Record.h"
+#include "clang-include-cleaner/Types.h"
 #include "index/Ref.h"
 #include "index/Relation.h"
 #include "index/Symbol.h"
@@ -22,9 +23,9 @@
 #include "clang/Index/IndexDataConsumer.h"
 #include "clang/Index/IndexSymbol.h"
 #include "clang/Sema/CodeCompleteConsumer.h"
-#include "llvm/ADT/ArrayRef.h"
 #include "llvm/ADT/DenseMap.h"
 #include <functional>
+#include <memory>
 #include <optional>
 
 namespace clang {
@@ -57,8 +58,8 @@ class SymbolCollector : public index::IndexDataConsumer {
     std::string FallbackDir;
     bool CollectIncludePath = false;
     /// If set, this is used to map symbol #include path to a potentially
-    /// 
diff erent #include path.
-    const CanonicalIncludes *Includes = nullptr;
+    /// 
diff erent #include path specified by IWYU pragmas.
+    const include_cleaner::PragmaIncludes *PragmaIncludes = nullptr;
     // Populate the Symbol.References field.
     bool CountReferences = false;
     /// The symbol ref kinds that will be collected.
@@ -166,13 +167,22 @@ class SymbolCollector : public index::IndexDataConsumer {
 
   // All Symbols collected from the AST.
   SymbolSlab::Builder Symbols;
-  // File IDs for Symbol.IncludeHeaders.
-  // The final spelling is calculated in finish().
+  // File IDs used to determine if the code contains Obj-C constructs.
+  // For Obj-C symbols, these File IDs are used to compute the include
+  // headers.
   llvm::DenseMap<SymbolID, FileID> IncludeFiles;
+  void setIncludeLocation(const Symbol &S, SourceLocation,
+                          const include_cleaner::Symbol &Sym);
+
+  // Providers for Symbol.IncludeHeaders.
+  // The final spelling is calculated in finish().
+  llvm::DenseMap<SymbolID, std::optional<include_cleaner::Header>>
+      SymbolProviders;
+
   // Files which contain ObjC symbols.
   // This is finalized and used in finish().
   llvm::DenseSet<FileID> FilesWithObjCConstructs;
-  void setIncludeLocation(const Symbol &S, SourceLocation);
+
   // Indexed macros, to be erased if they turned out to be include guards.
   llvm::DenseSet<const IdentifierInfo *> IndexedMacros;
   // All refs collected from the AST. It includes:

diff  --git a/clang-tools-extra/clangd/tool/Check.cpp b/clang-tools-extra/clangd/tool/Check.cpp
index 3a6f4453fa7e74..46fcab0b69ce00 100644
--- a/clang-tools-extra/clangd/tool/Check.cpp
+++ b/clang-tools-extra/clangd/tool/Check.cpp
@@ -47,7 +47,7 @@
 #include "SourceCode.h"
 #include "TidyProvider.h"
 #include "XRefs.h"
-#include "index/CanonicalIncludes.h"
+#include "clang-include-cleaner/Record.h"
 #include "index/FileIndex.h"
 #include "refactor/Tweak.h"
 #include "support/Context.h"
@@ -231,12 +231,12 @@ class Checker {
     Preamble = buildPreamble(
         File, *Invocation, Inputs, /*StoreInMemory=*/true,
         [&](CapturedASTCtx Ctx,
-            const std::shared_ptr<const CanonicalIncludes> Includes) {
+            std::shared_ptr<const include_cleaner::PragmaIncludes> PI) {
           if (!Opts.BuildDynamicSymbolIndex)
             return;
           log("Indexing headers...");
           Index.updatePreamble(File, /*Version=*/"null", Ctx.getASTContext(),
-                               Ctx.getPreprocessor(), *Includes);
+                               Ctx.getPreprocessor(), *PI);
         });
     if (!Preamble) {
       elog("Failed to build preamble");

diff  --git a/clang-tools-extra/clangd/unittests/CanonicalIncludesTests.cpp b/clang-tools-extra/clangd/unittests/CanonicalIncludesTests.cpp
index 0d6731ca59581f..3285306cbc17de 100644
--- a/clang-tools-extra/clangd/unittests/CanonicalIncludesTests.cpp
+++ b/clang-tools-extra/clangd/unittests/CanonicalIncludesTests.cpp
@@ -6,10 +6,10 @@
 //
 //===----------------------------------------------------------------------===//
 
-#include "TestFS.h"
 #include "index/CanonicalIncludes.h"
 #include "clang/Basic/FileEntry.h"
 #include "clang/Basic/FileManager.h"
+#include "clang/Basic/FileSystemOptions.h"
 #include "clang/Basic/LangOptions.h"
 #include "llvm/ADT/IntrusiveRefCntPtr.h"
 #include "llvm/ADT/StringRef.h"
@@ -30,82 +30,21 @@ FileEntryRef addFile(llvm::vfs::InMemoryFileSystem &FS, FileManager &FM,
   return *File;
 }
 
-TEST(CanonicalIncludesTest, CStandardLibrary) {
-  CanonicalIncludes CI;
-  auto Language = LangOptions();
-  Language.C11 = true;
-  CI.addSystemHeadersMapping(Language);
-  // Usual standard library symbols are mapped correctly.
-  EXPECT_EQ("<stdio.h>", CI.mapSymbol("", "printf", Language));
-  EXPECT_EQ("", CI.mapSymbol("", "unknown_symbol", Language));
-}
-
-TEST(CanonicalIncludesTest, CXXStandardLibrary) {
-  CanonicalIncludes CI;
-  auto Language = LangOptions();
-  Language.CPlusPlus = true;
-  CI.addSystemHeadersMapping(Language);
-
-  // Usual standard library symbols are mapped correctly.
-  EXPECT_EQ("<vector>", CI.mapSymbol("std::", "vector", Language));
-  EXPECT_EQ("<cstdio>", CI.mapSymbol("std::", "printf", Language));
-  // std::move is ambiguous, currently always mapped to <utility>
-  EXPECT_EQ("<utility>", CI.mapSymbol("std::", "move", Language));
-  EXPECT_EQ("<cstddef>", CI.mapSymbol("std::", "size_t", Language));
-  // Unknown std symbols aren't mapped.
-  EXPECT_EQ("", CI.mapSymbol("std::", "notathing", Language));
-  // iosfwd declares some symbols it doesn't own.
-  EXPECT_EQ("<ostream>", CI.mapSymbol("std::", "ostream", Language));
-  // And (for now) we assume it owns the others.
-  auto InMemFS = llvm::makeIntrusiveRefCnt<llvm::vfs::InMemoryFileSystem>();
-  FileManager Files(FileSystemOptions(), InMemFS);
-  auto File = addFile(*InMemFS, Files, testPath("iosfwd"));
-  EXPECT_EQ("<iosfwd>", CI.mapHeader(File));
-}
-
-TEST(CanonicalIncludesTest, PathMapping) {
-  auto InMemFS = llvm::makeIntrusiveRefCnt<llvm::vfs::InMemoryFileSystem>();
-  FileManager Files(FileSystemOptions(), InMemFS);
-  std::string BarPath = testPath("foo/bar");
-  auto Bar = addFile(*InMemFS, Files, BarPath);
-  auto Other = addFile(*InMemFS, Files, testPath("foo/baz"));
-  // As used for IWYU pragmas.
-  CanonicalIncludes CI;
-  CI.addMapping(Bar, "<baz>");
-
-  // We added a mapping for baz.
-  EXPECT_EQ("<baz>", CI.mapHeader(Bar));
-  // Other file doesn't have a mapping.
-  EXPECT_EQ("", CI.mapHeader(Other));
-
-  // Add hard link to "foo/bar" and check that it is also mapped to <baz>, hence
-  // does not depend on the header name.
-  std::string HardLinkPath = testPath("hard/link");
-  InMemFS->addHardLink(HardLinkPath, BarPath);
-  auto HardLinkFile = Files.getFileRef(HardLinkPath);
-  ASSERT_THAT_EXPECTED(HardLinkFile, llvm::Succeeded());
-  EXPECT_EQ("<baz>", CI.mapHeader(*HardLinkFile));
-}
-
-TEST(CanonicalIncludesTest, Precedence) {
+TEST(CanonicalIncludesTest, SystemHeaderMap) {
   auto InMemFS = llvm::makeIntrusiveRefCnt<llvm::vfs::InMemoryFileSystem>();
   FileManager Files(FileSystemOptions(), InMemFS);
-  auto File = addFile(*InMemFS, Files, testPath("some/path"));
 
   CanonicalIncludes CI;
-  CI.addMapping(File, "<path>");
   LangOptions Language;
   Language.CPlusPlus = true;
   CI.addSystemHeadersMapping(Language);
 
-  // We added a mapping from some/path to <path>.
-  ASSERT_EQ("<path>", CI.mapHeader(File));
   // We should have a path from 'bits/stl_vector.h' to '<vector>'.
   // FIXME: The Standrad Library map in CanonicalIncludes expects forward
   // slashes and Windows would use backward slashes instead, so the headers are
   // not matched appropriately.
   auto STLVectorFile = addFile(*InMemFS, Files, "bits/stl_vector.h");
-  ASSERT_EQ("<vector>", CI.mapHeader(STLVectorFile));
+  ASSERT_EQ("<vector>", CI.mapHeader(STLVectorFile.getName()));
 }
 
 } // namespace

diff  --git a/clang-tools-extra/clangd/unittests/FileIndexTests.cpp b/clang-tools-extra/clangd/unittests/FileIndexTests.cpp
index aedd21821e3a68..cf30b388d234df 100644
--- a/clang-tools-extra/clangd/unittests/FileIndexTests.cpp
+++ b/clang-tools-extra/clangd/unittests/FileIndexTests.cpp
@@ -15,7 +15,7 @@
 #include "TestTU.h"
 #include "TestWorkspace.h"
 #include "URI.h"
-#include "index/CanonicalIncludes.h"
+#include "clang-include-cleaner/Record.h"
 #include "index/FileIndex.h"
 #include "index/Index.h"
 #include "index/Ref.h"
@@ -25,12 +25,12 @@
 #include "index/SymbolID.h"
 #include "support/Threading.h"
 #include "clang/Frontend/CompilerInvocation.h"
-#include "clang/Lex/Preprocessor.h"
 #include "clang/Tooling/CompilationDatabase.h"
 #include "llvm/ADT/ArrayRef.h"
 #include "llvm/Support/Allocator.h"
 #include "gmock/gmock.h"
 #include "gtest/gtest.h"
+#include <memory>
 #include <utility>
 #include <vector>
 
@@ -60,6 +60,11 @@ MATCHER_P(qName, N, "") { return (arg.Scope + arg.Name).str() == N; }
 MATCHER_P(numReferences, N, "") { return arg.References == N; }
 MATCHER_P(hasOrign, O, "") { return bool(arg.Origin & O); }
 
+MATCHER_P(includeHeader, P, "") {
+  return (arg.IncludeHeaders.size() == 1) &&
+         (arg.IncludeHeaders.begin()->IncludeHeader == P);
+}
+
 namespace clang {
 namespace clangd {
 namespace {
@@ -171,7 +176,7 @@ void update(FileIndex &M, llvm::StringRef Basename, llvm::StringRef Code) {
   auto AST = File.build();
   M.updatePreamble(testPath(File.Filename), /*Version=*/"null",
                    AST.getASTContext(), AST.getPreprocessor(),
-                   AST.getCanonicalIncludes());
+                   *AST.getPragmaIncludes());
 }
 
 TEST(FileIndexTest, CustomizedURIScheme) {
@@ -234,6 +239,32 @@ TEST(FileIndexTest, IncludeCollected) {
               "<the/good/header.h>");
 }
 
+TEST(FileIndexTest, IWYUPragmaExport) {
+  FileIndex M;
+
+  TestTU File;
+  File.Code = R"cpp(#pragma once
+    #include "exporter.h"
+  )cpp";
+  File.HeaderFilename = "exporter.h";
+  File.HeaderCode = R"cpp(#pragma once
+    #include "private.h" // IWYU pragma: export
+  )cpp";
+  File.AdditionalFiles["private.h"] = "class Foo{};";
+  auto AST = File.build();
+  M.updatePreamble(testPath(File.Filename), /*Version=*/"null",
+                   AST.getASTContext(), AST.getPreprocessor(),
+                   *AST.getPragmaIncludes());
+
+  auto Symbols = runFuzzyFind(M, "");
+  EXPECT_THAT(
+      Symbols,
+      UnorderedElementsAre(AllOf(
+          qName("Foo"),
+          includeHeader(URI::create(testPath(File.HeaderFilename)).toString()),
+          declURI(URI::create(testPath("private.h")).toString()))));
+}
+
 TEST(FileIndexTest, HasSystemHeaderMappingsInPreamble) {
   TestTU TU;
   TU.HeaderCode = "class Foo{};";
@@ -309,13 +340,12 @@ TEST(FileIndexTest, RebuildWithPreamble) {
       FooCpp, *CI, PI,
       /*StoreInMemory=*/true,
       [&](CapturedASTCtx ASTCtx,
-          const std::shared_ptr<const CanonicalIncludes> CanonIncludes) {
+          std::shared_ptr<const include_cleaner::PragmaIncludes> PI) {
         auto &Ctx = ASTCtx.getASTContext();
         auto &PP = ASTCtx.getPreprocessor();
         EXPECT_FALSE(IndexUpdated) << "Expected only a single index update";
         IndexUpdated = true;
-        Index.updatePreamble(FooCpp, /*Version=*/"null", Ctx, PP,
-                             *CanonIncludes);
+        Index.updatePreamble(FooCpp, /*Version=*/"null", Ctx, PP, *PI);
       });
   ASSERT_TRUE(IndexUpdated);
 
@@ -416,7 +446,7 @@ TEST(FileIndexTest, Relations) {
   FileIndex Index;
   Index.updatePreamble(testPath(TU.Filename), /*Version=*/"null",
                        AST.getASTContext(), AST.getPreprocessor(),
-                       AST.getCanonicalIncludes());
+                       *AST.getPragmaIncludes());
   SymbolID A = findSymbol(TU.headerSymbols(), "A").ID;
   uint32_t Results = 0;
   RelationsRequest Req;
@@ -537,7 +567,7 @@ TEST(FileIndexTest, StalePreambleSymbolsDeleted) {
   auto AST = File.build();
   M.updatePreamble(testPath(File.Filename), /*Version=*/"null",
                    AST.getASTContext(), AST.getPreprocessor(),
-                   AST.getCanonicalIncludes());
+                   *AST.getPragmaIncludes());
   EXPECT_THAT(runFuzzyFind(M, ""), UnorderedElementsAre(qName("a")));
 
   File.Filename = "f2.cpp";
@@ -545,7 +575,7 @@ TEST(FileIndexTest, StalePreambleSymbolsDeleted) {
   AST = File.build();
   M.updatePreamble(testPath(File.Filename), /*Version=*/"null",
                    AST.getASTContext(), AST.getPreprocessor(),
-                   AST.getCanonicalIncludes());
+                   *AST.getPragmaIncludes());
   EXPECT_THAT(runFuzzyFind(M, ""), UnorderedElementsAre(qName("b")));
 }
 
@@ -690,7 +720,7 @@ TEST(FileIndexTest, Profile) {
   auto AST = TestTU::withHeaderCode("int a;").build();
   FI.updateMain(FileName, AST);
   FI.updatePreamble(FileName, "v1", AST.getASTContext(), AST.getPreprocessor(),
-                    AST.getCanonicalIncludes());
+                    *AST.getPragmaIncludes());
 
   llvm::BumpPtrAllocator Alloc;
   MemoryTree MT(&Alloc);

diff  --git a/clang-tools-extra/clangd/unittests/SymbolCollectorTests.cpp b/clang-tools-extra/clangd/unittests/SymbolCollectorTests.cpp
index a2bf1c0baf0b3f..32a47c5ebfe865 100644
--- a/clang-tools-extra/clangd/unittests/SymbolCollectorTests.cpp
+++ b/clang-tools-extra/clangd/unittests/SymbolCollectorTests.cpp
@@ -9,6 +9,8 @@
 #include "Annotations.h"
 #include "TestFS.h"
 #include "TestTU.h"
+#include "URI.h"
+#include "clang-include-cleaner/Record.h"
 #include "index/SymbolCollector.h"
 #include "clang/Basic/FileManager.h"
 #include "clang/Basic/FileSystemOptions.h"
@@ -20,7 +22,6 @@
 #include "llvm/ADT/StringRef.h"
 #include "llvm/Support/MemoryBuffer.h"
 #include "llvm/Support/VirtualFileSystem.h"
-#include "llvm/Testing/Support/Error.h"
 #include "gmock/gmock-matchers.h"
 #include "gmock/gmock.h"
 #include "gtest/gtest.h"
@@ -28,6 +29,7 @@
 #include <memory>
 #include <optional>
 #include <string>
+#include <utility>
 
 namespace clang {
 namespace clangd {
@@ -226,23 +228,21 @@ TEST_F(ShouldCollectSymbolTest, DoubleCheckProtoHeaderComment) {
 
 class SymbolIndexActionFactory : public tooling::FrontendActionFactory {
 public:
-  SymbolIndexActionFactory(SymbolCollector::Options COpts,
-                           CommentHandler *PragmaHandler)
-      : COpts(std::move(COpts)), PragmaHandler(PragmaHandler) {}
+  SymbolIndexActionFactory(SymbolCollector::Options COpts)
+      : COpts(std::move(COpts)) {}
 
   std::unique_ptr<FrontendAction> create() override {
     class IndexAction : public ASTFrontendAction {
     public:
       IndexAction(std::shared_ptr<index::IndexDataConsumer> DataConsumer,
                   const index::IndexingOptions &Opts,
-                  CommentHandler *PragmaHandler)
+                  std::shared_ptr<include_cleaner::PragmaIncludes> PI)
           : DataConsumer(std::move(DataConsumer)), Opts(Opts),
-            PragmaHandler(PragmaHandler) {}
+            PI(std::move(PI)) {}
 
       std::unique_ptr<ASTConsumer>
       CreateASTConsumer(CompilerInstance &CI, llvm::StringRef InFile) override {
-        if (PragmaHandler)
-          CI.getPreprocessor().addCommentHandler(PragmaHandler);
+        PI->record(CI);
         return createIndexingASTConsumer(DataConsumer, Opts,
                                          CI.getPreprocessorPtr());
       }
@@ -256,20 +256,22 @@ class SymbolIndexActionFactory : public tooling::FrontendActionFactory {
     private:
       std::shared_ptr<index::IndexDataConsumer> DataConsumer;
       index::IndexingOptions Opts;
-      CommentHandler *PragmaHandler;
+      std::shared_ptr<include_cleaner::PragmaIncludes> PI;
     };
     index::IndexingOptions IndexOpts;
     IndexOpts.SystemSymbolFilter =
         index::IndexingOptions::SystemSymbolFilterKind::All;
     IndexOpts.IndexFunctionLocals = true;
+    std::shared_ptr<include_cleaner::PragmaIncludes> PI =
+        std::make_shared<include_cleaner::PragmaIncludes>();
+    COpts.PragmaIncludes = PI.get();
     Collector = std::make_shared<SymbolCollector>(COpts);
     return std::make_unique<IndexAction>(Collector, std::move(IndexOpts),
-                                         PragmaHandler);
+                                         std::move(PI));
   }
 
   std::shared_ptr<SymbolCollector> Collector;
   SymbolCollector::Options COpts;
-  CommentHandler *PragmaHandler;
 };
 
 class SymbolCollectorTest : public ::testing::Test {
@@ -289,8 +291,7 @@ class SymbolCollectorTest : public ::testing::Test {
     llvm::IntrusiveRefCntPtr<FileManager> Files(
         new FileManager(FileSystemOptions(), InMemoryFileSystem));
 
-    auto Factory = std::make_unique<SymbolIndexActionFactory>(
-        CollectorOpts, PragmaHandler.get());
+    auto Factory = std::make_unique<SymbolIndexActionFactory>(CollectorOpts);
 
     std::vector<std::string> Args = {"symbol_collector", "-fsyntax-only",
                                      "-xc++", "-include", TestHeaderName};
@@ -324,7 +325,6 @@ class SymbolCollectorTest : public ::testing::Test {
   RefSlab Refs;
   RelationSlab Relations;
   SymbolCollector::Options CollectorOpts;
-  std::unique_ptr<CommentHandler> PragmaHandler;
 };
 
 TEST_F(SymbolCollectorTest, CollectSymbols) {
@@ -1545,11 +1545,6 @@ TEST_F(SymbolCollectorTest, IncludeHeaderSameAsFileURI) {
 
 TEST_F(SymbolCollectorTest, CanonicalSTLHeader) {
   CollectorOpts.CollectIncludePath = true;
-  CanonicalIncludes Includes;
-  auto Language = LangOptions();
-  Language.CPlusPlus = true;
-  Includes.addSystemHeadersMapping(Language);
-  CollectorOpts.Includes = &Includes;
   runSymbolCollector(
       R"cpp(
       namespace std {
@@ -1573,9 +1568,6 @@ TEST_F(SymbolCollectorTest, CanonicalSTLHeader) {
 
 TEST_F(SymbolCollectorTest, IWYUPragma) {
   CollectorOpts.CollectIncludePath = true;
-  CanonicalIncludes Includes;
-  PragmaHandler = collectIWYUHeaderMaps(&Includes);
-  CollectorOpts.Includes = &Includes;
   const std::string Header = R"(
     // IWYU pragma: private, include the/good/header.h
     class Foo {};
@@ -1588,9 +1580,6 @@ TEST_F(SymbolCollectorTest, IWYUPragma) {
 
 TEST_F(SymbolCollectorTest, IWYUPragmaWithDoubleQuotes) {
   CollectorOpts.CollectIncludePath = true;
-  CanonicalIncludes Includes;
-  PragmaHandler = collectIWYUHeaderMaps(&Includes);
-  CollectorOpts.Includes = &Includes;
   const std::string Header = R"(
     // IWYU pragma: private, include "the/good/header.h"
     class Foo {};
@@ -1601,29 +1590,25 @@ TEST_F(SymbolCollectorTest, IWYUPragmaWithDoubleQuotes) {
                                  includeHeader("\"the/good/header.h\""))));
 }
 
-TEST_F(SymbolCollectorTest, SkipIncFileWhenCanonicalizeHeaders) {
-  auto IncFile = testPath("test.inc");
-  auto IncURI = URI::create(IncFile).toString();
-  InMemoryFileSystem->addFile(IncFile, 0,
-                              llvm::MemoryBuffer::getMemBuffer("class X {};"));
-  llvm::IntrusiveRefCntPtr<FileManager> Files(
-      new FileManager(FileSystemOptions(), InMemoryFileSystem));
-  std::string HeaderCode = "#include \"test.inc\"\nclass Y {};";
-  InMemoryFileSystem->addFile(TestHeaderName, 0,
-                              llvm::MemoryBuffer::getMemBuffer(HeaderCode));
-  auto File = Files->getFileRef(TestHeaderName);
-  ASSERT_THAT_EXPECTED(File, llvm::Succeeded());
-  CanonicalIncludes Includes;
-  Includes.addMapping(*File, "<canonical>");
+TEST_F(SymbolCollectorTest, IWYUPragmaExport) {
   CollectorOpts.CollectIncludePath = true;
-  CollectorOpts.Includes = &Includes;
-  runSymbolCollector(HeaderCode, /*Main=*/"",
+  const std::string Header = R"cpp(#pragma once
+    #include "exporter.h"
+  )cpp";
+  auto ExporterFile = testPath("exporter.h");
+  InMemoryFileSystem->addFile(
+      ExporterFile, 0, llvm::MemoryBuffer::getMemBuffer(R"cpp(#pragma once
+    #include "private.h" // IWYU pragma: export
+  )cpp"));
+  auto PrivateFile = testPath("private.h");
+  InMemoryFileSystem->addFile(
+      PrivateFile, 0, llvm::MemoryBuffer::getMemBuffer("class Foo {};"));
+  runSymbolCollector(Header, /*Main=*/"",
                      /*ExtraArgs=*/{"-I", testRoot()});
-  EXPECT_THAT(Symbols,
-              UnorderedElementsAre(AllOf(qName("X"), declURI(IncURI),
-                                         includeHeader("<canonical>")),
-                                   AllOf(qName("Y"), declURI(TestHeaderURI),
-                                         includeHeader("<canonical>"))));
+  EXPECT_THAT(Symbols, UnorderedElementsAre(AllOf(
+                           qName("Foo"),
+                           includeHeader(URI::create(ExporterFile).toString()),
+                           declURI(URI::create(PrivateFile).toString()))));
 }
 
 TEST_F(SymbolCollectorTest, MainFileIsHeaderWhenSkipIncFile) {

diff  --git a/clang-tools-extra/clangd/unittests/TUSchedulerTests.cpp b/clang-tools-extra/clangd/unittests/TUSchedulerTests.cpp
index ef057158965d50..5d5b618a854806 100644
--- a/clang-tools-extra/clangd/unittests/TUSchedulerTests.cpp
+++ b/clang-tools-extra/clangd/unittests/TUSchedulerTests.cpp
@@ -18,6 +18,7 @@
 #include "TUScheduler.h"
 #include "TestFS.h"
 #include "TestIndex.h"
+#include "clang-include-cleaner/Record.h"
 #include "support/Cancellation.h"
 #include "support/Context.h"
 #include "support/Path.h"
@@ -1134,9 +1135,9 @@ TEST_F(TUSchedulerTests, AsyncPreambleThread) {
   public:
     BlockPreambleThread(llvm::StringRef BlockVersion, Notification &N)
         : BlockVersion(BlockVersion), N(N) {}
-    void
-    onPreambleAST(PathRef Path, llvm::StringRef Version, CapturedASTCtx,
-                  const std::shared_ptr<const CanonicalIncludes>) override {
+    void onPreambleAST(
+        PathRef Path, llvm::StringRef Version, CapturedASTCtx,
+        std::shared_ptr<const include_cleaner::PragmaIncludes>) override {
       if (Version == BlockVersion)
         N.wait();
     }
@@ -1213,9 +1214,9 @@ TEST_F(TUSchedulerTests, PublishWithStalePreamble) {
     BlockPreambleThread(Notification &UnblockPreamble, DiagsCB CB)
         : UnblockPreamble(UnblockPreamble), CB(std::move(CB)) {}
 
-    void
-    onPreambleAST(PathRef Path, llvm::StringRef Version, CapturedASTCtx,
-                  const std::shared_ptr<const CanonicalIncludes>) override {
+    void onPreambleAST(
+        PathRef Path, llvm::StringRef Version, CapturedASTCtx,
+        std::shared_ptr<const include_cleaner::PragmaIncludes>) override {
       if (BuildBefore)
         ASSERT_TRUE(UnblockPreamble.wait(timeoutSeconds(5)))
             << "Expected notification";
@@ -1563,9 +1564,9 @@ TEST_F(TUSchedulerTests, PreambleThrottle) {
     std::vector<std::string> &Filenames;
     CaptureBuiltFilenames(std::vector<std::string> &Filenames)
         : Filenames(Filenames) {}
-    void
-    onPreambleAST(PathRef Path, llvm::StringRef Version, CapturedASTCtx,
-                  const std::shared_ptr<const CanonicalIncludes>) override {
+    void onPreambleAST(
+        PathRef Path, llvm::StringRef Version, CapturedASTCtx,
+        std::shared_ptr<const include_cleaner::PragmaIncludes> PI) override {
       // Deliberately no synchronization.
       // The PreambleThrottler should serialize these calls, if not then tsan
       // will find a bug here.

diff  --git a/clang-tools-extra/clangd/unittests/TestTU.cpp b/clang-tools-extra/clangd/unittests/TestTU.cpp
index 3b6aff7b2c2ac9..e65ae825b41677 100644
--- a/clang-tools-extra/clangd/unittests/TestTU.cpp
+++ b/clang-tools-extra/clangd/unittests/TestTU.cpp
@@ -162,9 +162,9 @@ ParsedAST TestTU::build() const {
 
 SymbolSlab TestTU::headerSymbols() const {
   auto AST = build();
-  return std::get<0>(indexHeaderSymbols(/*Version=*/"null", AST.getASTContext(),
-                                        AST.getPreprocessor(),
-                                        AST.getCanonicalIncludes()));
+  return std::get<0>(indexHeaderSymbols(
+      /*Version=*/"null", AST.getASTContext(), AST.getPreprocessor(),
+      *AST.getPragmaIncludes()));
 }
 
 RefSlab TestTU::headerRefs() const {
@@ -177,7 +177,7 @@ std::unique_ptr<SymbolIndex> TestTU::index() const {
   auto Idx = std::make_unique<FileIndex>();
   Idx->updatePreamble(testPath(Filename), /*Version=*/"null",
                       AST.getASTContext(), AST.getPreprocessor(),
-                      AST.getCanonicalIncludes());
+                      *AST.getPragmaIncludes());
   Idx->updateMain(testPath(Filename), AST);
   return std::move(Idx);
 }

diff  --git a/clang-tools-extra/clangd/unittests/TestWorkspace.cpp b/clang-tools-extra/clangd/unittests/TestWorkspace.cpp
index 755fa2aaed6dd1..2130e7a4c6dd48 100644
--- a/clang-tools-extra/clangd/unittests/TestWorkspace.cpp
+++ b/clang-tools-extra/clangd/unittests/TestWorkspace.cpp
@@ -7,8 +7,10 @@
 //===----------------------------------------------------------------------===//
 
 #include "TestWorkspace.h"
+#include "clang-include-cleaner/Record.h"
 #include "index/FileIndex.h"
 #include "gtest/gtest.h"
+#include <memory>
 #include <optional>
 
 namespace clang {
@@ -21,14 +23,12 @@ std::unique_ptr<SymbolIndex> TestWorkspace::index() {
       continue;
     TU.Code = Input.second.Code;
     TU.Filename = Input.first().str();
-    TU.preamble(
-        [&](CapturedASTCtx ASTCtx,
-            const std::shared_ptr<const CanonicalIncludes> CanonIncludes) {
-          auto &Ctx = ASTCtx.getASTContext();
-          auto &PP = ASTCtx.getPreprocessor();
-          Index->updatePreamble(testPath(Input.first()), "null", Ctx, PP,
-                                *CanonIncludes);
-        });
+    TU.preamble([&](CapturedASTCtx ASTCtx,
+                    std::shared_ptr<const include_cleaner::PragmaIncludes> PI) {
+      auto &Ctx = ASTCtx.getASTContext();
+      auto &PP = ASTCtx.getPreprocessor();
+      Index->updatePreamble(testPath(Input.first()), "null", Ctx, PP, *PI);
+    });
     ParsedAST MainAST = TU.build();
     Index->updateMain(testPath(Input.first()), MainAST);
   }

diff  --git a/clang-tools-extra/include-cleaner/include/clang-include-cleaner/Types.h b/clang-tools-extra/include-cleaner/include/clang-include-cleaner/Types.h
index b16d494e95b5c9..91dddaf9031b4a 100644
--- a/clang-tools-extra/include-cleaner/include/clang-include-cleaner/Types.h
+++ b/clang-tools-extra/include-cleaner/include/clang-include-cleaner/Types.h
@@ -46,7 +46,7 @@ namespace include_cleaner {
 
 /// We consider a macro to be a 
diff erent symbol each time it is defined.
 struct Macro {
-  IdentifierInfo *Name;
+  const IdentifierInfo *Name;
   /// The location of the Name where the macro is defined.
   SourceLocation Definition;
 


        


More information about the cfe-commits mailing list