adamcz created this revision. Herald added a project: clang. Herald added a subscriber: cfe-commits. adamcz requested review of this revision.
When looking for compile commands for file of type X, other files of type X will be preferred over files of any other type, regardless of score. However, when gathering the set of candidates, we only look for files with similar name and files close to the requested one. If it happens that none of them are in language X, we previously (before this change) would choose one of the existing candidates of some other type. This patch adds all files in language X (regardless of name and location) to the list of candidates if the initial set of candidates did not contain any files of type X. This means we will always choose a file of type X if one exists anywhere in the project. Repository: rG LLVM Github Monorepo https://reviews.llvm.org/D87253 Files: clang/lib/Tooling/InterpolatingCompilationDatabase.cpp clang/unittests/Tooling/CompilationDatabaseTest.cpp Index: clang/unittests/Tooling/CompilationDatabaseTest.cpp =================================================================== --- clang/unittests/Tooling/CompilationDatabaseTest.cpp +++ clang/unittests/Tooling/CompilationDatabaseTest.cpp @@ -755,6 +755,7 @@ } TEST_F(InterpolateTest, Language) { + add("aaa/bbb/ccc/ddd/file.c", ""); add("dir/foo.cpp", "-std=c++17"); add("dir/bar.c", ""); add("dir/baz.cee", "-x c"); @@ -774,7 +775,10 @@ EXPECT_EQ(getCommand("baz.h"), "clang -D dir/baz.cee -x c-header"); // prefer a worse match with the right extension. EXPECT_EQ(getCommand("foo.c"), "clang -D dir/bar.c"); + // even when it is far away. + EXPECT_EQ(getCommand("aaa/bbb/ccc/ddd/file.hpp"), "clang -D dir/aux.cpp"); Entries.erase(path(StringRef("dir/bar.c"))); + Entries.erase(path(StringRef("aaa/bbb/ccc/ddd/file.c"))); // Now we transfer across languages, so drop -std too. EXPECT_EQ(getCommand("foo.c"), "clang -D dir/foo.cpp"); // Prefer -x over -std when overriding language. Index: clang/lib/Tooling/InterpolatingCompilationDatabase.cpp =================================================================== --- clang/lib/Tooling/InterpolatingCompilationDatabase.cpp +++ clang/lib/Tooling/InterpolatingCompilationDatabase.cpp @@ -352,7 +352,7 @@ types::ID PreferLanguage) const { assert(!empty() && "need at least one candidate!"); std::string Filename = OriginalFilename.lower(); - auto Candidates = scoreCandidates(Filename); + auto Candidates = scoreCandidates(Filename, PreferLanguage); std::pair<size_t, int> Best = pickWinner(Candidates, Filename, PreferLanguage); @@ -378,7 +378,8 @@ // Award points to candidate entries that should be considered for the file. // Returned keys are indexes into paths, and the values are (nonzero) scores. - DenseMap<size_t, int> scoreCandidates(StringRef Filename) const { + DenseMap<size_t, int> scoreCandidates(StringRef Filename, + types::ID PreferredLanguage) const { // Decompose Filename into the parts we care about. // /some/path/complicated/project/Interesting.h // [-prefix--][---dir---] [-dir-] [--stem---] @@ -410,6 +411,25 @@ // Award one more point if the whole rest of the path matches. if (sys::path::root_directory(Prefix) != Prefix) Award(1, indexLookup</*Prefix=*/true>(Prefix, Paths)); + + bool CandidateWithMatchingLanguageFound = false; + for (const auto &C : Candidates) { + if (Types[C.first] == PreferredLanguage) { + CandidateWithMatchingLanguageFound = true; + break; + } + } + if (!CandidateWithMatchingLanguageFound) { + // If none of the candidates we found so far use preferred language, try + // all other files, even if they are far away in the dir hierarchy. + for (size_t I = 0; I < OriginalPaths.size(); ++I) { + // Increase score by one. The actual value doesn't matter, the point is + // to have some candidates matching PreferredLanguage in the Candidates + // set at all. + if (Types[I] == PreferredLanguage) + Candidates[I] += 1; + } + } return Candidates; }
Index: clang/unittests/Tooling/CompilationDatabaseTest.cpp =================================================================== --- clang/unittests/Tooling/CompilationDatabaseTest.cpp +++ clang/unittests/Tooling/CompilationDatabaseTest.cpp @@ -755,6 +755,7 @@ } TEST_F(InterpolateTest, Language) { + add("aaa/bbb/ccc/ddd/file.c", ""); add("dir/foo.cpp", "-std=c++17"); add("dir/bar.c", ""); add("dir/baz.cee", "-x c"); @@ -774,7 +775,10 @@ EXPECT_EQ(getCommand("baz.h"), "clang -D dir/baz.cee -x c-header"); // prefer a worse match with the right extension. EXPECT_EQ(getCommand("foo.c"), "clang -D dir/bar.c"); + // even when it is far away. + EXPECT_EQ(getCommand("aaa/bbb/ccc/ddd/file.hpp"), "clang -D dir/aux.cpp"); Entries.erase(path(StringRef("dir/bar.c"))); + Entries.erase(path(StringRef("aaa/bbb/ccc/ddd/file.c"))); // Now we transfer across languages, so drop -std too. EXPECT_EQ(getCommand("foo.c"), "clang -D dir/foo.cpp"); // Prefer -x over -std when overriding language. Index: clang/lib/Tooling/InterpolatingCompilationDatabase.cpp =================================================================== --- clang/lib/Tooling/InterpolatingCompilationDatabase.cpp +++ clang/lib/Tooling/InterpolatingCompilationDatabase.cpp @@ -352,7 +352,7 @@ types::ID PreferLanguage) const { assert(!empty() && "need at least one candidate!"); std::string Filename = OriginalFilename.lower(); - auto Candidates = scoreCandidates(Filename); + auto Candidates = scoreCandidates(Filename, PreferLanguage); std::pair<size_t, int> Best = pickWinner(Candidates, Filename, PreferLanguage); @@ -378,7 +378,8 @@ // Award points to candidate entries that should be considered for the file. // Returned keys are indexes into paths, and the values are (nonzero) scores. - DenseMap<size_t, int> scoreCandidates(StringRef Filename) const { + DenseMap<size_t, int> scoreCandidates(StringRef Filename, + types::ID PreferredLanguage) const { // Decompose Filename into the parts we care about. // /some/path/complicated/project/Interesting.h // [-prefix--][---dir---] [-dir-] [--stem---] @@ -410,6 +411,25 @@ // Award one more point if the whole rest of the path matches. if (sys::path::root_directory(Prefix) != Prefix) Award(1, indexLookup</*Prefix=*/true>(Prefix, Paths)); + + bool CandidateWithMatchingLanguageFound = false; + for (const auto &C : Candidates) { + if (Types[C.first] == PreferredLanguage) { + CandidateWithMatchingLanguageFound = true; + break; + } + } + if (!CandidateWithMatchingLanguageFound) { + // If none of the candidates we found so far use preferred language, try + // all other files, even if they are far away in the dir hierarchy. + for (size_t I = 0; I < OriginalPaths.size(); ++I) { + // Increase score by one. The actual value doesn't matter, the point is + // to have some candidates matching PreferredLanguage in the Candidates + // set at all. + if (Types[I] == PreferredLanguage) + Candidates[I] += 1; + } + } return Candidates; }
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits