clang 24.0.0git
InterpolatingCompilationDatabase.cpp
Go to the documentation of this file.
1//===- InterpolatingCompilationDatabase.cpp ---------------------*- C++ -*-===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// InterpolatingCompilationDatabase wraps another CompilationDatabase and
10// attempts to heuristically determine appropriate compile commands for files
11// that are not included, such as headers or newly created files.
12//
13// Motivating cases include:
14// Header files that live next to their implementation files. These typically
15// share a base filename. (libclang/CXString.h, libclang/CXString.cpp).
16// Some projects separate headers from includes. Filenames still typically
17// match, maybe other path segments too. (include/llvm/IR/Use.h, lib/IR/Use.cc).
18// Matches are sometimes only approximate (Sema.h, SemaDecl.cpp). This goes
19// for directories too (Support/Unix/Process.inc, lib/Support/Process.cpp).
20// Even if we can't find a "right" compile command, even a random one from
21// the project will tend to get important flags like -I and -x right.
22//
23// We "borrow" the compile command for the closest available file:
24// - points are awarded if the filename matches (ignoring extension)
25// - points are awarded if the directory structure matches
26// - ties are broken by length of path prefix match
27//
28// The compile command is adjusted, replacing the filename and removing output
29// file arguments. The -x and -std flags may be affected too.
30//
31// Source language is a tricky issue: is it OK to use a .c file's command
32// for building a .cc file? What language is a .h file in?
33// - We only consider compile commands for c-family languages as candidates.
34// - For files whose language is implied by the filename (e.g. .m, .hpp)
35// we prefer candidates from the same language.
36// If we must cross languages, we drop any -x and -std flags.
37// - For .h files, candidates from any c-family language are acceptable.
38// We use the candidate's language, inserting e.g. -x c++-header.
39//
40// This class is only useful when wrapping databases that can enumerate all
41// their compile commands. If getAllFilenames() is empty, no inference occurs.
42//
43//===----------------------------------------------------------------------===//
44
46#include "clang/Driver/Driver.h"
47#include "clang/Driver/Types.h"
50#include "llvm/ADT/ArrayRef.h"
51#include "llvm/ADT/DenseMap.h"
52#include "llvm/ADT/StringExtras.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"
59#include <memory>
60#include <optional>
61
62namespace clang {
63namespace tooling {
64namespace {
65using namespace llvm;
66namespace types = clang::driver::types;
67namespace path = llvm::sys::path;
68
69// The length of the prefix these two strings have in common.
70size_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)
73 if (L[I] != R[I])
74 return I;
75 return Limit;
76}
77
78// A comparator for searching SubstringWithIndexes with std::equal_range etc.
79// Optionaly prefix semantics: compares equal if the key is a prefix.
80template <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;
83 return Key < V;
84 }
85 bool operator()(std::pair<StringRef, size_t> Value, StringRef Key) const {
86 StringRef V = Prefix ? Value.first.substr(0, Key.size()) : Value.first;
87 return V < Key;
88 }
89};
90
91// Infer type from filename. If we might have gotten it wrong, set *Certain.
92// *.h will be inferred as a C header, but not certain.
93types::ID guessType(StringRef Filename, bool *Certain = nullptr) {
94 // path::extension is ".cpp", lookupTypeForExtension wants "cpp".
95 auto Lang =
96 types::lookupTypeForExtension(path::extension(Filename).substr(1));
97 if (Certain)
98 *Certain = Lang != types::TY_CHeader && Lang != types::TY_INVALID;
99 return Lang;
100}
101
102// Return Lang as one of the canonical supported types.
103// e.g. c-header --> c; fortran --> TY_INVALID
104static types::ID foldType(types::ID Lang) {
105 switch (Lang) {
106 case types::TY_C:
107 case types::TY_CHeader:
108 return types::TY_C;
109 case types::TY_ObjC:
110 case types::TY_ObjCHeader:
111 return types::TY_ObjC;
112 case types::TY_CXX:
113 case types::TY_CXXHeader:
114 case types::TY_CXXModule:
115 case types::TY_PP_CXXModule:
116 case types::TY_CXXStdModule:
117 case types::TY_PP_CXXStdModule:
118 return types::TY_CXX;
119 case types::TY_ObjCXX:
120 case types::TY_ObjCXXHeader:
121 return types::TY_ObjCXX;
122 case types::TY_CUDA:
123 case types::TY_CUDA_DEVICE:
124 return types::TY_CUDA;
125 default:
126 return types::TY_INVALID;
127 }
128}
129
130// Whether two types use the same -std flag family.
131// C and ObjC share C standards; C++, ObjC++, CUDA, HIP share C++ standards.
132static bool typesSameStandardFamily(types::ID T1, types::ID T2) {
133 if (!types::isDerivedFromC(T1) || !types::isDerivedFromC(T2))
134 return false;
135 return types::isCXX(T1) == types::isCXX(T2);
136}
137
138// Return the language standard that's activated by the /std:clatest
139// flag in clang-CL mode.
140static LangStandard::Kind latestLangStandardC() {
141 // FIXME: Have a single source of truth for the mapping from
142 // clatest --> c23 that's shared by the driver code
143 // (clang/lib/Driver/ToolChains/Clang.cpp) and this file.
144 return LangStandard::lang_c23;
145}
146
147// Return the language standard that's activated by the /std:c++latest
148// flag in clang-CL mode.
149static LangStandard::Kind latestLangStandardCXX() {
150 // FIXME: Have a single source of truth for the mapping from
151 // c++latest --> c++29 that's shared by the driver code
152 // (clang/lib/Driver/ToolChains/Clang.cpp) and this file.
153 return LangStandard::lang_cxx29;
154}
155
156// A CompileCommand that can be applied to another file.
157struct TransferableCommand {
158 // Flags that should not apply to all files are stripped from CommandLine.
159 CompileCommand Cmd;
160 // Language detected from -x or the filename. Never TY_INVALID.
161 std::optional<types::ID> Type;
162 // Standard specified by -std.
164 // Whether the command line is for the cl-compatible driver.
165 bool ClangCLMode;
166
167 TransferableCommand(CompileCommand C)
168 : Cmd(std::move(C)), Type(guessType(Cmd.Filename)) {
169 std::vector<std::string> OldArgs = std::move(Cmd.CommandLine);
170 Cmd.CommandLine.clear();
171
172 // Wrap the old arguments in an InputArgList.
173 llvm::opt::InputArgList ArgList;
174 {
175 SmallVector<const char *, 16> TmpArgv;
176 for (const std::string &S : OldArgs)
177 TmpArgv.push_back(S.c_str());
178 ClangCLMode = !TmpArgv.empty() &&
180 TmpArgv.front(), llvm::ArrayRef(TmpArgv).slice(1)));
181 ArgList = {TmpArgv.begin(), TmpArgv.end()};
182 }
183
184 // Parse the old args in order to strip out and record unwanted flags.
185 // We parse each argument individually so that we can retain the exact
186 // spelling of each argument; re-rendering is lossy for aliased flags.
187 // E.g. in CL mode, /W4 maps to -Wall.
188 auto &OptTable = getDriverOptTable();
189 if (!OldArgs.empty())
190 Cmd.CommandLine.emplace_back(OldArgs.front());
191 for (unsigned Pos = 1; Pos < OldArgs.size();) {
192 using namespace options;
193
194 const unsigned OldPos = Pos;
195 std::unique_ptr<llvm::opt::Arg> Arg(OptTable.ParseOneArg(
196 ArgList, Pos,
197 llvm::opt::Visibility(ClangCLMode ? CLOption : ClangOption)));
198
199 if (!Arg)
200 continue;
201
202 const llvm::opt::Option &Opt = Arg->getOption();
203
204 // Strip input and output files.
205 if (Opt.matches(OPT_INPUT) || Opt.matches(OPT_o) ||
206 (ClangCLMode && (Opt.matches(OPT__SLASH_Fa) ||
207 Opt.matches(OPT__SLASH_Fe) ||
208 Opt.matches(OPT__SLASH_Fi) ||
209 Opt.matches(OPT__SLASH_Fo))))
210 continue;
211
212 // ...including when the inputs are passed after --.
213 if (Opt.matches(OPT__DASH_DASH))
214 break;
215
216 // Strip -x, but record the overridden language.
217 if (const auto GivenType = tryParseTypeArg(*Arg)) {
218 Type = *GivenType;
219 continue;
220 }
221
222 // Strip -std, but record the value.
223 if (const auto GivenStd = tryParseStdArg(*Arg)) {
224 if (*GivenStd != LangStandard::lang_unspecified)
225 Std = *GivenStd;
226 continue;
227 }
228
229 Cmd.CommandLine.insert(Cmd.CommandLine.end(),
230 OldArgs.data() + OldPos, OldArgs.data() + Pos);
231 }
232
233 // Make use of -std iff -x was missing.
234 if (Type == types::TY_INVALID && Std != LangStandard::lang_unspecified)
235 Type = toType(LangStandard::getLangStandardForKind(Std).getLanguage());
236 Type = foldType(*Type);
237 // The contract is to store None instead of TY_INVALID.
238 if (Type == types::TY_INVALID)
239 Type = std::nullopt;
240 }
241
242 // Produce a CompileCommand for \p filename, based on this one.
243 // (This consumes the TransferableCommand just to avoid copying Cmd).
244 CompileCommand transferTo(StringRef Filename) && {
245 CompileCommand Result = std::move(Cmd);
246 Result.Heuristic = "inferred from " + Result.Filename;
247 Result.Filename = std::string(Filename);
248 bool TypeCertain;
249 auto TargetType = guessType(Filename, &TypeCertain);
250 // If the filename doesn't determine the language (.h), transfer with -x.
251 if ((!TargetType || !TypeCertain) && Type) {
252 // Use *Type, or its header variant if the file is a header.
253 // Treat no/invalid extension as header (e.g. C++ standard library).
254 TargetType =
255 (!TargetType || types::onlyPrecompileType(TargetType)) // header?
256 ? types::lookupHeaderTypeForSourceType(*Type)
257 : *Type;
258 if (ClangCLMode) {
259 const StringRef Flag = toCLFlag(TargetType);
260 if (!Flag.empty())
261 Result.CommandLine.push_back(std::string(Flag));
262 } else {
263 Result.CommandLine.push_back("-x");
264 Result.CommandLine.push_back(types::getTypeName(TargetType));
265 }
266 }
267
268 // --std flag may only be transferred if the language families share
269 // compatible standards. C/ObjC share C standards; C++/ObjC++/CUDA/HIP
270 // share C++ standards.
271 if (Std != LangStandard::lang_unspecified && Type &&
272 typesSameStandardFamily(foldType(TargetType), *Type)) {
273 const char *Spelling =
275
276 // In clang-cl mode, some standards have different spellings, so emit
277 // the spelling that the driver does accept.
278 // Keep in sync with OPT__SLASH_std handling in Clang::ConstructJob().
279 if (ClangCLMode) {
280 if (Std == LangStandard::lang_cxx23)
281 Spelling = "c++23preview";
282 else if (Std == LangStandard::lang_cxx26)
283 Spelling = "c++26preview";
284 else if (Std == latestLangStandardC())
285 Spelling = "clatest";
286 else if (Std == latestLangStandardCXX())
287 Spelling = "c++latest";
288 }
289
290 Result.CommandLine.emplace_back(
291 (llvm::Twine(ClangCLMode ? "/std:" : "-std=") + Spelling).str());
292 }
293
294 Result.CommandLine.push_back("--");
295 Result.CommandLine.push_back(std::string(Filename));
296 return Result;
297 }
298
299private:
300 // Map the language from the --std flag to that of the -x flag.
301 static types::ID toType(Language Lang) {
302 switch (Lang) {
303 case Language::C:
304 return types::TY_C;
305 case Language::CXX:
306 return types::TY_CXX;
307 case Language::ObjC:
308 return types::TY_ObjC;
309 case Language::ObjCXX:
310 return types::TY_ObjCXX;
311 default:
312 return types::TY_INVALID;
313 }
314 }
315
316 // Convert a file type to the matching CL-style type flag.
317 static StringRef toCLFlag(types::ID Type) {
318 switch (Type) {
319 case types::TY_C:
320 case types::TY_CHeader:
321 return "/TC";
322 case types::TY_CXX:
323 case types::TY_CXXHeader:
324 return "/TP";
325 default:
326 return StringRef();
327 }
328 }
329
330 // Try to interpret the argument as a type specifier, e.g. '-x'.
331 std::optional<types::ID> tryParseTypeArg(const llvm::opt::Arg &Arg) {
332 const llvm::opt::Option &Opt = Arg.getOption();
333 using namespace options;
334 if (ClangCLMode) {
335 if (Opt.matches(OPT__SLASH_TC) || Opt.matches(OPT__SLASH_Tc))
336 return types::TY_C;
337 if (Opt.matches(OPT__SLASH_TP) || Opt.matches(OPT__SLASH_Tp))
338 return types::TY_CXX;
339 } else {
340 if (Opt.matches(options::OPT_x))
341 return types::lookupTypeForTypeSpecifier(Arg.getValue());
342 }
343 return std::nullopt;
344 }
345
346 // Try to interpret the argument as '-std='.
347 std::optional<LangStandard::Kind> tryParseStdArg(const llvm::opt::Arg &Arg) {
348 using namespace options;
349 if (Arg.getOption().matches(ClangCLMode ? OPT__SLASH_std : OPT_std_EQ)) {
350 if (ClangCLMode) {
351 // Handle clang-cl spellings not in LangStandards.def.
352 // Keep in sync with OPT__SLASH_std handling in Clang::ConstructJob().
353 if (StringRef(Arg.getValue()) == "c++23preview")
354 return LangStandard::lang_cxx23;
355 if (StringRef(Arg.getValue()) == "c++26preview")
356 return LangStandard::lang_cxx26;
357 if (StringRef(Arg.getValue()) == "clatest")
358 return latestLangStandardC();
359 if (StringRef(Arg.getValue()) == "c++latest")
360 return latestLangStandardCXX();
361 }
362 return LangStandard::getLangKind(Arg.getValue());
363 }
364 return std::nullopt;
365 }
366};
367
368// Given a filename, FileIndex picks the best matching file from the underlying
369// DB. This is the proxy file whose CompileCommand will be reused. The
370// heuristics incorporate file name, extension, and directory structure.
371// Strategy:
372// - Build indexes of each of the substrings we want to look up by.
373// These indexes are just sorted lists of the substrings.
374// - Each criterion corresponds to a range lookup into the index, so we only
375// need O(log N) string comparisons to determine scores.
376//
377// Apart from path proximity signals, also takes file extensions into account
378// when scoring the candidates.
379class FileIndex {
380public:
381 FileIndex(std::vector<std::string> Files)
382 : OriginalPaths(std::move(Files)), Strings(Arena) {
383 // Sort commands by filename for determinism (index is a tiebreaker later).
384 llvm::sort(OriginalPaths);
385 Paths.reserve(OriginalPaths.size());
386 Types.reserve(OriginalPaths.size());
387 Stems.reserve(OriginalPaths.size());
388 for (size_t I = 0; I < OriginalPaths.size(); ++I) {
389 StringRef Path = Strings.save(StringRef(OriginalPaths[I]).lower());
390
391 Paths.emplace_back(Path, I);
392 Types.push_back(foldType(guessType(OriginalPaths[I])));
393 Stems.emplace_back(sys::path::stem(Path), I);
394 auto Dir = ++sys::path::rbegin(Path), DirEnd = sys::path::rend(Path);
395 for (int J = 0; J < DirectorySegmentsIndexed && Dir != DirEnd; ++J, ++Dir)
396 if (Dir->size() > ShortDirectorySegment) // not trivial ones
397 Components.emplace_back(*Dir, I);
398 }
399 llvm::sort(Paths);
400 llvm::sort(Stems);
401 llvm::sort(Components);
402 }
403
404 bool empty() const { return Paths.empty(); }
405
406 // Returns the path for the file that best fits OriginalFilename.
407 // Candidates with extensions matching PreferLanguage will be chosen over
408 // others (unless it's TY_INVALID, or all candidates are bad).
409 StringRef chooseProxy(StringRef OriginalFilename,
410 types::ID PreferLanguage) const {
411 assert(!empty() && "need at least one candidate!");
412 std::string Filename = OriginalFilename.lower();
413 auto Candidates = scoreCandidates(Filename);
414 std::pair<size_t, int> Best =
415 pickWinner(Candidates, Filename, PreferLanguage);
416
417 DEBUG_WITH_TYPE(
418 "interpolate",
419 llvm::dbgs() << "interpolate: chose " << OriginalPaths[Best.first]
420 << " as proxy for " << OriginalFilename << " preferring "
421 << (PreferLanguage == types::TY_INVALID
422 ? "none"
423 : types::getTypeName(PreferLanguage))
424 << " score=" << Best.second << "\n");
425 return OriginalPaths[Best.first];
426 }
427
428private:
429 using SubstringAndIndex = std::pair<StringRef, size_t>;
430 // Directory matching parameters: we look at the last two segments of the
431 // parent directory (usually the semantically significant ones in practice).
432 // We search only the last four of each candidate (for efficiency).
433 constexpr static int DirectorySegmentsIndexed = 4;
434 constexpr static int DirectorySegmentsQueried = 2;
435 constexpr static int ShortDirectorySegment = 1; // Only look at longer names.
436
437 // Award points to candidate entries that should be considered for the file.
438 // Returned keys are indexes into paths, and the values are (nonzero) scores.
439 DenseMap<size_t, int> scoreCandidates(StringRef Filename) const {
440 // Decompose Filename into the parts we care about.
441 // /some/path/complicated/project/Interesting.h
442 // [-prefix--][---dir---] [-dir-] [--stem---]
443 StringRef Stem = sys::path::stem(Filename);
444 llvm::SmallVector<StringRef, DirectorySegmentsQueried> Dirs;
445 llvm::StringRef Prefix;
446 auto Dir = ++sys::path::rbegin(Filename),
447 DirEnd = sys::path::rend(Filename);
448 for (int I = 0; I < DirectorySegmentsQueried && Dir != DirEnd; ++I, ++Dir) {
449 if (Dir->size() > ShortDirectorySegment)
450 Dirs.push_back(*Dir);
451 Prefix = Filename.substr(0, Dir - DirEnd);
452 }
453
454 // Now award points based on lookups into our various indexes.
455 DenseMap<size_t, int> Candidates; // Index -> score.
456 auto Award = [&](int Points, ArrayRef<SubstringAndIndex> Range) {
457 for (const auto &Entry : Range)
458 Candidates[Entry.second] += Points;
459 };
460 // Award one point if the file's basename is a prefix of the candidate,
461 // and another if it's an exact match (so exact matches get two points).
462 Award(1, indexLookup</*Prefix=*/true>(Stem, Stems));
463 Award(1, indexLookup</*Prefix=*/false>(Stem, Stems));
464 // For each of the last few directories in the Filename, award a point
465 // if it's present in the candidate.
466 for (StringRef Dir : Dirs)
467 Award(1, indexLookup</*Prefix=*/false>(Dir, Components));
468 // Award one more point if the whole rest of the path matches.
469 if (sys::path::root_directory(Prefix) != Prefix)
470 Award(1, indexLookup</*Prefix=*/true>(Prefix, Paths));
471 return Candidates;
472 }
473
474 // Pick a single winner from the set of scored candidates.
475 // Returns (index, score).
476 std::pair<size_t, int> pickWinner(const DenseMap<size_t, int> &Candidates,
477 StringRef Filename,
478 types::ID PreferredLanguage) const {
479 struct ScoredCandidate {
480 size_t Index;
481 bool Preferred;
482 int Points;
483 size_t PrefixLength;
484 };
485 // Choose the best candidate by (preferred, points, prefix length, alpha).
486 ScoredCandidate Best = {size_t(-1), false, 0, 0};
487 for (const auto &Candidate : Candidates) {
488 ScoredCandidate S;
489 S.Index = Candidate.first;
490 S.Preferred = PreferredLanguage == types::TY_INVALID ||
491 PreferredLanguage == Types[S.Index];
492 S.Points = Candidate.second;
493 if (!S.Preferred && Best.Preferred)
494 continue;
495 if (S.Preferred == Best.Preferred) {
496 if (S.Points < Best.Points)
497 continue;
498 if (S.Points == Best.Points) {
499 S.PrefixLength = matchingPrefix(Filename, Paths[S.Index].first);
500 if (S.PrefixLength < Best.PrefixLength)
501 continue;
502 // hidden heuristics should at least be deterministic!
503 if (S.PrefixLength == Best.PrefixLength)
504 if (S.Index > Best.Index)
505 continue;
506 }
507 }
508 // PrefixLength was only set above if actually needed for a tiebreak.
509 // But it definitely needs to be set to break ties in the future.
510 S.PrefixLength = matchingPrefix(Filename, Paths[S.Index].first);
511 Best = S;
512 }
513 // Edge case: no candidate got any points.
514 // We ignore PreferredLanguage at this point (not ideal).
515 if (Best.Index == size_t(-1))
516 return {longestMatch(Filename, Paths).second, 0};
517 return {Best.Index, Best.Points};
518 }
519
520 // Returns the range within a sorted index that compares equal to Key.
521 // If Prefix is true, it's instead the range starting with Key.
522 template <bool Prefix>
523 ArrayRef<SubstringAndIndex>
524 indexLookup(StringRef Key, ArrayRef<SubstringAndIndex> Idx) const {
525 // Use pointers as iteratiors to ease conversion of result to ArrayRef.
526 auto Range = std::equal_range(Idx.data(), Idx.data() + Idx.size(), Key,
527 Less<Prefix>());
528 return {Range.first, Range.second};
529 }
530
531 // Performs a point lookup into a nonempty index, returning a longest match.
532 SubstringAndIndex longestMatch(StringRef Key,
533 ArrayRef<SubstringAndIndex> Idx) const {
534 assert(!Idx.empty());
535 // Longest substring match will be adjacent to a direct lookup.
536 auto It = llvm::lower_bound(Idx, SubstringAndIndex{Key, 0});
537 if (It == Idx.begin())
538 return *It;
539 if (It == Idx.end())
540 return *--It;
541 // Have to choose between It and It-1
542 size_t Prefix = matchingPrefix(Key, It->first);
543 size_t PrevPrefix = matchingPrefix(Key, (It - 1)->first);
544 return Prefix > PrevPrefix ? *It : *--It;
545 }
546
547 // Original paths, everything else is in lowercase.
548 std::vector<std::string> OriginalPaths;
549 BumpPtrAllocator Arena;
550 StringSaver Strings;
551 // Indexes of candidates by certain substrings.
552 // String is lowercase and sorted, index points into OriginalPaths.
553 std::vector<SubstringAndIndex> Paths; // Full path.
554 // Lang types obtained by guessing on the corresponding path. I-th element is
555 // a type for the I-th path.
556 std::vector<types::ID> Types;
557 std::vector<SubstringAndIndex> Stems; // Basename, without extension.
558 std::vector<SubstringAndIndex> Components; // Last path components.
559};
560
561// The actual CompilationDatabase wrapper delegates to its inner database.
562// If no match, looks up a proxy file in FileIndex and transfers its
563// command to the requested file.
564class InterpolatingCompilationDatabase : public CompilationDatabase {
565public:
566 InterpolatingCompilationDatabase(std::unique_ptr<CompilationDatabase> Inner)
567 : Inner(std::move(Inner)), Index(this->Inner->getAllFiles()) {}
568
569 std::vector<CompileCommand>
570 getCompileCommands(StringRef Filename) const override {
571 auto Known = Inner->getCompileCommands(Filename);
572 if (Index.empty() || !Known.empty())
573 return Known;
574 bool TypeCertain;
575 auto Lang = guessType(Filename, &TypeCertain);
576 if (!TypeCertain)
577 Lang = types::TY_INVALID;
578 auto ProxyCommands =
579 Inner->getCompileCommands(Index.chooseProxy(Filename, foldType(Lang)));
580 if (ProxyCommands.empty())
581 return {};
582 return {transferCompileCommand(std::move(ProxyCommands.front()), Filename)};
583 }
584
585 std::vector<std::string> getAllFiles() const override {
586 return Inner->getAllFiles();
587 }
588
589 std::vector<CompileCommand> getAllCompileCommands() const override {
590 return Inner->getAllCompileCommands();
591 }
592
593private:
594 std::unique_ptr<CompilationDatabase> Inner;
595 FileIndex Index;
596};
597
598} // namespace
599
600std::unique_ptr<CompilationDatabase>
601inferMissingCompileCommands(std::unique_ptr<CompilationDatabase> Inner) {
602 return std::make_unique<InterpolatingCompilationDatabase>(std::move(Inner));
603}
604
606 StringRef Filename) {
607 return TransferableCommand(std::move(Cmd)).transferTo(Filename);
608}
609
610} // namespace tooling
611} // namespace clang
#define V(N, I)
__SIZE_TYPE__ size_t
The unsigned integer type of the result of the sizeof operator.
Interface for compilation databases.
llvm::StringRef getDriverMode(StringRef ProgName, ArrayRef< const char * > Args)
Returns the driver mode option's value, i.e.
Definition Driver.cpp:7487
bool IsClangCL(StringRef DriverMode)
Checks whether the value produced by getDriverMode is for CL mode.
Definition Driver.cpp:7502
tooling::CompileCommand transferCompileCommand(tooling::CompileCommand, StringRef Filename)
Transforms a compile command so that it applies the same configuration to a different file.
std::unique_ptr< CompilationDatabase > inferMissingCompileCommands(std::unique_ptr< CompilationDatabase >)
Returns a wrapped CompilationDatabase that defers to the provided one, but getCompileCommands() will ...
The JSON file list parser is used to communicate input to InstallAPI.
Language
The language for the input, used to select and validate the language standard and possible actions.
@ C
Languages that the frontend can parse and compile.
@ Result
The result type of a method or function.
Definition TypeBase.h:905
const llvm::opt::OptTable & getDriverOptTable()
static const LangStandard & getLangStandardForKind(Kind K)
const char * getName() const
getName - Get the name of this standard.
static Kind getLangKind(StringRef Name)
Specifies the working directory and command of a compilation.