CrossTranslationUnit.cpp 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588
  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. //===----------------------------------------------------------------------===//
  12. #include "clang/CrossTU/CrossTranslationUnit.h"
  13. #include "clang/AST/ASTImporter.h"
  14. #include "clang/AST/Decl.h"
  15. #include "clang/Basic/TargetInfo.h"
  16. #include "clang/CrossTU/CrossTUDiagnostic.h"
  17. #include "clang/Frontend/ASTUnit.h"
  18. #include "clang/Frontend/CompilerInstance.h"
  19. #include "clang/Frontend/TextDiagnosticPrinter.h"
  20. #include "clang/Index/USRGeneration.h"
  21. #include "llvm/ADT/Triple.h"
  22. #include "llvm/ADT/Statistic.h"
  23. #include "llvm/Support/ErrorHandling.h"
  24. #include "llvm/Support/ManagedStatic.h"
  25. #include "llvm/Support/Path.h"
  26. #include "llvm/Support/raw_ostream.h"
  27. #include <fstream>
  28. #include <sstream>
  29. namespace clang {
  30. namespace cross_tu {
  31. namespace {
  32. #define DEBUG_TYPE "CrossTranslationUnit"
  33. STATISTIC(NumGetCTUCalled, "The # of getCTUDefinition function called");
  34. STATISTIC(
  35. NumNotInOtherTU,
  36. "The # of getCTUDefinition called but the function is not in any other TU");
  37. STATISTIC(NumGetCTUSuccess,
  38. "The # of getCTUDefinition successfully returned the "
  39. "requested function's body");
  40. STATISTIC(NumUnsupportedNodeFound, "The # of imports when the ASTImporter "
  41. "encountered an unsupported AST Node");
  42. STATISTIC(NumNameConflicts, "The # of imports when the ASTImporter "
  43. "encountered an ODR error");
  44. STATISTIC(NumTripleMismatch, "The # of triple mismatches");
  45. STATISTIC(NumLangMismatch, "The # of language mismatches");
  46. STATISTIC(NumLangDialectMismatch, "The # of language dialect mismatches");
  47. STATISTIC(NumASTLoadThresholdReached,
  48. "The # of ASTs not loaded because of threshold");
  49. // Same as Triple's equality operator, but we check a field only if that is
  50. // known in both instances.
  51. bool hasEqualKnownFields(const llvm::Triple &Lhs, const llvm::Triple &Rhs) {
  52. using llvm::Triple;
  53. if (Lhs.getArch() != Triple::UnknownArch &&
  54. Rhs.getArch() != Triple::UnknownArch && Lhs.getArch() != Rhs.getArch())
  55. return false;
  56. if (Lhs.getSubArch() != Triple::NoSubArch &&
  57. Rhs.getSubArch() != Triple::NoSubArch &&
  58. Lhs.getSubArch() != Rhs.getSubArch())
  59. return false;
  60. if (Lhs.getVendor() != Triple::UnknownVendor &&
  61. Rhs.getVendor() != Triple::UnknownVendor &&
  62. Lhs.getVendor() != Rhs.getVendor())
  63. return false;
  64. if (!Lhs.isOSUnknown() && !Rhs.isOSUnknown() &&
  65. Lhs.getOS() != Rhs.getOS())
  66. return false;
  67. if (Lhs.getEnvironment() != Triple::UnknownEnvironment &&
  68. Rhs.getEnvironment() != Triple::UnknownEnvironment &&
  69. Lhs.getEnvironment() != Rhs.getEnvironment())
  70. return false;
  71. if (Lhs.getObjectFormat() != Triple::UnknownObjectFormat &&
  72. Rhs.getObjectFormat() != Triple::UnknownObjectFormat &&
  73. Lhs.getObjectFormat() != Rhs.getObjectFormat())
  74. return false;
  75. return true;
  76. }
  77. // FIXME: This class is will be removed after the transition to llvm::Error.
  78. class IndexErrorCategory : public std::error_category {
  79. public:
  80. const char *name() const noexcept override { return "clang.index"; }
  81. std::string message(int Condition) const override {
  82. switch (static_cast<index_error_code>(Condition)) {
  83. case index_error_code::unspecified:
  84. return "An unknown error has occurred.";
  85. case index_error_code::missing_index_file:
  86. return "The index file is missing.";
  87. case index_error_code::invalid_index_format:
  88. return "Invalid index file format.";
  89. case index_error_code::multiple_definitions:
  90. return "Multiple definitions in the index file.";
  91. case index_error_code::missing_definition:
  92. return "Missing definition from the index file.";
  93. case index_error_code::failed_import:
  94. return "Failed to import the definition.";
  95. case index_error_code::failed_to_get_external_ast:
  96. return "Failed to load external AST source.";
  97. case index_error_code::failed_to_generate_usr:
  98. return "Failed to generate USR.";
  99. case index_error_code::triple_mismatch:
  100. return "Triple mismatch";
  101. case index_error_code::lang_mismatch:
  102. return "Language mismatch";
  103. case index_error_code::lang_dialect_mismatch:
  104. return "Language dialect mismatch";
  105. case index_error_code::load_threshold_reached:
  106. return "Load threshold reached";
  107. }
  108. llvm_unreachable("Unrecognized index_error_code.");
  109. }
  110. };
  111. static llvm::ManagedStatic<IndexErrorCategory> Category;
  112. } // end anonymous namespace
  113. char IndexError::ID;
  114. void IndexError::log(raw_ostream &OS) const {
  115. OS << Category->message(static_cast<int>(Code)) << '\n';
  116. }
  117. std::error_code IndexError::convertToErrorCode() const {
  118. return std::error_code(static_cast<int>(Code), *Category);
  119. }
  120. llvm::Expected<llvm::StringMap<std::string>>
  121. parseCrossTUIndex(StringRef IndexPath, StringRef CrossTUDir) {
  122. std::ifstream ExternalMapFile(IndexPath);
  123. if (!ExternalMapFile)
  124. return llvm::make_error<IndexError>(index_error_code::missing_index_file,
  125. IndexPath.str());
  126. llvm::StringMap<std::string> Result;
  127. std::string Line;
  128. unsigned LineNo = 1;
  129. while (std::getline(ExternalMapFile, Line)) {
  130. const size_t Pos = Line.find(" ");
  131. if (Pos > 0 && Pos != std::string::npos) {
  132. StringRef LineRef{Line};
  133. StringRef LookupName = LineRef.substr(0, Pos);
  134. if (Result.count(LookupName))
  135. return llvm::make_error<IndexError>(
  136. index_error_code::multiple_definitions, IndexPath.str(), LineNo);
  137. StringRef FileName = LineRef.substr(Pos + 1);
  138. SmallString<256> FilePath = CrossTUDir;
  139. llvm::sys::path::append(FilePath, FileName);
  140. Result[LookupName] = FilePath.str().str();
  141. } else
  142. return llvm::make_error<IndexError>(
  143. index_error_code::invalid_index_format, IndexPath.str(), LineNo);
  144. LineNo++;
  145. }
  146. return Result;
  147. }
  148. std::string
  149. createCrossTUIndexString(const llvm::StringMap<std::string> &Index) {
  150. std::ostringstream Result;
  151. for (const auto &E : Index)
  152. Result << E.getKey().str() << " " << E.getValue() << '\n';
  153. return Result.str();
  154. }
  155. bool containsConst(const VarDecl *VD, const ASTContext &ACtx) {
  156. CanQualType CT = ACtx.getCanonicalType(VD->getType());
  157. if (!CT.isConstQualified()) {
  158. const RecordType *RTy = CT->getAs<RecordType>();
  159. if (!RTy || !RTy->hasConstFields())
  160. return false;
  161. }
  162. return true;
  163. }
  164. static bool hasBodyOrInit(const FunctionDecl *D, const FunctionDecl *&DefD) {
  165. return D->hasBody(DefD);
  166. }
  167. static bool hasBodyOrInit(const VarDecl *D, const VarDecl *&DefD) {
  168. return D->getAnyInitializer(DefD);
  169. }
  170. template <typename T> static bool hasBodyOrInit(const T *D) {
  171. const T *Unused;
  172. return hasBodyOrInit(D, Unused);
  173. }
  174. CrossTranslationUnitContext::CrossTranslationUnitContext(CompilerInstance &CI)
  175. : Context(CI.getASTContext()), ASTStorage(CI) {}
  176. CrossTranslationUnitContext::~CrossTranslationUnitContext() {}
  177. llvm::Optional<std::string>
  178. CrossTranslationUnitContext::getLookupName(const NamedDecl *ND) {
  179. SmallString<128> DeclUSR;
  180. bool Ret = index::generateUSRForDecl(ND, DeclUSR);
  181. if (Ret)
  182. return {};
  183. return std::string(DeclUSR.str());
  184. }
  185. /// Recursively visits the decls of a DeclContext, and returns one with the
  186. /// given USR.
  187. template <typename T>
  188. const T *
  189. CrossTranslationUnitContext::findDefInDeclContext(const DeclContext *DC,
  190. StringRef LookupName) {
  191. assert(DC && "Declaration Context must not be null");
  192. for (const Decl *D : DC->decls()) {
  193. const auto *SubDC = dyn_cast<DeclContext>(D);
  194. if (SubDC)
  195. if (const auto *ND = findDefInDeclContext<T>(SubDC, LookupName))
  196. return ND;
  197. const auto *ND = dyn_cast<T>(D);
  198. const T *ResultDecl;
  199. if (!ND || !hasBodyOrInit(ND, ResultDecl))
  200. continue;
  201. llvm::Optional<std::string> ResultLookupName = getLookupName(ResultDecl);
  202. if (!ResultLookupName || *ResultLookupName != LookupName)
  203. continue;
  204. return ResultDecl;
  205. }
  206. return nullptr;
  207. }
  208. template <typename T>
  209. llvm::Expected<const T *> CrossTranslationUnitContext::getCrossTUDefinitionImpl(
  210. const T *D, StringRef CrossTUDir, StringRef IndexName,
  211. bool DisplayCTUProgress) {
  212. assert(D && "D is missing, bad call to this function!");
  213. assert(!hasBodyOrInit(D) &&
  214. "D has a body or init in current translation unit!");
  215. ++NumGetCTUCalled;
  216. const llvm::Optional<std::string> LookupName = getLookupName(D);
  217. if (!LookupName)
  218. return llvm::make_error<IndexError>(
  219. index_error_code::failed_to_generate_usr);
  220. llvm::Expected<ASTUnit *> ASTUnitOrError =
  221. loadExternalAST(*LookupName, CrossTUDir, IndexName, DisplayCTUProgress);
  222. if (!ASTUnitOrError)
  223. return ASTUnitOrError.takeError();
  224. ASTUnit *Unit = *ASTUnitOrError;
  225. assert(&Unit->getFileManager() ==
  226. &Unit->getASTContext().getSourceManager().getFileManager());
  227. const llvm::Triple &TripleTo = Context.getTargetInfo().getTriple();
  228. const llvm::Triple &TripleFrom =
  229. Unit->getASTContext().getTargetInfo().getTriple();
  230. // The imported AST had been generated for a different target.
  231. // Some parts of the triple in the loaded ASTContext can be unknown while the
  232. // very same parts in the target ASTContext are known. Thus we check for the
  233. // known parts only.
  234. if (!hasEqualKnownFields(TripleTo, TripleFrom)) {
  235. // TODO: Pass the SourceLocation of the CallExpression for more precise
  236. // diagnostics.
  237. ++NumTripleMismatch;
  238. return llvm::make_error<IndexError>(index_error_code::triple_mismatch,
  239. Unit->getMainFileName(), TripleTo.str(),
  240. TripleFrom.str());
  241. }
  242. const auto &LangTo = Context.getLangOpts();
  243. const auto &LangFrom = Unit->getASTContext().getLangOpts();
  244. // FIXME: Currenty we do not support CTU across C++ and C and across
  245. // different dialects of C++.
  246. if (LangTo.CPlusPlus != LangFrom.CPlusPlus) {
  247. ++NumLangMismatch;
  248. return llvm::make_error<IndexError>(index_error_code::lang_mismatch);
  249. }
  250. // If CPP dialects are different then return with error.
  251. //
  252. // Consider this STL code:
  253. // template<typename _Alloc>
  254. // struct __alloc_traits
  255. // #if __cplusplus >= 201103L
  256. // : std::allocator_traits<_Alloc>
  257. // #endif
  258. // { // ...
  259. // };
  260. // This class template would create ODR errors during merging the two units,
  261. // since in one translation unit the class template has a base class, however
  262. // in the other unit it has none.
  263. if (LangTo.CPlusPlus11 != LangFrom.CPlusPlus11 ||
  264. LangTo.CPlusPlus14 != LangFrom.CPlusPlus14 ||
  265. LangTo.CPlusPlus17 != LangFrom.CPlusPlus17 ||
  266. LangTo.CPlusPlus2a != LangFrom.CPlusPlus2a) {
  267. ++NumLangDialectMismatch;
  268. return llvm::make_error<IndexError>(
  269. index_error_code::lang_dialect_mismatch);
  270. }
  271. TranslationUnitDecl *TU = Unit->getASTContext().getTranslationUnitDecl();
  272. if (const T *ResultDecl = findDefInDeclContext<T>(TU, *LookupName))
  273. return importDefinition(ResultDecl, Unit);
  274. return llvm::make_error<IndexError>(index_error_code::failed_import);
  275. }
  276. llvm::Expected<const FunctionDecl *>
  277. CrossTranslationUnitContext::getCrossTUDefinition(const FunctionDecl *FD,
  278. StringRef CrossTUDir,
  279. StringRef IndexName,
  280. bool DisplayCTUProgress) {
  281. return getCrossTUDefinitionImpl(FD, CrossTUDir, IndexName,
  282. DisplayCTUProgress);
  283. }
  284. llvm::Expected<const VarDecl *>
  285. CrossTranslationUnitContext::getCrossTUDefinition(const VarDecl *VD,
  286. StringRef CrossTUDir,
  287. StringRef IndexName,
  288. bool DisplayCTUProgress) {
  289. return getCrossTUDefinitionImpl(VD, CrossTUDir, IndexName,
  290. DisplayCTUProgress);
  291. }
  292. void CrossTranslationUnitContext::emitCrossTUDiagnostics(const IndexError &IE) {
  293. switch (IE.getCode()) {
  294. case index_error_code::missing_index_file:
  295. Context.getDiagnostics().Report(diag::err_ctu_error_opening)
  296. << IE.getFileName();
  297. break;
  298. case index_error_code::invalid_index_format:
  299. Context.getDiagnostics().Report(diag::err_extdefmap_parsing)
  300. << IE.getFileName() << IE.getLineNum();
  301. break;
  302. case index_error_code::multiple_definitions:
  303. Context.getDiagnostics().Report(diag::err_multiple_def_index)
  304. << IE.getLineNum();
  305. break;
  306. case index_error_code::triple_mismatch:
  307. Context.getDiagnostics().Report(diag::warn_ctu_incompat_triple)
  308. << IE.getFileName() << IE.getTripleToName() << IE.getTripleFromName();
  309. break;
  310. default:
  311. break;
  312. }
  313. }
  314. CrossTranslationUnitContext::ASTFileLoader::ASTFileLoader(
  315. const CompilerInstance &CI)
  316. : CI(CI) {}
  317. std::unique_ptr<ASTUnit>
  318. CrossTranslationUnitContext::ASTFileLoader::operator()(StringRef ASTFilePath) {
  319. // Load AST from ast-dump.
  320. IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
  321. TextDiagnosticPrinter *DiagClient =
  322. new TextDiagnosticPrinter(llvm::errs(), &*DiagOpts);
  323. IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
  324. IntrusiveRefCntPtr<DiagnosticsEngine> Diags(
  325. new DiagnosticsEngine(DiagID, &*DiagOpts, DiagClient));
  326. return ASTUnit::LoadFromASTFile(
  327. ASTFilePath, CI.getPCHContainerOperations()->getRawReader(),
  328. ASTUnit::LoadEverything, Diags, CI.getFileSystemOpts());
  329. }
  330. CrossTranslationUnitContext::ASTUnitStorage::ASTUnitStorage(
  331. const CompilerInstance &CI)
  332. : FileAccessor(CI), LoadGuard(const_cast<CompilerInstance &>(CI)
  333. .getAnalyzerOpts()
  334. ->CTUImportThreshold) {}
  335. llvm::Expected<ASTUnit *>
  336. CrossTranslationUnitContext::ASTUnitStorage::getASTUnitForFile(
  337. StringRef FileName, bool DisplayCTUProgress) {
  338. // Try the cache first.
  339. auto ASTCacheEntry = FileASTUnitMap.find(FileName);
  340. if (ASTCacheEntry == FileASTUnitMap.end()) {
  341. // Do not load if the limit is reached.
  342. if (!LoadGuard) {
  343. ++NumASTLoadThresholdReached;
  344. return llvm::make_error<IndexError>(
  345. index_error_code::load_threshold_reached);
  346. }
  347. // Load the ASTUnit from the pre-dumped AST file specified by ASTFileName.
  348. std::unique_ptr<ASTUnit> LoadedUnit = FileAccessor(FileName);
  349. // Need the raw pointer and the unique_ptr as well.
  350. ASTUnit *Unit = LoadedUnit.get();
  351. // Update the cache.
  352. FileASTUnitMap[FileName] = std::move(LoadedUnit);
  353. LoadGuard.indicateLoadSuccess();
  354. if (DisplayCTUProgress)
  355. llvm::errs() << "CTU loaded AST file: " << FileName << "\n";
  356. return Unit;
  357. } else {
  358. // Found in the cache.
  359. return ASTCacheEntry->second.get();
  360. }
  361. }
  362. llvm::Expected<ASTUnit *>
  363. CrossTranslationUnitContext::ASTUnitStorage::getASTUnitForFunction(
  364. StringRef FunctionName, StringRef CrossTUDir, StringRef IndexName,
  365. bool DisplayCTUProgress) {
  366. // Try the cache first.
  367. auto ASTCacheEntry = NameASTUnitMap.find(FunctionName);
  368. if (ASTCacheEntry == NameASTUnitMap.end()) {
  369. // Load the ASTUnit from the pre-dumped AST file specified by ASTFileName.
  370. // Ensure that the Index is loaded, as we need to search in it.
  371. if (llvm::Error IndexLoadError =
  372. ensureCTUIndexLoaded(CrossTUDir, IndexName))
  373. return std::move(IndexLoadError);
  374. // Check if there is and entry in the index for the function.
  375. if (!NameFileMap.count(FunctionName)) {
  376. ++NumNotInOtherTU;
  377. return llvm::make_error<IndexError>(index_error_code::missing_definition);
  378. }
  379. // Search in the index for the filename where the definition of FuncitonName
  380. // resides.
  381. if (llvm::Expected<ASTUnit *> FoundForFile =
  382. getASTUnitForFile(NameFileMap[FunctionName], DisplayCTUProgress)) {
  383. // Update the cache.
  384. NameASTUnitMap[FunctionName] = *FoundForFile;
  385. return *FoundForFile;
  386. } else {
  387. return FoundForFile.takeError();
  388. }
  389. } else {
  390. // Found in the cache.
  391. return ASTCacheEntry->second;
  392. }
  393. }
  394. llvm::Expected<std::string>
  395. CrossTranslationUnitContext::ASTUnitStorage::getFileForFunction(
  396. StringRef FunctionName, StringRef CrossTUDir, StringRef IndexName) {
  397. if (llvm::Error IndexLoadError = ensureCTUIndexLoaded(CrossTUDir, IndexName))
  398. return std::move(IndexLoadError);
  399. return NameFileMap[FunctionName];
  400. }
  401. llvm::Error CrossTranslationUnitContext::ASTUnitStorage::ensureCTUIndexLoaded(
  402. StringRef CrossTUDir, StringRef IndexName) {
  403. // Dont initialize if the map is filled.
  404. if (!NameFileMap.empty())
  405. return llvm::Error::success();
  406. // Get the absolute path to the index file.
  407. SmallString<256> IndexFile = CrossTUDir;
  408. if (llvm::sys::path::is_absolute(IndexName))
  409. IndexFile = IndexName;
  410. else
  411. llvm::sys::path::append(IndexFile, IndexName);
  412. if (auto IndexMapping = parseCrossTUIndex(IndexFile, CrossTUDir)) {
  413. // Initialize member map.
  414. NameFileMap = *IndexMapping;
  415. return llvm::Error::success();
  416. } else {
  417. // Error while parsing CrossTU index file.
  418. return IndexMapping.takeError();
  419. };
  420. }
  421. llvm::Expected<ASTUnit *> CrossTranslationUnitContext::loadExternalAST(
  422. StringRef LookupName, StringRef CrossTUDir, StringRef IndexName,
  423. bool DisplayCTUProgress) {
  424. // FIXME: The current implementation only supports loading decls with
  425. // a lookup name from a single translation unit. If multiple
  426. // translation units contains decls with the same lookup name an
  427. // error will be returned.
  428. // Try to get the value from the heavily cached storage.
  429. llvm::Expected<ASTUnit *> Unit = ASTStorage.getASTUnitForFunction(
  430. LookupName, CrossTUDir, IndexName, DisplayCTUProgress);
  431. if (!Unit)
  432. return Unit.takeError();
  433. // Check whether the backing pointer of the Expected is a nullptr.
  434. if (!*Unit)
  435. return llvm::make_error<IndexError>(
  436. index_error_code::failed_to_get_external_ast);
  437. return Unit;
  438. }
  439. template <typename T>
  440. llvm::Expected<const T *>
  441. CrossTranslationUnitContext::importDefinitionImpl(const T *D, ASTUnit *Unit) {
  442. assert(hasBodyOrInit(D) && "Decls to be imported should have body or init.");
  443. assert(&D->getASTContext() == &Unit->getASTContext() &&
  444. "ASTContext of Decl and the unit should match.");
  445. ASTImporter &Importer = getOrCreateASTImporter(Unit);
  446. auto ToDeclOrError = Importer.Import(D);
  447. if (!ToDeclOrError) {
  448. handleAllErrors(ToDeclOrError.takeError(),
  449. [&](const ImportError &IE) {
  450. switch (IE.Error) {
  451. case ImportError::NameConflict:
  452. ++NumNameConflicts;
  453. break;
  454. case ImportError::UnsupportedConstruct:
  455. ++NumUnsupportedNodeFound;
  456. break;
  457. case ImportError::Unknown:
  458. llvm_unreachable("Unknown import error happened.");
  459. break;
  460. }
  461. });
  462. return llvm::make_error<IndexError>(index_error_code::failed_import);
  463. }
  464. auto *ToDecl = cast<T>(*ToDeclOrError);
  465. assert(hasBodyOrInit(ToDecl) && "Imported Decl should have body or init.");
  466. ++NumGetCTUSuccess;
  467. return ToDecl;
  468. }
  469. llvm::Expected<const FunctionDecl *>
  470. CrossTranslationUnitContext::importDefinition(const FunctionDecl *FD,
  471. ASTUnit *Unit) {
  472. return importDefinitionImpl(FD, Unit);
  473. }
  474. llvm::Expected<const VarDecl *>
  475. CrossTranslationUnitContext::importDefinition(const VarDecl *VD,
  476. ASTUnit *Unit) {
  477. return importDefinitionImpl(VD, Unit);
  478. }
  479. void CrossTranslationUnitContext::lazyInitImporterSharedSt(
  480. TranslationUnitDecl *ToTU) {
  481. if (!ImporterSharedSt)
  482. ImporterSharedSt = std::make_shared<ASTImporterSharedState>(*ToTU);
  483. }
  484. ASTImporter &
  485. CrossTranslationUnitContext::getOrCreateASTImporter(ASTUnit *Unit) {
  486. ASTContext &From = Unit->getASTContext();
  487. auto I = ASTUnitImporterMap.find(From.getTranslationUnitDecl());
  488. if (I != ASTUnitImporterMap.end())
  489. return *I->second;
  490. lazyInitImporterSharedSt(Context.getTranslationUnitDecl());
  491. ASTImporter *NewImporter = new ASTImporter(
  492. Context, Context.getSourceManager().getFileManager(), From,
  493. From.getSourceManager().getFileManager(), false, ImporterSharedSt);
  494. NewImporter->setFileIDImportHandler([this, Unit](FileID ToID, FileID FromID) {
  495. assert(ImportedFileIDs.find(ToID) == ImportedFileIDs.end() &&
  496. "FileID already imported, should not happen.");
  497. ImportedFileIDs[ToID] = std::make_pair(FromID, Unit);
  498. });
  499. ASTUnitImporterMap[From.getTranslationUnitDecl()].reset(NewImporter);
  500. return *NewImporter;
  501. }
  502. llvm::Optional<std::pair<SourceLocation, ASTUnit *>>
  503. CrossTranslationUnitContext::getImportedFromSourceLocation(
  504. const clang::SourceLocation &ToLoc) const {
  505. const SourceManager &SM = Context.getSourceManager();
  506. auto DecToLoc = SM.getDecomposedLoc(ToLoc);
  507. auto I = ImportedFileIDs.find(DecToLoc.first);
  508. if (I == ImportedFileIDs.end())
  509. return {};
  510. FileID FromID = I->second.first;
  511. clang::ASTUnit *Unit = I->second.second;
  512. SourceLocation FromLoc =
  513. Unit->getSourceManager().getComposedLoc(FromID, DecToLoc.second);
  514. return std::make_pair(FromLoc, Unit);
  515. }
  516. } // namespace cross_tu
  517. } // namespace clang