50 #include "llvm/ADT/DenseMap.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 {
131 TransferableCommand(CompileCommand C)
132 : Cmd(
std::move(C)), Type(guessType(Cmd.Filename)) {
133 std::vector<std::string> NewArgs = {Cmd.CommandLine.front()};
136 std::vector<const char *> Argv;
137 for (
unsigned I = 1; I < Cmd.CommandLine.size(); ++I)
138 Argv.push_back(Cmd.CommandLine[I].c_str());
139 unsigned MissingI, MissingC;
140 auto ArgList = OptTable->ParseArgs(Argv, MissingI, MissingC);
141 for (
const auto *Arg : ArgList) {
142 const auto &option = Arg->getOption();
144 if (option.matches(clang::driver::options::OPT_INPUT) ||
145 option.matches(clang::driver::options::OPT_o)) {
149 if (option.matches(clang::driver::options::OPT_x)) {
150 for (
const char *Value : Arg->getValues())
155 if (option.matches(clang::driver::options::OPT_std_EQ)) {
156 for (
const char *Value : Arg->getValues()) {
157 Std = llvm::StringSwitch<LangStandard::Kind>(
Value)
159 .Case(name, LangStandard::lang_##
id)
160 #define LANGSTANDARD_ALIAS(id, alias) .Case(alias, LangStandard::lang_##id) 161 #include "clang/Frontend/LangStandards.def" 166 llvm::opt::ArgStringList ArgStrs;
167 Arg->render(ArgList, ArgStrs);
168 NewArgs.insert(NewArgs.end(), ArgStrs.begin(), ArgStrs.end());
170 Cmd.CommandLine = std::move(NewArgs);
174 Type = foldType(Type);
178 CompileCommand transferTo(StringRef Filename)
const {
179 CompileCommand Result =
Cmd;
182 auto TargetType = guessType(Filename, &TypeCertain);
188 Result.CommandLine.push_back(
"-x");
194 Result.CommandLine.push_back(
198 Result.CommandLine.push_back(Filename);
209 return types::TY_CXX;
211 return types::TY_ObjC;
213 return types::TY_ObjCXX;
230 CommandIndex(std::vector<TransferableCommand> AllCommands)
231 : Commands(std::move(AllCommands)), Strings(Arena) {
234 Commands.begin(), Commands.end(),
235 [](
const TransferableCommand &Left,
const TransferableCommand &Right) {
236 return Left.Cmd.Filename < Right.Cmd.Filename;
238 for (
size_t I = 0; I < Commands.size(); ++I) {
240 Strings.save(StringRef(Commands[I].
Cmd.Filename).lower());
241 Paths.push_back({Path, I});
242 Stems.emplace_back(sys::path::stem(Path), I);
243 auto Dir = ++sys::path::rbegin(Path), DirEnd = sys::path::rend(Path);
244 for (
int J = 0; J < DirectorySegmentsIndexed && Dir != DirEnd; ++J, ++Dir)
245 if (Dir->size() > ShortDirectorySegment)
246 Components.emplace_back(*Dir, I);
248 llvm::sort(Paths.begin(), Paths.end());
249 llvm::sort(Stems.begin(), Stems.end());
250 llvm::sort(Components.begin(), Components.end());
253 bool empty()
const {
return Commands.empty(); }
258 const TransferableCommand &chooseProxy(StringRef OriginalFilename,
260 assert(!empty() &&
"need at least one candidate!");
261 std::string Filename = OriginalFilename.lower();
262 auto Candidates = scoreCandidates(Filename);
263 std::pair<size_t, int> Best =
264 pickWinner(Candidates, Filename, PreferLanguage);
266 DEBUG_WITH_TYPE(
"interpolate",
268 <<
"interpolate: chose " 269 << Commands[Best.first].Cmd.Filename <<
" as proxy for " 270 << OriginalFilename <<
" preferring " 274 <<
" score=" << Best.second <<
"\n");
275 return Commands[Best.first];
279 using SubstringAndIndex = std::pair<StringRef, size_t>;
283 constexpr
static int DirectorySegmentsIndexed = 4;
284 constexpr
static int DirectorySegmentsQueried = 2;
285 constexpr
static int ShortDirectorySegment = 1;
289 DenseMap<size_t, int> scoreCandidates(StringRef Filename)
const {
293 StringRef Stem = sys::path::stem(Filename);
295 llvm::StringRef Prefix;
296 auto Dir = ++sys::path::rbegin(Filename),
297 DirEnd = sys::path::rend(Filename);
298 for (
int I = 0; I < DirectorySegmentsQueried && Dir != DirEnd; ++I, ++Dir) {
299 if (Dir->size() > ShortDirectorySegment)
300 Dirs.push_back(*Dir);
301 Prefix = Filename.substr(0, Dir - DirEnd);
305 DenseMap<size_t, int> Candidates;
307 for (
const auto &Entry : Range)
308 Candidates[Entry.second] += Points;
312 Award(1, indexLookup</*Prefix=*/true>(Stem, Stems));
313 Award(1, indexLookup</*Prefix=*/false>(Stem, Stems));
316 for (StringRef Dir : Dirs)
317 Award(1, indexLookup</*Prefix=*/false>(Dir, Components));
319 if (sys::path::root_directory(Prefix) != Prefix)
320 Award(1, indexLookup</*Prefix=*/true>(Prefix, Paths));
326 std::pair<size_t, int> pickWinner(
const DenseMap<size_t, int> &Candidates,
329 struct ScoredCandidate {
336 ScoredCandidate Best = {
size_t(-1),
false, 0, 0};
337 for (
const auto &Candidate : Candidates) {
339 S.Index = Candidate.first;
341 PreferredLanguage == Commands[S.Index].Type;
342 S.Points = Candidate.second;
343 if (!S.Preferred && Best.Preferred)
345 if (S.Preferred == Best.Preferred) {
346 if (S.Points < Best.Points)
348 if (S.Points == Best.Points) {
349 S.PrefixLength = matchingPrefix(Filename, Paths[S.Index].first);
350 if (S.PrefixLength < Best.PrefixLength)
353 if (S.PrefixLength == Best.PrefixLength)
354 if (S.Index > Best.Index)
360 S.PrefixLength = matchingPrefix(Filename, Paths[S.Index].first);
365 if (Best.Index ==
size_t(-1))
366 return {longestMatch(Filename, Paths).second, 0};
367 return {Best.Index, Best.Points};
372 template <
bool Prefix>
374 indexLookup(StringRef Key,
const std::vector<SubstringAndIndex> &Idx)
const {
376 auto Range = std::equal_range(Idx.data(), Idx.data() + Idx.size(), Key,
378 return {Range.first, Range.second};
383 longestMatch(StringRef Key,
const std::vector<SubstringAndIndex> &Idx)
const {
384 assert(!Idx.empty());
387 std::lower_bound(Idx.begin(), Idx.end(), SubstringAndIndex{Key, 0});
388 if (It == Idx.begin())
393 size_t Prefix = matchingPrefix(Key, It->first);
394 size_t PrevPrefix = matchingPrefix(Key, (It - 1)->first);
395 return Prefix > PrevPrefix ? *It : *--It;
398 std::vector<TransferableCommand> Commands;
399 BumpPtrAllocator Arena;
403 std::vector<SubstringAndIndex> Paths;
404 std::vector<SubstringAndIndex> Stems;
405 std::vector<SubstringAndIndex> Components;
410 class InterpolatingCompilationDatabase :
public CompilationDatabase {
412 InterpolatingCompilationDatabase(std::unique_ptr<CompilationDatabase> Inner)
413 : Inner(std::move(Inner)), Index(allCommands()) {}
415 std::vector<CompileCommand>
416 getCompileCommands(StringRef Filename)
const override {
417 auto Known = Inner->getCompileCommands(Filename);
418 if (Index.empty() || !Known.empty())
421 auto Lang = guessType(Filename, &TypeCertain);
424 return {Index.chooseProxy(Filename, foldType(Lang)).transferTo(Filename)};
427 std::vector<std::string> getAllFiles()
const override {
428 return Inner->getAllFiles();
431 std::vector<CompileCommand> getAllCompileCommands()
const override {
432 return Inner->getAllCompileCommands();
436 std::vector<TransferableCommand> allCommands() {
437 std::vector<TransferableCommand> Result;
438 for (
auto Command : Inner->getAllCompileCommands()) {
439 Result.emplace_back(std::move(Command));
446 std::unique_ptr<CompilationDatabase> Inner;
452 std::unique_ptr<CompilationDatabase>
454 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.
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.
__DEVICE__ int min(int __a, int __b)
ID lookupTypeForTypeSpecifier(const char *Name)
lookupTypeForTypSpecifier - Lookup the type to use for a user specified type name.
#define LANGSTANDARD(id, name, lang, desc, features)