kbobyrev created this revision.
kbobyrev added a reviewer: sammccall.
Herald added subscribers: usaxena95, kadircet, arphaman.
kbobyrev requested review of this revision.
Herald added subscribers: cfe-commits, MaskRay, ilya-biryukov.
Herald added a project: clang-tools-extra.

Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D120306

Files:
  clang-tools-extra/clangd/Headers.cpp
  clang-tools-extra/clangd/Headers.h
  clang-tools-extra/clangd/IncludeCleaner.cpp
  clang-tools-extra/clangd/IncludeCleaner.h
  clang-tools-extra/clangd/unittests/IncludeCleanerTests.cpp

Index: clang-tools-extra/clangd/unittests/IncludeCleanerTests.cpp
===================================================================
--- clang-tools-extra/clangd/unittests/IncludeCleanerTests.cpp
+++ clang-tools-extra/clangd/unittests/IncludeCleanerTests.cpp
@@ -266,8 +266,9 @@
 
     ReferencedLocations Locs = findReferencedLocations(AST);
     EXPECT_THAT(Locs.Stdlib, ElementsAreArray(WantSyms));
-    ReferencedFiles Files = findReferencedFiles(Locs, AST.getIncludeStructure(),
-                                                AST.getSourceManager());
+    ReferencedFiles Files =
+        findReferencedFiles(Locs, AST.getIncludeStructure(),
+                            AST.getCanonicalIncludes(), AST.getSourceManager());
     EXPECT_THAT(Files.Stdlib, ElementsAreArray(WantHeaders));
   }
 }
@@ -378,8 +379,8 @@
   auto &SM = AST.getSourceManager();
   auto &Includes = AST.getIncludeStructure();
 
-  auto ReferencedFiles =
-      findReferencedFiles(findReferencedLocations(AST), Includes, SM);
+  auto ReferencedFiles = findReferencedFiles(
+      findReferencedLocations(AST), Includes, AST.getCanonicalIncludes(), SM);
   llvm::StringSet<> ReferencedFileNames;
   for (FileID FID : ReferencedFiles.User)
     ReferencedFileNames.insert(
@@ -427,9 +428,9 @@
 
   ParsedAST AST = TU.build();
 
-  auto ReferencedFiles =
-      findReferencedFiles(findReferencedLocations(AST),
-                          AST.getIncludeStructure(), AST.getSourceManager());
+  auto ReferencedFiles = findReferencedFiles(
+      findReferencedLocations(AST), AST.getIncludeStructure(),
+      AST.getCanonicalIncludes(), AST.getSourceManager());
   llvm::StringSet<> ReferencedFileNames;
   auto &SM = AST.getSourceManager();
   for (FileID FID : ReferencedFiles.User)
@@ -461,9 +462,9 @@
 
   ParsedAST AST = TU.build();
 
-  auto ReferencedFiles =
-      findReferencedFiles(findReferencedLocations(AST),
-                          AST.getIncludeStructure(), AST.getSourceManager());
+  auto ReferencedFiles = findReferencedFiles(
+      findReferencedLocations(AST), AST.getIncludeStructure(),
+      AST.getCanonicalIncludes(), AST.getSourceManager());
   llvm::StringSet<> ReferencedFileNames;
   auto &SM = AST.getSourceManager();
   for (FileID FID : ReferencedFiles.User)
@@ -483,9 +484,9 @@
   TU.AdditionalFiles["behind_keep.h"] = guard("");
   ParsedAST AST = TU.build();
 
-  auto ReferencedFiles =
-      findReferencedFiles(findReferencedLocations(AST),
-                          AST.getIncludeStructure(), AST.getSourceManager());
+  auto ReferencedFiles = findReferencedFiles(
+      findReferencedLocations(AST), AST.getIncludeStructure(),
+      AST.getCanonicalIncludes(), AST.getSourceManager());
   EXPECT_TRUE(ReferencedFiles.User.empty());
   EXPECT_THAT(AST.getDiagnostics(), llvm::ValueIs(IsEmpty()));
 }
Index: clang-tools-extra/clangd/IncludeCleaner.h
===================================================================
--- clang-tools-extra/clangd/IncludeCleaner.h
+++ clang-tools-extra/clangd/IncludeCleaner.h
@@ -13,9 +13,6 @@
 /// to provide useful warnings in most popular scenarios but not 1:1 exact
 /// feature compatibility.
 ///
-/// FIXME(kirillbobyrev): Add support for IWYU pragmas.
-/// FIXME(kirillbobyrev): Add support for standard library headers.
-///
 //===----------------------------------------------------------------------===//
 
 #ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_INCLUDECLEANER_H
@@ -23,6 +20,7 @@
 
 #include "Headers.h"
 #include "ParsedAST.h"
+#include "index/CanonicalIncludes.h"
 #include "clang/Basic/SourceLocation.h"
 #include "clang/Tooling/Inclusions/StandardLibrary.h"
 #include "llvm/ADT/DenseSet.h"
@@ -72,6 +70,7 @@
                     llvm::function_ref<FileID(FileID)> HeaderResponsible);
 ReferencedFiles findReferencedFiles(const ReferencedLocations &Locs,
                                     const IncludeStructure &Includes,
+                                    const CanonicalIncludes &CanonIncludes,
                                     const SourceManager &SM);
 
 /// Maps FileIDs to the internal IncludeStructure representation (HeaderIDs).
Index: clang-tools-extra/clangd/IncludeCleaner.cpp
===================================================================
--- clang-tools-extra/clangd/IncludeCleaner.cpp
+++ clang-tools-extra/clangd/IncludeCleaner.cpp
@@ -12,6 +12,7 @@
 #include "ParsedAST.h"
 #include "Protocol.h"
 #include "SourceCode.h"
+#include "index/CanonicalIncludes.h"
 #include "support/Logger.h"
 #include "support/Trace.h"
 #include "clang/AST/ASTContext.h"
@@ -266,7 +267,8 @@
 // include, so it will be responsible for bringing the symbols from given
 // header into the scope.
 FileID headerResponsible(FileID ID, const SourceManager &SM,
-                         const IncludeStructure &Includes) {
+                         const IncludeStructure &Includes,
+                         const CanonicalIncludes &CanonIncludes) {
   // Unroll the chain of non self-contained headers until we find the one that
   // can be included.
   for (const FileEntry *FE = SM.getFileEntryForID(ID); ID != SM.getMainFileID();
@@ -277,11 +279,28 @@
     auto HID = Includes.getID(FE);
     assert(HID && "We're iterating over headers already existing in "
                   "IncludeStructure");
-    if (Includes.isSelfContained(*HID))
-      break;
-    // The header is not self-contained: put the responsibility for its symbols
-    // on its includer.
-    ID = SM.getFileID(SM.getIncludeLoc(ID));
+    if (!Includes.isSelfContained(*HID)) {
+      // The header is not self-contained: put the responsibility for its
+      // symbols on its includer.
+      ID = SM.getFileID(SM.getIncludeLoc(ID));
+      continue;
+    }
+    if (auto Filename = SM.getNonBuiltinFilenameForID(ID)) {
+      vlog("Querying canonical include for {0}", *Filename);
+      auto CanonicalHeader = CanonIncludes.mapHeader(*Filename);
+      if (CanonicalHeader.empty())
+        break;
+      CanonicalHeader = CanonicalHeader.drop_front().drop_back();
+      auto FullHeader = Includes.getRealNameFromSuffix(CanonicalHeader);
+      vlog("Canoncal include for {0}: {1}, full: {2}", *Filename,
+           CanonicalHeader, FullHeader);
+      if (!FullHeader.hasValue())
+        break;
+      auto Entry = SM.getFileManager().getFile(*FullHeader);
+      assert(Entry);
+      ID = SM.translateFile(*Entry);
+    }
+    break;
   }
   return ID;
 }
@@ -339,10 +358,12 @@
 
 ReferencedFiles findReferencedFiles(const ReferencedLocations &Locs,
                                     const IncludeStructure &Includes,
+                                    const CanonicalIncludes &CanonIncludes,
                                     const SourceManager &SM) {
-  return findReferencedFiles(Locs, SM, [&SM, &Includes](FileID ID) {
-    return headerResponsible(ID, SM, Includes);
-  });
+  return findReferencedFiles(
+      Locs, SM, [&SM, &Includes, &CanonIncludes](FileID ID) {
+        return headerResponsible(ID, SM, Includes, CanonIncludes);
+      });
 }
 
 std::vector<const Inclusion *>
@@ -402,8 +423,9 @@
   const auto &SM = AST.getSourceManager();
 
   auto Refs = findReferencedLocations(AST);
-  auto ReferencedFileIDs = findReferencedFiles(Refs, AST.getIncludeStructure(),
-                                               AST.getSourceManager());
+  auto ReferencedFileIDs =
+      findReferencedFiles(Refs, AST.getIncludeStructure(),
+                          AST.getCanonicalIncludes(), AST.getSourceManager());
   auto ReferencedHeaders =
       translateToHeaderIDs(ReferencedFileIDs, AST.getIncludeStructure(), SM);
   return getUnused(AST, ReferencedHeaders);
Index: clang-tools-extra/clangd/Headers.h
===================================================================
--- clang-tools-extra/clangd/Headers.h
+++ clang-tools-extra/clangd/Headers.h
@@ -25,6 +25,8 @@
 #include "clang/Tooling/Inclusions/StandardLibrary.h"
 #include "llvm/ADT/ArrayRef.h"
 #include "llvm/ADT/DenseSet.h"
+#include "llvm/ADT/Optional.h"
+#include "llvm/ADT/StringMap.h"
 #include "llvm/ADT/StringRef.h"
 #include "llvm/ADT/StringSet.h"
 #include "llvm/Support/Error.h"
@@ -139,6 +141,9 @@
   llvm::Optional<HeaderID> getID(const FileEntry *Entry) const;
   HeaderID getOrCreateID(const FileEntry *Entry);
 
+  llvm::Optional<std::string>
+  getRealNameFromSuffix(llvm::StringRef Suffix) const;
+
   StringRef getRealPath(HeaderID ID) const {
     assert(static_cast<unsigned>(ID) <= RealPathNames.size());
     return RealPathNames[static_cast<unsigned>(ID)];
@@ -188,6 +193,7 @@
   // Contains HeaderIDs of all non self-contained entries in the
   // IncludeStructure.
   llvm::DenseSet<HeaderID> NonSelfContained;
+  llvm::StringMap<std::string> SuffixToRealPath;
 };
 
 // Calculates insertion edit for including a new header in a file.
Index: clang-tools-extra/clangd/Headers.cpp
===================================================================
--- clang-tools-extra/clangd/Headers.cpp
+++ clang-tools-extra/clangd/Headers.cpp
@@ -19,6 +19,7 @@
 #include "clang/Lex/HeaderSearch.h"
 #include "clang/Lex/PPCallbacks.h"
 #include "clang/Lex/Preprocessor.h"
+#include "llvm/ADT/Optional.h"
 #include "llvm/ADT/StringRef.h"
 #include "llvm/Support/Path.h"
 
@@ -229,6 +230,8 @@
   return It->second;
 }
 
+const static int MaxComponents = 4;
+
 IncludeStructure::HeaderID
 IncludeStructure::getOrCreateID(const FileEntry *Entry) {
   // Main file's FileEntry was not known at IncludeStructure creation time.
@@ -244,11 +247,34 @@
     RealPathNames.emplace_back();
   IncludeStructure::HeaderID Result = R.first->getSecond();
   std::string &RealPathName = RealPathNames[static_cast<unsigned>(Result)];
-  if (RealPathName.empty())
-    RealPathName = Entry->tryGetRealPathName().str();
+  if (RealPathName.empty()) {
+    auto RealPath = Entry->tryGetRealPathName().str();
+    if (!RealPath.empty()) {
+      RealPathName = RealPath;
+
+      int Components = 1;
+
+      // FIXME: check that this works on Windows and add tests.
+      for (auto It = llvm::sys::path::rbegin(RealPath),
+                End = llvm::sys::path::rend(RealPath);
+           It != End && Components <= MaxComponents; ++It, ++Components) {
+        auto Suffix = RealPath.substr(It->data() - RealPath.data());
+        vlog("Mapping header {0} suffix {1}", RealPath, Suffix);
+        SuffixToRealPath[Suffix] = RealPath;
+      }
+    }
+  }
   return Result;
 }
 
+llvm::Optional<std::string>
+IncludeStructure::getRealNameFromSuffix(llvm::StringRef Suffix) const {
+  auto It = SuffixToRealPath.find(Suffix);
+  if (It == SuffixToRealPath.end())
+    return llvm::None;
+  return It->second;
+}
+
 llvm::DenseMap<IncludeStructure::HeaderID, unsigned>
 IncludeStructure::includeDepth(HeaderID Root) const {
   // Include depth 0 is the main file only.
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to