xref: /freebsd-src/contrib/llvm-project/clang/lib/CrossTU/CrossTranslationUnit.cpp (revision 7a6dacaca14b62ca4b74406814becb87a3fefac0)
10b57cec5SDimitry Andric //===--- CrossTranslationUnit.cpp - -----------------------------*- C++ -*-===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric //
90b57cec5SDimitry Andric //  This file implements the CrossTranslationUnit interface.
100b57cec5SDimitry Andric //
110b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
120b57cec5SDimitry Andric #include "clang/CrossTU/CrossTranslationUnit.h"
130b57cec5SDimitry Andric #include "clang/AST/ASTImporter.h"
140b57cec5SDimitry Andric #include "clang/AST/Decl.h"
155ffd83dbSDimitry Andric #include "clang/AST/ParentMapContext.h"
160b57cec5SDimitry Andric #include "clang/Basic/TargetInfo.h"
170b57cec5SDimitry Andric #include "clang/CrossTU/CrossTUDiagnostic.h"
180b57cec5SDimitry Andric #include "clang/Frontend/ASTUnit.h"
190b57cec5SDimitry Andric #include "clang/Frontend/CompilerInstance.h"
200b57cec5SDimitry Andric #include "clang/Frontend/TextDiagnosticPrinter.h"
210b57cec5SDimitry Andric #include "clang/Index/USRGeneration.h"
220b57cec5SDimitry Andric #include "llvm/ADT/Statistic.h"
235ffd83dbSDimitry Andric #include "llvm/Option/ArgList.h"
240b57cec5SDimitry Andric #include "llvm/Support/ErrorHandling.h"
250b57cec5SDimitry Andric #include "llvm/Support/ManagedStatic.h"
260b57cec5SDimitry Andric #include "llvm/Support/Path.h"
275ffd83dbSDimitry Andric #include "llvm/Support/YAMLParser.h"
280b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h"
2906c3fb27SDimitry Andric #include "llvm/TargetParser/Triple.h"
305ffd83dbSDimitry Andric #include <algorithm>
310b57cec5SDimitry Andric #include <fstream>
32bdd1243dSDimitry Andric #include <optional>
330b57cec5SDimitry Andric #include <sstream>
345ffd83dbSDimitry Andric #include <tuple>
350b57cec5SDimitry Andric 
360b57cec5SDimitry Andric namespace clang {
370b57cec5SDimitry Andric namespace cross_tu {
380b57cec5SDimitry Andric 
390b57cec5SDimitry Andric namespace {
400b57cec5SDimitry Andric 
410b57cec5SDimitry Andric #define DEBUG_TYPE "CrossTranslationUnit"
420b57cec5SDimitry Andric STATISTIC(NumGetCTUCalled, "The # of getCTUDefinition function called");
430b57cec5SDimitry Andric STATISTIC(
440b57cec5SDimitry Andric     NumNotInOtherTU,
450b57cec5SDimitry Andric     "The # of getCTUDefinition called but the function is not in any other TU");
460b57cec5SDimitry Andric STATISTIC(NumGetCTUSuccess,
470b57cec5SDimitry Andric           "The # of getCTUDefinition successfully returned the "
480b57cec5SDimitry Andric           "requested function's body");
490b57cec5SDimitry Andric STATISTIC(NumUnsupportedNodeFound, "The # of imports when the ASTImporter "
500b57cec5SDimitry Andric                                    "encountered an unsupported AST Node");
510b57cec5SDimitry Andric STATISTIC(NumNameConflicts, "The # of imports when the ASTImporter "
520b57cec5SDimitry Andric                             "encountered an ODR error");
530b57cec5SDimitry Andric STATISTIC(NumTripleMismatch, "The # of triple mismatches");
540b57cec5SDimitry Andric STATISTIC(NumLangMismatch, "The # of language mismatches");
550b57cec5SDimitry Andric STATISTIC(NumLangDialectMismatch, "The # of language dialect mismatches");
560b57cec5SDimitry Andric STATISTIC(NumASTLoadThresholdReached,
570b57cec5SDimitry Andric           "The # of ASTs not loaded because of threshold");
580b57cec5SDimitry Andric 
590b57cec5SDimitry Andric // Same as Triple's equality operator, but we check a field only if that is
600b57cec5SDimitry Andric // known in both instances.
hasEqualKnownFields(const llvm::Triple & Lhs,const llvm::Triple & Rhs)610b57cec5SDimitry Andric bool hasEqualKnownFields(const llvm::Triple &Lhs, const llvm::Triple &Rhs) {
620b57cec5SDimitry Andric   using llvm::Triple;
630b57cec5SDimitry Andric   if (Lhs.getArch() != Triple::UnknownArch &&
640b57cec5SDimitry Andric       Rhs.getArch() != Triple::UnknownArch && Lhs.getArch() != Rhs.getArch())
650b57cec5SDimitry Andric     return false;
660b57cec5SDimitry Andric   if (Lhs.getSubArch() != Triple::NoSubArch &&
670b57cec5SDimitry Andric       Rhs.getSubArch() != Triple::NoSubArch &&
680b57cec5SDimitry Andric       Lhs.getSubArch() != Rhs.getSubArch())
690b57cec5SDimitry Andric     return false;
700b57cec5SDimitry Andric   if (Lhs.getVendor() != Triple::UnknownVendor &&
710b57cec5SDimitry Andric       Rhs.getVendor() != Triple::UnknownVendor &&
720b57cec5SDimitry Andric       Lhs.getVendor() != Rhs.getVendor())
730b57cec5SDimitry Andric     return false;
740b57cec5SDimitry Andric   if (!Lhs.isOSUnknown() && !Rhs.isOSUnknown() &&
750b57cec5SDimitry Andric       Lhs.getOS() != Rhs.getOS())
760b57cec5SDimitry Andric     return false;
770b57cec5SDimitry Andric   if (Lhs.getEnvironment() != Triple::UnknownEnvironment &&
780b57cec5SDimitry Andric       Rhs.getEnvironment() != Triple::UnknownEnvironment &&
790b57cec5SDimitry Andric       Lhs.getEnvironment() != Rhs.getEnvironment())
800b57cec5SDimitry Andric     return false;
810b57cec5SDimitry Andric   if (Lhs.getObjectFormat() != Triple::UnknownObjectFormat &&
820b57cec5SDimitry Andric       Rhs.getObjectFormat() != Triple::UnknownObjectFormat &&
830b57cec5SDimitry Andric       Lhs.getObjectFormat() != Rhs.getObjectFormat())
840b57cec5SDimitry Andric     return false;
850b57cec5SDimitry Andric   return true;
860b57cec5SDimitry Andric }
870b57cec5SDimitry Andric 
880b57cec5SDimitry Andric // FIXME: This class is will be removed after the transition to llvm::Error.
890b57cec5SDimitry Andric class IndexErrorCategory : public std::error_category {
900b57cec5SDimitry Andric public:
name() const910b57cec5SDimitry Andric   const char *name() const noexcept override { return "clang.index"; }
920b57cec5SDimitry Andric 
message(int Condition) const930b57cec5SDimitry Andric   std::string message(int Condition) const override {
940b57cec5SDimitry Andric     switch (static_cast<index_error_code>(Condition)) {
95fe6060f1SDimitry Andric     case index_error_code::success:
96fe6060f1SDimitry Andric       // There should not be a success error. Jump to unreachable directly.
97fe6060f1SDimitry Andric       // Add this case to make the compiler stop complaining.
98fe6060f1SDimitry Andric       break;
990b57cec5SDimitry Andric     case index_error_code::unspecified:
1000b57cec5SDimitry Andric       return "An unknown error has occurred.";
1010b57cec5SDimitry Andric     case index_error_code::missing_index_file:
1020b57cec5SDimitry Andric       return "The index file is missing.";
1030b57cec5SDimitry Andric     case index_error_code::invalid_index_format:
1040b57cec5SDimitry Andric       return "Invalid index file format.";
1050b57cec5SDimitry Andric     case index_error_code::multiple_definitions:
1060b57cec5SDimitry Andric       return "Multiple definitions in the index file.";
1070b57cec5SDimitry Andric     case index_error_code::missing_definition:
1080b57cec5SDimitry Andric       return "Missing definition from the index file.";
1090b57cec5SDimitry Andric     case index_error_code::failed_import:
1100b57cec5SDimitry Andric       return "Failed to import the definition.";
1110b57cec5SDimitry Andric     case index_error_code::failed_to_get_external_ast:
1120b57cec5SDimitry Andric       return "Failed to load external AST source.";
1130b57cec5SDimitry Andric     case index_error_code::failed_to_generate_usr:
1140b57cec5SDimitry Andric       return "Failed to generate USR.";
1150b57cec5SDimitry Andric     case index_error_code::triple_mismatch:
1160b57cec5SDimitry Andric       return "Triple mismatch";
1170b57cec5SDimitry Andric     case index_error_code::lang_mismatch:
1180b57cec5SDimitry Andric       return "Language mismatch";
1190b57cec5SDimitry Andric     case index_error_code::lang_dialect_mismatch:
1200b57cec5SDimitry Andric       return "Language dialect mismatch";
1210b57cec5SDimitry Andric     case index_error_code::load_threshold_reached:
1220b57cec5SDimitry Andric       return "Load threshold reached";
1235ffd83dbSDimitry Andric     case index_error_code::invocation_list_ambiguous:
1245ffd83dbSDimitry Andric       return "Invocation list file contains multiple references to the same "
1255ffd83dbSDimitry Andric              "source file.";
1265ffd83dbSDimitry Andric     case index_error_code::invocation_list_file_not_found:
1275ffd83dbSDimitry Andric       return "Invocation list file is not found.";
1285ffd83dbSDimitry Andric     case index_error_code::invocation_list_empty:
1295ffd83dbSDimitry Andric       return "Invocation list file is empty.";
1305ffd83dbSDimitry Andric     case index_error_code::invocation_list_wrong_format:
1315ffd83dbSDimitry Andric       return "Invocation list file is in wrong format.";
1325ffd83dbSDimitry Andric     case index_error_code::invocation_list_lookup_unsuccessful:
1335ffd83dbSDimitry Andric       return "Invocation list file does not contain the requested source file.";
1340b57cec5SDimitry Andric     }
1350b57cec5SDimitry Andric     llvm_unreachable("Unrecognized index_error_code.");
1360b57cec5SDimitry Andric   }
1370b57cec5SDimitry Andric };
1380b57cec5SDimitry Andric 
1390b57cec5SDimitry Andric static llvm::ManagedStatic<IndexErrorCategory> Category;
1400b57cec5SDimitry Andric } // end anonymous namespace
1410b57cec5SDimitry Andric 
1420b57cec5SDimitry Andric char IndexError::ID;
1430b57cec5SDimitry Andric 
log(raw_ostream & OS) const1440b57cec5SDimitry Andric void IndexError::log(raw_ostream &OS) const {
1450b57cec5SDimitry Andric   OS << Category->message(static_cast<int>(Code)) << '\n';
1460b57cec5SDimitry Andric }
1470b57cec5SDimitry Andric 
convertToErrorCode() const1480b57cec5SDimitry Andric std::error_code IndexError::convertToErrorCode() const {
1490b57cec5SDimitry Andric   return std::error_code(static_cast<int>(Code), *Category);
1500b57cec5SDimitry Andric }
1510b57cec5SDimitry Andric 
15281ad6265SDimitry Andric /// Parse one line of the input CTU index file.
15381ad6265SDimitry Andric ///
15481ad6265SDimitry Andric /// @param[in]  LineRef     The input CTU index item in format
15581ad6265SDimitry Andric ///                         "<USR-Length>:<USR> <File-Path>".
15681ad6265SDimitry Andric /// @param[out] LookupName  The lookup name in format "<USR-Length>:<USR>".
15781ad6265SDimitry Andric /// @param[out] FilePath    The file path "<File-Path>".
parseCrossTUIndexItem(StringRef LineRef,StringRef & LookupName,StringRef & FilePath)15881ad6265SDimitry Andric static bool parseCrossTUIndexItem(StringRef LineRef, StringRef &LookupName,
15981ad6265SDimitry Andric                                   StringRef &FilePath) {
16081ad6265SDimitry Andric   // `LineRef` is "<USR-Length>:<USR> <File-Path>" now.
16181ad6265SDimitry Andric 
16281ad6265SDimitry Andric   size_t USRLength = 0;
16381ad6265SDimitry Andric   if (LineRef.consumeInteger(10, USRLength))
16481ad6265SDimitry Andric     return false;
16581ad6265SDimitry Andric   assert(USRLength && "USRLength should be greater than zero.");
16681ad6265SDimitry Andric 
16781ad6265SDimitry Andric   if (!LineRef.consume_front(":"))
16881ad6265SDimitry Andric     return false;
16981ad6265SDimitry Andric 
17081ad6265SDimitry Andric   // `LineRef` is now just "<USR> <File-Path>".
17181ad6265SDimitry Andric 
17281ad6265SDimitry Andric   // Check LookupName length out of bound and incorrect delimiter.
17381ad6265SDimitry Andric   if (USRLength >= LineRef.size() || ' ' != LineRef[USRLength])
17481ad6265SDimitry Andric     return false;
17581ad6265SDimitry Andric 
17681ad6265SDimitry Andric   LookupName = LineRef.substr(0, USRLength);
17781ad6265SDimitry Andric   FilePath = LineRef.substr(USRLength + 1);
17881ad6265SDimitry Andric   return true;
17981ad6265SDimitry Andric }
18081ad6265SDimitry Andric 
1810b57cec5SDimitry Andric llvm::Expected<llvm::StringMap<std::string>>
parseCrossTUIndex(StringRef IndexPath)1825ffd83dbSDimitry Andric parseCrossTUIndex(StringRef IndexPath) {
1835ffd83dbSDimitry Andric   std::ifstream ExternalMapFile{std::string(IndexPath)};
1840b57cec5SDimitry Andric   if (!ExternalMapFile)
1850b57cec5SDimitry Andric     return llvm::make_error<IndexError>(index_error_code::missing_index_file,
1860b57cec5SDimitry Andric                                         IndexPath.str());
1870b57cec5SDimitry Andric 
1880b57cec5SDimitry Andric   llvm::StringMap<std::string> Result;
1890b57cec5SDimitry Andric   std::string Line;
1900b57cec5SDimitry Andric   unsigned LineNo = 1;
1910b57cec5SDimitry Andric   while (std::getline(ExternalMapFile, Line)) {
19281ad6265SDimitry Andric     // Split lookup name and file path
19381ad6265SDimitry Andric     StringRef LookupName, FilePathInIndex;
19481ad6265SDimitry Andric     if (!parseCrossTUIndexItem(Line, LookupName, FilePathInIndex))
19581ad6265SDimitry Andric       return llvm::make_error<IndexError>(
19681ad6265SDimitry Andric           index_error_code::invalid_index_format, IndexPath.str(), LineNo);
1975ffd83dbSDimitry Andric 
1985ffd83dbSDimitry Andric     // Store paths with posix-style directory separator.
19981ad6265SDimitry Andric     SmallString<32> FilePath(FilePathInIndex);
2005ffd83dbSDimitry Andric     llvm::sys::path::native(FilePath, llvm::sys::path::Style::posix);
2015ffd83dbSDimitry Andric 
2025ffd83dbSDimitry Andric     bool InsertionOccured;
2035ffd83dbSDimitry Andric     std::tie(std::ignore, InsertionOccured) =
2045ffd83dbSDimitry Andric         Result.try_emplace(LookupName, FilePath.begin(), FilePath.end());
2055ffd83dbSDimitry Andric     if (!InsertionOccured)
2060b57cec5SDimitry Andric       return llvm::make_error<IndexError>(
2070b57cec5SDimitry Andric           index_error_code::multiple_definitions, IndexPath.str(), LineNo);
20881ad6265SDimitry Andric 
2095ffd83dbSDimitry Andric     ++LineNo;
2100b57cec5SDimitry Andric   }
2110b57cec5SDimitry Andric   return Result;
2120b57cec5SDimitry Andric }
2130b57cec5SDimitry Andric 
2140b57cec5SDimitry Andric std::string
createCrossTUIndexString(const llvm::StringMap<std::string> & Index)2150b57cec5SDimitry Andric createCrossTUIndexString(const llvm::StringMap<std::string> &Index) {
2160b57cec5SDimitry Andric   std::ostringstream Result;
2170b57cec5SDimitry Andric   for (const auto &E : Index)
21881ad6265SDimitry Andric     Result << E.getKey().size() << ':' << E.getKey().str() << ' '
21981ad6265SDimitry Andric            << E.getValue() << '\n';
2200b57cec5SDimitry Andric   return Result.str();
2210b57cec5SDimitry Andric }
2220b57cec5SDimitry Andric 
shouldImport(const VarDecl * VD,const ASTContext & ACtx)22381ad6265SDimitry Andric bool shouldImport(const VarDecl *VD, const ASTContext &ACtx) {
2240b57cec5SDimitry Andric   CanQualType CT = ACtx.getCanonicalType(VD->getType());
22581ad6265SDimitry Andric   return CT.isConstQualified() && VD->getType().isTrivialType(ACtx);
2260b57cec5SDimitry Andric }
2270b57cec5SDimitry Andric 
hasBodyOrInit(const FunctionDecl * D,const FunctionDecl * & DefD)2280b57cec5SDimitry Andric static bool hasBodyOrInit(const FunctionDecl *D, const FunctionDecl *&DefD) {
2290b57cec5SDimitry Andric   return D->hasBody(DefD);
2300b57cec5SDimitry Andric }
hasBodyOrInit(const VarDecl * D,const VarDecl * & DefD)2310b57cec5SDimitry Andric static bool hasBodyOrInit(const VarDecl *D, const VarDecl *&DefD) {
2320b57cec5SDimitry Andric   return D->getAnyInitializer(DefD);
2330b57cec5SDimitry Andric }
hasBodyOrInit(const T * D)2340b57cec5SDimitry Andric template <typename T> static bool hasBodyOrInit(const T *D) {
2350b57cec5SDimitry Andric   const T *Unused;
2360b57cec5SDimitry Andric   return hasBodyOrInit(D, Unused);
2370b57cec5SDimitry Andric }
2380b57cec5SDimitry Andric 
CrossTranslationUnitContext(CompilerInstance & CI)2390b57cec5SDimitry Andric CrossTranslationUnitContext::CrossTranslationUnitContext(CompilerInstance &CI)
240a7dea167SDimitry Andric     : Context(CI.getASTContext()), ASTStorage(CI) {}
2410b57cec5SDimitry Andric 
~CrossTranslationUnitContext()2420b57cec5SDimitry Andric CrossTranslationUnitContext::~CrossTranslationUnitContext() {}
2430b57cec5SDimitry Andric 
244bdd1243dSDimitry Andric std::optional<std::string>
getLookupName(const NamedDecl * ND)245a7dea167SDimitry Andric CrossTranslationUnitContext::getLookupName(const NamedDecl *ND) {
2460b57cec5SDimitry Andric   SmallString<128> DeclUSR;
2470b57cec5SDimitry Andric   bool Ret = index::generateUSRForDecl(ND, DeclUSR);
248a7dea167SDimitry Andric   if (Ret)
249a7dea167SDimitry Andric     return {};
250*7a6dacacSDimitry Andric   return std::string(DeclUSR);
2510b57cec5SDimitry Andric }
2520b57cec5SDimitry Andric 
2530b57cec5SDimitry Andric /// Recursively visits the decls of a DeclContext, and returns one with the
2540b57cec5SDimitry Andric /// given USR.
2550b57cec5SDimitry Andric template <typename T>
2560b57cec5SDimitry Andric const T *
findDefInDeclContext(const DeclContext * DC,StringRef LookupName)2570b57cec5SDimitry Andric CrossTranslationUnitContext::findDefInDeclContext(const DeclContext *DC,
2580b57cec5SDimitry Andric                                                   StringRef LookupName) {
2590b57cec5SDimitry Andric   assert(DC && "Declaration Context must not be null");
2600b57cec5SDimitry Andric   for (const Decl *D : DC->decls()) {
2610b57cec5SDimitry Andric     const auto *SubDC = dyn_cast<DeclContext>(D);
2620b57cec5SDimitry Andric     if (SubDC)
2630b57cec5SDimitry Andric       if (const auto *ND = findDefInDeclContext<T>(SubDC, LookupName))
2640b57cec5SDimitry Andric         return ND;
2650b57cec5SDimitry Andric 
2660b57cec5SDimitry Andric     const auto *ND = dyn_cast<T>(D);
2670b57cec5SDimitry Andric     const T *ResultDecl;
2680b57cec5SDimitry Andric     if (!ND || !hasBodyOrInit(ND, ResultDecl))
2690b57cec5SDimitry Andric       continue;
270bdd1243dSDimitry Andric     std::optional<std::string> ResultLookupName = getLookupName(ResultDecl);
271a7dea167SDimitry Andric     if (!ResultLookupName || *ResultLookupName != LookupName)
2720b57cec5SDimitry Andric       continue;
2730b57cec5SDimitry Andric     return ResultDecl;
2740b57cec5SDimitry Andric   }
2750b57cec5SDimitry Andric   return nullptr;
2760b57cec5SDimitry Andric }
2770b57cec5SDimitry Andric 
2780b57cec5SDimitry Andric template <typename T>
getCrossTUDefinitionImpl(const T * D,StringRef CrossTUDir,StringRef IndexName,bool DisplayCTUProgress)2790b57cec5SDimitry Andric llvm::Expected<const T *> CrossTranslationUnitContext::getCrossTUDefinitionImpl(
2800b57cec5SDimitry Andric     const T *D, StringRef CrossTUDir, StringRef IndexName,
2810b57cec5SDimitry Andric     bool DisplayCTUProgress) {
2820b57cec5SDimitry Andric   assert(D && "D is missing, bad call to this function!");
2830b57cec5SDimitry Andric   assert(!hasBodyOrInit(D) &&
2840b57cec5SDimitry Andric          "D has a body or init in current translation unit!");
2850b57cec5SDimitry Andric   ++NumGetCTUCalled;
286bdd1243dSDimitry Andric   const std::optional<std::string> LookupName = getLookupName(D);
287a7dea167SDimitry Andric   if (!LookupName)
2880b57cec5SDimitry Andric     return llvm::make_error<IndexError>(
2890b57cec5SDimitry Andric         index_error_code::failed_to_generate_usr);
290a7dea167SDimitry Andric   llvm::Expected<ASTUnit *> ASTUnitOrError =
291a7dea167SDimitry Andric       loadExternalAST(*LookupName, CrossTUDir, IndexName, DisplayCTUProgress);
2920b57cec5SDimitry Andric   if (!ASTUnitOrError)
2930b57cec5SDimitry Andric     return ASTUnitOrError.takeError();
2940b57cec5SDimitry Andric   ASTUnit *Unit = *ASTUnitOrError;
2950b57cec5SDimitry Andric   assert(&Unit->getFileManager() ==
2960b57cec5SDimitry Andric          &Unit->getASTContext().getSourceManager().getFileManager());
2970b57cec5SDimitry Andric 
2980b57cec5SDimitry Andric   const llvm::Triple &TripleTo = Context.getTargetInfo().getTriple();
2990b57cec5SDimitry Andric   const llvm::Triple &TripleFrom =
3000b57cec5SDimitry Andric       Unit->getASTContext().getTargetInfo().getTriple();
3010b57cec5SDimitry Andric   // The imported AST had been generated for a different target.
3020b57cec5SDimitry Andric   // Some parts of the triple in the loaded ASTContext can be unknown while the
3030b57cec5SDimitry Andric   // very same parts in the target ASTContext are known. Thus we check for the
3040b57cec5SDimitry Andric   // known parts only.
3050b57cec5SDimitry Andric   if (!hasEqualKnownFields(TripleTo, TripleFrom)) {
3060b57cec5SDimitry Andric     // TODO: Pass the SourceLocation of the CallExpression for more precise
3070b57cec5SDimitry Andric     // diagnostics.
3080b57cec5SDimitry Andric     ++NumTripleMismatch;
3090b57cec5SDimitry Andric     return llvm::make_error<IndexError>(index_error_code::triple_mismatch,
3105ffd83dbSDimitry Andric                                         std::string(Unit->getMainFileName()),
3115ffd83dbSDimitry Andric                                         TripleTo.str(), TripleFrom.str());
3120b57cec5SDimitry Andric   }
3130b57cec5SDimitry Andric 
3140b57cec5SDimitry Andric   const auto &LangTo = Context.getLangOpts();
3150b57cec5SDimitry Andric   const auto &LangFrom = Unit->getASTContext().getLangOpts();
3160b57cec5SDimitry Andric 
3170b57cec5SDimitry Andric   // FIXME: Currenty we do not support CTU across C++ and C and across
3180b57cec5SDimitry Andric   // different dialects of C++.
3190b57cec5SDimitry Andric   if (LangTo.CPlusPlus != LangFrom.CPlusPlus) {
3200b57cec5SDimitry Andric     ++NumLangMismatch;
3210b57cec5SDimitry Andric     return llvm::make_error<IndexError>(index_error_code::lang_mismatch);
3220b57cec5SDimitry Andric   }
3230b57cec5SDimitry Andric 
3240b57cec5SDimitry Andric   // If CPP dialects are different then return with error.
3250b57cec5SDimitry Andric   //
3260b57cec5SDimitry Andric   // Consider this STL code:
3270b57cec5SDimitry Andric   //   template<typename _Alloc>
3280b57cec5SDimitry Andric   //     struct __alloc_traits
3290b57cec5SDimitry Andric   //   #if __cplusplus >= 201103L
3300b57cec5SDimitry Andric   //     : std::allocator_traits<_Alloc>
3310b57cec5SDimitry Andric   //   #endif
3320b57cec5SDimitry Andric   //     { // ...
3330b57cec5SDimitry Andric   //     };
3340b57cec5SDimitry Andric   // This class template would create ODR errors during merging the two units,
3350b57cec5SDimitry Andric   // since in one translation unit the class template has a base class, however
3360b57cec5SDimitry Andric   // in the other unit it has none.
3370b57cec5SDimitry Andric   if (LangTo.CPlusPlus11 != LangFrom.CPlusPlus11 ||
3380b57cec5SDimitry Andric       LangTo.CPlusPlus14 != LangFrom.CPlusPlus14 ||
3390b57cec5SDimitry Andric       LangTo.CPlusPlus17 != LangFrom.CPlusPlus17 ||
3405ffd83dbSDimitry Andric       LangTo.CPlusPlus20 != LangFrom.CPlusPlus20) {
3410b57cec5SDimitry Andric     ++NumLangDialectMismatch;
3420b57cec5SDimitry Andric     return llvm::make_error<IndexError>(
3430b57cec5SDimitry Andric         index_error_code::lang_dialect_mismatch);
3440b57cec5SDimitry Andric   }
3450b57cec5SDimitry Andric 
3460b57cec5SDimitry Andric   TranslationUnitDecl *TU = Unit->getASTContext().getTranslationUnitDecl();
347a7dea167SDimitry Andric   if (const T *ResultDecl = findDefInDeclContext<T>(TU, *LookupName))
348a7dea167SDimitry Andric     return importDefinition(ResultDecl, Unit);
3490b57cec5SDimitry Andric   return llvm::make_error<IndexError>(index_error_code::failed_import);
3500b57cec5SDimitry Andric }
3510b57cec5SDimitry Andric 
3520b57cec5SDimitry Andric llvm::Expected<const FunctionDecl *>
getCrossTUDefinition(const FunctionDecl * FD,StringRef CrossTUDir,StringRef IndexName,bool DisplayCTUProgress)3530b57cec5SDimitry Andric CrossTranslationUnitContext::getCrossTUDefinition(const FunctionDecl *FD,
3540b57cec5SDimitry Andric                                                   StringRef CrossTUDir,
3550b57cec5SDimitry Andric                                                   StringRef IndexName,
3560b57cec5SDimitry Andric                                                   bool DisplayCTUProgress) {
3570b57cec5SDimitry Andric   return getCrossTUDefinitionImpl(FD, CrossTUDir, IndexName,
3580b57cec5SDimitry Andric                                   DisplayCTUProgress);
3590b57cec5SDimitry Andric }
3600b57cec5SDimitry Andric 
3610b57cec5SDimitry Andric llvm::Expected<const VarDecl *>
getCrossTUDefinition(const VarDecl * VD,StringRef CrossTUDir,StringRef IndexName,bool DisplayCTUProgress)3620b57cec5SDimitry Andric CrossTranslationUnitContext::getCrossTUDefinition(const VarDecl *VD,
3630b57cec5SDimitry Andric                                                   StringRef CrossTUDir,
3640b57cec5SDimitry Andric                                                   StringRef IndexName,
3650b57cec5SDimitry Andric                                                   bool DisplayCTUProgress) {
3660b57cec5SDimitry Andric   return getCrossTUDefinitionImpl(VD, CrossTUDir, IndexName,
3670b57cec5SDimitry Andric                                   DisplayCTUProgress);
3680b57cec5SDimitry Andric }
3690b57cec5SDimitry Andric 
emitCrossTUDiagnostics(const IndexError & IE)3700b57cec5SDimitry Andric void CrossTranslationUnitContext::emitCrossTUDiagnostics(const IndexError &IE) {
3710b57cec5SDimitry Andric   switch (IE.getCode()) {
3720b57cec5SDimitry Andric   case index_error_code::missing_index_file:
3730b57cec5SDimitry Andric     Context.getDiagnostics().Report(diag::err_ctu_error_opening)
3740b57cec5SDimitry Andric         << IE.getFileName();
3750b57cec5SDimitry Andric     break;
3760b57cec5SDimitry Andric   case index_error_code::invalid_index_format:
3770b57cec5SDimitry Andric     Context.getDiagnostics().Report(diag::err_extdefmap_parsing)
3780b57cec5SDimitry Andric         << IE.getFileName() << IE.getLineNum();
3790b57cec5SDimitry Andric     break;
3800b57cec5SDimitry Andric   case index_error_code::multiple_definitions:
3810b57cec5SDimitry Andric     Context.getDiagnostics().Report(diag::err_multiple_def_index)
3820b57cec5SDimitry Andric         << IE.getLineNum();
3830b57cec5SDimitry Andric     break;
3840b57cec5SDimitry Andric   case index_error_code::triple_mismatch:
3850b57cec5SDimitry Andric     Context.getDiagnostics().Report(diag::warn_ctu_incompat_triple)
3860b57cec5SDimitry Andric         << IE.getFileName() << IE.getTripleToName() << IE.getTripleFromName();
3870b57cec5SDimitry Andric     break;
3880b57cec5SDimitry Andric   default:
3890b57cec5SDimitry Andric     break;
3900b57cec5SDimitry Andric   }
3910b57cec5SDimitry Andric }
3920b57cec5SDimitry Andric 
ASTUnitStorage(CompilerInstance & CI)393a7dea167SDimitry Andric CrossTranslationUnitContext::ASTUnitStorage::ASTUnitStorage(
3945ffd83dbSDimitry Andric     CompilerInstance &CI)
3955f757f3fSDimitry Andric     : Loader(CI, CI.getAnalyzerOpts().CTUDir,
3965f757f3fSDimitry Andric              CI.getAnalyzerOpts().CTUInvocationList),
3975ffd83dbSDimitry Andric       LoadGuard(CI.getASTContext().getLangOpts().CPlusPlus
3985f757f3fSDimitry Andric                     ? CI.getAnalyzerOpts().CTUImportCppThreshold
3995f757f3fSDimitry Andric                     : CI.getAnalyzerOpts().CTUImportThreshold) {}
400a7dea167SDimitry Andric 
401a7dea167SDimitry Andric llvm::Expected<ASTUnit *>
getASTUnitForFile(StringRef FileName,bool DisplayCTUProgress)402a7dea167SDimitry Andric CrossTranslationUnitContext::ASTUnitStorage::getASTUnitForFile(
403a7dea167SDimitry Andric     StringRef FileName, bool DisplayCTUProgress) {
404a7dea167SDimitry Andric   // Try the cache first.
405a7dea167SDimitry Andric   auto ASTCacheEntry = FileASTUnitMap.find(FileName);
406a7dea167SDimitry Andric   if (ASTCacheEntry == FileASTUnitMap.end()) {
407a7dea167SDimitry Andric 
408a7dea167SDimitry Andric     // Do not load if the limit is reached.
409a7dea167SDimitry Andric     if (!LoadGuard) {
410a7dea167SDimitry Andric       ++NumASTLoadThresholdReached;
411a7dea167SDimitry Andric       return llvm::make_error<IndexError>(
412a7dea167SDimitry Andric           index_error_code::load_threshold_reached);
413a7dea167SDimitry Andric     }
414a7dea167SDimitry Andric 
4155ffd83dbSDimitry Andric     auto LoadAttempt = Loader.load(FileName);
4165ffd83dbSDimitry Andric 
4175ffd83dbSDimitry Andric     if (!LoadAttempt)
4185ffd83dbSDimitry Andric       return LoadAttempt.takeError();
4195ffd83dbSDimitry Andric 
4205ffd83dbSDimitry Andric     std::unique_ptr<ASTUnit> LoadedUnit = std::move(LoadAttempt.get());
421a7dea167SDimitry Andric 
422a7dea167SDimitry Andric     // Need the raw pointer and the unique_ptr as well.
423a7dea167SDimitry Andric     ASTUnit *Unit = LoadedUnit.get();
424a7dea167SDimitry Andric 
425a7dea167SDimitry Andric     // Update the cache.
426a7dea167SDimitry Andric     FileASTUnitMap[FileName] = std::move(LoadedUnit);
427a7dea167SDimitry Andric 
428a7dea167SDimitry Andric     LoadGuard.indicateLoadSuccess();
429a7dea167SDimitry Andric 
430a7dea167SDimitry Andric     if (DisplayCTUProgress)
431a7dea167SDimitry Andric       llvm::errs() << "CTU loaded AST file: " << FileName << "\n";
432a7dea167SDimitry Andric 
433a7dea167SDimitry Andric     return Unit;
434a7dea167SDimitry Andric 
435a7dea167SDimitry Andric   } else {
436a7dea167SDimitry Andric     // Found in the cache.
437a7dea167SDimitry Andric     return ASTCacheEntry->second.get();
438a7dea167SDimitry Andric   }
439a7dea167SDimitry Andric }
440a7dea167SDimitry Andric 
441a7dea167SDimitry Andric llvm::Expected<ASTUnit *>
getASTUnitForFunction(StringRef FunctionName,StringRef CrossTUDir,StringRef IndexName,bool DisplayCTUProgress)442a7dea167SDimitry Andric CrossTranslationUnitContext::ASTUnitStorage::getASTUnitForFunction(
443a7dea167SDimitry Andric     StringRef FunctionName, StringRef CrossTUDir, StringRef IndexName,
444a7dea167SDimitry Andric     bool DisplayCTUProgress) {
445a7dea167SDimitry Andric   // Try the cache first.
446a7dea167SDimitry Andric   auto ASTCacheEntry = NameASTUnitMap.find(FunctionName);
447a7dea167SDimitry Andric   if (ASTCacheEntry == NameASTUnitMap.end()) {
448a7dea167SDimitry Andric     // Load the ASTUnit from the pre-dumped AST file specified by ASTFileName.
449a7dea167SDimitry Andric 
450a7dea167SDimitry Andric     // Ensure that the Index is loaded, as we need to search in it.
451a7dea167SDimitry Andric     if (llvm::Error IndexLoadError =
452a7dea167SDimitry Andric             ensureCTUIndexLoaded(CrossTUDir, IndexName))
453a7dea167SDimitry Andric       return std::move(IndexLoadError);
454a7dea167SDimitry Andric 
45581ad6265SDimitry Andric     // Check if there is an entry in the index for the function.
456a7dea167SDimitry Andric     if (!NameFileMap.count(FunctionName)) {
457a7dea167SDimitry Andric       ++NumNotInOtherTU;
458a7dea167SDimitry Andric       return llvm::make_error<IndexError>(index_error_code::missing_definition);
459a7dea167SDimitry Andric     }
460a7dea167SDimitry Andric 
461bdd1243dSDimitry Andric     // Search in the index for the filename where the definition of FunctionName
462a7dea167SDimitry Andric     // resides.
463a7dea167SDimitry Andric     if (llvm::Expected<ASTUnit *> FoundForFile =
464a7dea167SDimitry Andric             getASTUnitForFile(NameFileMap[FunctionName], DisplayCTUProgress)) {
465a7dea167SDimitry Andric 
466a7dea167SDimitry Andric       // Update the cache.
467a7dea167SDimitry Andric       NameASTUnitMap[FunctionName] = *FoundForFile;
468a7dea167SDimitry Andric       return *FoundForFile;
469a7dea167SDimitry Andric 
470a7dea167SDimitry Andric     } else {
471a7dea167SDimitry Andric       return FoundForFile.takeError();
472a7dea167SDimitry Andric     }
473a7dea167SDimitry Andric   } else {
474a7dea167SDimitry Andric     // Found in the cache.
475a7dea167SDimitry Andric     return ASTCacheEntry->second;
476a7dea167SDimitry Andric   }
477a7dea167SDimitry Andric }
478a7dea167SDimitry Andric 
479a7dea167SDimitry Andric llvm::Expected<std::string>
getFileForFunction(StringRef FunctionName,StringRef CrossTUDir,StringRef IndexName)480a7dea167SDimitry Andric CrossTranslationUnitContext::ASTUnitStorage::getFileForFunction(
481a7dea167SDimitry Andric     StringRef FunctionName, StringRef CrossTUDir, StringRef IndexName) {
482a7dea167SDimitry Andric   if (llvm::Error IndexLoadError = ensureCTUIndexLoaded(CrossTUDir, IndexName))
483a7dea167SDimitry Andric     return std::move(IndexLoadError);
484a7dea167SDimitry Andric   return NameFileMap[FunctionName];
485a7dea167SDimitry Andric }
486a7dea167SDimitry Andric 
ensureCTUIndexLoaded(StringRef CrossTUDir,StringRef IndexName)487a7dea167SDimitry Andric llvm::Error CrossTranslationUnitContext::ASTUnitStorage::ensureCTUIndexLoaded(
488a7dea167SDimitry Andric     StringRef CrossTUDir, StringRef IndexName) {
489a7dea167SDimitry Andric   // Dont initialize if the map is filled.
490a7dea167SDimitry Andric   if (!NameFileMap.empty())
491a7dea167SDimitry Andric     return llvm::Error::success();
492a7dea167SDimitry Andric 
493a7dea167SDimitry Andric   // Get the absolute path to the index file.
494a7dea167SDimitry Andric   SmallString<256> IndexFile = CrossTUDir;
495a7dea167SDimitry Andric   if (llvm::sys::path::is_absolute(IndexName))
496a7dea167SDimitry Andric     IndexFile = IndexName;
497a7dea167SDimitry Andric   else
498a7dea167SDimitry Andric     llvm::sys::path::append(IndexFile, IndexName);
499a7dea167SDimitry Andric 
5005ffd83dbSDimitry Andric   if (auto IndexMapping = parseCrossTUIndex(IndexFile)) {
501a7dea167SDimitry Andric     // Initialize member map.
502a7dea167SDimitry Andric     NameFileMap = *IndexMapping;
503a7dea167SDimitry Andric     return llvm::Error::success();
504a7dea167SDimitry Andric   } else {
505a7dea167SDimitry Andric     // Error while parsing CrossTU index file.
506a7dea167SDimitry Andric     return IndexMapping.takeError();
507a7dea167SDimitry Andric   };
508a7dea167SDimitry Andric }
509a7dea167SDimitry Andric 
loadExternalAST(StringRef LookupName,StringRef CrossTUDir,StringRef IndexName,bool DisplayCTUProgress)5100b57cec5SDimitry Andric llvm::Expected<ASTUnit *> CrossTranslationUnitContext::loadExternalAST(
5110b57cec5SDimitry Andric     StringRef LookupName, StringRef CrossTUDir, StringRef IndexName,
5120b57cec5SDimitry Andric     bool DisplayCTUProgress) {
5130b57cec5SDimitry Andric   // FIXME: The current implementation only supports loading decls with
5140b57cec5SDimitry Andric   //        a lookup name from a single translation unit. If multiple
5150b57cec5SDimitry Andric   //        translation units contains decls with the same lookup name an
5160b57cec5SDimitry Andric   //        error will be returned.
5170b57cec5SDimitry Andric 
518a7dea167SDimitry Andric   // Try to get the value from the heavily cached storage.
519a7dea167SDimitry Andric   llvm::Expected<ASTUnit *> Unit = ASTStorage.getASTUnitForFunction(
520a7dea167SDimitry Andric       LookupName, CrossTUDir, IndexName, DisplayCTUProgress);
5210b57cec5SDimitry Andric 
5220b57cec5SDimitry Andric   if (!Unit)
523a7dea167SDimitry Andric     return Unit.takeError();
524a7dea167SDimitry Andric 
525a7dea167SDimitry Andric   // Check whether the backing pointer of the Expected is a nullptr.
526a7dea167SDimitry Andric   if (!*Unit)
5270b57cec5SDimitry Andric     return llvm::make_error<IndexError>(
5280b57cec5SDimitry Andric         index_error_code::failed_to_get_external_ast);
529a7dea167SDimitry Andric 
5300b57cec5SDimitry Andric   return Unit;
5310b57cec5SDimitry Andric }
5320b57cec5SDimitry Andric 
ASTLoader(CompilerInstance & CI,StringRef CTUDir,StringRef InvocationListFilePath)5335ffd83dbSDimitry Andric CrossTranslationUnitContext::ASTLoader::ASTLoader(
5345ffd83dbSDimitry Andric     CompilerInstance &CI, StringRef CTUDir, StringRef InvocationListFilePath)
5355ffd83dbSDimitry Andric     : CI(CI), CTUDir(CTUDir), InvocationListFilePath(InvocationListFilePath) {}
5365ffd83dbSDimitry Andric 
5375ffd83dbSDimitry Andric CrossTranslationUnitContext::LoadResultTy
load(StringRef Identifier)5385ffd83dbSDimitry Andric CrossTranslationUnitContext::ASTLoader::load(StringRef Identifier) {
5395ffd83dbSDimitry Andric   llvm::SmallString<256> Path;
5405ffd83dbSDimitry Andric   if (llvm::sys::path::is_absolute(Identifier, PathStyle)) {
5415ffd83dbSDimitry Andric     Path = Identifier;
5425ffd83dbSDimitry Andric   } else {
5435ffd83dbSDimitry Andric     Path = CTUDir;
5445ffd83dbSDimitry Andric     llvm::sys::path::append(Path, PathStyle, Identifier);
5455ffd83dbSDimitry Andric   }
5465ffd83dbSDimitry Andric 
5475ffd83dbSDimitry Andric   // The path is stored in the InvocationList member in posix style. To
5485ffd83dbSDimitry Andric   // successfully lookup an entry based on filepath, it must be converted.
5495ffd83dbSDimitry Andric   llvm::sys::path::native(Path, PathStyle);
5505ffd83dbSDimitry Andric 
5515ffd83dbSDimitry Andric   // Normalize by removing relative path components.
5525ffd83dbSDimitry Andric   llvm::sys::path::remove_dots(Path, /*remove_dot_dot*/ true, PathStyle);
5535ffd83dbSDimitry Andric 
5545f757f3fSDimitry Andric   if (Path.ends_with(".ast"))
5555ffd83dbSDimitry Andric     return loadFromDump(Path);
5565ffd83dbSDimitry Andric   else
5575ffd83dbSDimitry Andric     return loadFromSource(Path);
5585ffd83dbSDimitry Andric }
5595ffd83dbSDimitry Andric 
5605ffd83dbSDimitry Andric CrossTranslationUnitContext::LoadResultTy
loadFromDump(StringRef ASTDumpPath)5615ffd83dbSDimitry Andric CrossTranslationUnitContext::ASTLoader::loadFromDump(StringRef ASTDumpPath) {
5625ffd83dbSDimitry Andric   IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
5635ffd83dbSDimitry Andric   TextDiagnosticPrinter *DiagClient =
5645ffd83dbSDimitry Andric       new TextDiagnosticPrinter(llvm::errs(), &*DiagOpts);
5655ffd83dbSDimitry Andric   IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
5665ffd83dbSDimitry Andric   IntrusiveRefCntPtr<DiagnosticsEngine> Diags(
5675ffd83dbSDimitry Andric       new DiagnosticsEngine(DiagID, &*DiagOpts, DiagClient));
5685ffd83dbSDimitry Andric   return ASTUnit::LoadFromASTFile(
5695ffd83dbSDimitry Andric       std::string(ASTDumpPath.str()),
5705ffd83dbSDimitry Andric       CI.getPCHContainerOperations()->getRawReader(), ASTUnit::LoadEverything,
57106c3fb27SDimitry Andric       Diags, CI.getFileSystemOpts(), CI.getHeaderSearchOptsPtr());
5725ffd83dbSDimitry Andric }
5735ffd83dbSDimitry Andric 
5745ffd83dbSDimitry Andric /// Load the AST from a source-file, which is supposed to be located inside the
5755ffd83dbSDimitry Andric /// YAML formatted invocation list file under the filesystem path specified by
5765ffd83dbSDimitry Andric /// \p InvocationList. The invocation list should contain absolute paths.
5775ffd83dbSDimitry Andric /// \p SourceFilePath is the absolute path of the source file that contains the
5785ffd83dbSDimitry Andric /// function definition the analysis is looking for. The Index is built by the
5795ffd83dbSDimitry Andric /// \p clang-extdef-mapping tool, which is also supposed to be generating
5805ffd83dbSDimitry Andric /// absolute paths.
5815ffd83dbSDimitry Andric ///
5825ffd83dbSDimitry Andric /// Proper diagnostic emission requires absolute paths, so even if a future
5835ffd83dbSDimitry Andric /// change introduces the handling of relative paths, this must be taken into
5845ffd83dbSDimitry Andric /// consideration.
5855ffd83dbSDimitry Andric CrossTranslationUnitContext::LoadResultTy
loadFromSource(StringRef SourceFilePath)5865ffd83dbSDimitry Andric CrossTranslationUnitContext::ASTLoader::loadFromSource(
5875ffd83dbSDimitry Andric     StringRef SourceFilePath) {
5885ffd83dbSDimitry Andric 
5895ffd83dbSDimitry Andric   if (llvm::Error InitError = lazyInitInvocationList())
5905ffd83dbSDimitry Andric     return std::move(InitError);
5915ffd83dbSDimitry Andric   assert(InvocationList);
5925ffd83dbSDimitry Andric 
5935ffd83dbSDimitry Andric   auto Invocation = InvocationList->find(SourceFilePath);
5945ffd83dbSDimitry Andric   if (Invocation == InvocationList->end())
5955ffd83dbSDimitry Andric     return llvm::make_error<IndexError>(
5965ffd83dbSDimitry Andric         index_error_code::invocation_list_lookup_unsuccessful);
5975ffd83dbSDimitry Andric 
5985ffd83dbSDimitry Andric   const InvocationListTy::mapped_type &InvocationCommand = Invocation->second;
5995ffd83dbSDimitry Andric 
6005ffd83dbSDimitry Andric   SmallVector<const char *, 32> CommandLineArgs(InvocationCommand.size());
6015ffd83dbSDimitry Andric   std::transform(InvocationCommand.begin(), InvocationCommand.end(),
6025ffd83dbSDimitry Andric                  CommandLineArgs.begin(),
6035ffd83dbSDimitry Andric                  [](auto &&CmdPart) { return CmdPart.c_str(); });
6045ffd83dbSDimitry Andric 
6055ffd83dbSDimitry Andric   IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts{&CI.getDiagnosticOpts()};
6065ffd83dbSDimitry Andric   auto *DiagClient = new ForwardingDiagnosticConsumer{CI.getDiagnosticClient()};
6075ffd83dbSDimitry Andric   IntrusiveRefCntPtr<DiagnosticIDs> DiagID{
6085ffd83dbSDimitry Andric       CI.getDiagnostics().getDiagnosticIDs()};
6095ffd83dbSDimitry Andric   IntrusiveRefCntPtr<DiagnosticsEngine> Diags(
6105ffd83dbSDimitry Andric       new DiagnosticsEngine{DiagID, &*DiagOpts, DiagClient});
6115ffd83dbSDimitry Andric 
61206c3fb27SDimitry Andric   return ASTUnit::LoadFromCommandLine(CommandLineArgs.begin(),
61306c3fb27SDimitry Andric                                       (CommandLineArgs.end()),
6145ffd83dbSDimitry Andric                                       CI.getPCHContainerOperations(), Diags,
61506c3fb27SDimitry Andric                                       CI.getHeaderSearchOpts().ResourceDir);
6165ffd83dbSDimitry Andric }
6175ffd83dbSDimitry Andric 
6185ffd83dbSDimitry Andric llvm::Expected<InvocationListTy>
parseInvocationList(StringRef FileContent,llvm::sys::path::Style PathStyle)6195ffd83dbSDimitry Andric parseInvocationList(StringRef FileContent, llvm::sys::path::Style PathStyle) {
6205ffd83dbSDimitry Andric   InvocationListTy InvocationList;
6215ffd83dbSDimitry Andric 
6225ffd83dbSDimitry Andric   /// LLVM YAML parser is used to extract information from invocation list file.
6235ffd83dbSDimitry Andric   llvm::SourceMgr SM;
6245ffd83dbSDimitry Andric   llvm::yaml::Stream InvocationFile(FileContent, SM);
6255ffd83dbSDimitry Andric 
6265ffd83dbSDimitry Andric   /// Only the first document is processed.
6275ffd83dbSDimitry Andric   llvm::yaml::document_iterator FirstInvocationFile = InvocationFile.begin();
6285ffd83dbSDimitry Andric 
6295ffd83dbSDimitry Andric   /// There has to be at least one document available.
6305ffd83dbSDimitry Andric   if (FirstInvocationFile == InvocationFile.end())
6315ffd83dbSDimitry Andric     return llvm::make_error<IndexError>(
6325ffd83dbSDimitry Andric         index_error_code::invocation_list_empty);
6335ffd83dbSDimitry Andric 
6345ffd83dbSDimitry Andric   llvm::yaml::Node *DocumentRoot = FirstInvocationFile->getRoot();
6355ffd83dbSDimitry Andric   if (!DocumentRoot)
6365ffd83dbSDimitry Andric     return llvm::make_error<IndexError>(
6375ffd83dbSDimitry Andric         index_error_code::invocation_list_wrong_format);
6385ffd83dbSDimitry Andric 
6395ffd83dbSDimitry Andric   /// According to the format specified the document must be a mapping, where
6405ffd83dbSDimitry Andric   /// the keys are paths to source files, and values are sequences of invocation
6415ffd83dbSDimitry Andric   /// parts.
6425ffd83dbSDimitry Andric   auto *Mappings = dyn_cast<llvm::yaml::MappingNode>(DocumentRoot);
6435ffd83dbSDimitry Andric   if (!Mappings)
6445ffd83dbSDimitry Andric     return llvm::make_error<IndexError>(
6455ffd83dbSDimitry Andric         index_error_code::invocation_list_wrong_format);
6465ffd83dbSDimitry Andric 
6475ffd83dbSDimitry Andric   for (auto &NextMapping : *Mappings) {
6485ffd83dbSDimitry Andric     /// The keys should be strings, which represent a source-file path.
6495ffd83dbSDimitry Andric     auto *Key = dyn_cast<llvm::yaml::ScalarNode>(NextMapping.getKey());
6505ffd83dbSDimitry Andric     if (!Key)
6515ffd83dbSDimitry Andric       return llvm::make_error<IndexError>(
6525ffd83dbSDimitry Andric           index_error_code::invocation_list_wrong_format);
6535ffd83dbSDimitry Andric 
654e8d8bef9SDimitry Andric     SmallString<32> ValueStorage;
6555ffd83dbSDimitry Andric     StringRef SourcePath = Key->getValue(ValueStorage);
6565ffd83dbSDimitry Andric 
6575ffd83dbSDimitry Andric     // Store paths with PathStyle directory separator.
658e8d8bef9SDimitry Andric     SmallString<32> NativeSourcePath(SourcePath);
6595ffd83dbSDimitry Andric     llvm::sys::path::native(NativeSourcePath, PathStyle);
6605ffd83dbSDimitry Andric 
661fe6060f1SDimitry Andric     StringRef InvocationKey = NativeSourcePath;
6625ffd83dbSDimitry Andric 
66306c3fb27SDimitry Andric     if (InvocationList.contains(InvocationKey))
6645ffd83dbSDimitry Andric       return llvm::make_error<IndexError>(
6655ffd83dbSDimitry Andric           index_error_code::invocation_list_ambiguous);
6665ffd83dbSDimitry Andric 
6675ffd83dbSDimitry Andric     /// The values should be sequences of strings, each representing a part of
6685ffd83dbSDimitry Andric     /// the invocation.
6695ffd83dbSDimitry Andric     auto *Args = dyn_cast<llvm::yaml::SequenceNode>(NextMapping.getValue());
6705ffd83dbSDimitry Andric     if (!Args)
6715ffd83dbSDimitry Andric       return llvm::make_error<IndexError>(
6725ffd83dbSDimitry Andric           index_error_code::invocation_list_wrong_format);
6735ffd83dbSDimitry Andric 
6745ffd83dbSDimitry Andric     for (auto &Arg : *Args) {
6755ffd83dbSDimitry Andric       auto *CmdString = dyn_cast<llvm::yaml::ScalarNode>(&Arg);
6765ffd83dbSDimitry Andric       if (!CmdString)
6775ffd83dbSDimitry Andric         return llvm::make_error<IndexError>(
6785ffd83dbSDimitry Andric             index_error_code::invocation_list_wrong_format);
6795ffd83dbSDimitry Andric       /// Every conversion starts with an empty working storage, as it is not
6805ffd83dbSDimitry Andric       /// clear if this is a requirement of the YAML parser.
6815ffd83dbSDimitry Andric       ValueStorage.clear();
6825ffd83dbSDimitry Andric       InvocationList[InvocationKey].emplace_back(
6835ffd83dbSDimitry Andric           CmdString->getValue(ValueStorage));
6845ffd83dbSDimitry Andric     }
6855ffd83dbSDimitry Andric 
6865ffd83dbSDimitry Andric     if (InvocationList[InvocationKey].empty())
6875ffd83dbSDimitry Andric       return llvm::make_error<IndexError>(
6885ffd83dbSDimitry Andric           index_error_code::invocation_list_wrong_format);
6895ffd83dbSDimitry Andric   }
6905ffd83dbSDimitry Andric 
6915ffd83dbSDimitry Andric   return InvocationList;
6925ffd83dbSDimitry Andric }
6935ffd83dbSDimitry Andric 
lazyInitInvocationList()6945ffd83dbSDimitry Andric llvm::Error CrossTranslationUnitContext::ASTLoader::lazyInitInvocationList() {
6955ffd83dbSDimitry Andric   /// Lazily initialize the invocation list member used for on-demand parsing.
6965ffd83dbSDimitry Andric   if (InvocationList)
6975ffd83dbSDimitry Andric     return llvm::Error::success();
698fe6060f1SDimitry Andric   if (index_error_code::success != PreviousParsingResult)
699fe6060f1SDimitry Andric     return llvm::make_error<IndexError>(PreviousParsingResult);
7005ffd83dbSDimitry Andric 
7015ffd83dbSDimitry Andric   llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> FileContent =
7025ffd83dbSDimitry Andric       llvm::MemoryBuffer::getFile(InvocationListFilePath);
703fe6060f1SDimitry Andric   if (!FileContent) {
704fe6060f1SDimitry Andric     PreviousParsingResult = index_error_code::invocation_list_file_not_found;
705fe6060f1SDimitry Andric     return llvm::make_error<IndexError>(PreviousParsingResult);
706fe6060f1SDimitry Andric   }
7075ffd83dbSDimitry Andric   std::unique_ptr<llvm::MemoryBuffer> ContentBuffer = std::move(*FileContent);
7085ffd83dbSDimitry Andric   assert(ContentBuffer && "If no error was produced after loading, the pointer "
7095ffd83dbSDimitry Andric                           "should not be nullptr.");
7105ffd83dbSDimitry Andric 
7115ffd83dbSDimitry Andric   llvm::Expected<InvocationListTy> ExpectedInvocationList =
7125ffd83dbSDimitry Andric       parseInvocationList(ContentBuffer->getBuffer(), PathStyle);
7135ffd83dbSDimitry Andric 
714fe6060f1SDimitry Andric   // Handle the error to store the code for next call to this function.
715fe6060f1SDimitry Andric   if (!ExpectedInvocationList) {
716fe6060f1SDimitry Andric     llvm::handleAllErrors(
717fe6060f1SDimitry Andric         ExpectedInvocationList.takeError(),
718fe6060f1SDimitry Andric         [&](const IndexError &E) { PreviousParsingResult = E.getCode(); });
719fe6060f1SDimitry Andric     return llvm::make_error<IndexError>(PreviousParsingResult);
720fe6060f1SDimitry Andric   }
7215ffd83dbSDimitry Andric 
7225ffd83dbSDimitry Andric   InvocationList = *ExpectedInvocationList;
7235ffd83dbSDimitry Andric 
7245ffd83dbSDimitry Andric   return llvm::Error::success();
7255ffd83dbSDimitry Andric }
7265ffd83dbSDimitry Andric 
7270b57cec5SDimitry Andric template <typename T>
7280b57cec5SDimitry Andric llvm::Expected<const T *>
importDefinitionImpl(const T * D,ASTUnit * Unit)729a7dea167SDimitry Andric CrossTranslationUnitContext::importDefinitionImpl(const T *D, ASTUnit *Unit) {
7300b57cec5SDimitry Andric   assert(hasBodyOrInit(D) && "Decls to be imported should have body or init.");
7310b57cec5SDimitry Andric 
732a7dea167SDimitry Andric   assert(&D->getASTContext() == &Unit->getASTContext() &&
733a7dea167SDimitry Andric          "ASTContext of Decl and the unit should match.");
734a7dea167SDimitry Andric   ASTImporter &Importer = getOrCreateASTImporter(Unit);
735a7dea167SDimitry Andric 
7360b57cec5SDimitry Andric   auto ToDeclOrError = Importer.Import(D);
7370b57cec5SDimitry Andric   if (!ToDeclOrError) {
73881ad6265SDimitry Andric     handleAllErrors(ToDeclOrError.takeError(), [&](const ASTImportError &IE) {
7390b57cec5SDimitry Andric       switch (IE.Error) {
74081ad6265SDimitry Andric       case ASTImportError::NameConflict:
7410b57cec5SDimitry Andric         ++NumNameConflicts;
7420b57cec5SDimitry Andric         break;
74381ad6265SDimitry Andric       case ASTImportError::UnsupportedConstruct:
7440b57cec5SDimitry Andric         ++NumUnsupportedNodeFound;
7450b57cec5SDimitry Andric         break;
74681ad6265SDimitry Andric       case ASTImportError::Unknown:
7470b57cec5SDimitry Andric         llvm_unreachable("Unknown import error happened.");
7480b57cec5SDimitry Andric         break;
7490b57cec5SDimitry Andric       }
7500b57cec5SDimitry Andric     });
7510b57cec5SDimitry Andric     return llvm::make_error<IndexError>(index_error_code::failed_import);
7520b57cec5SDimitry Andric   }
7530b57cec5SDimitry Andric   auto *ToDecl = cast<T>(*ToDeclOrError);
7540b57cec5SDimitry Andric   assert(hasBodyOrInit(ToDecl) && "Imported Decl should have body or init.");
7550b57cec5SDimitry Andric   ++NumGetCTUSuccess;
7560b57cec5SDimitry Andric 
7575ffd83dbSDimitry Andric   // Parent map is invalidated after changing the AST.
7585ffd83dbSDimitry Andric   ToDecl->getASTContext().getParentMapContext().clear();
7595ffd83dbSDimitry Andric 
7600b57cec5SDimitry Andric   return ToDecl;
7610b57cec5SDimitry Andric }
7620b57cec5SDimitry Andric 
7630b57cec5SDimitry Andric llvm::Expected<const FunctionDecl *>
importDefinition(const FunctionDecl * FD,ASTUnit * Unit)764a7dea167SDimitry Andric CrossTranslationUnitContext::importDefinition(const FunctionDecl *FD,
765a7dea167SDimitry Andric                                               ASTUnit *Unit) {
766a7dea167SDimitry Andric   return importDefinitionImpl(FD, Unit);
7670b57cec5SDimitry Andric }
7680b57cec5SDimitry Andric 
7690b57cec5SDimitry Andric llvm::Expected<const VarDecl *>
importDefinition(const VarDecl * VD,ASTUnit * Unit)770a7dea167SDimitry Andric CrossTranslationUnitContext::importDefinition(const VarDecl *VD,
771a7dea167SDimitry Andric                                               ASTUnit *Unit) {
772a7dea167SDimitry Andric   return importDefinitionImpl(VD, Unit);
7730b57cec5SDimitry Andric }
7740b57cec5SDimitry Andric 
lazyInitImporterSharedSt(TranslationUnitDecl * ToTU)7750b57cec5SDimitry Andric void CrossTranslationUnitContext::lazyInitImporterSharedSt(
7760b57cec5SDimitry Andric     TranslationUnitDecl *ToTU) {
7770b57cec5SDimitry Andric   if (!ImporterSharedSt)
7780b57cec5SDimitry Andric     ImporterSharedSt = std::make_shared<ASTImporterSharedState>(*ToTU);
7790b57cec5SDimitry Andric }
7800b57cec5SDimitry Andric 
7810b57cec5SDimitry Andric ASTImporter &
getOrCreateASTImporter(ASTUnit * Unit)782a7dea167SDimitry Andric CrossTranslationUnitContext::getOrCreateASTImporter(ASTUnit *Unit) {
783a7dea167SDimitry Andric   ASTContext &From = Unit->getASTContext();
784a7dea167SDimitry Andric 
7850b57cec5SDimitry Andric   auto I = ASTUnitImporterMap.find(From.getTranslationUnitDecl());
7860b57cec5SDimitry Andric   if (I != ASTUnitImporterMap.end())
7870b57cec5SDimitry Andric     return *I->second;
7880b57cec5SDimitry Andric   lazyInitImporterSharedSt(Context.getTranslationUnitDecl());
7890b57cec5SDimitry Andric   ASTImporter *NewImporter = new ASTImporter(
7900b57cec5SDimitry Andric       Context, Context.getSourceManager().getFileManager(), From,
7910b57cec5SDimitry Andric       From.getSourceManager().getFileManager(), false, ImporterSharedSt);
7920b57cec5SDimitry Andric   ASTUnitImporterMap[From.getTranslationUnitDecl()].reset(NewImporter);
7930b57cec5SDimitry Andric   return *NewImporter;
7940b57cec5SDimitry Andric }
7950b57cec5SDimitry Andric 
796bdd1243dSDimitry Andric std::optional<clang::MacroExpansionContext>
getMacroExpansionContextForSourceLocation(const clang::SourceLocation & ToLoc) const797fe6060f1SDimitry Andric CrossTranslationUnitContext::getMacroExpansionContextForSourceLocation(
798a7dea167SDimitry Andric     const clang::SourceLocation &ToLoc) const {
799fe6060f1SDimitry Andric   // FIXME: Implement: Record such a context for every imported ASTUnit; lookup.
800bdd1243dSDimitry Andric   return std::nullopt;
801a7dea167SDimitry Andric }
802a7dea167SDimitry Andric 
isImportedAsNew(const Decl * ToDecl) const80381ad6265SDimitry Andric bool CrossTranslationUnitContext::isImportedAsNew(const Decl *ToDecl) const {
80481ad6265SDimitry Andric   if (!ImporterSharedSt)
80581ad6265SDimitry Andric     return false;
80681ad6265SDimitry Andric   return ImporterSharedSt->isNewDecl(const_cast<Decl *>(ToDecl));
80781ad6265SDimitry Andric }
80881ad6265SDimitry Andric 
hasError(const Decl * ToDecl) const80981ad6265SDimitry Andric bool CrossTranslationUnitContext::hasError(const Decl *ToDecl) const {
81081ad6265SDimitry Andric   if (!ImporterSharedSt)
81181ad6265SDimitry Andric     return false;
81281ad6265SDimitry Andric   return static_cast<bool>(
81381ad6265SDimitry Andric       ImporterSharedSt->getImportDeclErrorIfAny(const_cast<Decl *>(ToDecl)));
81481ad6265SDimitry Andric }
81581ad6265SDimitry Andric 
8160b57cec5SDimitry Andric } // namespace cross_tu
8170b57cec5SDimitry Andric } // namespace clang
818