diff --git a/clang/lib/Tooling/InterpolatingCompilationDatabase.cpp b/clang/lib/Tooling/InterpolatingCompilationDatabase.cpp --- a/clang/lib/Tooling/InterpolatingCompilationDatabase.cpp +++ b/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 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 scoreCandidates(StringRef Filename) const { + DenseMap 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, 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; } diff --git a/clang/unittests/Tooling/CompilationDatabaseTest.cpp b/clang/unittests/Tooling/CompilationDatabaseTest.cpp --- a/clang/unittests/Tooling/CompilationDatabaseTest.cpp +++ b/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.