50 #include "llvm/ADT/DenseMap.h" 51 #include "llvm/ADT/Optional.h" 52 #include "llvm/ADT/StringExtras.h" 53 #include "llvm/ADT/StringSwitch.h" 54 #include "llvm/Option/ArgList.h" 55 #include "llvm/Option/OptTable.h" 56 #include "llvm/Support/Debug.h" 57 #include "llvm/Support/Path.h" 58 #include "llvm/Support/StringSaver.h" 59 #include "llvm/Support/raw_ostream.h" 67 namespace path = llvm::sys::path;
70 size_t matchingPrefix(StringRef L, StringRef R) {
71 size_t Limit =
std::min(L.size(), R.size());
72 for (
size_t I = 0; I < Limit; ++I)
80 template <
bool Prefix>
struct Less {
81 bool operator()(StringRef Key, std::pair<StringRef, size_t>
Value)
const {
82 StringRef V = Prefix ? Value.first.substr(0, Key.size()) : Value.first;
85 bool operator()(std::pair<StringRef, size_t> Value, StringRef Key)
const {
86 StringRef V = Prefix ? Value.first.substr(0, Key.size()) : Value.first;
107 case types::TY_CHeader:
110 case types::TY_ObjCHeader:
111 return types::TY_ObjC;
113 case types::TY_CXXHeader:
114 return types::TY_CXX;
115 case types::TY_ObjCXX:
116 case types::TY_ObjCXXHeader:
117 return types::TY_ObjCXX;
124 struct TransferableCommand {
134 TransferableCommand(CompileCommand C)
135 : Cmd(
std::move(C)), Type(guessType(Cmd.Filename)),
136 ClangCLMode(checkIsCLMode(Cmd.CommandLine)) {
137 std::vector<std::string> OldArgs = std::move(Cmd.CommandLine);
138 Cmd.CommandLine.clear();
141 llvm::opt::InputArgList ArgList;
144 for (
const std::string &S : OldArgs)
145 TmpArgv.push_back(S.c_str());
146 ArgList = {TmpArgv.begin(), TmpArgv.end()};
154 Cmd.CommandLine.emplace_back(OldArgs.front());
155 for (
unsigned Pos = 1; Pos < OldArgs.size();) {
156 using namespace driver::options;
158 const unsigned OldPos = Pos;
159 std::unique_ptr<llvm::opt::Arg> Arg(OptTable->ParseOneArg(
167 const llvm::opt::Option &Opt = Arg->getOption();
170 if (Opt.matches(OPT_INPUT) || Opt.matches(OPT_o) ||
171 (ClangCLMode && (Opt.matches(OPT__SLASH_Fa) ||
172 Opt.matches(OPT__SLASH_Fe) ||
173 Opt.matches(OPT__SLASH_Fi) ||
174 Opt.matches(OPT__SLASH_Fo))))
178 if (
const auto GivenType = tryParseTypeArg(*Arg)) {
184 if (
const auto GivenStd = tryParseStdArg(*Arg)) {
190 Cmd.CommandLine.insert(Cmd.CommandLine.end(),
191 OldArgs.data() + OldPos, OldArgs.data() + Pos);
196 Type = foldType(*Type);
203 CompileCommand transferTo(StringRef Filename)
const {
204 CompileCommand Result =
Cmd;
207 auto TargetType = guessType(Filename, &TypeCertain);
214 const StringRef Flag = toCLFlag(TargetType);
216 Result.CommandLine.push_back(Flag);
218 Result.CommandLine.push_back(
"-x");
225 Result.CommandLine.emplace_back((
226 llvm::Twine(ClangCLMode ?
"/std:" :
"-std=") +
229 Result.CommandLine.push_back(Filename);
237 for (StringRef S : llvm::reverse(CmdLine)) {
238 if (S.consume_front(
"--driver-mode="))
243 return llvm::sys::path::stem(CmdLine.front()).endswith_lower(
"cl");
252 return types::TY_CXX;
254 return types::TY_ObjC;
256 return types::TY_ObjCXX;
263 static StringRef toCLFlag(
types::ID Type) {
266 case types::TY_CHeader:
269 case types::TY_CXXHeader:
278 const llvm::opt::Option &Opt = Arg.getOption();
279 using namespace driver::options;
281 if (Opt.matches(OPT__SLASH_TC) || Opt.matches(OPT__SLASH_Tc))
283 if (Opt.matches(OPT__SLASH_TP) || Opt.matches(OPT__SLASH_Tp))
284 return types::TY_CXX;
286 if (Opt.matches(driver::options::OPT_x))
294 using namespace driver::options;
295 if (Arg.getOption().matches(ClangCLMode ? OPT__SLASH_std : OPT_std_EQ)) {
296 return llvm::StringSwitch<LangStandard::Kind>(Arg.getValue())
297 #define
LANGSTANDARD(
id, name, lang, ...) .Case(name, LangStandard::lang_##
id)
298 #define LANGSTANDARD_ALIAS(id, alias) .Case(alias, LangStandard::lang_##id) 299 #include "clang/Frontend/LangStandards.def" 300 #undef LANGSTANDARD_ALIAS 321 FileIndex(std::vector<std::string> Files)
322 : OriginalPaths(std::move(Files)), Strings(Arena) {
324 llvm::sort(OriginalPaths);
325 Paths.reserve(OriginalPaths.size());
326 Types.reserve(OriginalPaths.size());
327 Stems.reserve(OriginalPaths.size());
328 for (
size_t I = 0; I < OriginalPaths.size(); ++I) {
329 StringRef Path = Strings.save(StringRef(OriginalPaths[I]).lower());
331 Paths.emplace_back(Path, I);
332 Types.push_back(foldType(guessType(Path)));
333 Stems.emplace_back(sys::path::stem(Path), I);
334 auto Dir = ++sys::path::rbegin(Path), DirEnd = sys::path::rend(Path);
335 for (
int J = 0; J < DirectorySegmentsIndexed && Dir != DirEnd; ++J, ++Dir)
336 if (Dir->size() > ShortDirectorySegment)
337 Components.emplace_back(*Dir, I);
341 llvm::sort(Components);
344 bool empty()
const {
return Paths.empty(); }
349 StringRef chooseProxy(StringRef OriginalFilename,
351 assert(!empty() &&
"need at least one candidate!");
352 std::string Filename = OriginalFilename.lower();
353 auto Candidates = scoreCandidates(Filename);
354 std::pair<size_t, int> Best =
355 pickWinner(Candidates, Filename, PreferLanguage);
359 llvm::dbgs() <<
"interpolate: chose " << OriginalPaths[Best.first]
360 <<
" as proxy for " << OriginalFilename <<
" preferring " 364 <<
" score=" << Best.second <<
"\n");
365 return OriginalPaths[Best.first];
369 using SubstringAndIndex = std::pair<StringRef, size_t>;
373 constexpr
static int DirectorySegmentsIndexed = 4;
374 constexpr
static int DirectorySegmentsQueried = 2;
375 constexpr
static int ShortDirectorySegment = 1;
379 DenseMap<size_t, int> scoreCandidates(StringRef Filename)
const {
383 StringRef Stem = sys::path::stem(Filename);
385 llvm::StringRef Prefix;
386 auto Dir = ++sys::path::rbegin(Filename),
387 DirEnd = sys::path::rend(Filename);
388 for (
int I = 0; I < DirectorySegmentsQueried && Dir != DirEnd; ++I, ++Dir) {
389 if (Dir->size() > ShortDirectorySegment)
390 Dirs.push_back(*Dir);
391 Prefix = Filename.substr(0, Dir - DirEnd);
395 DenseMap<size_t, int> Candidates;
397 for (
const auto &Entry : Range)
398 Candidates[Entry.second] += Points;
402 Award(1, indexLookup</*Prefix=*/true>(Stem, Stems));
403 Award(1, indexLookup</*Prefix=*/false>(Stem, Stems));
406 for (StringRef Dir : Dirs)
407 Award(1, indexLookup</*Prefix=*/false>(Dir, Components));
409 if (sys::path::root_directory(Prefix) != Prefix)
410 Award(1, indexLookup</*Prefix=*/true>(Prefix, Paths));
416 std::pair<size_t, int> pickWinner(
const DenseMap<size_t, int> &Candidates,
419 struct ScoredCandidate {
426 ScoredCandidate Best = {
size_t(-1),
false, 0, 0};
427 for (
const auto &Candidate : Candidates) {
429 S.Index = Candidate.first;
431 PreferredLanguage == Types[S.Index];
432 S.Points = Candidate.second;
433 if (!S.Preferred && Best.Preferred)
435 if (S.Preferred == Best.Preferred) {
436 if (S.Points < Best.Points)
438 if (S.Points == Best.Points) {
439 S.PrefixLength = matchingPrefix(Filename, Paths[S.Index].first);
440 if (S.PrefixLength < Best.PrefixLength)
443 if (S.PrefixLength == Best.PrefixLength)
444 if (S.Index > Best.Index)
450 S.PrefixLength = matchingPrefix(Filename, Paths[S.Index].first);
455 if (Best.Index ==
size_t(-1))
456 return {longestMatch(Filename, Paths).second, 0};
457 return {Best.Index, Best.Points};
462 template <
bool Prefix>
466 auto Range = std::equal_range(Idx.data(), Idx.data() + Idx.size(), Key,
468 return {Range.first, Range.second};
472 SubstringAndIndex longestMatch(StringRef Key,
474 assert(!Idx.empty());
477 std::lower_bound(Idx.begin(), Idx.end(), SubstringAndIndex{Key, 0});
478 if (It == Idx.begin())
483 size_t Prefix = matchingPrefix(Key, It->first);
484 size_t PrevPrefix = matchingPrefix(Key, (It - 1)->first);
485 return Prefix > PrevPrefix ? *It : *--It;
489 std::vector<std::string> OriginalPaths;
490 BumpPtrAllocator Arena;
494 std::vector<SubstringAndIndex> Paths;
497 std::vector<types::ID> Types;
498 std::vector<SubstringAndIndex> Stems;
499 std::vector<SubstringAndIndex> Components;
505 class InterpolatingCompilationDatabase :
public CompilationDatabase {
507 InterpolatingCompilationDatabase(std::unique_ptr<CompilationDatabase> Inner)
508 : Inner(std::move(Inner)), Index(this->Inner->getAllFiles()) {}
510 std::vector<CompileCommand>
511 getCompileCommands(StringRef Filename)
const override {
512 auto Known = Inner->getCompileCommands(Filename);
513 if (Index.empty() || !Known.empty())
516 auto Lang = guessType(Filename, &TypeCertain);
520 Inner->getCompileCommands(Index.chooseProxy(Filename, foldType(Lang)));
521 if (ProxyCommands.empty())
523 return {TransferableCommand(ProxyCommands[0]).transferTo(Filename)};
526 std::vector<std::string> getAllFiles()
const override {
527 return Inner->getAllFiles();
530 std::vector<CompileCommand> getAllCompileCommands()
const override {
531 return Inner->getAllCompileCommands();
535 std::unique_ptr<CompilationDatabase> Inner;
541 std::unique_ptr<CompilationDatabase>
543 return llvm::make_unique<InterpolatingCompilationDatabase>(std::move(Inner));
__SIZE_TYPE__ size_t
The unsigned integer type of the result of the sizeof operator.
DominatorTree GraphTraits specialization so the DominatorTree can be iterable by generic graph iterat...
static const LangStandard & getLangStandardForKind(Kind K)
std::string getName(ArrayRef< StringRef > Parts) const
Get the platform-specific name separator.
std::unique_ptr< llvm::opt::OptTable > createDriverOptTable()
ID lookupHeaderTypeForSourceType(ID Id)
Lookup header file input type that corresponds to given source file type (used for clang-cl emulation...
const char * getTypeName(ID Id)
getTypeName - Return the name of the type for Id.
Optional< types::ID > Type
Dataflow Directional Tag Classes.
ID lookupTypeForExtension(llvm::StringRef Ext)
lookupTypeForExtension - Lookup the type to use for the file extension Ext.
bool onlyPrecompileType(ID Id)
onlyPrecompileType - Should this type only be precompiled.
#define LANGSTANDARD(id, name, lang,...)
__DEVICE__ int min(int __a, int __b)
ID lookupTypeForTypeSpecifier(const char *Name)
lookupTypeForTypSpecifier - Lookup the type to use for a user specified type name.