49 #include "llvm/ADT/DenseMap.h" 50 #include "llvm/ADT/Optional.h" 51 #include "llvm/ADT/StringExtras.h" 52 #include "llvm/ADT/StringSwitch.h" 53 #include "llvm/Option/ArgList.h" 54 #include "llvm/Option/OptTable.h" 55 #include "llvm/Support/Debug.h" 56 #include "llvm/Support/Path.h" 57 #include "llvm/Support/StringSaver.h" 58 #include "llvm/Support/raw_ostream.h" 66 namespace path = llvm::sys::path;
69 size_t matchingPrefix(StringRef L, StringRef R) {
70 size_t Limit =
std::min(L.size(), R.size());
71 for (
size_t I = 0; I < Limit; ++I)
79 template <
bool Prefix>
struct Less {
80 bool operator()(StringRef Key, std::pair<StringRef, size_t>
Value)
const {
81 StringRef
V = Prefix ? Value.first.substr(0, Key.size()) : Value.first;
84 bool operator()(std::pair<StringRef, size_t> Value, StringRef Key)
const {
85 StringRef V = Prefix ? Value.first.substr(0, Key.size()) : Value.first;
106 case types::TY_CHeader:
109 case types::TY_ObjCHeader:
110 return types::TY_ObjC;
112 case types::TY_CXXHeader:
113 return types::TY_CXX;
114 case types::TY_ObjCXX:
115 case types::TY_ObjCXXHeader:
116 return types::TY_ObjCXX;
123 struct TransferableCommand {
133 TransferableCommand(CompileCommand C)
134 : Cmd(
std::move(C)), Type(guessType(Cmd.Filename)),
135 ClangCLMode(checkIsCLMode(Cmd.CommandLine)) {
136 std::vector<std::string> OldArgs = std::move(Cmd.CommandLine);
137 Cmd.CommandLine.clear();
140 llvm::opt::InputArgList ArgList;
143 for (
const std::string &S : OldArgs)
144 TmpArgv.push_back(S.c_str());
145 ArgList = {TmpArgv.begin(), TmpArgv.end()};
153 if (!OldArgs.empty())
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);
209 if ((!TargetType || !TypeCertain) && Type) {
217 const StringRef Flag = toCLFlag(TargetType);
219 Result.CommandLine.push_back(Flag);
221 Result.CommandLine.push_back(
"-x");
228 Result.CommandLine.emplace_back((
229 llvm::Twine(ClangCLMode ?
"/std:" :
"-std=") +
232 Result.CommandLine.push_back(Filename);
233 Result.Heuristic =
"inferred from " + Cmd.Filename;
241 for (StringRef S : llvm::reverse(CmdLine)) {
242 if (S.consume_front(
"--driver-mode="))
247 return !CmdLine.empty() &&
248 llvm::sys::path::stem(CmdLine.front()).endswith_lower(
"cl");
257 return types::TY_CXX;
259 return types::TY_ObjC;
261 return types::TY_ObjCXX;
268 static StringRef toCLFlag(
types::ID Type) {
271 case types::TY_CHeader:
274 case types::TY_CXXHeader:
283 const llvm::opt::Option &Opt = Arg.getOption();
284 using namespace driver::options;
286 if (Opt.matches(OPT__SLASH_TC) || Opt.matches(OPT__SLASH_Tc))
288 if (Opt.matches(OPT__SLASH_TP) || Opt.matches(OPT__SLASH_Tp))
289 return types::TY_CXX;
291 if (Opt.matches(driver::options::OPT_x))
299 using namespace driver::options;
300 if (Arg.getOption().matches(ClangCLMode ? OPT__SLASH_std : OPT_std_EQ)) {
301 return llvm::StringSwitch<LangStandard::Kind>(Arg.getValue())
303 #define LANGSTANDARD_ALIAS(id, alias) .Case(alias, LangStandard::lang_##id) 304 #include "clang/Frontend/LangStandards.def" 305 #undef LANGSTANDARD_ALIAS 326 FileIndex(std::vector<std::string> Files)
327 : OriginalPaths(std::move(Files)), Strings(Arena) {
329 llvm::sort(OriginalPaths);
330 Paths.reserve(OriginalPaths.size());
331 Types.reserve(OriginalPaths.size());
332 Stems.reserve(OriginalPaths.size());
333 for (
size_t I = 0; I < OriginalPaths.size(); ++I) {
334 StringRef Path = Strings.save(StringRef(OriginalPaths[I]).lower());
336 Paths.emplace_back(Path, I);
337 Types.push_back(foldType(guessType(Path)));
338 Stems.emplace_back(sys::path::stem(Path), I);
339 auto Dir = ++sys::path::rbegin(Path), DirEnd = sys::path::rend(Path);
340 for (
int J = 0; J < DirectorySegmentsIndexed && Dir != DirEnd; ++J, ++Dir)
341 if (Dir->size() > ShortDirectorySegment)
342 Components.emplace_back(*Dir, I);
346 llvm::sort(Components);
349 bool empty()
const {
return Paths.empty(); }
354 StringRef chooseProxy(StringRef OriginalFilename,
356 assert(!empty() &&
"need at least one candidate!");
357 std::string Filename = OriginalFilename.lower();
358 auto Candidates = scoreCandidates(Filename);
359 std::pair<size_t, int> Best =
360 pickWinner(Candidates, Filename, PreferLanguage);
364 llvm::dbgs() <<
"interpolate: chose " << OriginalPaths[Best.first]
365 <<
" as proxy for " << OriginalFilename <<
" preferring " 369 <<
" score=" << Best.second <<
"\n");
370 return OriginalPaths[Best.first];
374 using SubstringAndIndex = std::pair<StringRef, size_t>;
378 constexpr
static int DirectorySegmentsIndexed = 4;
379 constexpr
static int DirectorySegmentsQueried = 2;
380 constexpr
static int ShortDirectorySegment = 1;
384 DenseMap<size_t, int> scoreCandidates(StringRef Filename)
const {
388 StringRef Stem = sys::path::stem(Filename);
390 llvm::StringRef Prefix;
391 auto Dir = ++sys::path::rbegin(Filename),
392 DirEnd = sys::path::rend(Filename);
393 for (
int I = 0; I < DirectorySegmentsQueried && Dir != DirEnd; ++I, ++Dir) {
394 if (Dir->size() > ShortDirectorySegment)
395 Dirs.push_back(*Dir);
396 Prefix = Filename.substr(0, Dir - DirEnd);
400 DenseMap<size_t, int> Candidates;
402 for (
const auto &Entry : Range)
403 Candidates[Entry.second] += Points;
407 Award(1, indexLookup</*Prefix=*/true>(Stem, Stems));
408 Award(1, indexLookup</*Prefix=*/false>(Stem, Stems));
411 for (StringRef Dir : Dirs)
412 Award(1, indexLookup</*Prefix=*/false>(Dir, Components));
414 if (sys::path::root_directory(Prefix) != Prefix)
415 Award(1, indexLookup</*Prefix=*/true>(Prefix, Paths));
421 std::pair<size_t, int> pickWinner(
const DenseMap<size_t, int> &Candidates,
424 struct ScoredCandidate {
431 ScoredCandidate Best = {
size_t(-1),
false, 0, 0};
432 for (
const auto &Candidate : Candidates) {
434 S.Index = Candidate.first;
436 PreferredLanguage == Types[S.Index];
437 S.Points = Candidate.second;
438 if (!S.Preferred && Best.Preferred)
440 if (S.Preferred == Best.Preferred) {
441 if (S.Points < Best.Points)
443 if (S.Points == Best.Points) {
444 S.PrefixLength = matchingPrefix(Filename, Paths[S.Index].first);
445 if (S.PrefixLength < Best.PrefixLength)
448 if (S.PrefixLength == Best.PrefixLength)
449 if (S.Index > Best.Index)
455 S.PrefixLength = matchingPrefix(Filename, Paths[S.Index].first);
460 if (Best.Index ==
size_t(-1))
461 return {longestMatch(Filename, Paths).second, 0};
462 return {Best.Index, Best.Points};
467 template <
bool Prefix>
471 auto Range = std::equal_range(Idx.data(), Idx.data() + Idx.size(), Key,
473 return {Range.first, Range.second};
477 SubstringAndIndex longestMatch(StringRef Key,
479 assert(!Idx.empty());
481 auto It = llvm::lower_bound(Idx, SubstringAndIndex{Key, 0});
482 if (It == Idx.begin())
487 size_t Prefix = matchingPrefix(Key, It->first);
488 size_t PrevPrefix = matchingPrefix(Key, (It - 1)->first);
489 return Prefix > PrevPrefix ? *It : *--It;
493 std::vector<std::string> OriginalPaths;
494 BumpPtrAllocator Arena;
498 std::vector<SubstringAndIndex> Paths;
501 std::vector<types::ID> Types;
502 std::vector<SubstringAndIndex> Stems;
503 std::vector<SubstringAndIndex> Components;
509 class InterpolatingCompilationDatabase :
public CompilationDatabase {
511 InterpolatingCompilationDatabase(std::unique_ptr<CompilationDatabase> Inner)
512 : Inner(std::move(Inner)), Index(this->Inner->getAllFiles()) {}
514 std::vector<CompileCommand>
515 getCompileCommands(StringRef Filename)
const override {
516 auto Known = Inner->getCompileCommands(Filename);
517 if (Index.empty() || !Known.empty())
520 auto Lang = guessType(Filename, &TypeCertain);
524 Inner->getCompileCommands(Index.chooseProxy(Filename, foldType(Lang)));
525 if (ProxyCommands.empty())
527 return {TransferableCommand(ProxyCommands[0]).transferTo(Filename)};
530 std::vector<std::string> getAllFiles()
const override {
531 return Inner->getAllFiles();
534 std::vector<CompileCommand> getAllCompileCommands()
const override {
535 return Inner->getAllCompileCommands();
539 std::unique_ptr<CompilationDatabase> Inner;
545 std::unique_ptr<CompilationDatabase>
547 return llvm::make_unique<InterpolatingCompilationDatabase>(std::move(Inner));
Specialize PointerLikeTypeTraits to allow LazyGenerationalUpdatePtr to be placed into a PointerUnion...
static const LangStandard & getLangStandardForKind(Kind K)
__SIZE_TYPE__ size_t
The unsigned integer type of the result of the sizeof operator.
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.
static std::string getName(const CallEvent &Call)
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.
__DEVICE__ int min(int __a, int __b)
#define LANGSTANDARD(id, name, lang,...)
ID lookupTypeForTypeSpecifier(const char *Name)
lookupTypeForTypSpecifier - Lookup the type to use for a user specified type name.