CrossTranslationUnit.cpp 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817
  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/AST/ParentMapContext.h"
  16. #include "clang/Basic/TargetInfo.h"
  17. #include "clang/CrossTU/CrossTUDiagnostic.h"
  18. #include "clang/Frontend/ASTUnit.h"
  19. #include "clang/Frontend/CompilerInstance.h"
  20. #include "clang/Frontend/TextDiagnosticPrinter.h"
  21. #include "clang/Index/USRGeneration.h"
  22. #include "llvm/ADT/Statistic.h"
  23. #include "llvm/ADT/Triple.h"
  24. #include "llvm/Option/ArgList.h"
  25. #include "llvm/Support/ErrorHandling.h"
  26. #include "llvm/Support/ManagedStatic.h"
  27. #include "llvm/Support/Path.h"
  28. #include "llvm/Support/YAMLParser.h"
  29. #include "llvm/Support/raw_ostream.h"
  30. #include <algorithm>
  31. #include <fstream>
  32. #include <optional>
  33. #include <sstream>
  34. #include <tuple>
  35. namespace clang {
  36. namespace cross_tu {
  37. namespace {
  38. #define DEBUG_TYPE "CrossTranslationUnit"
  39. STATISTIC(NumGetCTUCalled, "The # of getCTUDefinition function called");
  40. STATISTIC(
  41. NumNotInOtherTU,
  42. "The # of getCTUDefinition called but the function is not in any other TU");
  43. STATISTIC(NumGetCTUSuccess,
  44. "The # of getCTUDefinition successfully returned the "
  45. "requested function's body");
  46. STATISTIC(NumUnsupportedNodeFound, "The # of imports when the ASTImporter "
  47. "encountered an unsupported AST Node");
  48. STATISTIC(NumNameConflicts, "The # of imports when the ASTImporter "
  49. "encountered an ODR error");
  50. STATISTIC(NumTripleMismatch, "The # of triple mismatches");
  51. STATISTIC(NumLangMismatch, "The # of language mismatches");
  52. STATISTIC(NumLangDialectMismatch, "The # of language dialect mismatches");
  53. STATISTIC(NumASTLoadThresholdReached,
  54. "The # of ASTs not loaded because of threshold");
  55. // Same as Triple's equality operator, but we check a field only if that is
  56. // known in both instances.
  57. bool hasEqualKnownFields(const llvm::Triple &Lhs, const llvm::Triple &Rhs) {
  58. using llvm::Triple;
  59. if (Lhs.getArch() != Triple::UnknownArch &&
  60. Rhs.getArch() != Triple::UnknownArch && Lhs.getArch() != Rhs.getArch())
  61. return false;
  62. if (Lhs.getSubArch() != Triple::NoSubArch &&
  63. Rhs.getSubArch() != Triple::NoSubArch &&
  64. Lhs.getSubArch() != Rhs.getSubArch())
  65. return false;
  66. if (Lhs.getVendor() != Triple::UnknownVendor &&
  67. Rhs.getVendor() != Triple::UnknownVendor &&
  68. Lhs.getVendor() != Rhs.getVendor())
  69. return false;
  70. if (!Lhs.isOSUnknown() && !Rhs.isOSUnknown() &&
  71. Lhs.getOS() != Rhs.getOS())
  72. return false;
  73. if (Lhs.getEnvironment() != Triple::UnknownEnvironment &&
  74. Rhs.getEnvironment() != Triple::UnknownEnvironment &&
  75. Lhs.getEnvironment() != Rhs.getEnvironment())
  76. return false;
  77. if (Lhs.getObjectFormat() != Triple::UnknownObjectFormat &&
  78. Rhs.getObjectFormat() != Triple::UnknownObjectFormat &&
  79. Lhs.getObjectFormat() != Rhs.getObjectFormat())
  80. return false;
  81. return true;
  82. }
  83. // FIXME: This class is will be removed after the transition to llvm::Error.
  84. class IndexErrorCategory : public std::error_category {
  85. public:
  86. const char *name() const noexcept override { return "clang.index"; }
  87. std::string message(int Condition) const override {
  88. switch (static_cast<index_error_code>(Condition)) {
  89. case index_error_code::success:
  90. // There should not be a success error. Jump to unreachable directly.
  91. // Add this case to make the compiler stop complaining.
  92. break;
  93. case index_error_code::unspecified:
  94. return "An unknown error has occurred.";
  95. case index_error_code::missing_index_file:
  96. return "The index file is missing.";
  97. case index_error_code::invalid_index_format:
  98. return "Invalid index file format.";
  99. case index_error_code::multiple_definitions:
  100. return "Multiple definitions in the index file.";
  101. case index_error_code::missing_definition:
  102. return "Missing definition from the index file.";
  103. case index_error_code::failed_import:
  104. return "Failed to import the definition.";
  105. case index_error_code::failed_to_get_external_ast:
  106. return "Failed to load external AST source.";
  107. case index_error_code::failed_to_generate_usr:
  108. return "Failed to generate USR.";
  109. case index_error_code::triple_mismatch:
  110. return "Triple mismatch";
  111. case index_error_code::lang_mismatch:
  112. return "Language mismatch";
  113. case index_error_code::lang_dialect_mismatch:
  114. return "Language dialect mismatch";
  115. case index_error_code::load_threshold_reached:
  116. return "Load threshold reached";
  117. case index_error_code::invocation_list_ambiguous:
  118. return "Invocation list file contains multiple references to the same "
  119. "source file.";
  120. case index_error_code::invocation_list_file_not_found:
  121. return "Invocation list file is not found.";
  122. case index_error_code::invocation_list_empty:
  123. return "Invocation list file is empty.";
  124. case index_error_code::invocation_list_wrong_format:
  125. return "Invocation list file is in wrong format.";
  126. case index_error_code::invocation_list_lookup_unsuccessful:
  127. return "Invocation list file does not contain the requested source file.";
  128. }
  129. llvm_unreachable("Unrecognized index_error_code.");
  130. }
  131. };
  132. static llvm::ManagedStatic<IndexErrorCategory> Category;
  133. } // end anonymous namespace
  134. char IndexError::ID;
  135. void IndexError::log(raw_ostream &OS) const {
  136. OS << Category->message(static_cast<int>(Code)) << '\n';
  137. }
  138. std::error_code IndexError::convertToErrorCode() const {
  139. return std::error_code(static_cast<int>(Code), *Category);
  140. }
  141. /// Parse one line of the input CTU index file.
  142. ///
  143. /// @param[in] LineRef The input CTU index item in format
  144. /// "<USR-Length>:<USR> <File-Path>".
  145. /// @param[out] LookupName The lookup name in format "<USR-Length>:<USR>".
  146. /// @param[out] FilePath The file path "<File-Path>".
  147. static bool parseCrossTUIndexItem(StringRef LineRef, StringRef &LookupName,
  148. StringRef &FilePath) {
  149. // `LineRef` is "<USR-Length>:<USR> <File-Path>" now.
  150. size_t USRLength = 0;
  151. if (LineRef.consumeInteger(10, USRLength))
  152. return false;
  153. assert(USRLength && "USRLength should be greater than zero.");
  154. if (!LineRef.consume_front(":"))
  155. return false;
  156. // `LineRef` is now just "<USR> <File-Path>".
  157. // Check LookupName length out of bound and incorrect delimiter.
  158. if (USRLength >= LineRef.size() || ' ' != LineRef[USRLength])
  159. return false;
  160. LookupName = LineRef.substr(0, USRLength);
  161. FilePath = LineRef.substr(USRLength + 1);
  162. return true;
  163. }
  164. llvm::Expected<llvm::StringMap<std::string>>
  165. parseCrossTUIndex(StringRef IndexPath) {
  166. std::ifstream ExternalMapFile{std::string(IndexPath)};
  167. if (!ExternalMapFile)
  168. return llvm::make_error<IndexError>(index_error_code::missing_index_file,
  169. IndexPath.str());
  170. llvm::StringMap<std::string> Result;
  171. std::string Line;
  172. unsigned LineNo = 1;
  173. while (std::getline(ExternalMapFile, Line)) {
  174. // Split lookup name and file path
  175. StringRef LookupName, FilePathInIndex;
  176. if (!parseCrossTUIndexItem(Line, LookupName, FilePathInIndex))
  177. return llvm::make_error<IndexError>(
  178. index_error_code::invalid_index_format, IndexPath.str(), LineNo);
  179. // Store paths with posix-style directory separator.
  180. SmallString<32> FilePath(FilePathInIndex);
  181. llvm::sys::path::native(FilePath, llvm::sys::path::Style::posix);
  182. bool InsertionOccured;
  183. std::tie(std::ignore, InsertionOccured) =
  184. Result.try_emplace(LookupName, FilePath.begin(), FilePath.end());
  185. if (!InsertionOccured)
  186. return llvm::make_error<IndexError>(
  187. index_error_code::multiple_definitions, IndexPath.str(), LineNo);
  188. ++LineNo;
  189. }
  190. return Result;
  191. }
  192. std::string
  193. createCrossTUIndexString(const llvm::StringMap<std::string> &Index) {
  194. std::ostringstream Result;
  195. for (const auto &E : Index)
  196. Result << E.getKey().size() << ':' << E.getKey().str() << ' '
  197. << E.getValue() << '\n';
  198. return Result.str();
  199. }
  200. bool shouldImport(const VarDecl *VD, const ASTContext &ACtx) {
  201. CanQualType CT = ACtx.getCanonicalType(VD->getType());
  202. return CT.isConstQualified() && VD->getType().isTrivialType(ACtx);
  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. CrossTranslationUnitContext::CrossTranslationUnitContext(CompilerInstance &CI)
  215. : Context(CI.getASTContext()), ASTStorage(CI) {}
  216. CrossTranslationUnitContext::~CrossTranslationUnitContext() {}
  217. std::optional<std::string>
  218. CrossTranslationUnitContext::getLookupName(const NamedDecl *ND) {
  219. SmallString<128> DeclUSR;
  220. bool Ret = index::generateUSRForDecl(ND, DeclUSR);
  221. if (Ret)
  222. return {};
  223. return std::string(DeclUSR.str());
  224. }
  225. /// Recursively visits the decls of a DeclContext, and returns one with the
  226. /// given USR.
  227. template <typename T>
  228. const T *
  229. CrossTranslationUnitContext::findDefInDeclContext(const DeclContext *DC,
  230. StringRef LookupName) {
  231. assert(DC && "Declaration Context must not be null");
  232. for (const Decl *D : DC->decls()) {
  233. const auto *SubDC = dyn_cast<DeclContext>(D);
  234. if (SubDC)
  235. if (const auto *ND = findDefInDeclContext<T>(SubDC, LookupName))
  236. return ND;
  237. const auto *ND = dyn_cast<T>(D);
  238. const T *ResultDecl;
  239. if (!ND || !hasBodyOrInit(ND, ResultDecl))
  240. continue;
  241. std::optional<std::string> ResultLookupName = getLookupName(ResultDecl);
  242. if (!ResultLookupName || *ResultLookupName != LookupName)
  243. continue;
  244. return ResultDecl;
  245. }
  246. return nullptr;
  247. }
  248. template <typename T>
  249. llvm::Expected<const T *> CrossTranslationUnitContext::getCrossTUDefinitionImpl(
  250. const T *D, StringRef CrossTUDir, StringRef IndexName,
  251. bool DisplayCTUProgress) {
  252. assert(D && "D is missing, bad call to this function!");
  253. assert(!hasBodyOrInit(D) &&
  254. "D has a body or init in current translation unit!");
  255. ++NumGetCTUCalled;
  256. const std::optional<std::string> LookupName = getLookupName(D);
  257. if (!LookupName)
  258. return llvm::make_error<IndexError>(
  259. index_error_code::failed_to_generate_usr);
  260. llvm::Expected<ASTUnit *> ASTUnitOrError =
  261. loadExternalAST(*LookupName, CrossTUDir, IndexName, DisplayCTUProgress);
  262. if (!ASTUnitOrError)
  263. return ASTUnitOrError.takeError();
  264. ASTUnit *Unit = *ASTUnitOrError;
  265. assert(&Unit->getFileManager() ==
  266. &Unit->getASTContext().getSourceManager().getFileManager());
  267. const llvm::Triple &TripleTo = Context.getTargetInfo().getTriple();
  268. const llvm::Triple &TripleFrom =
  269. Unit->getASTContext().getTargetInfo().getTriple();
  270. // The imported AST had been generated for a different target.
  271. // Some parts of the triple in the loaded ASTContext can be unknown while the
  272. // very same parts in the target ASTContext are known. Thus we check for the
  273. // known parts only.
  274. if (!hasEqualKnownFields(TripleTo, TripleFrom)) {
  275. // TODO: Pass the SourceLocation of the CallExpression for more precise
  276. // diagnostics.
  277. ++NumTripleMismatch;
  278. return llvm::make_error<IndexError>(index_error_code::triple_mismatch,
  279. std::string(Unit->getMainFileName()),
  280. TripleTo.str(), TripleFrom.str());
  281. }
  282. const auto &LangTo = Context.getLangOpts();
  283. const auto &LangFrom = Unit->getASTContext().getLangOpts();
  284. // FIXME: Currenty we do not support CTU across C++ and C and across
  285. // different dialects of C++.
  286. if (LangTo.CPlusPlus != LangFrom.CPlusPlus) {
  287. ++NumLangMismatch;
  288. return llvm::make_error<IndexError>(index_error_code::lang_mismatch);
  289. }
  290. // If CPP dialects are different then return with error.
  291. //
  292. // Consider this STL code:
  293. // template<typename _Alloc>
  294. // struct __alloc_traits
  295. // #if __cplusplus >= 201103L
  296. // : std::allocator_traits<_Alloc>
  297. // #endif
  298. // { // ...
  299. // };
  300. // This class template would create ODR errors during merging the two units,
  301. // since in one translation unit the class template has a base class, however
  302. // in the other unit it has none.
  303. if (LangTo.CPlusPlus11 != LangFrom.CPlusPlus11 ||
  304. LangTo.CPlusPlus14 != LangFrom.CPlusPlus14 ||
  305. LangTo.CPlusPlus17 != LangFrom.CPlusPlus17 ||
  306. LangTo.CPlusPlus20 != LangFrom.CPlusPlus20) {
  307. ++NumLangDialectMismatch;
  308. return llvm::make_error<IndexError>(
  309. index_error_code::lang_dialect_mismatch);
  310. }
  311. TranslationUnitDecl *TU = Unit->getASTContext().getTranslationUnitDecl();
  312. if (const T *ResultDecl = findDefInDeclContext<T>(TU, *LookupName))
  313. return importDefinition(ResultDecl, Unit);
  314. return llvm::make_error<IndexError>(index_error_code::failed_import);
  315. }
  316. llvm::Expected<const FunctionDecl *>
  317. CrossTranslationUnitContext::getCrossTUDefinition(const FunctionDecl *FD,
  318. StringRef CrossTUDir,
  319. StringRef IndexName,
  320. bool DisplayCTUProgress) {
  321. return getCrossTUDefinitionImpl(FD, CrossTUDir, IndexName,
  322. DisplayCTUProgress);
  323. }
  324. llvm::Expected<const VarDecl *>
  325. CrossTranslationUnitContext::getCrossTUDefinition(const VarDecl *VD,
  326. StringRef CrossTUDir,
  327. StringRef IndexName,
  328. bool DisplayCTUProgress) {
  329. return getCrossTUDefinitionImpl(VD, CrossTUDir, IndexName,
  330. DisplayCTUProgress);
  331. }
  332. void CrossTranslationUnitContext::emitCrossTUDiagnostics(const IndexError &IE) {
  333. switch (IE.getCode()) {
  334. case index_error_code::missing_index_file:
  335. Context.getDiagnostics().Report(diag::err_ctu_error_opening)
  336. << IE.getFileName();
  337. break;
  338. case index_error_code::invalid_index_format:
  339. Context.getDiagnostics().Report(diag::err_extdefmap_parsing)
  340. << IE.getFileName() << IE.getLineNum();
  341. break;
  342. case index_error_code::multiple_definitions:
  343. Context.getDiagnostics().Report(diag::err_multiple_def_index)
  344. << IE.getLineNum();
  345. break;
  346. case index_error_code::triple_mismatch:
  347. Context.getDiagnostics().Report(diag::warn_ctu_incompat_triple)
  348. << IE.getFileName() << IE.getTripleToName() << IE.getTripleFromName();
  349. break;
  350. default:
  351. break;
  352. }
  353. }
  354. CrossTranslationUnitContext::ASTUnitStorage::ASTUnitStorage(
  355. CompilerInstance &CI)
  356. : Loader(CI, CI.getAnalyzerOpts()->CTUDir,
  357. CI.getAnalyzerOpts()->CTUInvocationList),
  358. LoadGuard(CI.getASTContext().getLangOpts().CPlusPlus
  359. ? CI.getAnalyzerOpts()->CTUImportCppThreshold
  360. : CI.getAnalyzerOpts()->CTUImportThreshold) {}
  361. llvm::Expected<ASTUnit *>
  362. CrossTranslationUnitContext::ASTUnitStorage::getASTUnitForFile(
  363. StringRef FileName, bool DisplayCTUProgress) {
  364. // Try the cache first.
  365. auto ASTCacheEntry = FileASTUnitMap.find(FileName);
  366. if (ASTCacheEntry == FileASTUnitMap.end()) {
  367. // Do not load if the limit is reached.
  368. if (!LoadGuard) {
  369. ++NumASTLoadThresholdReached;
  370. return llvm::make_error<IndexError>(
  371. index_error_code::load_threshold_reached);
  372. }
  373. auto LoadAttempt = Loader.load(FileName);
  374. if (!LoadAttempt)
  375. return LoadAttempt.takeError();
  376. std::unique_ptr<ASTUnit> LoadedUnit = std::move(LoadAttempt.get());
  377. // Need the raw pointer and the unique_ptr as well.
  378. ASTUnit *Unit = LoadedUnit.get();
  379. // Update the cache.
  380. FileASTUnitMap[FileName] = std::move(LoadedUnit);
  381. LoadGuard.indicateLoadSuccess();
  382. if (DisplayCTUProgress)
  383. llvm::errs() << "CTU loaded AST file: " << FileName << "\n";
  384. return Unit;
  385. } else {
  386. // Found in the cache.
  387. return ASTCacheEntry->second.get();
  388. }
  389. }
  390. llvm::Expected<ASTUnit *>
  391. CrossTranslationUnitContext::ASTUnitStorage::getASTUnitForFunction(
  392. StringRef FunctionName, StringRef CrossTUDir, StringRef IndexName,
  393. bool DisplayCTUProgress) {
  394. // Try the cache first.
  395. auto ASTCacheEntry = NameASTUnitMap.find(FunctionName);
  396. if (ASTCacheEntry == NameASTUnitMap.end()) {
  397. // Load the ASTUnit from the pre-dumped AST file specified by ASTFileName.
  398. // Ensure that the Index is loaded, as we need to search in it.
  399. if (llvm::Error IndexLoadError =
  400. ensureCTUIndexLoaded(CrossTUDir, IndexName))
  401. return std::move(IndexLoadError);
  402. // Check if there is an entry in the index for the function.
  403. if (!NameFileMap.count(FunctionName)) {
  404. ++NumNotInOtherTU;
  405. return llvm::make_error<IndexError>(index_error_code::missing_definition);
  406. }
  407. // Search in the index for the filename where the definition of FunctionName
  408. // resides.
  409. if (llvm::Expected<ASTUnit *> FoundForFile =
  410. getASTUnitForFile(NameFileMap[FunctionName], DisplayCTUProgress)) {
  411. // Update the cache.
  412. NameASTUnitMap[FunctionName] = *FoundForFile;
  413. return *FoundForFile;
  414. } else {
  415. return FoundForFile.takeError();
  416. }
  417. } else {
  418. // Found in the cache.
  419. return ASTCacheEntry->second;
  420. }
  421. }
  422. llvm::Expected<std::string>
  423. CrossTranslationUnitContext::ASTUnitStorage::getFileForFunction(
  424. StringRef FunctionName, StringRef CrossTUDir, StringRef IndexName) {
  425. if (llvm::Error IndexLoadError = ensureCTUIndexLoaded(CrossTUDir, IndexName))
  426. return std::move(IndexLoadError);
  427. return NameFileMap[FunctionName];
  428. }
  429. llvm::Error CrossTranslationUnitContext::ASTUnitStorage::ensureCTUIndexLoaded(
  430. StringRef CrossTUDir, StringRef IndexName) {
  431. // Dont initialize if the map is filled.
  432. if (!NameFileMap.empty())
  433. return llvm::Error::success();
  434. // Get the absolute path to the index file.
  435. SmallString<256> IndexFile = CrossTUDir;
  436. if (llvm::sys::path::is_absolute(IndexName))
  437. IndexFile = IndexName;
  438. else
  439. llvm::sys::path::append(IndexFile, IndexName);
  440. if (auto IndexMapping = parseCrossTUIndex(IndexFile)) {
  441. // Initialize member map.
  442. NameFileMap = *IndexMapping;
  443. return llvm::Error::success();
  444. } else {
  445. // Error while parsing CrossTU index file.
  446. return IndexMapping.takeError();
  447. };
  448. }
  449. llvm::Expected<ASTUnit *> CrossTranslationUnitContext::loadExternalAST(
  450. StringRef LookupName, StringRef CrossTUDir, StringRef IndexName,
  451. bool DisplayCTUProgress) {
  452. // FIXME: The current implementation only supports loading decls with
  453. // a lookup name from a single translation unit. If multiple
  454. // translation units contains decls with the same lookup name an
  455. // error will be returned.
  456. // Try to get the value from the heavily cached storage.
  457. llvm::Expected<ASTUnit *> Unit = ASTStorage.getASTUnitForFunction(
  458. LookupName, CrossTUDir, IndexName, DisplayCTUProgress);
  459. if (!Unit)
  460. return Unit.takeError();
  461. // Check whether the backing pointer of the Expected is a nullptr.
  462. if (!*Unit)
  463. return llvm::make_error<IndexError>(
  464. index_error_code::failed_to_get_external_ast);
  465. return Unit;
  466. }
  467. CrossTranslationUnitContext::ASTLoader::ASTLoader(
  468. CompilerInstance &CI, StringRef CTUDir, StringRef InvocationListFilePath)
  469. : CI(CI), CTUDir(CTUDir), InvocationListFilePath(InvocationListFilePath) {}
  470. CrossTranslationUnitContext::LoadResultTy
  471. CrossTranslationUnitContext::ASTLoader::load(StringRef Identifier) {
  472. llvm::SmallString<256> Path;
  473. if (llvm::sys::path::is_absolute(Identifier, PathStyle)) {
  474. Path = Identifier;
  475. } else {
  476. Path = CTUDir;
  477. llvm::sys::path::append(Path, PathStyle, Identifier);
  478. }
  479. // The path is stored in the InvocationList member in posix style. To
  480. // successfully lookup an entry based on filepath, it must be converted.
  481. llvm::sys::path::native(Path, PathStyle);
  482. // Normalize by removing relative path components.
  483. llvm::sys::path::remove_dots(Path, /*remove_dot_dot*/ true, PathStyle);
  484. if (Path.endswith(".ast"))
  485. return loadFromDump(Path);
  486. else
  487. return loadFromSource(Path);
  488. }
  489. CrossTranslationUnitContext::LoadResultTy
  490. CrossTranslationUnitContext::ASTLoader::loadFromDump(StringRef ASTDumpPath) {
  491. IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
  492. TextDiagnosticPrinter *DiagClient =
  493. new TextDiagnosticPrinter(llvm::errs(), &*DiagOpts);
  494. IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
  495. IntrusiveRefCntPtr<DiagnosticsEngine> Diags(
  496. new DiagnosticsEngine(DiagID, &*DiagOpts, DiagClient));
  497. return ASTUnit::LoadFromASTFile(
  498. std::string(ASTDumpPath.str()),
  499. CI.getPCHContainerOperations()->getRawReader(), ASTUnit::LoadEverything,
  500. Diags, CI.getFileSystemOpts());
  501. }
  502. /// Load the AST from a source-file, which is supposed to be located inside the
  503. /// YAML formatted invocation list file under the filesystem path specified by
  504. /// \p InvocationList. The invocation list should contain absolute paths.
  505. /// \p SourceFilePath is the absolute path of the source file that contains the
  506. /// function definition the analysis is looking for. The Index is built by the
  507. /// \p clang-extdef-mapping tool, which is also supposed to be generating
  508. /// absolute paths.
  509. ///
  510. /// Proper diagnostic emission requires absolute paths, so even if a future
  511. /// change introduces the handling of relative paths, this must be taken into
  512. /// consideration.
  513. CrossTranslationUnitContext::LoadResultTy
  514. CrossTranslationUnitContext::ASTLoader::loadFromSource(
  515. StringRef SourceFilePath) {
  516. if (llvm::Error InitError = lazyInitInvocationList())
  517. return std::move(InitError);
  518. assert(InvocationList);
  519. auto Invocation = InvocationList->find(SourceFilePath);
  520. if (Invocation == InvocationList->end())
  521. return llvm::make_error<IndexError>(
  522. index_error_code::invocation_list_lookup_unsuccessful);
  523. const InvocationListTy::mapped_type &InvocationCommand = Invocation->second;
  524. SmallVector<const char *, 32> CommandLineArgs(InvocationCommand.size());
  525. std::transform(InvocationCommand.begin(), InvocationCommand.end(),
  526. CommandLineArgs.begin(),
  527. [](auto &&CmdPart) { return CmdPart.c_str(); });
  528. IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts{&CI.getDiagnosticOpts()};
  529. auto *DiagClient = new ForwardingDiagnosticConsumer{CI.getDiagnosticClient()};
  530. IntrusiveRefCntPtr<DiagnosticIDs> DiagID{
  531. CI.getDiagnostics().getDiagnosticIDs()};
  532. IntrusiveRefCntPtr<DiagnosticsEngine> Diags(
  533. new DiagnosticsEngine{DiagID, &*DiagOpts, DiagClient});
  534. return std::unique_ptr<ASTUnit>(ASTUnit::LoadFromCommandLine(
  535. CommandLineArgs.begin(), (CommandLineArgs.end()),
  536. CI.getPCHContainerOperations(), Diags,
  537. CI.getHeaderSearchOpts().ResourceDir));
  538. }
  539. llvm::Expected<InvocationListTy>
  540. parseInvocationList(StringRef FileContent, llvm::sys::path::Style PathStyle) {
  541. InvocationListTy InvocationList;
  542. /// LLVM YAML parser is used to extract information from invocation list file.
  543. llvm::SourceMgr SM;
  544. llvm::yaml::Stream InvocationFile(FileContent, SM);
  545. /// Only the first document is processed.
  546. llvm::yaml::document_iterator FirstInvocationFile = InvocationFile.begin();
  547. /// There has to be at least one document available.
  548. if (FirstInvocationFile == InvocationFile.end())
  549. return llvm::make_error<IndexError>(
  550. index_error_code::invocation_list_empty);
  551. llvm::yaml::Node *DocumentRoot = FirstInvocationFile->getRoot();
  552. if (!DocumentRoot)
  553. return llvm::make_error<IndexError>(
  554. index_error_code::invocation_list_wrong_format);
  555. /// According to the format specified the document must be a mapping, where
  556. /// the keys are paths to source files, and values are sequences of invocation
  557. /// parts.
  558. auto *Mappings = dyn_cast<llvm::yaml::MappingNode>(DocumentRoot);
  559. if (!Mappings)
  560. return llvm::make_error<IndexError>(
  561. index_error_code::invocation_list_wrong_format);
  562. for (auto &NextMapping : *Mappings) {
  563. /// The keys should be strings, which represent a source-file path.
  564. auto *Key = dyn_cast<llvm::yaml::ScalarNode>(NextMapping.getKey());
  565. if (!Key)
  566. return llvm::make_error<IndexError>(
  567. index_error_code::invocation_list_wrong_format);
  568. SmallString<32> ValueStorage;
  569. StringRef SourcePath = Key->getValue(ValueStorage);
  570. // Store paths with PathStyle directory separator.
  571. SmallString<32> NativeSourcePath(SourcePath);
  572. llvm::sys::path::native(NativeSourcePath, PathStyle);
  573. StringRef InvocationKey = NativeSourcePath;
  574. if (InvocationList.find(InvocationKey) != InvocationList.end())
  575. return llvm::make_error<IndexError>(
  576. index_error_code::invocation_list_ambiguous);
  577. /// The values should be sequences of strings, each representing a part of
  578. /// the invocation.
  579. auto *Args = dyn_cast<llvm::yaml::SequenceNode>(NextMapping.getValue());
  580. if (!Args)
  581. return llvm::make_error<IndexError>(
  582. index_error_code::invocation_list_wrong_format);
  583. for (auto &Arg : *Args) {
  584. auto *CmdString = dyn_cast<llvm::yaml::ScalarNode>(&Arg);
  585. if (!CmdString)
  586. return llvm::make_error<IndexError>(
  587. index_error_code::invocation_list_wrong_format);
  588. /// Every conversion starts with an empty working storage, as it is not
  589. /// clear if this is a requirement of the YAML parser.
  590. ValueStorage.clear();
  591. InvocationList[InvocationKey].emplace_back(
  592. CmdString->getValue(ValueStorage));
  593. }
  594. if (InvocationList[InvocationKey].empty())
  595. return llvm::make_error<IndexError>(
  596. index_error_code::invocation_list_wrong_format);
  597. }
  598. return InvocationList;
  599. }
  600. llvm::Error CrossTranslationUnitContext::ASTLoader::lazyInitInvocationList() {
  601. /// Lazily initialize the invocation list member used for on-demand parsing.
  602. if (InvocationList)
  603. return llvm::Error::success();
  604. if (index_error_code::success != PreviousParsingResult)
  605. return llvm::make_error<IndexError>(PreviousParsingResult);
  606. llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> FileContent =
  607. llvm::MemoryBuffer::getFile(InvocationListFilePath);
  608. if (!FileContent) {
  609. PreviousParsingResult = index_error_code::invocation_list_file_not_found;
  610. return llvm::make_error<IndexError>(PreviousParsingResult);
  611. }
  612. std::unique_ptr<llvm::MemoryBuffer> ContentBuffer = std::move(*FileContent);
  613. assert(ContentBuffer && "If no error was produced after loading, the pointer "
  614. "should not be nullptr.");
  615. llvm::Expected<InvocationListTy> ExpectedInvocationList =
  616. parseInvocationList(ContentBuffer->getBuffer(), PathStyle);
  617. // Handle the error to store the code for next call to this function.
  618. if (!ExpectedInvocationList) {
  619. llvm::handleAllErrors(
  620. ExpectedInvocationList.takeError(),
  621. [&](const IndexError &E) { PreviousParsingResult = E.getCode(); });
  622. return llvm::make_error<IndexError>(PreviousParsingResult);
  623. }
  624. InvocationList = *ExpectedInvocationList;
  625. return llvm::Error::success();
  626. }
  627. template <typename T>
  628. llvm::Expected<const T *>
  629. CrossTranslationUnitContext::importDefinitionImpl(const T *D, ASTUnit *Unit) {
  630. assert(hasBodyOrInit(D) && "Decls to be imported should have body or init.");
  631. assert(&D->getASTContext() == &Unit->getASTContext() &&
  632. "ASTContext of Decl and the unit should match.");
  633. ASTImporter &Importer = getOrCreateASTImporter(Unit);
  634. auto ToDeclOrError = Importer.Import(D);
  635. if (!ToDeclOrError) {
  636. handleAllErrors(ToDeclOrError.takeError(), [&](const ASTImportError &IE) {
  637. switch (IE.Error) {
  638. case ASTImportError::NameConflict:
  639. ++NumNameConflicts;
  640. break;
  641. case ASTImportError::UnsupportedConstruct:
  642. ++NumUnsupportedNodeFound;
  643. break;
  644. case ASTImportError::Unknown:
  645. llvm_unreachable("Unknown import error happened.");
  646. break;
  647. }
  648. });
  649. return llvm::make_error<IndexError>(index_error_code::failed_import);
  650. }
  651. auto *ToDecl = cast<T>(*ToDeclOrError);
  652. assert(hasBodyOrInit(ToDecl) && "Imported Decl should have body or init.");
  653. ++NumGetCTUSuccess;
  654. // Parent map is invalidated after changing the AST.
  655. ToDecl->getASTContext().getParentMapContext().clear();
  656. return ToDecl;
  657. }
  658. llvm::Expected<const FunctionDecl *>
  659. CrossTranslationUnitContext::importDefinition(const FunctionDecl *FD,
  660. ASTUnit *Unit) {
  661. return importDefinitionImpl(FD, Unit);
  662. }
  663. llvm::Expected<const VarDecl *>
  664. CrossTranslationUnitContext::importDefinition(const VarDecl *VD,
  665. ASTUnit *Unit) {
  666. return importDefinitionImpl(VD, Unit);
  667. }
  668. void CrossTranslationUnitContext::lazyInitImporterSharedSt(
  669. TranslationUnitDecl *ToTU) {
  670. if (!ImporterSharedSt)
  671. ImporterSharedSt = std::make_shared<ASTImporterSharedState>(*ToTU);
  672. }
  673. ASTImporter &
  674. CrossTranslationUnitContext::getOrCreateASTImporter(ASTUnit *Unit) {
  675. ASTContext &From = Unit->getASTContext();
  676. auto I = ASTUnitImporterMap.find(From.getTranslationUnitDecl());
  677. if (I != ASTUnitImporterMap.end())
  678. return *I->second;
  679. lazyInitImporterSharedSt(Context.getTranslationUnitDecl());
  680. ASTImporter *NewImporter = new ASTImporter(
  681. Context, Context.getSourceManager().getFileManager(), From,
  682. From.getSourceManager().getFileManager(), false, ImporterSharedSt);
  683. ASTUnitImporterMap[From.getTranslationUnitDecl()].reset(NewImporter);
  684. return *NewImporter;
  685. }
  686. std::optional<clang::MacroExpansionContext>
  687. CrossTranslationUnitContext::getMacroExpansionContextForSourceLocation(
  688. const clang::SourceLocation &ToLoc) const {
  689. // FIXME: Implement: Record such a context for every imported ASTUnit; lookup.
  690. return std::nullopt;
  691. }
  692. bool CrossTranslationUnitContext::isImportedAsNew(const Decl *ToDecl) const {
  693. if (!ImporterSharedSt)
  694. return false;
  695. return ImporterSharedSt->isNewDecl(const_cast<Decl *>(ToDecl));
  696. }
  697. bool CrossTranslationUnitContext::hasError(const Decl *ToDecl) const {
  698. if (!ImporterSharedSt)
  699. return false;
  700. return static_cast<bool>(
  701. ImporterSharedSt->getImportDeclErrorIfAny(const_cast<Decl *>(ToDecl)));
  702. }
  703. } // namespace cross_tu
  704. } // namespace clang