diff options
Diffstat (limited to 'clang')
| -rw-r--r-- | clang/include/clang/Lex/HeaderSearch.h | 12 | ||||
| -rw-r--r-- | clang/lib/Lex/HeaderSearch.cpp | 44 | ||||
| -rw-r--r-- | clang/lib/Sema/SemaLookup.cpp | 21 | ||||
| -rw-r--r-- | clang/unittests/Lex/HeaderSearchTest.cpp | 40 |
4 files changed, 83 insertions, 34 deletions
diff --git a/clang/include/clang/Lex/HeaderSearch.h b/clang/include/clang/Lex/HeaderSearch.h index d6602360728..c5e66242444 100644 --- a/clang/include/clang/Lex/HeaderSearch.h +++ b/clang/include/clang/Lex/HeaderSearch.h @@ -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(); diff --git a/clang/lib/Lex/HeaderSearch.cpp b/clang/lib/Lex/HeaderSearch.cpp index 3ad0e1e5e83..ca94883ebec 100644 --- a/clang/lib/Lex/HeaderSearch.cpp +++ b/clang/lib/Lex/HeaderSearch.cpp @@ -1665,28 +1665,25 @@ void HeaderSearch::loadSubdirectoryModuleMaps(DirectoryLookup &SearchDir) { 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::suggestPathToFileForDiagnostics( unsigned PrefixLength = NI - path::begin(File); if (PrefixLength > BestPrefixLength) { BestPrefixLength = PrefixLength; - BestSearchDir = I; + return true; } break; } @@ -1723,9 +1720,24 @@ std::string HeaderSearch::suggestPathToFileForDiagnostics( 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)); } diff --git a/clang/lib/Sema/SemaLookup.cpp b/clang/lib/Sema/SemaLookup.cpp index 086f90f5e93..c50592c4ff8 100644 --- a/clang/lib/Sema/SemaLookup.cpp +++ b/clang/lib/Sema/SemaLookup.cpp @@ -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(SourceLocation Loc, NamedDecl *Decl, /// 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(SourceLocation UseLoc, NamedDecl *Decl, 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(SourceLocation UseLoc, NamedDecl *Decl, // 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(SourceLocation UseLoc, NamedDecl *Decl, // 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) diff --git a/clang/unittests/Lex/HeaderSearchTest.cpp b/clang/unittests/Lex/HeaderSearchTest.cpp index 499acec9bfd..626cfadb15f 100644 --- a/clang/unittests/Lex/HeaderSearchTest.cpp +++ b/clang/unittests/Lex/HeaderSearchTest.cpp @@ -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, BackSlashWithDotDot) { 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 |

