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 return types::TY_CXX;
117 case types::TY_ObjCXX:
118 case types::TY_ObjCXXHeader:
119 return types::TY_ObjCXX;
120 case types::TY_CUDA:
121 case types::TY_CUDA_DEVICE:
122 return types::TY_CUDA;
123 default:
124 return types::TY_INVALID;
125 }
126}
127
128// Whether two types use the same -std flag family.
129// C and ObjC share C standards; C++, ObjC++, CUDA, HIP share C++ standards.
130static bool typesSameStandardFamily(types::ID T1, types::ID T2) {
131 if (!types::isDerivedFromC(T1) || !types::isDerivedFromC(T2))
132 return false;
133 return types::isCXX(T1) == types::isCXX(T2);
134}
135
136// Return the language standard that's activated by the /std:clatest
137// flag in clang-CL mode.
138static LangStandard::Kind latestLangStandardC() {
139 // FIXME: Have a single source of truth for the mapping from
140 // clatest --> c23 that's shared by the driver code
141 // (clang/lib/Driver/ToolChains/Clang.cpp) and this file.
142 return LangStandard::lang_c23;
143}
144
145// Return the language standard that's activated by the /std:c++latest
146// flag in clang-CL mode.
147static LangStandard::Kind latestLangStandardCXX() {
148 // FIXME: Have a single source of truth for the mapping from
149 // c++latest --> c++26 that's shared by the driver code
150 // (clang/lib/Driver/ToolChains/Clang.cpp) and this file.
151 return LangStandard::lang_cxx26;
152}
153
154// A CompileCommand that can be applied to another file.
155struct TransferableCommand {
156 // Flags that should not apply to all files are stripped from CommandLine.
157 CompileCommand Cmd;
158 // Language detected from -x or the filename. Never TY_INVALID.
159 std::optional<types::ID> Type;
160 // Standard specified by -std.
162 // Whether the command line is for the cl-compatible driver.
163 bool ClangCLMode;
164
165 TransferableCommand(CompileCommand C)
166 : Cmd(std::move(C)), Type(guessType(Cmd.Filename)) {
167 std::vector<std::string> OldArgs = std::move(Cmd.CommandLine);
168 Cmd.CommandLine.clear();
169
170 // Wrap the old arguments in an InputArgList.
171 llvm::opt::InputArgList ArgList;
172 {
173 SmallVector<const char *, 16> TmpArgv;
174 for (const std::string &S : OldArgs)
175 TmpArgv.push_back(S.c_str());
176 ClangCLMode = !TmpArgv.empty() &&
178 TmpArgv.front(), llvm::ArrayRef(TmpArgv).slice(1)));
179 ArgList = {TmpArgv.begin(), TmpArgv.end()};
180 }
181
182 // Parse the old args in order to strip out and record unwanted flags.
183 // We parse each argument individually so that we can retain the exact
184 // spelling of each argument; re-rendering is lossy for aliased flags.
185 // E.g. in CL mode, /W4 maps to -Wall.
186 auto &OptTable = getDriverOptTable();
187 if (!OldArgs.empty())
188 Cmd.CommandLine.emplace_back(OldArgs.front());
189 for (unsigned Pos = 1; Pos < OldArgs.size();) {
190 using namespace options;
191
192 const unsigned OldPos = Pos;
193 std::unique_ptr<llvm::opt::Arg> Arg(OptTable.ParseOneArg(
194 ArgList, Pos,
195 llvm::opt::Visibility(ClangCLMode ? CLOption : ClangOption)));
196
197 if (!Arg)
198 continue;
199
200 const llvm::opt::Option &Opt = Arg->getOption();
201
202 // Strip input and output files.
203 if (Opt.matches(OPT_INPUT) || Opt.matches(OPT_o) ||
204 (ClangCLMode && (Opt.matches(OPT__SLASH_Fa) ||
205 Opt.matches(OPT__SLASH_Fe) ||
206 Opt.matches(OPT__SLASH_Fi) ||
207 Opt.matches(OPT__SLASH_Fo))))
208 continue;
209
210 // ...including when the inputs are passed after --.
211 if (Opt.matches(OPT__DASH_DASH))
212 break;
213
214 // Strip -x, but record the overridden language.
215 if (const auto GivenType = tryParseTypeArg(*Arg)) {
216 Type = *GivenType;
217 continue;
218 }
219
220 // Strip -std, but record the value.
221 if (const auto GivenStd = tryParseStdArg(*Arg)) {
222 if (*GivenStd != LangStandard::lang_unspecified)
223 Std = *GivenStd;
224 continue;
225 }
226
227 Cmd.CommandLine.insert(Cmd.CommandLine.end(),
228 OldArgs.data() + OldPos, OldArgs.data() + Pos);
229 }
230
231 // Make use of -std iff -x was missing.
232 if (Type == types::TY_INVALID && Std != LangStandard::lang_unspecified)
233 Type = toType(LangStandard::getLangStandardForKind(Std).getLanguage());
234 Type = foldType(*Type);
235 // The contract is to store None instead of TY_INVALID.
236 if (Type == types::TY_INVALID)
237 Type = std::nullopt;
238 }
239
240 // Produce a CompileCommand for \p filename, based on this one.
241 // (This consumes the TransferableCommand just to avoid copying Cmd).
242 CompileCommand transferTo(StringRef Filename) && {
243 CompileCommand Result = std::move(Cmd);
244 Result.Heuristic = "inferred from " + Result.Filename;
245 Result.Filename = std::string(Filename);
246 bool TypeCertain;
247 auto TargetType = guessType(Filename, &TypeCertain);
248 // If the filename doesn't determine the language (.h), transfer with -x.
249 if ((!TargetType || !TypeCertain) && Type) {
250 // Use *Type, or its header variant if the file is a header.
251 // Treat no/invalid extension as header (e.g. C++ standard library).
252 TargetType =
253 (!TargetType || types::onlyPrecompileType(TargetType)) // header?
254 ? types::lookupHeaderTypeForSourceType(*Type)
255 : *Type;
256 if (ClangCLMode) {
257 const StringRef Flag = toCLFlag(TargetType);
258 if (!Flag.empty())
259 Result.CommandLine.push_back(std::string(Flag));
260 } else {
261 Result.CommandLine.push_back("-x");
262 Result.CommandLine.push_back(types::getTypeName(TargetType));
263 }
264 }
265
266 // --std flag may only be transferred if the language families share
267 // compatible standards. C/ObjC share C standards; C++/ObjC++/CUDA/HIP
268 // share C++ standards.
269 if (Std != LangStandard::lang_unspecified && Type &&
270 typesSameStandardFamily(foldType(TargetType), *Type)) {
271 const char *Spelling =
273
274 // In clang-cl mode, some standards have different spellings, so emit
275 // the spelling that the driver does accept.
276 // Keep in sync with OPT__SLASH_std handling in Clang::ConstructJob().
277 if (ClangCLMode) {
278 if (Std == LangStandard::lang_cxx23)
279 Spelling = "c++23preview";
280 else if (Std == latestLangStandardC())
281 Spelling = "clatest";
282 else if (Std == latestLangStandardCXX())
283 Spelling = "c++latest";
284 }
285
286 Result.CommandLine.emplace_back(
287 (llvm::Twine(ClangCLMode ? "/std:" : "-std=") + Spelling).str());
288 }
289
290 Result.CommandLine.push_back("--");
291 Result.CommandLine.push_back(std::string(Filename));
292 return Result;
293 }
294
295private:
296 // Map the language from the --std flag to that of the -x flag.
297 static types::ID toType(Language Lang) {
298 switch (Lang) {
299 case Language::C:
300 return types::TY_C;
301 case Language::CXX:
302 return types::TY_CXX;
303 case Language::ObjC:
304 return types::TY_ObjC;
305 case Language::ObjCXX:
306 return types::TY_ObjCXX;
307 default:
308 return types::TY_INVALID;
309 }
310 }
311
312 // Convert a file type to the matching CL-style type flag.
313 static StringRef toCLFlag(types::ID Type) {
314 switch (Type) {
315 case types::TY_C:
316 case types::TY_CHeader:
317 return "/TC";
318 case types::TY_CXX:
319 case types::TY_CXXHeader:
320 return "/TP";
321 default:
322 return StringRef();
323 }
324 }
325
326 // Try to interpret the argument as a type specifier, e.g. '-x'.
327 std::optional<types::ID> tryParseTypeArg(const llvm::opt::Arg &Arg) {
328 const llvm::opt::Option &Opt = Arg.getOption();
329 using namespace options;
330 if (ClangCLMode) {
331 if (Opt.matches(OPT__SLASH_TC) || Opt.matches(OPT__SLASH_Tc))
332 return types::TY_C;
333 if (Opt.matches(OPT__SLASH_TP) || Opt.matches(OPT__SLASH_Tp))
334 return types::TY_CXX;
335 } else {
336 if (Opt.matches(options::OPT_x))
337 return types::lookupTypeForTypeSpecifier(Arg.getValue());
338 }
339 return std::nullopt;
340 }
341
342 // Try to interpret the argument as '-std='.
343 std::optional<LangStandard::Kind> tryParseStdArg(const llvm::opt::Arg &Arg) {
344 using namespace options;
345 if (Arg.getOption().matches(ClangCLMode ? OPT__SLASH_std : OPT_std_EQ)) {
346 if (ClangCLMode) {
347 // Handle clang-cl spellings not in LangStandards.def.
348 // Keep in sync with OPT__SLASH_std handling in Clang::ConstructJob().
349 if (StringRef(Arg.getValue()) == "c++23preview")
350 return LangStandard::lang_cxx23;
351 if (StringRef(Arg.getValue()) == "clatest")
352 return latestLangStandardC();
353 if (StringRef(Arg.getValue()) == "c++latest")
354 return latestLangStandardCXX();
355 }
356 return LangStandard::getLangKind(Arg.getValue());
357 }
358 return std::nullopt;
359 }
360};
361
362// Given a filename, FileIndex picks the best matching file from the underlying
363// DB. This is the proxy file whose CompileCommand will be reused. The
364// heuristics incorporate file name, extension, and directory structure.
365// Strategy:
366// - Build indexes of each of the substrings we want to look up by.
367// These indexes are just sorted lists of the substrings.
368// - Each criterion corresponds to a range lookup into the index, so we only
369// need O(log N) string comparisons to determine scores.
370//
371// Apart from path proximity signals, also takes file extensions into account
372// when scoring the candidates.
373class FileIndex {
374public:
375 FileIndex(std::vector<std::string> Files)
376 : OriginalPaths(std::move(Files)), Strings(Arena) {
377 // Sort commands by filename for determinism (index is a tiebreaker later).
378 llvm::sort(OriginalPaths);
379 Paths.reserve(OriginalPaths.size());
380 Types.reserve(OriginalPaths.size());
381 Stems.reserve(OriginalPaths.size());
382 for (size_t I = 0; I < OriginalPaths.size(); ++I) {
383 StringRef Path = Strings.save(StringRef(OriginalPaths[I]).lower());
384
385 Paths.emplace_back(Path, I);
386 Types.push_back(foldType(guessType(OriginalPaths[I])));
387 Stems.emplace_back(sys::path::stem(Path), I);
388 auto Dir = ++sys::path::rbegin(Path), DirEnd = sys::path::rend(Path);
389 for (int J = 0; J < DirectorySegmentsIndexed && Dir != DirEnd; ++J, ++Dir)
390 if (Dir->size() > ShortDirectorySegment) // not trivial ones
391 Components.emplace_back(*Dir, I);
392 }
393 llvm::sort(Paths);
394 llvm::sort(Stems);
395 llvm::sort(Components);
396 }
397
398 bool empty() const { return Paths.empty(); }
399
400 // Returns the path for the file that best fits OriginalFilename.
401 // Candidates with extensions matching PreferLanguage will be chosen over
402 // others (unless it's TY_INVALID, or all candidates are bad).
403 StringRef chooseProxy(StringRef OriginalFilename,
404 types::ID PreferLanguage) const {
405 assert(!empty() && "need at least one candidate!");
406 std::string Filename = OriginalFilename.lower();
407 auto Candidates = scoreCandidates(Filename);
408 std::pair<size_t, int> Best =
409 pickWinner(Candidates, Filename, PreferLanguage);
410
411 DEBUG_WITH_TYPE(
412 "interpolate",
413 llvm::dbgs() << "interpolate: chose " << OriginalPaths[Best.first]
414 << " as proxy for " << OriginalFilename << " preferring "
415 << (PreferLanguage == types::TY_INVALID
416 ? "none"
417 : types::getTypeName(PreferLanguage))
418 << " score=" << Best.second << "\n");
419 return OriginalPaths[Best.first];
420 }
421
422private:
423 using SubstringAndIndex = std::pair<StringRef, size_t>;
424 // Directory matching parameters: we look at the last two segments of the
425 // parent directory (usually the semantically significant ones in practice).
426 // We search only the last four of each candidate (for efficiency).
427 constexpr static int DirectorySegmentsIndexed = 4;
428 constexpr static int DirectorySegmentsQueried = 2;
429 constexpr static int ShortDirectorySegment = 1; // Only look at longer names.
430
431 // Award points to candidate entries that should be considered for the file.
432 // Returned keys are indexes into paths, and the values are (nonzero) scores.
433 DenseMap<size_t, int> scoreCandidates(StringRef Filename) const {
434 // Decompose Filename into the parts we care about.
435 // /some/path/complicated/project/Interesting.h
436 // [-prefix--][---dir---] [-dir-] [--stem---]
437 StringRef Stem = sys::path::stem(Filename);
438 llvm::SmallVector<StringRef, DirectorySegmentsQueried> Dirs;
439 llvm::StringRef Prefix;
440 auto Dir = ++sys::path::rbegin(Filename),
441 DirEnd = sys::path::rend(Filename);
442 for (int I = 0; I < DirectorySegmentsQueried && Dir != DirEnd; ++I, ++Dir) {
443 if (Dir->size() > ShortDirectorySegment)
444 Dirs.push_back(*Dir);
445 Prefix = Filename.substr(0, Dir - DirEnd);
446 }
447
448 // Now award points based on lookups into our various indexes.
449 DenseMap<size_t, int> Candidates; // Index -> score.
450 auto Award = [&](int Points, ArrayRef<SubstringAndIndex> Range) {
451 for (const auto &Entry : Range)
452 Candidates[Entry.second] += Points;
453 };
454 // Award one point if the file's basename is a prefix of the candidate,
455 // and another if it's an exact match (so exact matches get two points).
456 Award(1, indexLookup</*Prefix=*/true>(Stem, Stems));
457 Award(1, indexLookup</*Prefix=*/false>(Stem, Stems));
458 // For each of the last few directories in the Filename, award a point
459 // if it's present in the candidate.
460 for (StringRef Dir : Dirs)
461 Award(1, indexLookup</*Prefix=*/false>(Dir, Components));
462 // Award one more point if the whole rest of the path matches.
463 if (sys::path::root_directory(Prefix) != Prefix)
464 Award(1, indexLookup</*Prefix=*/true>(Prefix, Paths));
465 return Candidates;
466 }
467
468 // Pick a single winner from the set of scored candidates.
469 // Returns (index, score).
470 std::pair<size_t, int> pickWinner(const DenseMap<size_t, int> &Candidates,
471 StringRef Filename,
472 types::ID PreferredLanguage) const {
473 struct ScoredCandidate {
474 size_t Index;
475 bool Preferred;
476 int Points;
477 size_t PrefixLength;
478 };
479 // Choose the best candidate by (preferred, points, prefix length, alpha).
480 ScoredCandidate Best = {size_t(-1), false, 0, 0};
481 for (const auto &Candidate : Candidates) {
482 ScoredCandidate S;
483 S.Index = Candidate.first;
484 S.Preferred = PreferredLanguage == types::TY_INVALID ||
485 PreferredLanguage == Types[S.Index];
486 S.Points = Candidate.second;
487 if (!S.Preferred && Best.Preferred)
488 continue;
489 if (S.Preferred == Best.Preferred) {
490 if (S.Points < Best.Points)
491 continue;
492 if (S.Points == Best.Points) {
493 S.PrefixLength = matchingPrefix(Filename, Paths[S.Index].first);
494 if (S.PrefixLength < Best.PrefixLength)
495 continue;
496 // hidden heuristics should at least be deterministic!
497 if (S.PrefixLength == Best.PrefixLength)
498 if (S.Index > Best.Index)
499 continue;
500 }
501 }
502 // PrefixLength was only set above if actually needed for a tiebreak.
503 // But it definitely needs to be set to break ties in the future.
504 S.PrefixLength = matchingPrefix(Filename, Paths[S.Index].first);
505 Best = S;
506 }
507 // Edge case: no candidate got any points.
508 // We ignore PreferredLanguage at this point (not ideal).
509 if (Best.Index == size_t(-1))
510 return {longestMatch(Filename, Paths).second, 0};
511 return {Best.Index, Best.Points};
512 }
513
514 // Returns the range within a sorted index that compares equal to Key.
515 // If Prefix is true, it's instead the range starting with Key.
516 template <bool Prefix>
517 ArrayRef<SubstringAndIndex>
518 indexLookup(StringRef Key, ArrayRef<SubstringAndIndex> Idx) const {
519 // Use pointers as iteratiors to ease conversion of result to ArrayRef.
520 auto Range = std::equal_range(Idx.data(), Idx.data() + Idx.size(), Key,
521 Less<Prefix>());
522 return {Range.first, Range.second};
523 }
524
525 // Performs a point lookup into a nonempty index, returning a longest match.
526 SubstringAndIndex longestMatch(StringRef Key,
527 ArrayRef<SubstringAndIndex> Idx) const {
528 assert(!Idx.empty());
529 // Longest substring match will be adjacent to a direct lookup.
530 auto It = llvm::lower_bound(Idx, SubstringAndIndex{Key, 0});
531 if (It == Idx.begin())
532 return *It;
533 if (It == Idx.end())
534 return *--It;
535 // Have to choose between It and It-1
536 size_t Prefix = matchingPrefix(Key, It->first);
537 size_t PrevPrefix = matchingPrefix(Key, (It - 1)->first);
538 return Prefix > PrevPrefix ? *It : *--It;
539 }
540
541 // Original paths, everything else is in lowercase.
542 std::vector<std::string> OriginalPaths;
543 BumpPtrAllocator Arena;
544 StringSaver Strings;
545 // Indexes of candidates by certain substrings.
546 // String is lowercase and sorted, index points into OriginalPaths.
547 std::vector<SubstringAndIndex> Paths; // Full path.
548 // Lang types obtained by guessing on the corresponding path. I-th element is
549 // a type for the I-th path.
550 std::vector<types::ID> Types;
551 std::vector<SubstringAndIndex> Stems; // Basename, without extension.
552 std::vector<SubstringAndIndex> Components; // Last path components.
553};
554
555// The actual CompilationDatabase wrapper delegates to its inner database.
556// If no match, looks up a proxy file in FileIndex and transfers its
557// command to the requested file.
558class InterpolatingCompilationDatabase : public CompilationDatabase {
559public:
560 InterpolatingCompilationDatabase(std::unique_ptr<CompilationDatabase> Inner)
561 : Inner(std::move(Inner)), Index(this->Inner->getAllFiles()) {}
562
563 std::vector<CompileCommand>
564 getCompileCommands(StringRef Filename) const override {
565 auto Known = Inner->getCompileCommands(Filename);
566 if (Index.empty() || !Known.empty())
567 return Known;
568 bool TypeCertain;
569 auto Lang = guessType(Filename, &TypeCertain);
570 if (!TypeCertain)
571 Lang = types::TY_INVALID;
572 auto ProxyCommands =
573 Inner->getCompileCommands(Index.chooseProxy(Filename, foldType(Lang)));
574 if (ProxyCommands.empty())
575 return {};
576 return {transferCompileCommand(std::move(ProxyCommands.front()), Filename)};
577 }
578
579 std::vector<std::string> getAllFiles() const override {
580 return Inner->getAllFiles();
581 }
582
583 std::vector<CompileCommand> getAllCompileCommands() const override {
584 return Inner->getAllCompileCommands();
585 }
586
587private:
588 std::unique_ptr<CompilationDatabase> Inner;
589 FileIndex Index;
590};
591
592} // namespace
593
594std::unique_ptr<CompilationDatabase>
595inferMissingCompileCommands(std::unique_ptr<CompilationDatabase> Inner) {
596 return std::make_unique<InterpolatingCompilationDatabase>(std::move(Inner));
597}
598
600 StringRef Filename) {
601 return TransferableCommand(std::move(Cmd)).transferTo(Filename);
602}
603
604} // namespace tooling
605} // 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:7375
bool IsClangCL(StringRef DriverMode)
Checks whether the value produced by getDriverMode is for CL mode.
Definition Driver.cpp:7390
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.