clang 23.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++26 that's shared by the driver code
152 // (clang/lib/Driver/ToolChains/Clang.cpp) and this file.
153 return LangStandard::lang_cxx26;
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 == latestLangStandardC())
283 Spelling = "clatest";
284 else if (Std == latestLangStandardCXX())
285 Spelling = "c++latest";
286 }
287
288 Result.CommandLine.emplace_back(
289 (llvm::Twine(ClangCLMode ? "/std:" : "-std=") + Spelling).str());
290 }
291
292 Result.CommandLine.push_back("--");
293 Result.CommandLine.push_back(std::string(Filename));
294 return Result;
295 }
296
297private:
298 // Map the language from the --std flag to that of the -x flag.
299 static types::ID toType(Language Lang) {
300 switch (Lang) {
301 case Language::C:
302 return types::TY_C;
303 case Language::CXX:
304 return types::TY_CXX;
305 case Language::ObjC:
306 return types::TY_ObjC;
307 case Language::ObjCXX:
308 return types::TY_ObjCXX;
309 default:
310 return types::TY_INVALID;
311 }
312 }
313
314 // Convert a file type to the matching CL-style type flag.
315 static StringRef toCLFlag(types::ID Type) {
316 switch (Type) {
317 case types::TY_C:
318 case types::TY_CHeader:
319 return "/TC";
320 case types::TY_CXX:
321 case types::TY_CXXHeader:
322 return "/TP";
323 default:
324 return StringRef();
325 }
326 }
327
328 // Try to interpret the argument as a type specifier, e.g. '-x'.
329 std::optional<types::ID> tryParseTypeArg(const llvm::opt::Arg &Arg) {
330 const llvm::opt::Option &Opt = Arg.getOption();
331 using namespace options;
332 if (ClangCLMode) {
333 if (Opt.matches(OPT__SLASH_TC) || Opt.matches(OPT__SLASH_Tc))
334 return types::TY_C;
335 if (Opt.matches(OPT__SLASH_TP) || Opt.matches(OPT__SLASH_Tp))
336 return types::TY_CXX;
337 } else {
338 if (Opt.matches(options::OPT_x))
339 return types::lookupTypeForTypeSpecifier(Arg.getValue());
340 }
341 return std::nullopt;
342 }
343
344 // Try to interpret the argument as '-std='.
345 std::optional<LangStandard::Kind> tryParseStdArg(const llvm::opt::Arg &Arg) {
346 using namespace options;
347 if (Arg.getOption().matches(ClangCLMode ? OPT__SLASH_std : OPT_std_EQ)) {
348 if (ClangCLMode) {
349 // Handle clang-cl spellings not in LangStandards.def.
350 // Keep in sync with OPT__SLASH_std handling in Clang::ConstructJob().
351 if (StringRef(Arg.getValue()) == "c++23preview")
352 return LangStandard::lang_cxx23;
353 if (StringRef(Arg.getValue()) == "clatest")
354 return latestLangStandardC();
355 if (StringRef(Arg.getValue()) == "c++latest")
356 return latestLangStandardCXX();
357 }
358 return LangStandard::getLangKind(Arg.getValue());
359 }
360 return std::nullopt;
361 }
362};
363
364// Given a filename, FileIndex picks the best matching file from the underlying
365// DB. This is the proxy file whose CompileCommand will be reused. The
366// heuristics incorporate file name, extension, and directory structure.
367// Strategy:
368// - Build indexes of each of the substrings we want to look up by.
369// These indexes are just sorted lists of the substrings.
370// - Each criterion corresponds to a range lookup into the index, so we only
371// need O(log N) string comparisons to determine scores.
372//
373// Apart from path proximity signals, also takes file extensions into account
374// when scoring the candidates.
375class FileIndex {
376public:
377 FileIndex(std::vector<std::string> Files)
378 : OriginalPaths(std::move(Files)), Strings(Arena) {
379 // Sort commands by filename for determinism (index is a tiebreaker later).
380 llvm::sort(OriginalPaths);
381 Paths.reserve(OriginalPaths.size());
382 Types.reserve(OriginalPaths.size());
383 Stems.reserve(OriginalPaths.size());
384 for (size_t I = 0; I < OriginalPaths.size(); ++I) {
385 StringRef Path = Strings.save(StringRef(OriginalPaths[I]).lower());
386
387 Paths.emplace_back(Path, I);
388 Types.push_back(foldType(guessType(OriginalPaths[I])));
389 Stems.emplace_back(sys::path::stem(Path), I);
390 auto Dir = ++sys::path::rbegin(Path), DirEnd = sys::path::rend(Path);
391 for (int J = 0; J < DirectorySegmentsIndexed && Dir != DirEnd; ++J, ++Dir)
392 if (Dir->size() > ShortDirectorySegment) // not trivial ones
393 Components.emplace_back(*Dir, I);
394 }
395 llvm::sort(Paths);
396 llvm::sort(Stems);
397 llvm::sort(Components);
398 }
399
400 bool empty() const { return Paths.empty(); }
401
402 // Returns the path for the file that best fits OriginalFilename.
403 // Candidates with extensions matching PreferLanguage will be chosen over
404 // others (unless it's TY_INVALID, or all candidates are bad).
405 StringRef chooseProxy(StringRef OriginalFilename,
406 types::ID PreferLanguage) const {
407 assert(!empty() && "need at least one candidate!");
408 std::string Filename = OriginalFilename.lower();
409 auto Candidates = scoreCandidates(Filename);
410 std::pair<size_t, int> Best =
411 pickWinner(Candidates, Filename, PreferLanguage);
412
413 DEBUG_WITH_TYPE(
414 "interpolate",
415 llvm::dbgs() << "interpolate: chose " << OriginalPaths[Best.first]
416 << " as proxy for " << OriginalFilename << " preferring "
417 << (PreferLanguage == types::TY_INVALID
418 ? "none"
419 : types::getTypeName(PreferLanguage))
420 << " score=" << Best.second << "\n");
421 return OriginalPaths[Best.first];
422 }
423
424private:
425 using SubstringAndIndex = std::pair<StringRef, size_t>;
426 // Directory matching parameters: we look at the last two segments of the
427 // parent directory (usually the semantically significant ones in practice).
428 // We search only the last four of each candidate (for efficiency).
429 constexpr static int DirectorySegmentsIndexed = 4;
430 constexpr static int DirectorySegmentsQueried = 2;
431 constexpr static int ShortDirectorySegment = 1; // Only look at longer names.
432
433 // Award points to candidate entries that should be considered for the file.
434 // Returned keys are indexes into paths, and the values are (nonzero) scores.
435 DenseMap<size_t, int> scoreCandidates(StringRef Filename) const {
436 // Decompose Filename into the parts we care about.
437 // /some/path/complicated/project/Interesting.h
438 // [-prefix--][---dir---] [-dir-] [--stem---]
439 StringRef Stem = sys::path::stem(Filename);
440 llvm::SmallVector<StringRef, DirectorySegmentsQueried> Dirs;
441 llvm::StringRef Prefix;
442 auto Dir = ++sys::path::rbegin(Filename),
443 DirEnd = sys::path::rend(Filename);
444 for (int I = 0; I < DirectorySegmentsQueried && Dir != DirEnd; ++I, ++Dir) {
445 if (Dir->size() > ShortDirectorySegment)
446 Dirs.push_back(*Dir);
447 Prefix = Filename.substr(0, Dir - DirEnd);
448 }
449
450 // Now award points based on lookups into our various indexes.
451 DenseMap<size_t, int> Candidates; // Index -> score.
452 auto Award = [&](int Points, ArrayRef<SubstringAndIndex> Range) {
453 for (const auto &Entry : Range)
454 Candidates[Entry.second] += Points;
455 };
456 // Award one point if the file's basename is a prefix of the candidate,
457 // and another if it's an exact match (so exact matches get two points).
458 Award(1, indexLookup</*Prefix=*/true>(Stem, Stems));
459 Award(1, indexLookup</*Prefix=*/false>(Stem, Stems));
460 // For each of the last few directories in the Filename, award a point
461 // if it's present in the candidate.
462 for (StringRef Dir : Dirs)
463 Award(1, indexLookup</*Prefix=*/false>(Dir, Components));
464 // Award one more point if the whole rest of the path matches.
465 if (sys::path::root_directory(Prefix) != Prefix)
466 Award(1, indexLookup</*Prefix=*/true>(Prefix, Paths));
467 return Candidates;
468 }
469
470 // Pick a single winner from the set of scored candidates.
471 // Returns (index, score).
472 std::pair<size_t, int> pickWinner(const DenseMap<size_t, int> &Candidates,
473 StringRef Filename,
474 types::ID PreferredLanguage) const {
475 struct ScoredCandidate {
476 size_t Index;
477 bool Preferred;
478 int Points;
479 size_t PrefixLength;
480 };
481 // Choose the best candidate by (preferred, points, prefix length, alpha).
482 ScoredCandidate Best = {size_t(-1), false, 0, 0};
483 for (const auto &Candidate : Candidates) {
484 ScoredCandidate S;
485 S.Index = Candidate.first;
486 S.Preferred = PreferredLanguage == types::TY_INVALID ||
487 PreferredLanguage == Types[S.Index];
488 S.Points = Candidate.second;
489 if (!S.Preferred && Best.Preferred)
490 continue;
491 if (S.Preferred == Best.Preferred) {
492 if (S.Points < Best.Points)
493 continue;
494 if (S.Points == Best.Points) {
495 S.PrefixLength = matchingPrefix(Filename, Paths[S.Index].first);
496 if (S.PrefixLength < Best.PrefixLength)
497 continue;
498 // hidden heuristics should at least be deterministic!
499 if (S.PrefixLength == Best.PrefixLength)
500 if (S.Index > Best.Index)
501 continue;
502 }
503 }
504 // PrefixLength was only set above if actually needed for a tiebreak.
505 // But it definitely needs to be set to break ties in the future.
506 S.PrefixLength = matchingPrefix(Filename, Paths[S.Index].first);
507 Best = S;
508 }
509 // Edge case: no candidate got any points.
510 // We ignore PreferredLanguage at this point (not ideal).
511 if (Best.Index == size_t(-1))
512 return {longestMatch(Filename, Paths).second, 0};
513 return {Best.Index, Best.Points};
514 }
515
516 // Returns the range within a sorted index that compares equal to Key.
517 // If Prefix is true, it's instead the range starting with Key.
518 template <bool Prefix>
519 ArrayRef<SubstringAndIndex>
520 indexLookup(StringRef Key, ArrayRef<SubstringAndIndex> Idx) const {
521 // Use pointers as iteratiors to ease conversion of result to ArrayRef.
522 auto Range = std::equal_range(Idx.data(), Idx.data() + Idx.size(), Key,
523 Less<Prefix>());
524 return {Range.first, Range.second};
525 }
526
527 // Performs a point lookup into a nonempty index, returning a longest match.
528 SubstringAndIndex longestMatch(StringRef Key,
529 ArrayRef<SubstringAndIndex> Idx) const {
530 assert(!Idx.empty());
531 // Longest substring match will be adjacent to a direct lookup.
532 auto It = llvm::lower_bound(Idx, SubstringAndIndex{Key, 0});
533 if (It == Idx.begin())
534 return *It;
535 if (It == Idx.end())
536 return *--It;
537 // Have to choose between It and It-1
538 size_t Prefix = matchingPrefix(Key, It->first);
539 size_t PrevPrefix = matchingPrefix(Key, (It - 1)->first);
540 return Prefix > PrevPrefix ? *It : *--It;
541 }
542
543 // Original paths, everything else is in lowercase.
544 std::vector<std::string> OriginalPaths;
545 BumpPtrAllocator Arena;
546 StringSaver Strings;
547 // Indexes of candidates by certain substrings.
548 // String is lowercase and sorted, index points into OriginalPaths.
549 std::vector<SubstringAndIndex> Paths; // Full path.
550 // Lang types obtained by guessing on the corresponding path. I-th element is
551 // a type for the I-th path.
552 std::vector<types::ID> Types;
553 std::vector<SubstringAndIndex> Stems; // Basename, without extension.
554 std::vector<SubstringAndIndex> Components; // Last path components.
555};
556
557// The actual CompilationDatabase wrapper delegates to its inner database.
558// If no match, looks up a proxy file in FileIndex and transfers its
559// command to the requested file.
560class InterpolatingCompilationDatabase : public CompilationDatabase {
561public:
562 InterpolatingCompilationDatabase(std::unique_ptr<CompilationDatabase> Inner)
563 : Inner(std::move(Inner)), Index(this->Inner->getAllFiles()) {}
564
565 std::vector<CompileCommand>
566 getCompileCommands(StringRef Filename) const override {
567 auto Known = Inner->getCompileCommands(Filename);
568 if (Index.empty() || !Known.empty())
569 return Known;
570 bool TypeCertain;
571 auto Lang = guessType(Filename, &TypeCertain);
572 if (!TypeCertain)
573 Lang = types::TY_INVALID;
574 auto ProxyCommands =
575 Inner->getCompileCommands(Index.chooseProxy(Filename, foldType(Lang)));
576 if (ProxyCommands.empty())
577 return {};
578 return {transferCompileCommand(std::move(ProxyCommands.front()), Filename)};
579 }
580
581 std::vector<std::string> getAllFiles() const override {
582 return Inner->getAllFiles();
583 }
584
585 std::vector<CompileCommand> getAllCompileCommands() const override {
586 return Inner->getAllCompileCommands();
587 }
588
589private:
590 std::unique_ptr<CompilationDatabase> Inner;
591 FileIndex Index;
592};
593
594} // namespace
595
596std::unique_ptr<CompilationDatabase>
597inferMissingCompileCommands(std::unique_ptr<CompilationDatabase> Inner) {
598 return std::make_unique<InterpolatingCompilationDatabase>(std::move(Inner));
599}
600
602 StringRef Filename) {
603 return TransferableCommand(std::move(Cmd)).transferTo(Filename);
604}
605
606} // namespace tooling
607} // 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:7495
bool IsClangCL(StringRef DriverMode)
Checks whether the value produced by getDriverMode is for CL mode.
Definition Driver.cpp:7510
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.