CrossTranslationUnit.cpp 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781
  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/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. 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. llvm::Expected<llvm::StringMap<std::string>>
  142. parseCrossTUIndex(StringRef IndexPath) {
  143. std::ifstream ExternalMapFile{std::string(IndexPath)};
  144. if (!ExternalMapFile)
  145. return llvm::make_error<IndexError>(index_error_code::missing_index_file,
  146. IndexPath.str());
  147. llvm::StringMap<std::string> Result;
  148. std::string Line;
  149. unsigned LineNo = 1;
  150. while (std::getline(ExternalMapFile, Line)) {
  151. StringRef LineRef{Line};
  152. const size_t Delimiter = LineRef.find(' ');
  153. if (Delimiter > 0 && Delimiter != std::string::npos) {
  154. StringRef LookupName = LineRef.substr(0, Delimiter);
  155. // Store paths with posix-style directory separator.
  156. SmallString<32> FilePath(LineRef.substr(Delimiter + 1));
  157. llvm::sys::path::native(FilePath, llvm::sys::path::Style::posix);
  158. bool InsertionOccured;
  159. std::tie(std::ignore, InsertionOccured) =
  160. Result.try_emplace(LookupName, FilePath.begin(), FilePath.end());
  161. if (!InsertionOccured)
  162. return llvm::make_error<IndexError>(
  163. index_error_code::multiple_definitions, IndexPath.str(), LineNo);
  164. } else
  165. return llvm::make_error<IndexError>(
  166. index_error_code::invalid_index_format, IndexPath.str(), LineNo);
  167. ++LineNo;
  168. }
  169. return Result;
  170. }
  171. std::string
  172. createCrossTUIndexString(const llvm::StringMap<std::string> &Index) {
  173. std::ostringstream Result;
  174. for (const auto &E : Index)
  175. Result << E.getKey().str() << " " << E.getValue() << '\n';
  176. return Result.str();
  177. }
  178. bool containsConst(const VarDecl *VD, const ASTContext &ACtx) {
  179. CanQualType CT = ACtx.getCanonicalType(VD->getType());
  180. if (!CT.isConstQualified()) {
  181. const RecordType *RTy = CT->getAs<RecordType>();
  182. if (!RTy || !RTy->hasConstFields())
  183. return false;
  184. }
  185. return true;
  186. }
  187. static bool hasBodyOrInit(const FunctionDecl *D, const FunctionDecl *&DefD) {
  188. return D->hasBody(DefD);
  189. }
  190. static bool hasBodyOrInit(const VarDecl *D, const VarDecl *&DefD) {
  191. return D->getAnyInitializer(DefD);
  192. }
  193. template <typename T> static bool hasBodyOrInit(const T *D) {
  194. const T *Unused;
  195. return hasBodyOrInit(D, Unused);
  196. }
  197. CrossTranslationUnitContext::CrossTranslationUnitContext(CompilerInstance &CI)
  198. : Context(CI.getASTContext()), ASTStorage(CI) {}
  199. CrossTranslationUnitContext::~CrossTranslationUnitContext() {}
  200. llvm::Optional<std::string>
  201. CrossTranslationUnitContext::getLookupName(const NamedDecl *ND) {
  202. SmallString<128> DeclUSR;
  203. bool Ret = index::generateUSRForDecl(ND, DeclUSR);
  204. if (Ret)
  205. return {};
  206. return std::string(DeclUSR.str());
  207. }
  208. /// Recursively visits the decls of a DeclContext, and returns one with the
  209. /// given USR.
  210. template <typename T>
  211. const T *
  212. CrossTranslationUnitContext::findDefInDeclContext(const DeclContext *DC,
  213. StringRef LookupName) {
  214. assert(DC && "Declaration Context must not be null");
  215. for (const Decl *D : DC->decls()) {
  216. const auto *SubDC = dyn_cast<DeclContext>(D);
  217. if (SubDC)
  218. if (const auto *ND = findDefInDeclContext<T>(SubDC, LookupName))
  219. return ND;
  220. const auto *ND = dyn_cast<T>(D);
  221. const T *ResultDecl;
  222. if (!ND || !hasBodyOrInit(ND, ResultDecl))
  223. continue;
  224. llvm::Optional<std::string> ResultLookupName = getLookupName(ResultDecl);
  225. if (!ResultLookupName || *ResultLookupName != LookupName)
  226. continue;
  227. return ResultDecl;
  228. }
  229. return nullptr;
  230. }
  231. template <typename T>
  232. llvm::Expected<const T *> CrossTranslationUnitContext::getCrossTUDefinitionImpl(
  233. const T *D, StringRef CrossTUDir, StringRef IndexName,
  234. bool DisplayCTUProgress) {
  235. assert(D && "D is missing, bad call to this function!");
  236. assert(!hasBodyOrInit(D) &&
  237. "D has a body or init in current translation unit!");
  238. ++NumGetCTUCalled;
  239. const llvm::Optional<std::string> LookupName = getLookupName(D);
  240. if (!LookupName)
  241. return llvm::make_error<IndexError>(
  242. index_error_code::failed_to_generate_usr);
  243. llvm::Expected<ASTUnit *> ASTUnitOrError =
  244. loadExternalAST(*LookupName, CrossTUDir, IndexName, DisplayCTUProgress);
  245. if (!ASTUnitOrError)
  246. return ASTUnitOrError.takeError();
  247. ASTUnit *Unit = *ASTUnitOrError;
  248. assert(&Unit->getFileManager() ==
  249. &Unit->getASTContext().getSourceManager().getFileManager());
  250. const llvm::Triple &TripleTo = Context.getTargetInfo().getTriple();
  251. const llvm::Triple &TripleFrom =
  252. Unit->getASTContext().getTargetInfo().getTriple();
  253. // The imported AST had been generated for a different target.
  254. // Some parts of the triple in the loaded ASTContext can be unknown while the
  255. // very same parts in the target ASTContext are known. Thus we check for the
  256. // known parts only.
  257. if (!hasEqualKnownFields(TripleTo, TripleFrom)) {
  258. // TODO: Pass the SourceLocation of the CallExpression for more precise
  259. // diagnostics.
  260. ++NumTripleMismatch;
  261. return llvm::make_error<IndexError>(index_error_code::triple_mismatch,
  262. std::string(Unit->getMainFileName()),
  263. TripleTo.str(), TripleFrom.str());
  264. }
  265. const auto &LangTo = Context.getLangOpts();
  266. const auto &LangFrom = Unit->getASTContext().getLangOpts();
  267. // FIXME: Currenty we do not support CTU across C++ and C and across
  268. // different dialects of C++.
  269. if (LangTo.CPlusPlus != LangFrom.CPlusPlus) {
  270. ++NumLangMismatch;
  271. return llvm::make_error<IndexError>(index_error_code::lang_mismatch);
  272. }
  273. // If CPP dialects are different then return with error.
  274. //
  275. // Consider this STL code:
  276. // template<typename _Alloc>
  277. // struct __alloc_traits
  278. // #if __cplusplus >= 201103L
  279. // : std::allocator_traits<_Alloc>
  280. // #endif
  281. // { // ...
  282. // };
  283. // This class template would create ODR errors during merging the two units,
  284. // since in one translation unit the class template has a base class, however
  285. // in the other unit it has none.
  286. if (LangTo.CPlusPlus11 != LangFrom.CPlusPlus11 ||
  287. LangTo.CPlusPlus14 != LangFrom.CPlusPlus14 ||
  288. LangTo.CPlusPlus17 != LangFrom.CPlusPlus17 ||
  289. LangTo.CPlusPlus20 != LangFrom.CPlusPlus20) {
  290. ++NumLangDialectMismatch;
  291. return llvm::make_error<IndexError>(
  292. index_error_code::lang_dialect_mismatch);
  293. }
  294. TranslationUnitDecl *TU = Unit->getASTContext().getTranslationUnitDecl();
  295. if (const T *ResultDecl = findDefInDeclContext<T>(TU, *LookupName))
  296. return importDefinition(ResultDecl, Unit);
  297. return llvm::make_error<IndexError>(index_error_code::failed_import);
  298. }
  299. llvm::Expected<const FunctionDecl *>
  300. CrossTranslationUnitContext::getCrossTUDefinition(const FunctionDecl *FD,
  301. StringRef CrossTUDir,
  302. StringRef IndexName,
  303. bool DisplayCTUProgress) {
  304. return getCrossTUDefinitionImpl(FD, CrossTUDir, IndexName,
  305. DisplayCTUProgress);
  306. }
  307. llvm::Expected<const VarDecl *>
  308. CrossTranslationUnitContext::getCrossTUDefinition(const VarDecl *VD,
  309. StringRef CrossTUDir,
  310. StringRef IndexName,
  311. bool DisplayCTUProgress) {
  312. return getCrossTUDefinitionImpl(VD, CrossTUDir, IndexName,
  313. DisplayCTUProgress);
  314. }
  315. void CrossTranslationUnitContext::emitCrossTUDiagnostics(const IndexError &IE) {
  316. switch (IE.getCode()) {
  317. case index_error_code::missing_index_file:
  318. Context.getDiagnostics().Report(diag::err_ctu_error_opening)
  319. << IE.getFileName();
  320. break;
  321. case index_error_code::invalid_index_format:
  322. Context.getDiagnostics().Report(diag::err_extdefmap_parsing)
  323. << IE.getFileName() << IE.getLineNum();
  324. break;
  325. case index_error_code::multiple_definitions:
  326. Context.getDiagnostics().Report(diag::err_multiple_def_index)
  327. << IE.getLineNum();
  328. break;
  329. case index_error_code::triple_mismatch:
  330. Context.getDiagnostics().Report(diag::warn_ctu_incompat_triple)
  331. << IE.getFileName() << IE.getTripleToName() << IE.getTripleFromName();
  332. break;
  333. default:
  334. break;
  335. }
  336. }
  337. CrossTranslationUnitContext::ASTUnitStorage::ASTUnitStorage(
  338. CompilerInstance &CI)
  339. : Loader(CI, CI.getAnalyzerOpts()->CTUDir,
  340. CI.getAnalyzerOpts()->CTUInvocationList),
  341. LoadGuard(CI.getASTContext().getLangOpts().CPlusPlus
  342. ? CI.getAnalyzerOpts()->CTUImportCppThreshold
  343. : CI.getAnalyzerOpts()->CTUImportThreshold) {}
  344. llvm::Expected<ASTUnit *>
  345. CrossTranslationUnitContext::ASTUnitStorage::getASTUnitForFile(
  346. StringRef FileName, bool DisplayCTUProgress) {
  347. // Try the cache first.
  348. auto ASTCacheEntry = FileASTUnitMap.find(FileName);
  349. if (ASTCacheEntry == FileASTUnitMap.end()) {
  350. // Do not load if the limit is reached.
  351. if (!LoadGuard) {
  352. ++NumASTLoadThresholdReached;
  353. return llvm::make_error<IndexError>(
  354. index_error_code::load_threshold_reached);
  355. }
  356. auto LoadAttempt = Loader.load(FileName);
  357. if (!LoadAttempt)
  358. return LoadAttempt.takeError();
  359. std::unique_ptr<ASTUnit> LoadedUnit = std::move(LoadAttempt.get());
  360. // Need the raw pointer and the unique_ptr as well.
  361. ASTUnit *Unit = LoadedUnit.get();
  362. // Update the cache.
  363. FileASTUnitMap[FileName] = std::move(LoadedUnit);
  364. LoadGuard.indicateLoadSuccess();
  365. if (DisplayCTUProgress)
  366. llvm::errs() << "CTU loaded AST file: " << FileName << "\n";
  367. return Unit;
  368. } else {
  369. // Found in the cache.
  370. return ASTCacheEntry->second.get();
  371. }
  372. }
  373. llvm::Expected<ASTUnit *>
  374. CrossTranslationUnitContext::ASTUnitStorage::getASTUnitForFunction(
  375. StringRef FunctionName, StringRef CrossTUDir, StringRef IndexName,
  376. bool DisplayCTUProgress) {
  377. // Try the cache first.
  378. auto ASTCacheEntry = NameASTUnitMap.find(FunctionName);
  379. if (ASTCacheEntry == NameASTUnitMap.end()) {
  380. // Load the ASTUnit from the pre-dumped AST file specified by ASTFileName.
  381. // Ensure that the Index is loaded, as we need to search in it.
  382. if (llvm::Error IndexLoadError =
  383. ensureCTUIndexLoaded(CrossTUDir, IndexName))
  384. return std::move(IndexLoadError);
  385. // Check if there is and entry in the index for the function.
  386. if (!NameFileMap.count(FunctionName)) {
  387. ++NumNotInOtherTU;
  388. return llvm::make_error<IndexError>(index_error_code::missing_definition);
  389. }
  390. // Search in the index for the filename where the definition of FuncitonName
  391. // resides.
  392. if (llvm::Expected<ASTUnit *> FoundForFile =
  393. getASTUnitForFile(NameFileMap[FunctionName], DisplayCTUProgress)) {
  394. // Update the cache.
  395. NameASTUnitMap[FunctionName] = *FoundForFile;
  396. return *FoundForFile;
  397. } else {
  398. return FoundForFile.takeError();
  399. }
  400. } else {
  401. // Found in the cache.
  402. return ASTCacheEntry->second;
  403. }
  404. }
  405. llvm::Expected<std::string>
  406. CrossTranslationUnitContext::ASTUnitStorage::getFileForFunction(
  407. StringRef FunctionName, StringRef CrossTUDir, StringRef IndexName) {
  408. if (llvm::Error IndexLoadError = ensureCTUIndexLoaded(CrossTUDir, IndexName))
  409. return std::move(IndexLoadError);
  410. return NameFileMap[FunctionName];
  411. }
  412. llvm::Error CrossTranslationUnitContext::ASTUnitStorage::ensureCTUIndexLoaded(
  413. StringRef CrossTUDir, StringRef IndexName) {
  414. // Dont initialize if the map is filled.
  415. if (!NameFileMap.empty())
  416. return llvm::Error::success();
  417. // Get the absolute path to the index file.
  418. SmallString<256> IndexFile = CrossTUDir;
  419. if (llvm::sys::path::is_absolute(IndexName))
  420. IndexFile = IndexName;
  421. else
  422. llvm::sys::path::append(IndexFile, IndexName);
  423. if (auto IndexMapping = parseCrossTUIndex(IndexFile)) {
  424. // Initialize member map.
  425. NameFileMap = *IndexMapping;
  426. return llvm::Error::success();
  427. } else {
  428. // Error while parsing CrossTU index file.
  429. return IndexMapping.takeError();
  430. };
  431. }
  432. llvm::Expected<ASTUnit *> CrossTranslationUnitContext::loadExternalAST(
  433. StringRef LookupName, StringRef CrossTUDir, StringRef IndexName,
  434. bool DisplayCTUProgress) {
  435. // FIXME: The current implementation only supports loading decls with
  436. // a lookup name from a single translation unit. If multiple
  437. // translation units contains decls with the same lookup name an
  438. // error will be returned.
  439. // Try to get the value from the heavily cached storage.
  440. llvm::Expected<ASTUnit *> Unit = ASTStorage.getASTUnitForFunction(
  441. LookupName, CrossTUDir, IndexName, DisplayCTUProgress);
  442. if (!Unit)
  443. return Unit.takeError();
  444. // Check whether the backing pointer of the Expected is a nullptr.
  445. if (!*Unit)
  446. return llvm::make_error<IndexError>(
  447. index_error_code::failed_to_get_external_ast);
  448. return Unit;
  449. }
  450. CrossTranslationUnitContext::ASTLoader::ASTLoader(
  451. CompilerInstance &CI, StringRef CTUDir, StringRef InvocationListFilePath)
  452. : CI(CI), CTUDir(CTUDir), InvocationListFilePath(InvocationListFilePath) {}
  453. CrossTranslationUnitContext::LoadResultTy
  454. CrossTranslationUnitContext::ASTLoader::load(StringRef Identifier) {
  455. llvm::SmallString<256> Path;
  456. if (llvm::sys::path::is_absolute(Identifier, PathStyle)) {
  457. Path = Identifier;
  458. } else {
  459. Path = CTUDir;
  460. llvm::sys::path::append(Path, PathStyle, Identifier);
  461. }
  462. // The path is stored in the InvocationList member in posix style. To
  463. // successfully lookup an entry based on filepath, it must be converted.
  464. llvm::sys::path::native(Path, PathStyle);
  465. // Normalize by removing relative path components.
  466. llvm::sys::path::remove_dots(Path, /*remove_dot_dot*/ true, PathStyle);
  467. if (Path.endswith(".ast"))
  468. return loadFromDump(Path);
  469. else
  470. return loadFromSource(Path);
  471. }
  472. CrossTranslationUnitContext::LoadResultTy
  473. CrossTranslationUnitContext::ASTLoader::loadFromDump(StringRef ASTDumpPath) {
  474. IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
  475. TextDiagnosticPrinter *DiagClient =
  476. new TextDiagnosticPrinter(llvm::errs(), &*DiagOpts);
  477. IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
  478. IntrusiveRefCntPtr<DiagnosticsEngine> Diags(
  479. new DiagnosticsEngine(DiagID, &*DiagOpts, DiagClient));
  480. return ASTUnit::LoadFromASTFile(
  481. std::string(ASTDumpPath.str()),
  482. CI.getPCHContainerOperations()->getRawReader(), ASTUnit::LoadEverything,
  483. Diags, CI.getFileSystemOpts());
  484. }
  485. /// Load the AST from a source-file, which is supposed to be located inside the
  486. /// YAML formatted invocation list file under the filesystem path specified by
  487. /// \p InvocationList. The invocation list should contain absolute paths.
  488. /// \p SourceFilePath is the absolute path of the source file that contains the
  489. /// function definition the analysis is looking for. The Index is built by the
  490. /// \p clang-extdef-mapping tool, which is also supposed to be generating
  491. /// absolute paths.
  492. ///
  493. /// Proper diagnostic emission requires absolute paths, so even if a future
  494. /// change introduces the handling of relative paths, this must be taken into
  495. /// consideration.
  496. CrossTranslationUnitContext::LoadResultTy
  497. CrossTranslationUnitContext::ASTLoader::loadFromSource(
  498. StringRef SourceFilePath) {
  499. if (llvm::Error InitError = lazyInitInvocationList())
  500. return std::move(InitError);
  501. assert(InvocationList);
  502. auto Invocation = InvocationList->find(SourceFilePath);
  503. if (Invocation == InvocationList->end())
  504. return llvm::make_error<IndexError>(
  505. index_error_code::invocation_list_lookup_unsuccessful);
  506. const InvocationListTy::mapped_type &InvocationCommand = Invocation->second;
  507. SmallVector<const char *, 32> CommandLineArgs(InvocationCommand.size());
  508. std::transform(InvocationCommand.begin(), InvocationCommand.end(),
  509. CommandLineArgs.begin(),
  510. [](auto &&CmdPart) { return CmdPart.c_str(); });
  511. IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts{&CI.getDiagnosticOpts()};
  512. auto *DiagClient = new ForwardingDiagnosticConsumer{CI.getDiagnosticClient()};
  513. IntrusiveRefCntPtr<DiagnosticIDs> DiagID{
  514. CI.getDiagnostics().getDiagnosticIDs()};
  515. IntrusiveRefCntPtr<DiagnosticsEngine> Diags(
  516. new DiagnosticsEngine{DiagID, &*DiagOpts, DiagClient});
  517. return std::unique_ptr<ASTUnit>(ASTUnit::LoadFromCommandLine(
  518. CommandLineArgs.begin(), (CommandLineArgs.end()),
  519. CI.getPCHContainerOperations(), Diags,
  520. CI.getHeaderSearchOpts().ResourceDir));
  521. }
  522. llvm::Expected<InvocationListTy>
  523. parseInvocationList(StringRef FileContent, llvm::sys::path::Style PathStyle) {
  524. InvocationListTy InvocationList;
  525. /// LLVM YAML parser is used to extract information from invocation list file.
  526. llvm::SourceMgr SM;
  527. llvm::yaml::Stream InvocationFile(FileContent, SM);
  528. /// Only the first document is processed.
  529. llvm::yaml::document_iterator FirstInvocationFile = InvocationFile.begin();
  530. /// There has to be at least one document available.
  531. if (FirstInvocationFile == InvocationFile.end())
  532. return llvm::make_error<IndexError>(
  533. index_error_code::invocation_list_empty);
  534. llvm::yaml::Node *DocumentRoot = FirstInvocationFile->getRoot();
  535. if (!DocumentRoot)
  536. return llvm::make_error<IndexError>(
  537. index_error_code::invocation_list_wrong_format);
  538. /// According to the format specified the document must be a mapping, where
  539. /// the keys are paths to source files, and values are sequences of invocation
  540. /// parts.
  541. auto *Mappings = dyn_cast<llvm::yaml::MappingNode>(DocumentRoot);
  542. if (!Mappings)
  543. return llvm::make_error<IndexError>(
  544. index_error_code::invocation_list_wrong_format);
  545. for (auto &NextMapping : *Mappings) {
  546. /// The keys should be strings, which represent a source-file path.
  547. auto *Key = dyn_cast<llvm::yaml::ScalarNode>(NextMapping.getKey());
  548. if (!Key)
  549. return llvm::make_error<IndexError>(
  550. index_error_code::invocation_list_wrong_format);
  551. SmallString<32> ValueStorage;
  552. StringRef SourcePath = Key->getValue(ValueStorage);
  553. // Store paths with PathStyle directory separator.
  554. SmallString<32> NativeSourcePath(SourcePath);
  555. llvm::sys::path::native(NativeSourcePath, PathStyle);
  556. StringRef InvocationKey = NativeSourcePath;
  557. if (InvocationList.find(InvocationKey) != InvocationList.end())
  558. return llvm::make_error<IndexError>(
  559. index_error_code::invocation_list_ambiguous);
  560. /// The values should be sequences of strings, each representing a part of
  561. /// the invocation.
  562. auto *Args = dyn_cast<llvm::yaml::SequenceNode>(NextMapping.getValue());
  563. if (!Args)
  564. return llvm::make_error<IndexError>(
  565. index_error_code::invocation_list_wrong_format);
  566. for (auto &Arg : *Args) {
  567. auto *CmdString = dyn_cast<llvm::yaml::ScalarNode>(&Arg);
  568. if (!CmdString)
  569. return llvm::make_error<IndexError>(
  570. index_error_code::invocation_list_wrong_format);
  571. /// Every conversion starts with an empty working storage, as it is not
  572. /// clear if this is a requirement of the YAML parser.
  573. ValueStorage.clear();
  574. InvocationList[InvocationKey].emplace_back(
  575. CmdString->getValue(ValueStorage));
  576. }
  577. if (InvocationList[InvocationKey].empty())
  578. return llvm::make_error<IndexError>(
  579. index_error_code::invocation_list_wrong_format);
  580. }
  581. return InvocationList;
  582. }
  583. llvm::Error CrossTranslationUnitContext::ASTLoader::lazyInitInvocationList() {
  584. /// Lazily initialize the invocation list member used for on-demand parsing.
  585. if (InvocationList)
  586. return llvm::Error::success();
  587. if (index_error_code::success != PreviousParsingResult)
  588. return llvm::make_error<IndexError>(PreviousParsingResult);
  589. llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> FileContent =
  590. llvm::MemoryBuffer::getFile(InvocationListFilePath);
  591. if (!FileContent) {
  592. PreviousParsingResult = index_error_code::invocation_list_file_not_found;
  593. return llvm::make_error<IndexError>(PreviousParsingResult);
  594. }
  595. std::unique_ptr<llvm::MemoryBuffer> ContentBuffer = std::move(*FileContent);
  596. assert(ContentBuffer && "If no error was produced after loading, the pointer "
  597. "should not be nullptr.");
  598. llvm::Expected<InvocationListTy> ExpectedInvocationList =
  599. parseInvocationList(ContentBuffer->getBuffer(), PathStyle);
  600. // Handle the error to store the code for next call to this function.
  601. if (!ExpectedInvocationList) {
  602. llvm::handleAllErrors(
  603. ExpectedInvocationList.takeError(),
  604. [&](const IndexError &E) { PreviousParsingResult = E.getCode(); });
  605. return llvm::make_error<IndexError>(PreviousParsingResult);
  606. }
  607. InvocationList = *ExpectedInvocationList;
  608. return llvm::Error::success();
  609. }
  610. template <typename T>
  611. llvm::Expected<const T *>
  612. CrossTranslationUnitContext::importDefinitionImpl(const T *D, ASTUnit *Unit) {
  613. assert(hasBodyOrInit(D) && "Decls to be imported should have body or init.");
  614. assert(&D->getASTContext() == &Unit->getASTContext() &&
  615. "ASTContext of Decl and the unit should match.");
  616. ASTImporter &Importer = getOrCreateASTImporter(Unit);
  617. auto ToDeclOrError = Importer.Import(D);
  618. if (!ToDeclOrError) {
  619. handleAllErrors(ToDeclOrError.takeError(),
  620. [&](const ImportError &IE) {
  621. switch (IE.Error) {
  622. case ImportError::NameConflict:
  623. ++NumNameConflicts;
  624. break;
  625. case ImportError::UnsupportedConstruct:
  626. ++NumUnsupportedNodeFound;
  627. break;
  628. case ImportError::Unknown:
  629. llvm_unreachable("Unknown import error happened.");
  630. break;
  631. }
  632. });
  633. return llvm::make_error<IndexError>(index_error_code::failed_import);
  634. }
  635. auto *ToDecl = cast<T>(*ToDeclOrError);
  636. assert(hasBodyOrInit(ToDecl) && "Imported Decl should have body or init.");
  637. ++NumGetCTUSuccess;
  638. // Parent map is invalidated after changing the AST.
  639. ToDecl->getASTContext().getParentMapContext().clear();
  640. return ToDecl;
  641. }
  642. llvm::Expected<const FunctionDecl *>
  643. CrossTranslationUnitContext::importDefinition(const FunctionDecl *FD,
  644. ASTUnit *Unit) {
  645. return importDefinitionImpl(FD, Unit);
  646. }
  647. llvm::Expected<const VarDecl *>
  648. CrossTranslationUnitContext::importDefinition(const VarDecl *VD,
  649. ASTUnit *Unit) {
  650. return importDefinitionImpl(VD, Unit);
  651. }
  652. void CrossTranslationUnitContext::lazyInitImporterSharedSt(
  653. TranslationUnitDecl *ToTU) {
  654. if (!ImporterSharedSt)
  655. ImporterSharedSt = std::make_shared<ASTImporterSharedState>(*ToTU);
  656. }
  657. ASTImporter &
  658. CrossTranslationUnitContext::getOrCreateASTImporter(ASTUnit *Unit) {
  659. ASTContext &From = Unit->getASTContext();
  660. auto I = ASTUnitImporterMap.find(From.getTranslationUnitDecl());
  661. if (I != ASTUnitImporterMap.end())
  662. return *I->second;
  663. lazyInitImporterSharedSt(Context.getTranslationUnitDecl());
  664. ASTImporter *NewImporter = new ASTImporter(
  665. Context, Context.getSourceManager().getFileManager(), From,
  666. From.getSourceManager().getFileManager(), false, ImporterSharedSt);
  667. ASTUnitImporterMap[From.getTranslationUnitDecl()].reset(NewImporter);
  668. return *NewImporter;
  669. }
  670. llvm::Optional<clang::MacroExpansionContext>
  671. CrossTranslationUnitContext::getMacroExpansionContextForSourceLocation(
  672. const clang::SourceLocation &ToLoc) const {
  673. // FIXME: Implement: Record such a context for every imported ASTUnit; lookup.
  674. return llvm::None;
  675. }
  676. } // namespace cross_tu
  677. } // namespace clang