clang  14.0.0git
CrossTranslationUnit.cpp
Go to the documentation of this file.
1 //===--- CrossTranslationUnit.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 // This file implements the CrossTranslationUnit interface.
10 //
11 //===----------------------------------------------------------------------===//
13 #include "clang/AST/ASTImporter.h"
14 #include "clang/AST/Decl.h"
16 #include "clang/Basic/TargetInfo.h"
18 #include "clang/Frontend/ASTUnit.h"
22 #include "llvm/ADT/Optional.h"
23 #include "llvm/ADT/Statistic.h"
24 #include "llvm/ADT/Triple.h"
25 #include "llvm/Option/ArgList.h"
26 #include "llvm/Support/ErrorHandling.h"
27 #include "llvm/Support/ManagedStatic.h"
28 #include "llvm/Support/Path.h"
29 #include "llvm/Support/YAMLParser.h"
30 #include "llvm/Support/raw_ostream.h"
31 #include <algorithm>
32 #include <fstream>
33 #include <sstream>
34 #include <tuple>
35 
36 namespace clang {
37 namespace cross_tu {
38 
39 namespace {
40 
41 #define DEBUG_TYPE "CrossTranslationUnit"
42 STATISTIC(NumGetCTUCalled, "The # of getCTUDefinition function called");
43 STATISTIC(
44  NumNotInOtherTU,
45  "The # of getCTUDefinition called but the function is not in any other TU");
46 STATISTIC(NumGetCTUSuccess,
47  "The # of getCTUDefinition successfully returned the "
48  "requested function's body");
49 STATISTIC(NumUnsupportedNodeFound, "The # of imports when the ASTImporter "
50  "encountered an unsupported AST Node");
51 STATISTIC(NumNameConflicts, "The # of imports when the ASTImporter "
52  "encountered an ODR error");
53 STATISTIC(NumTripleMismatch, "The # of triple mismatches");
54 STATISTIC(NumLangMismatch, "The # of language mismatches");
55 STATISTIC(NumLangDialectMismatch, "The # of language dialect mismatches");
56 STATISTIC(NumASTLoadThresholdReached,
57  "The # of ASTs not loaded because of threshold");
58 
59 // Same as Triple's equality operator, but we check a field only if that is
60 // known in both instances.
61 bool hasEqualKnownFields(const llvm::Triple &Lhs, const llvm::Triple &Rhs) {
62  using llvm::Triple;
63  if (Lhs.getArch() != Triple::UnknownArch &&
64  Rhs.getArch() != Triple::UnknownArch && Lhs.getArch() != Rhs.getArch())
65  return false;
66  if (Lhs.getSubArch() != Triple::NoSubArch &&
67  Rhs.getSubArch() != Triple::NoSubArch &&
68  Lhs.getSubArch() != Rhs.getSubArch())
69  return false;
70  if (Lhs.getVendor() != Triple::UnknownVendor &&
71  Rhs.getVendor() != Triple::UnknownVendor &&
72  Lhs.getVendor() != Rhs.getVendor())
73  return false;
74  if (!Lhs.isOSUnknown() && !Rhs.isOSUnknown() &&
75  Lhs.getOS() != Rhs.getOS())
76  return false;
77  if (Lhs.getEnvironment() != Triple::UnknownEnvironment &&
78  Rhs.getEnvironment() != Triple::UnknownEnvironment &&
79  Lhs.getEnvironment() != Rhs.getEnvironment())
80  return false;
81  if (Lhs.getObjectFormat() != Triple::UnknownObjectFormat &&
82  Rhs.getObjectFormat() != Triple::UnknownObjectFormat &&
83  Lhs.getObjectFormat() != Rhs.getObjectFormat())
84  return false;
85  return true;
86 }
87 
88 // FIXME: This class is will be removed after the transition to llvm::Error.
89 class IndexErrorCategory : public std::error_category {
90 public:
91  const char *name() const noexcept override { return "clang.index"; }
92 
93  std::string message(int Condition) const override {
94  switch (static_cast<index_error_code>(Condition)) {
96  // There should not be a success error. Jump to unreachable directly.
97  // Add this case to make the compiler stop complaining.
98  break;
100  return "An unknown error has occurred.";
102  return "The index file is missing.";
104  return "Invalid index file format.";
106  return "Multiple definitions in the index file.";
108  return "Missing definition from the index file.";
110  return "Failed to import the definition.";
112  return "Failed to load external AST source.";
114  return "Failed to generate USR.";
116  return "Triple mismatch";
118  return "Language mismatch";
120  return "Language dialect mismatch";
122  return "Load threshold reached";
124  return "Invocation list file contains multiple references to the same "
125  "source file.";
127  return "Invocation list file is not found.";
129  return "Invocation list file is empty.";
131  return "Invocation list file is in wrong format.";
133  return "Invocation list file does not contain the requested source file.";
134  }
135  llvm_unreachable("Unrecognized index_error_code.");
136  }
137 };
138 
139 static llvm::ManagedStatic<IndexErrorCategory> Category;
140 } // end anonymous namespace
141 
142 char IndexError::ID;
143 
144 void IndexError::log(raw_ostream &OS) const {
145  OS << Category->message(static_cast<int>(Code)) << '\n';
146 }
147 
148 std::error_code IndexError::convertToErrorCode() const {
149  return std::error_code(static_cast<int>(Code), *Category);
150 }
151 
153 parseCrossTUIndex(StringRef IndexPath) {
154  std::ifstream ExternalMapFile{std::string(IndexPath)};
155  if (!ExternalMapFile)
156  return llvm::make_error<IndexError>(index_error_code::missing_index_file,
157  IndexPath.str());
158 
159  llvm::StringMap<std::string> Result;
161  unsigned LineNo = 1;
162  while (std::getline(ExternalMapFile, Line)) {
163  StringRef LineRef{Line};
164  const size_t Delimiter = LineRef.find(' ');
165  if (Delimiter > 0 && Delimiter != std::string::npos) {
166  StringRef LookupName = LineRef.substr(0, Delimiter);
167 
168  // Store paths with posix-style directory separator.
169  SmallString<32> FilePath(LineRef.substr(Delimiter + 1));
170  llvm::sys::path::native(FilePath, llvm::sys::path::Style::posix);
171 
172  bool InsertionOccured;
173  std::tie(std::ignore, InsertionOccured) =
174  Result.try_emplace(LookupName, FilePath.begin(), FilePath.end());
175  if (!InsertionOccured)
176  return llvm::make_error<IndexError>(
177  index_error_code::multiple_definitions, IndexPath.str(), LineNo);
178  } else
179  return llvm::make_error<IndexError>(
180  index_error_code::invalid_index_format, IndexPath.str(), LineNo);
181  ++LineNo;
182  }
183  return Result;
184 }
185 
187 createCrossTUIndexString(const llvm::StringMap<std::string> &Index) {
188  std::ostringstream Result;
189  for (const auto &E : Index)
190  Result << E.getKey().str() << " " << E.getValue() << '\n';
191  return Result.str();
192 }
193 
194 bool containsConst(const VarDecl *VD, const ASTContext &ACtx) {
195  CanQualType CT = ACtx.getCanonicalType(VD->getType());
196  if (!CT.isConstQualified()) {
197  const RecordType *RTy = CT->getAs<RecordType>();
198  if (!RTy || !RTy->hasConstFields())
199  return false;
200  }
201  return true;
202 }
203 
204 static bool hasBodyOrInit(const FunctionDecl *D, const FunctionDecl *&DefD) {
205  return D->hasBody(DefD);
206 }
207 static bool hasBodyOrInit(const VarDecl *D, const VarDecl *&DefD) {
208  return D->getAnyInitializer(DefD);
209 }
210 template <typename T> static bool hasBodyOrInit(const T *D) {
211  const T *Unused;
212  return hasBodyOrInit(D, Unused);
213 }
214 
216  : Context(CI.getASTContext()), ASTStorage(CI) {}
217 
219 
222  SmallString<128> DeclUSR;
223  bool Ret = index::generateUSRForDecl(ND, DeclUSR);
224  if (Ret)
225  return {};
226  return std::string(DeclUSR.str());
227 }
228 
229 /// Recursively visits the decls of a DeclContext, and returns one with the
230 /// given USR.
231 template <typename T>
232 const T *
233 CrossTranslationUnitContext::findDefInDeclContext(const DeclContext *DC,
234  StringRef LookupName) {
235  assert(DC && "Declaration Context must not be null");
236  for (const Decl *D : DC->decls()) {
237  const auto *SubDC = dyn_cast<DeclContext>(D);
238  if (SubDC)
239  if (const auto *ND = findDefInDeclContext<T>(SubDC, LookupName))
240  return ND;
241 
242  const auto *ND = dyn_cast<T>(D);
243  const T *ResultDecl;
244  if (!ND || !hasBodyOrInit(ND, ResultDecl))
245  continue;
246  llvm::Optional<std::string> ResultLookupName = getLookupName(ResultDecl);
247  if (!ResultLookupName || *ResultLookupName != LookupName)
248  continue;
249  return ResultDecl;
250  }
251  return nullptr;
252 }
253 
254 template <typename T>
255 llvm::Expected<const T *> CrossTranslationUnitContext::getCrossTUDefinitionImpl(
256  const T *D, StringRef CrossTUDir, StringRef IndexName,
257  bool DisplayCTUProgress) {
258  assert(D && "D is missing, bad call to this function!");
259  assert(!hasBodyOrInit(D) &&
260  "D has a body or init in current translation unit!");
261  ++NumGetCTUCalled;
262  const llvm::Optional<std::string> LookupName = getLookupName(D);
263  if (!LookupName)
264  return llvm::make_error<IndexError>(
266  llvm::Expected<ASTUnit *> ASTUnitOrError =
267  loadExternalAST(*LookupName, CrossTUDir, IndexName, DisplayCTUProgress);
268  if (!ASTUnitOrError)
269  return ASTUnitOrError.takeError();
270  ASTUnit *Unit = *ASTUnitOrError;
271  assert(&Unit->getFileManager() ==
272  &Unit->getASTContext().getSourceManager().getFileManager());
273 
274  const llvm::Triple &TripleTo = Context.getTargetInfo().getTriple();
275  const llvm::Triple &TripleFrom =
276  Unit->getASTContext().getTargetInfo().getTriple();
277  // The imported AST had been generated for a different target.
278  // Some parts of the triple in the loaded ASTContext can be unknown while the
279  // very same parts in the target ASTContext are known. Thus we check for the
280  // known parts only.
281  if (!hasEqualKnownFields(TripleTo, TripleFrom)) {
282  // TODO: Pass the SourceLocation of the CallExpression for more precise
283  // diagnostics.
284  ++NumTripleMismatch;
285  return llvm::make_error<IndexError>(index_error_code::triple_mismatch,
286  std::string(Unit->getMainFileName()),
287  TripleTo.str(), TripleFrom.str());
288  }
289 
290  const auto &LangTo = Context.getLangOpts();
291  const auto &LangFrom = Unit->getASTContext().getLangOpts();
292 
293  // FIXME: Currenty we do not support CTU across C++ and C and across
294  // different dialects of C++.
295  if (LangTo.CPlusPlus != LangFrom.CPlusPlus) {
296  ++NumLangMismatch;
297  return llvm::make_error<IndexError>(index_error_code::lang_mismatch);
298  }
299 
300  // If CPP dialects are different then return with error.
301  //
302  // Consider this STL code:
303  // template<typename _Alloc>
304  // struct __alloc_traits
305  // #if __cplusplus >= 201103L
306  // : std::allocator_traits<_Alloc>
307  // #endif
308  // { // ...
309  // };
310  // This class template would create ODR errors during merging the two units,
311  // since in one translation unit the class template has a base class, however
312  // in the other unit it has none.
313  if (LangTo.CPlusPlus11 != LangFrom.CPlusPlus11 ||
314  LangTo.CPlusPlus14 != LangFrom.CPlusPlus14 ||
315  LangTo.CPlusPlus17 != LangFrom.CPlusPlus17 ||
316  LangTo.CPlusPlus20 != LangFrom.CPlusPlus20) {
317  ++NumLangDialectMismatch;
318  return llvm::make_error<IndexError>(
320  }
321 
322  TranslationUnitDecl *TU = Unit->getASTContext().getTranslationUnitDecl();
323  if (const T *ResultDecl = findDefInDeclContext<T>(TU, *LookupName))
324  return importDefinition(ResultDecl, Unit);
325  return llvm::make_error<IndexError>(index_error_code::failed_import);
326 }
327 
330  StringRef CrossTUDir,
331  StringRef IndexName,
332  bool DisplayCTUProgress) {
333  return getCrossTUDefinitionImpl(FD, CrossTUDir, IndexName,
334  DisplayCTUProgress);
335 }
336 
339  StringRef CrossTUDir,
340  StringRef IndexName,
341  bool DisplayCTUProgress) {
342  return getCrossTUDefinitionImpl(VD, CrossTUDir, IndexName,
343  DisplayCTUProgress);
344 }
345 
347  switch (IE.getCode()) {
349  Context.getDiagnostics().Report(diag::err_ctu_error_opening)
350  << IE.getFileName();
351  break;
353  Context.getDiagnostics().Report(diag::err_extdefmap_parsing)
354  << IE.getFileName() << IE.getLineNum();
355  break;
357  Context.getDiagnostics().Report(diag::err_multiple_def_index)
358  << IE.getLineNum();
359  break;
361  Context.getDiagnostics().Report(diag::warn_ctu_incompat_triple)
362  << IE.getFileName() << IE.getTripleToName() << IE.getTripleFromName();
363  break;
364  default:
365  break;
366  }
367 }
368 
369 CrossTranslationUnitContext::ASTUnitStorage::ASTUnitStorage(
370  CompilerInstance &CI)
371  : Loader(CI, CI.getAnalyzerOpts()->CTUDir,
372  CI.getAnalyzerOpts()->CTUInvocationList),
373  LoadGuard(CI.getASTContext().getLangOpts().CPlusPlus
374  ? CI.getAnalyzerOpts()->CTUImportCppThreshold
375  : CI.getAnalyzerOpts()->CTUImportThreshold) {}
376 
378 CrossTranslationUnitContext::ASTUnitStorage::getASTUnitForFile(
379  StringRef FileName, bool DisplayCTUProgress) {
380  // Try the cache first.
381  auto ASTCacheEntry = FileASTUnitMap.find(FileName);
382  if (ASTCacheEntry == FileASTUnitMap.end()) {
383 
384  // Do not load if the limit is reached.
385  if (!LoadGuard) {
386  ++NumASTLoadThresholdReached;
387  return llvm::make_error<IndexError>(
389  }
390 
391  auto LoadAttempt = Loader.load(FileName);
392 
393  if (!LoadAttempt)
394  return LoadAttempt.takeError();
395 
396  std::unique_ptr<ASTUnit> LoadedUnit = std::move(LoadAttempt.get());
397 
398  // Need the raw pointer and the unique_ptr as well.
399  ASTUnit *Unit = LoadedUnit.get();
400 
401  // Update the cache.
402  FileASTUnitMap[FileName] = std::move(LoadedUnit);
403 
404  LoadGuard.indicateLoadSuccess();
405 
406  if (DisplayCTUProgress)
407  llvm::errs() << "CTU loaded AST file: " << FileName << "\n";
408 
409  return Unit;
410 
411  } else {
412  // Found in the cache.
413  return ASTCacheEntry->second.get();
414  }
415 }
416 
418 CrossTranslationUnitContext::ASTUnitStorage::getASTUnitForFunction(
419  StringRef FunctionName, StringRef CrossTUDir, StringRef IndexName,
420  bool DisplayCTUProgress) {
421  // Try the cache first.
422  auto ASTCacheEntry = NameASTUnitMap.find(FunctionName);
423  if (ASTCacheEntry == NameASTUnitMap.end()) {
424  // Load the ASTUnit from the pre-dumped AST file specified by ASTFileName.
425 
426  // Ensure that the Index is loaded, as we need to search in it.
427  if (llvm::Error IndexLoadError =
428  ensureCTUIndexLoaded(CrossTUDir, IndexName))
429  return std::move(IndexLoadError);
430 
431  // Check if there is and entry in the index for the function.
432  if (!NameFileMap.count(FunctionName)) {
433  ++NumNotInOtherTU;
434  return llvm::make_error<IndexError>(index_error_code::missing_definition);
435  }
436 
437  // Search in the index for the filename where the definition of FuncitonName
438  // resides.
439  if (llvm::Expected<ASTUnit *> FoundForFile =
440  getASTUnitForFile(NameFileMap[FunctionName], DisplayCTUProgress)) {
441 
442  // Update the cache.
443  NameASTUnitMap[FunctionName] = *FoundForFile;
444  return *FoundForFile;
445 
446  } else {
447  return FoundForFile.takeError();
448  }
449  } else {
450  // Found in the cache.
451  return ASTCacheEntry->second;
452  }
453 }
454 
456 CrossTranslationUnitContext::ASTUnitStorage::getFileForFunction(
457  StringRef FunctionName, StringRef CrossTUDir, StringRef IndexName) {
458  if (llvm::Error IndexLoadError = ensureCTUIndexLoaded(CrossTUDir, IndexName))
459  return std::move(IndexLoadError);
460  return NameFileMap[FunctionName];
461 }
462 
463 llvm::Error CrossTranslationUnitContext::ASTUnitStorage::ensureCTUIndexLoaded(
464  StringRef CrossTUDir, StringRef IndexName) {
465  // Dont initialize if the map is filled.
466  if (!NameFileMap.empty())
467  return llvm::Error::success();
468 
469  // Get the absolute path to the index file.
470  SmallString<256> IndexFile = CrossTUDir;
471  if (llvm::sys::path::is_absolute(IndexName))
472  IndexFile = IndexName;
473  else
474  llvm::sys::path::append(IndexFile, IndexName);
475 
476  if (auto IndexMapping = parseCrossTUIndex(IndexFile)) {
477  // Initialize member map.
478  NameFileMap = *IndexMapping;
479  return llvm::Error::success();
480  } else {
481  // Error while parsing CrossTU index file.
482  return IndexMapping.takeError();
483  };
484 }
485 
487  StringRef LookupName, StringRef CrossTUDir, StringRef IndexName,
488  bool DisplayCTUProgress) {
489  // FIXME: The current implementation only supports loading decls with
490  // a lookup name from a single translation unit. If multiple
491  // translation units contains decls with the same lookup name an
492  // error will be returned.
493 
494  // Try to get the value from the heavily cached storage.
495  llvm::Expected<ASTUnit *> Unit = ASTStorage.getASTUnitForFunction(
496  LookupName, CrossTUDir, IndexName, DisplayCTUProgress);
497 
498  if (!Unit)
499  return Unit.takeError();
500 
501  // Check whether the backing pointer of the Expected is a nullptr.
502  if (!*Unit)
503  return llvm::make_error<IndexError>(
505 
506  return Unit;
507 }
508 
509 CrossTranslationUnitContext::ASTLoader::ASTLoader(
510  CompilerInstance &CI, StringRef CTUDir, StringRef InvocationListFilePath)
511  : CI(CI), CTUDir(CTUDir), InvocationListFilePath(InvocationListFilePath) {}
512 
513 CrossTranslationUnitContext::LoadResultTy
514 CrossTranslationUnitContext::ASTLoader::load(StringRef Identifier) {
516  if (llvm::sys::path::is_absolute(Identifier, PathStyle)) {
517  Path = Identifier;
518  } else {
519  Path = CTUDir;
520  llvm::sys::path::append(Path, PathStyle, Identifier);
521  }
522 
523  // The path is stored in the InvocationList member in posix style. To
524  // successfully lookup an entry based on filepath, it must be converted.
525  llvm::sys::path::native(Path, PathStyle);
526 
527  // Normalize by removing relative path components.
528  llvm::sys::path::remove_dots(Path, /*remove_dot_dot*/ true, PathStyle);
529 
530  if (Path.endswith(".ast"))
531  return loadFromDump(Path);
532  else
533  return loadFromSource(Path);
534 }
535 
536 CrossTranslationUnitContext::LoadResultTy
537 CrossTranslationUnitContext::ASTLoader::loadFromDump(StringRef ASTDumpPath) {
538  IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
539  TextDiagnosticPrinter *DiagClient =
540  new TextDiagnosticPrinter(llvm::errs(), &*DiagOpts);
541  IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
542  IntrusiveRefCntPtr<DiagnosticsEngine> Diags(
543  new DiagnosticsEngine(DiagID, &*DiagOpts, DiagClient));
545  std::string(ASTDumpPath.str()),
546  CI.getPCHContainerOperations()->getRawReader(), ASTUnit::LoadEverything,
547  Diags, CI.getFileSystemOpts());
548 }
549 
550 /// Load the AST from a source-file, which is supposed to be located inside the
551 /// YAML formatted invocation list file under the filesystem path specified by
552 /// \p InvocationList. The invocation list should contain absolute paths.
553 /// \p SourceFilePath is the absolute path of the source file that contains the
554 /// function definition the analysis is looking for. The Index is built by the
555 /// \p clang-extdef-mapping tool, which is also supposed to be generating
556 /// absolute paths.
557 ///
558 /// Proper diagnostic emission requires absolute paths, so even if a future
559 /// change introduces the handling of relative paths, this must be taken into
560 /// consideration.
561 CrossTranslationUnitContext::LoadResultTy
562 CrossTranslationUnitContext::ASTLoader::loadFromSource(
563  StringRef SourceFilePath) {
564 
565  if (llvm::Error InitError = lazyInitInvocationList())
566  return std::move(InitError);
567  assert(InvocationList);
568 
569  auto Invocation = InvocationList->find(SourceFilePath);
570  if (Invocation == InvocationList->end())
571  return llvm::make_error<IndexError>(
573 
574  const InvocationListTy::mapped_type &InvocationCommand = Invocation->second;
575 
576  SmallVector<const char *, 32> CommandLineArgs(InvocationCommand.size());
577  std::transform(InvocationCommand.begin(), InvocationCommand.end(),
578  CommandLineArgs.begin(),
579  [](auto &&CmdPart) { return CmdPart.c_str(); });
580 
581  IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts{&CI.getDiagnosticOpts()};
582  auto *DiagClient = new ForwardingDiagnosticConsumer{CI.getDiagnosticClient()};
583  IntrusiveRefCntPtr<DiagnosticIDs> DiagID{
584  CI.getDiagnostics().getDiagnosticIDs()};
585  IntrusiveRefCntPtr<DiagnosticsEngine> Diags(
586  new DiagnosticsEngine{DiagID, &*DiagOpts, DiagClient});
587 
588  return std::unique_ptr<ASTUnit>(ASTUnit::LoadFromCommandLine(
589  CommandLineArgs.begin(), (CommandLineArgs.end()),
590  CI.getPCHContainerOperations(), Diags,
591  CI.getHeaderSearchOpts().ResourceDir));
592 }
593 
595 parseInvocationList(StringRef FileContent, llvm::sys::path::Style PathStyle) {
596  InvocationListTy InvocationList;
597 
598  /// LLVM YAML parser is used to extract information from invocation list file.
599  llvm::SourceMgr SM;
600  llvm::yaml::Stream InvocationFile(FileContent, SM);
601 
602  /// Only the first document is processed.
603  llvm::yaml::document_iterator FirstInvocationFile = InvocationFile.begin();
604 
605  /// There has to be at least one document available.
606  if (FirstInvocationFile == InvocationFile.end())
607  return llvm::make_error<IndexError>(
609 
610  llvm::yaml::Node *DocumentRoot = FirstInvocationFile->getRoot();
611  if (!DocumentRoot)
612  return llvm::make_error<IndexError>(
614 
615  /// According to the format specified the document must be a mapping, where
616  /// the keys are paths to source files, and values are sequences of invocation
617  /// parts.
618  auto *Mappings = dyn_cast<llvm::yaml::MappingNode>(DocumentRoot);
619  if (!Mappings)
620  return llvm::make_error<IndexError>(
622 
623  for (auto &NextMapping : *Mappings) {
624  /// The keys should be strings, which represent a source-file path.
625  auto *Key = dyn_cast<llvm::yaml::ScalarNode>(NextMapping.getKey());
626  if (!Key)
627  return llvm::make_error<IndexError>(
629 
630  SmallString<32> ValueStorage;
631  StringRef SourcePath = Key->getValue(ValueStorage);
632 
633  // Store paths with PathStyle directory separator.
634  SmallString<32> NativeSourcePath(SourcePath);
635  llvm::sys::path::native(NativeSourcePath, PathStyle);
636 
637  StringRef InvocationKey = NativeSourcePath;
638 
639  if (InvocationList.find(InvocationKey) != InvocationList.end())
640  return llvm::make_error<IndexError>(
642 
643  /// The values should be sequences of strings, each representing a part of
644  /// the invocation.
645  auto *Args = dyn_cast<llvm::yaml::SequenceNode>(NextMapping.getValue());
646  if (!Args)
647  return llvm::make_error<IndexError>(
649 
650  for (auto &Arg : *Args) {
651  auto *CmdString = dyn_cast<llvm::yaml::ScalarNode>(&Arg);
652  if (!CmdString)
653  return llvm::make_error<IndexError>(
655  /// Every conversion starts with an empty working storage, as it is not
656  /// clear if this is a requirement of the YAML parser.
657  ValueStorage.clear();
658  InvocationList[InvocationKey].emplace_back(
659  CmdString->getValue(ValueStorage));
660  }
661 
662  if (InvocationList[InvocationKey].empty())
663  return llvm::make_error<IndexError>(
665  }
666 
667  return InvocationList;
668 }
669 
670 llvm::Error CrossTranslationUnitContext::ASTLoader::lazyInitInvocationList() {
671  /// Lazily initialize the invocation list member used for on-demand parsing.
672  if (InvocationList)
673  return llvm::Error::success();
674  if (index_error_code::success != PreviousParsingResult)
675  return llvm::make_error<IndexError>(PreviousParsingResult);
676 
677  llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> FileContent =
678  llvm::MemoryBuffer::getFile(InvocationListFilePath);
679  if (!FileContent) {
680  PreviousParsingResult = index_error_code::invocation_list_file_not_found;
681  return llvm::make_error<IndexError>(PreviousParsingResult);
682  }
683  std::unique_ptr<llvm::MemoryBuffer> ContentBuffer = std::move(*FileContent);
684  assert(ContentBuffer && "If no error was produced after loading, the pointer "
685  "should not be nullptr.");
686 
687  llvm::Expected<InvocationListTy> ExpectedInvocationList =
688  parseInvocationList(ContentBuffer->getBuffer(), PathStyle);
689 
690  // Handle the error to store the code for next call to this function.
691  if (!ExpectedInvocationList) {
692  llvm::handleAllErrors(
693  ExpectedInvocationList.takeError(),
694  [&](const IndexError &E) { PreviousParsingResult = E.getCode(); });
695  return llvm::make_error<IndexError>(PreviousParsingResult);
696  }
697 
698  InvocationList = *ExpectedInvocationList;
699 
700  return llvm::Error::success();
701 }
702 
703 template <typename T>
705 CrossTranslationUnitContext::importDefinitionImpl(const T *D, ASTUnit *Unit) {
706  assert(hasBodyOrInit(D) && "Decls to be imported should have body or init.");
707 
708  assert(&D->getASTContext() == &Unit->getASTContext() &&
709  "ASTContext of Decl and the unit should match.");
710  ASTImporter &Importer = getOrCreateASTImporter(Unit);
711 
712  auto ToDeclOrError = Importer.Import(D);
713  if (!ToDeclOrError) {
714  handleAllErrors(ToDeclOrError.takeError(),
715  [&](const ImportError &IE) {
716  switch (IE.Error) {
717  case ImportError::NameConflict:
718  ++NumNameConflicts;
719  break;
720  case ImportError::UnsupportedConstruct:
721  ++NumUnsupportedNodeFound;
722  break;
723  case ImportError::Unknown:
724  llvm_unreachable("Unknown import error happened.");
725  break;
726  }
727  });
728  return llvm::make_error<IndexError>(index_error_code::failed_import);
729  }
730  auto *ToDecl = cast<T>(*ToDeclOrError);
731  assert(hasBodyOrInit(ToDecl) && "Imported Decl should have body or init.");
732  ++NumGetCTUSuccess;
733 
734  // Parent map is invalidated after changing the AST.
735  ToDecl->getASTContext().getParentMapContext().clear();
736 
737  return ToDecl;
738 }
739 
741 CrossTranslationUnitContext::importDefinition(const FunctionDecl *FD,
742  ASTUnit *Unit) {
743  return importDefinitionImpl(FD, Unit);
744 }
745 
747 CrossTranslationUnitContext::importDefinition(const VarDecl *VD,
748  ASTUnit *Unit) {
749  return importDefinitionImpl(VD, Unit);
750 }
751 
752 void CrossTranslationUnitContext::lazyInitImporterSharedSt(
753  TranslationUnitDecl *ToTU) {
754  if (!ImporterSharedSt)
755  ImporterSharedSt = std::make_shared<ASTImporterSharedState>(*ToTU);
756 }
757 
758 ASTImporter &
759 CrossTranslationUnitContext::getOrCreateASTImporter(ASTUnit *Unit) {
760  ASTContext &From = Unit->getASTContext();
761 
762  auto I = ASTUnitImporterMap.find(From.getTranslationUnitDecl());
763  if (I != ASTUnitImporterMap.end())
764  return *I->second;
765  lazyInitImporterSharedSt(Context.getTranslationUnitDecl());
766  ASTImporter *NewImporter = new ASTImporter(
767  Context, Context.getSourceManager().getFileManager(), From,
768  From.getSourceManager().getFileManager(), false, ImporterSharedSt);
769  ASTUnitImporterMap[From.getTranslationUnitDecl()].reset(NewImporter);
770  return *NewImporter;
771 }
772 
774 CrossTranslationUnitContext::getMacroExpansionContextForSourceLocation(
775  const clang::SourceLocation &ToLoc) const {
776  // FIXME: Implement: Record such a context for every imported ASTUnit; lookup.
777  return llvm::None;
778 }
779 
780 } // namespace cross_tu
781 } // namespace clang
clang::cross_tu::InvocationListTy
llvm::StringMap< llvm::SmallVector< std::string, 32 > > InvocationListTy
Definition: CrossTranslationUnit.h:102
clang::cross_tu::IndexError::getCode
index_error_code getCode() const
Definition: CrossTranslationUnit.h:74
clang::ASTUnit
Utility class for loading a ASTContext from an AST file.
Definition: ASTUnit.h:89
clang::DeclContext::decls
decl_range decls() const
decls_begin/decls_end - Iterate over the declarations stored in this context.
Definition: DeclBase.h:2115
clang::cross_tu::CrossTranslationUnitContext::loadExternalAST
llvm::Expected< ASTUnit * > loadExternalAST(StringRef LookupName, StringRef CrossTUDir, StringRef IndexName, bool DisplayCTUProgress=false)
This function loads a definition from an external AST file.
Definition: CrossTranslationUnit.cpp:486
clang::cross_tu::index_error_code::missing_index_file
@ missing_index_file
string
string(SUBSTRING ${CMAKE_CURRENT_BINARY_DIR} 0 ${PATH_LIB_START} PATH_HEAD) string(SUBSTRING $
Definition: CMakeLists.txt:22
clang::DeclContext
DeclContext - This is used only as base class of specific decl types that can act as declaration cont...
Definition: DeclBase.h:1347
Ret
static bool Ret(InterpState &S, CodePtr &PC, APValue &Result)
Definition: Interp.cpp:34
clang::cross_tu::index_error_code::lang_mismatch
@ lang_mismatch
clang::cross_tu::IndexError::getFileName
std::string getFileName() const
Definition: CrossTranslationUnit.h:76
clang::cross_tu::index_error_code::load_threshold_reached
@ load_threshold_reached
clang::SourceLocation
Encodes a location in the source.
Definition: SourceLocation.h:88
clang::NamedDecl
This represents a decl that may have a name.
Definition: Decl.h:249
TargetInfo.h
clang::cross_tu::IndexError::convertToErrorCode
std::error_code convertToErrorCode() const override
Definition: CrossTranslationUnit.cpp:148
clang::cross_tu::index_error_code::invalid_index_format
@ invalid_index_format
clang::CanQual::isConstQualified
bool isConstQualified() const
Definition: CanonicalType.h:137
llvm::Optional< std::string >
clang::cross_tu::index_error_code::invocation_list_wrong_format
@ invocation_list_wrong_format
clang::cross_tu::index_error_code::failed_to_get_external_ast
@ failed_to_get_external_ast
llvm::Expected
Definition: LLVM.h:41
clang::cross_tu::hasBodyOrInit
static bool hasBodyOrInit(const FunctionDecl *D, const FunctionDecl *&DefD)
Definition: CrossTranslationUnit.cpp:204
Identifier
StringRef Identifier
Definition: Format.cpp:2341
clang::cross_tu::index_error_code::failed_import
@ failed_import
clang::ASTContext::getSourceManager
SourceManager & getSourceManager()
Definition: ASTContext.h:695
clang::ASTContext::getTranslationUnitDecl
TranslationUnitDecl * getTranslationUnitDecl() const
Definition: ASTContext.h:1057
Decl.h
ParentMapContext.h
clang::cross_tu::index_error_code::invocation_list_empty
@ invocation_list_empty
clang::cross_tu::index_error_code::invocation_list_ambiguous
@ invocation_list_ambiguous
clang::ASTUnit::getASTContext
const ASTContext & getASTContext() const
Definition: ASTUnit.h:439
clang::TranslationUnitDecl
The top declaration context.
Definition: Decl.h:82
clang::RecordType
A helper class that allows the use of isa/cast/dyncast to detect TagType objects of structs/unions/cl...
Definition: Type.h:4613
clang::cross_tu::IndexError::ID
static char ID
Definition: CrossTranslationUnit.h:63
clang::cross_tu::CrossTranslationUnitContext::emitCrossTUDiagnostics
void emitCrossTUDiagnostics(const IndexError &IE)
Emit diagnostics for the user for potential configuration errors.
Definition: CrossTranslationUnit.cpp:346
Node
DynTypedNode Node
Definition: ASTMatchFinder.cpp:67
clang::ASTUnit::LoadFromASTFile
static std::unique_ptr< ASTUnit > LoadFromASTFile(const std::string &Filename, const PCHContainerReader &PCHContainerRdr, WhatToLoad ToLoad, IntrusiveRefCntPtr< DiagnosticsEngine > Diags, const FileSystemOptions &FileSystemOpts, bool UseDebugInfo=false, bool OnlyLocalDecls=false, CaptureDiagsKind CaptureDiagnostics=CaptureDiagsKind::None, bool AllowASTWithCompilerErrors=false, bool UserFilesAreVolatile=false)
Create a ASTUnit from an AST file.
Definition: ASTUnit.cpp:757
clang::cross_tu::index_error_code
index_error_code
Definition: CrossTranslationUnit.h:40
clang::ASTContext
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
Definition: ASTContext.h:212
clang::cross_tu::index_error_code::invocation_list_lookup_unsuccessful
@ invocation_list_lookup_unsuccessful
clang::CPlusPlus
@ CPlusPlus
Definition: LangStandard.h:48
llvm::SmallString< 32 >
clang::cross_tu::CrossTranslationUnitContext::importDefinition
llvm::Expected< const FunctionDecl * > importDefinition(const FunctionDecl *FD, ASTUnit *Unit)
This function merges a definition from a separate AST Unit into the current one which was created by ...
Definition: CrossTranslationUnit.cpp:741
clang::VarDecl
Represents a variable declaration or definition.
Definition: Decl.h:876
clang::cross_tu::IndexError::getTripleToName
std::string getTripleToName() const
Definition: CrossTranslationUnit.h:77
Category
int Category
Definition: Format.cpp:2336
clang::ASTContext::getCanonicalType
CanQualType getCanonicalType(QualType T) const
Return the canonical (structural) type corresponding to the specified potentially non-canonical type ...
Definition: ASTContext.h:2468
clang::cross_tu::index_error_code::success
@ success
clang::CanQual< Type >
Line
const AnnotatedLine * Line
Definition: UsingDeclarationsSorter.cpp:68
clang::CompilerInstance
CompilerInstance - Helper class for managing a single instance of the Clang compiler.
Definition: CompilerInstance.h:74
clang::cross_tu::index_error_code::invocation_list_file_not_found
@ invocation_list_file_not_found
clang::cross_tu::index_error_code::multiple_definitions
@ multiple_definitions
clang::cross_tu::index_error_code::lang_dialect_mismatch
@ lang_dialect_mismatch
clang::ASTImporter
Imports selected nodes from one AST context into another context, merging AST nodes where appropriate...
Definition: ASTImporter.h:90
clang::FunctionDecl::hasBody
bool hasBody(const FunctionDecl *&Definition) const
Returns true if the function has a body.
Definition: Decl.cpp:2955
clang::RecordType::hasConstFields
bool hasConstFields() const
Recursively check all fields in the record for const-ness.
Definition: Type.cpp:3503
clang::cross_tu::IndexError::getLineNum
int getLineNum() const
Definition: CrossTranslationUnit.h:75
clang::TargetInfo::getTriple
const llvm::Triple & getTriple() const
Returns the target triple of the primary target.
Definition: TargetInfo.h:1130
clang::VarDecl::getAnyInitializer
const Expr * getAnyInitializer() const
Get the initializer for this variable, no matter which declaration it is attached to.
Definition: Decl.h:1275
clang::cross_tu::index_error_code::triple_mismatch
@ triple_mismatch
clang::cross_tu::CrossTranslationUnitContext::~CrossTranslationUnitContext
~CrossTranslationUnitContext()
Definition: CrossTranslationUnit.cpp:218
clang::cross_tu::IndexError::log
void log(raw_ostream &OS) const override
Definition: CrossTranslationUnit.cpp:144
clang::cross_tu::parseInvocationList
llvm::Expected< InvocationListTy > parseInvocationList(StringRef FileContent, llvm::sys::path::Style PathStyle=llvm::sys::path::Style::posix)
Parse the YAML formatted invocation list file content FileContent.
Definition: CrossTranslationUnit.cpp:595
TextDiagnosticPrinter.h
clang::cross_tu::index_error_code::failed_to_generate_usr
@ failed_to_generate_usr
clang::Decl
Decl - This represents one declaration (or definition), e.g.
Definition: DeclBase.h:89
clang::cross_tu::parseCrossTUIndex
llvm::Expected< llvm::StringMap< std::string > > parseCrossTUIndex(StringRef IndexPath)
This function parses an index file that determines which translation unit contains which definition.
Definition: CrossTranslationUnit.cpp:153
USRGeneration.h
ASTUnit.h
STATISTIC
STATISTIC(NumObjCCallEdges, "Number of Objective-C method call edges")
Unused
@ Unused
Definition: ObjCUnusedIVarsChecker.cpp:29
clang::ASTContext::getTargetInfo
const TargetInfo & getTargetInfo() const
Definition: ASTContext.h:747
clang::cross_tu::CrossTranslationUnitContext::getCrossTUDefinition
llvm::Expected< const FunctionDecl * > getCrossTUDefinition(const FunctionDecl *FD, StringRef CrossTUDir, StringRef IndexName, bool DisplayCTUProgress=false)
This function loads a function or variable definition from an external AST file and merges it into th...
Definition: CrossTranslationUnit.cpp:329
ASTImporter.h
clang::cross_tu::index_error_code::unspecified
@ unspecified
clang::index::generateUSRForDecl
bool generateUSRForDecl(const Decl *D, SmallVectorImpl< char > &Buf)
Generate a USR for a Decl, including the USR prefix.
Definition: USRGeneration.cpp:1081
clang
Definition: CalledOnceCheck.h:17
clang::cross_tu::IndexError::getTripleFromName
std::string getTripleFromName() const
Definition: CrossTranslationUnit.h:78
CrossTUDiagnostic.h
clang::cross_tu::index_error_code::missing_definition
@ missing_definition
clang::ASTUnit::LoadEverything
@ LoadEverything
Load everything, including Sema.
Definition: ASTUnit.h:678
clang::SourceManager::getFileManager
FileManager & getFileManager() const
Definition: SourceManager.h:806
clang::cross_tu::IndexError
Definition: CrossTranslationUnit.h:61
CompilerInstance.h
clang::CanQual::getAs
CanProxy< U > getAs() const
Retrieve a canonical type pointer with a different static type, upcasting or downcasting as needed.
Definition: CanonicalType.h:653
clang::cross_tu::CrossTranslationUnitContext::getLookupName
static llvm::Optional< std::string > getLookupName(const NamedDecl *ND)
Get a name to identify a named decl.
Definition: CrossTranslationUnit.cpp:221
clang::ValueDecl::getType
QualType getType() const
Definition: Decl.h:687
CrossTranslationUnit.h
SM
#define SM(sm)
Definition: Cuda.cpp:78
clang::cross_tu::CrossTranslationUnitContext::CrossTranslationUnitContext
CrossTranslationUnitContext(CompilerInstance &CI)
Definition: CrossTranslationUnit.cpp:215
clang::transformer::name
RangeSelector name(std::string ID)
Given a node with a "name", (like NamedDecl, DeclRefExpr, CxxCtorInitializer, and TypeLoc) selects th...
Definition: RangeSelector.cpp:200
clang::cross_tu::createCrossTUIndexString
std::string createCrossTUIndexString(const llvm::StringMap< std::string > &Index)
Definition: CrossTranslationUnit.cpp:187
clang::FunctionDecl
Represents a function declaration or definition.
Definition: Decl.h:1856
clang::cross_tu::containsConst
bool containsConst(const VarDecl *VD, const ASTContext &ACtx)
Definition: CrossTranslationUnit.cpp:194
clang::ASTContext::getLangOpts
const LangOptions & getLangOpts() const
Definition: ASTContext.h:765
clang::ASTContext::getDiagnostics
DiagnosticsEngine & getDiagnostics() const
Definition: ASTContext.cpp:1499
clang::DiagnosticsEngine::Report
DiagnosticBuilder Report(SourceLocation Loc, unsigned DiagID)
Issue the message to the client.
Definition: Diagnostic.h:1523
clang::ASTUnit::LoadFromCommandLine
static ASTUnit * LoadFromCommandLine(const char **ArgBegin, const char **ArgEnd, std::shared_ptr< PCHContainerOperations > PCHContainerOps, IntrusiveRefCntPtr< DiagnosticsEngine > Diags, StringRef ResourceFilesPath, bool OnlyLocalDecls=false, CaptureDiagsKind CaptureDiagnostics=CaptureDiagsKind::None, ArrayRef< RemappedFile > RemappedFiles=None, bool RemappedFilesKeepOriginalName=true, unsigned PrecompilePreambleAfterNParses=0, TranslationUnitKind TUKind=TU_Complete, bool CacheCodeCompletionResults=false, bool IncludeBriefCommentsInCodeCompletion=false, bool AllowPCHWithCompilerErrors=false, SkipFunctionBodiesScope SkipFunctionBodies=SkipFunctionBodiesScope::None, bool SingleFileParse=false, bool UserFilesAreVolatile=false, bool ForSerialization=false, bool RetainExcludedConditionalBlocks=false, llvm::Optional< StringRef > ModuleFormat=llvm::None, std::unique_ptr< ASTUnit > *ErrAST=nullptr, IntrusiveRefCntPtr< llvm::vfs::FileSystem > VFS=nullptr)
LoadFromCommandLine - Create an ASTUnit from a vector of command line arguments, which must specify e...
Definition: ASTUnit.cpp:1709