r365005 - [clang][HeaderSearch] Shorten paths for includes in mainfile's directory

Kadir Cetinkaya via cfe-commits cfe-commits at lists.llvm.org
Wed Jul 3 00:47:19 PDT 2019


Author: kadircet
Date: Wed Jul  3 00:47:19 2019
New Revision: 365005

URL: http://llvm.org/viewvc/llvm-project?rev=365005&view=rev
Log:
[clang][HeaderSearch] Shorten paths for includes in mainfile's directory

Summary:
Currently HeaderSearch only looks at SearchDir's passed into it, but in
addition to those paths headers can be relative to including file's directory.

This patch makes sure that is taken into account.

Reviewers: gribozavr

Subscribers: jkorous, arphaman, cfe-commits

Tags: #clang

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

Modified:
    cfe/trunk/include/clang/Lex/HeaderSearch.h
    cfe/trunk/lib/Lex/HeaderSearch.cpp
    cfe/trunk/lib/Sema/SemaLookup.cpp
    cfe/trunk/unittests/Lex/HeaderSearchTest.cpp

Modified: cfe/trunk/include/clang/Lex/HeaderSearch.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Lex/HeaderSearch.h?rev=365005&r1=365004&r2=365005&view=diff
==============================================================================
--- cfe/trunk/include/clang/Lex/HeaderSearch.h (original)
+++ cfe/trunk/include/clang/Lex/HeaderSearch.h Wed Jul  3 00:47:19 2019
@@ -709,21 +709,29 @@ public:
 
   /// Suggest a path by which the specified file could be found, for use in
   /// diagnostics to suggest a #include. Returned path will only contain forward
-  /// slashes as separators.
+  /// slashes as separators. MainFile is the absolute path of the file that we
+  /// are generating the diagnostics for. It will try to shorten the path using
+  /// MainFile location, if none of the include search directories were prefix
+  /// of File.
   ///
   /// \param IsSystem If non-null, filled in to indicate whether the suggested
   ///        path is relative to a system header directory.
   std::string suggestPathToFileForDiagnostics(const FileEntry *File,
+                                              llvm::StringRef MainFile,
                                               bool *IsSystem = nullptr);
 
   /// Suggest a path by which the specified file could be found, for use in
   /// diagnostics to suggest a #include. Returned path will only contain forward
-  /// slashes as separators.
+  /// slashes as separators. MainFile is the absolute path of the file that we
+  /// are generating the diagnostics for. It will try to shorten the path using
+  /// MainFile location, if none of the include search directories were prefix
+  /// of File.
   ///
   /// \param WorkingDir If non-empty, this will be prepended to search directory
   /// paths that are relative.
   std::string suggestPathToFileForDiagnostics(llvm::StringRef File,
                                               llvm::StringRef WorkingDir,
+                                              llvm::StringRef MainFile,
                                               bool *IsSystem = nullptr);
 
   void PrintStats();

Modified: cfe/trunk/lib/Lex/HeaderSearch.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Lex/HeaderSearch.cpp?rev=365005&r1=365004&r2=365005&view=diff
==============================================================================
--- cfe/trunk/lib/Lex/HeaderSearch.cpp (original)
+++ cfe/trunk/lib/Lex/HeaderSearch.cpp Wed Jul  3 00:47:19 2019
@@ -1665,28 +1665,25 @@ void HeaderSearch::loadSubdirectoryModul
   SearchDir.setSearchedAllModuleMaps(true);
 }
 
-std::string HeaderSearch::suggestPathToFileForDiagnostics(const FileEntry *File,
-                                                          bool *IsSystem) {
+std::string HeaderSearch::suggestPathToFileForDiagnostics(
+    const FileEntry *File, llvm::StringRef MainFile, bool *IsSystem) {
   // FIXME: We assume that the path name currently cached in the FileEntry is
   // the most appropriate one for this analysis (and that it's spelled the
   // same way as the corresponding header search path).
-  return suggestPathToFileForDiagnostics(File->getName(), /*BuildDir=*/"",
-                                         IsSystem);
+  return suggestPathToFileForDiagnostics(File->getName(), /*WorkingDir=*/"",
+                                         MainFile, IsSystem);
 }
 
 std::string HeaderSearch::suggestPathToFileForDiagnostics(
-    llvm::StringRef File, llvm::StringRef WorkingDir, bool *IsSystem) {
+    llvm::StringRef File, llvm::StringRef WorkingDir, llvm::StringRef MainFile,
+    bool *IsSystem) {
   using namespace llvm::sys;
 
   unsigned BestPrefixLength = 0;
-  unsigned BestSearchDir;
-
-  for (unsigned I = 0; I != SearchDirs.size(); ++I) {
-    // FIXME: Support this search within frameworks and header maps.
-    if (!SearchDirs[I].isNormalDir())
-      continue;
-
-    StringRef Dir = SearchDirs[I].getDir()->getName();
+  // Checks whether Dir and File shares a common prefix, if they do and that's
+  // the longest prefix we've seen so for it returns true and updates the
+  // BestPrefixLength accordingly.
+  auto CheckDir = [&](llvm::StringRef Dir) -> bool {
     llvm::SmallString<32> DirPath(Dir.begin(), Dir.end());
     if (!WorkingDir.empty() && !path::is_absolute(Dir))
       fs::make_absolute(WorkingDir, DirPath);
@@ -1710,7 +1707,7 @@ std::string HeaderSearch::suggestPathToF
         unsigned PrefixLength = NI - path::begin(File);
         if (PrefixLength > BestPrefixLength) {
           BestPrefixLength = PrefixLength;
-          BestSearchDir = I;
+          return true;
         }
         break;
       }
@@ -1723,9 +1720,24 @@ std::string HeaderSearch::suggestPathToF
       if (*NI != *DI)
         break;
     }
+    return false;
+  };
+
+  for (unsigned I = 0; I != SearchDirs.size(); ++I) {
+    // FIXME: Support this search within frameworks and header maps.
+    if (!SearchDirs[I].isNormalDir())
+      continue;
+
+    StringRef Dir = SearchDirs[I].getDir()->getName();
+    if (CheckDir(Dir) && IsSystem)
+      *IsSystem = BestPrefixLength ? I >= SystemDirIdx : false;
   }
 
-  if (IsSystem)
-    *IsSystem = BestPrefixLength ? BestSearchDir >= SystemDirIdx : false;
+  // Try to shorten include path using TUs directory, if we couldn't find any
+  // suitable prefix in include search paths.
+  if (!BestPrefixLength && CheckDir(path::parent_path(MainFile)) && IsSystem)
+    *IsSystem = false;
+
+
   return path::convert_to_slash(File.drop_front(BestPrefixLength));
 }

Modified: cfe/trunk/lib/Sema/SemaLookup.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaLookup.cpp?rev=365005&r1=365004&r2=365005&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaLookup.cpp (original)
+++ cfe/trunk/lib/Sema/SemaLookup.cpp Wed Jul  3 00:47:19 2019
@@ -21,6 +21,7 @@
 #include "clang/AST/Expr.h"
 #include "clang/AST/ExprCXX.h"
 #include "clang/Basic/Builtins.h"
+#include "clang/Basic/FileManager.h"
 #include "clang/Basic/LangOptions.h"
 #include "clang/Lex/HeaderSearch.h"
 #include "clang/Lex/ModuleLoader.h"
@@ -5195,10 +5196,11 @@ void Sema::diagnoseMissingImport(SourceL
 /// Get a "quoted.h" or <angled.h> include path to use in a diagnostic
 /// suggesting the addition of a #include of the specified file.
 static std::string getIncludeStringForHeader(Preprocessor &PP,
-                                             const FileEntry *E) {
-  bool IsSystem;
-  auto Path =
-      PP.getHeaderSearchInfo().suggestPathToFileForDiagnostics(E, &IsSystem);
+                                             const FileEntry *E,
+                                             llvm::StringRef IncludingFile) {
+  bool IsSystem = false;
+  auto Path = PP.getHeaderSearchInfo().suggestPathToFileForDiagnostics(
+      E, IncludingFile, &IsSystem);
   return (IsSystem ? '<' : '"') + Path + (IsSystem ? '>' : '"');
 }
 
@@ -5240,6 +5242,11 @@ void Sema::diagnoseMissingImport(SourceL
       UniqueModules.push_back(M);
   }
 
+  llvm::StringRef IncludingFile;
+  if (const FileEntry *FE =
+          SourceMgr.getFileEntryForID(SourceMgr.getFileID(UseLoc)))
+    IncludingFile = FE->tryGetRealPathName();
+
   if (UniqueModules.empty()) {
     // All candidates were global module fragments. Try to suggest a #include.
     const FileEntry *E =
@@ -5248,7 +5255,7 @@ void Sema::diagnoseMissingImport(SourceL
     // a FixItHint there.
     Diag(UseLoc, diag::err_module_unimported_use_global_module_fragment)
         << (int)MIK << Decl << !!E
-        << (E ? getIncludeStringForHeader(PP, E) : "");
+        << (E ? getIncludeStringForHeader(PP, E, IncludingFile) : "");
     // Produce a "previous" note if it will point to a header rather than some
     // random global module fragment.
     // FIXME: Suppress the note backtrace even under
@@ -5284,8 +5291,8 @@ void Sema::diagnoseMissingImport(SourceL
     // FIXME: Find a smart place to suggest inserting a #include, and add
     // a FixItHint there.
     Diag(UseLoc, diag::err_module_unimported_use_header)
-      << (int)MIK << Decl << Modules[0]->getFullModuleName()
-      << getIncludeStringForHeader(PP, E);
+        << (int)MIK << Decl << Modules[0]->getFullModuleName()
+        << getIncludeStringForHeader(PP, E, IncludingFile);
   } else {
     // FIXME: Add a FixItHint that imports the corresponding module.
     Diag(UseLoc, diag::err_module_unimported_use)

Modified: cfe/trunk/unittests/Lex/HeaderSearchTest.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/Lex/HeaderSearchTest.cpp?rev=365005&r1=365004&r2=365005&view=diff
==============================================================================
--- cfe/trunk/unittests/Lex/HeaderSearchTest.cpp (original)
+++ cfe/trunk/unittests/Lex/HeaderSearchTest.cpp Wed Jul  3 00:47:19 2019
@@ -59,35 +59,41 @@ protected:
 
 TEST_F(HeaderSearchTest, NoSearchDir) {
   EXPECT_EQ(Search.search_dir_size(), 0u);
-  EXPECT_EQ(Search.suggestPathToFileForDiagnostics("/x/y/z", /*WorkingDir=*/""),
+  EXPECT_EQ(Search.suggestPathToFileForDiagnostics("/x/y/z", /*WorkingDir=*/"",
+                                                   /*MainFile=*/""),
             "/x/y/z");
 }
 
 TEST_F(HeaderSearchTest, SimpleShorten) {
   addSearchDir("/x");
   addSearchDir("/x/y");
-  EXPECT_EQ(Search.suggestPathToFileForDiagnostics("/x/y/z", /*WorkingDir=*/""),
+  EXPECT_EQ(Search.suggestPathToFileForDiagnostics("/x/y/z", /*WorkingDir=*/"",
+                                                   /*MainFile=*/""),
             "z");
   addSearchDir("/a/b/");
-  EXPECT_EQ(Search.suggestPathToFileForDiagnostics("/a/b/c", /*WorkingDir=*/""),
+  EXPECT_EQ(Search.suggestPathToFileForDiagnostics("/a/b/c", /*WorkingDir=*/"",
+                                                   /*MainFile=*/""),
             "c");
 }
 
 TEST_F(HeaderSearchTest, ShortenWithWorkingDir) {
   addSearchDir("x/y");
   EXPECT_EQ(Search.suggestPathToFileForDiagnostics("/a/b/c/x/y/z",
-                                                   /*WorkingDir=*/"/a/b/c"),
+                                                   /*WorkingDir=*/"/a/b/c",
+                                                   /*MainFile=*/""),
             "z");
 }
 
 TEST_F(HeaderSearchTest, Dots) {
   addSearchDir("/x/./y/");
   EXPECT_EQ(Search.suggestPathToFileForDiagnostics("/x/y/./z",
-                                                   /*WorkingDir=*/""),
+                                                   /*WorkingDir=*/"",
+                                                   /*MainFile=*/""),
             "z");
   addSearchDir("a/.././c/");
   EXPECT_EQ(Search.suggestPathToFileForDiagnostics("/m/n/./c/z",
-                                                   /*WorkingDir=*/"/m/n/"),
+                                                   /*WorkingDir=*/"/m/n/",
+                                                   /*MainFile=*/""),
             "z");
 }
 
@@ -95,14 +101,16 @@ TEST_F(HeaderSearchTest, Dots) {
 TEST_F(HeaderSearchTest, BackSlash) {
   addSearchDir("C:\\x\\y\\");
   EXPECT_EQ(Search.suggestPathToFileForDiagnostics("C:\\x\\y\\z\\t",
-                                                   /*WorkingDir=*/""),
+                                                   /*WorkingDir=*/"",
+                                                   /*MainFile=*/""),
             "z/t");
 }
 
 TEST_F(HeaderSearchTest, BackSlashWithDotDot) {
   addSearchDir("..\\y");
   EXPECT_EQ(Search.suggestPathToFileForDiagnostics("C:\\x\\y\\z\\t",
-                                                   /*WorkingDir=*/"C:/x/y/"),
+                                                   /*WorkingDir=*/"C:/x/y/",
+                                                   /*MainFile=*/""),
             "z/t");
 }
 #endif
@@ -110,9 +118,23 @@ TEST_F(HeaderSearchTest, BackSlashWithDo
 TEST_F(HeaderSearchTest, DotDotsWithAbsPath) {
   addSearchDir("/x/../y/");
   EXPECT_EQ(Search.suggestPathToFileForDiagnostics("/y/z",
-                                                   /*WorkingDir=*/""),
+                                                   /*WorkingDir=*/"",
+                                                   /*MainFile=*/""),
             "z");
 }
 
+TEST_F(HeaderSearchTest, IncludeFromSameDirectory) {
+  EXPECT_EQ(Search.suggestPathToFileForDiagnostics("/y/z/t.h",
+                                                   /*WorkingDir=*/"",
+                                                   /*MainFile=*/"/y/a.cc"),
+            "z/t.h");
+
+  addSearchDir("/");
+  EXPECT_EQ(Search.suggestPathToFileForDiagnostics("/y/z/t.h",
+                                                   /*WorkingDir=*/"",
+                                                   /*MainFile=*/"/y/a.cc"),
+            "y/z/t.h");
+}
+
 } // namespace
 } // namespace clang




More information about the cfe-commits mailing list