1e350b0a1SGabor Horvath //===--- CrossTranslationUnit.cpp - -----------------------------*- C++ -*-===// 2e350b0a1SGabor Horvath // 32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information. 52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6e350b0a1SGabor Horvath // 7e350b0a1SGabor Horvath //===----------------------------------------------------------------------===// 8e350b0a1SGabor Horvath // 9e350b0a1SGabor Horvath // This file implements the CrossTranslationUnit interface. 10e350b0a1SGabor Horvath // 11e350b0a1SGabor Horvath //===----------------------------------------------------------------------===// 12e350b0a1SGabor Horvath #include "clang/CrossTU/CrossTranslationUnit.h" 13e350b0a1SGabor Horvath #include "clang/AST/ASTImporter.h" 14e350b0a1SGabor Horvath #include "clang/AST/Decl.h" 15f3b34466SBalázs Kéri #include "clang/AST/ParentMapContext.h" 16e350b0a1SGabor Horvath #include "clang/Basic/TargetInfo.h" 17e350b0a1SGabor Horvath #include "clang/CrossTU/CrossTUDiagnostic.h" 18e350b0a1SGabor Horvath #include "clang/Frontend/ASTUnit.h" 19e350b0a1SGabor Horvath #include "clang/Frontend/CompilerInstance.h" 20e350b0a1SGabor Horvath #include "clang/Frontend/TextDiagnosticPrinter.h" 21e350b0a1SGabor Horvath #include "clang/Index/USRGeneration.h" 22435b458aSEndre Fülöp #include "llvm/ADT/Statistic.h" 235cc18516SEndre Fülöp #include "llvm/Option/ArgList.h" 24e350b0a1SGabor Horvath #include "llvm/Support/ErrorHandling.h" 25e350b0a1SGabor Horvath #include "llvm/Support/ManagedStatic.h" 26e350b0a1SGabor Horvath #include "llvm/Support/Path.h" 275cc18516SEndre Fülöp #include "llvm/Support/YAMLParser.h" 28e350b0a1SGabor Horvath #include "llvm/Support/raw_ostream.h" 2962c7f035SArchibald Elliott #include "llvm/TargetParser/Triple.h" 305cc18516SEndre Fülöp #include <algorithm> 31e350b0a1SGabor Horvath #include <fstream> 32a1580d7bSKazu Hirata #include <optional> 33e350b0a1SGabor Horvath #include <sstream> 345cc18516SEndre Fülöp #include <tuple> 35e350b0a1SGabor Horvath 36e350b0a1SGabor Horvath namespace clang { 37e350b0a1SGabor Horvath namespace cross_tu { 38e350b0a1SGabor Horvath 39e350b0a1SGabor Horvath namespace { 4032aff2ebSGabor Marton 41700a29a1SGabor Marton #define DEBUG_TYPE "CrossTranslationUnit" 42700a29a1SGabor Marton STATISTIC(NumGetCTUCalled, "The # of getCTUDefinition function called"); 43700a29a1SGabor Marton STATISTIC( 44700a29a1SGabor Marton NumNotInOtherTU, 45700a29a1SGabor Marton "The # of getCTUDefinition called but the function is not in any other TU"); 46700a29a1SGabor Marton STATISTIC(NumGetCTUSuccess, 47700a29a1SGabor Marton "The # of getCTUDefinition successfully returned the " 48700a29a1SGabor Marton "requested function's body"); 498ab8a60aSGabor Marton STATISTIC(NumUnsupportedNodeFound, "The # of imports when the ASTImporter " 508ab8a60aSGabor Marton "encountered an unsupported AST Node"); 518ab8a60aSGabor Marton STATISTIC(NumNameConflicts, "The # of imports when the ASTImporter " 528ab8a60aSGabor Marton "encountered an ODR error"); 5332aff2ebSGabor Marton STATISTIC(NumTripleMismatch, "The # of triple mismatches"); 5432aff2ebSGabor Marton STATISTIC(NumLangMismatch, "The # of language mismatches"); 55a006b80aSGabor Marton STATISTIC(NumLangDialectMismatch, "The # of language dialect mismatches"); 560752d12cSEndre Fulop STATISTIC(NumASTLoadThresholdReached, 570752d12cSEndre Fulop "The # of ASTs not loaded because of threshold"); 5832aff2ebSGabor Marton 5932aff2ebSGabor Marton // Same as Triple's equality operator, but we check a field only if that is 6032aff2ebSGabor Marton // known in both instances. 6132aff2ebSGabor Marton bool hasEqualKnownFields(const llvm::Triple &Lhs, const llvm::Triple &Rhs) { 6232aff2ebSGabor Marton using llvm::Triple; 6332aff2ebSGabor Marton if (Lhs.getArch() != Triple::UnknownArch && 6432aff2ebSGabor Marton Rhs.getArch() != Triple::UnknownArch && Lhs.getArch() != Rhs.getArch()) 6532aff2ebSGabor Marton return false; 6632aff2ebSGabor Marton if (Lhs.getSubArch() != Triple::NoSubArch && 6732aff2ebSGabor Marton Rhs.getSubArch() != Triple::NoSubArch && 6832aff2ebSGabor Marton Lhs.getSubArch() != Rhs.getSubArch()) 6932aff2ebSGabor Marton return false; 7032aff2ebSGabor Marton if (Lhs.getVendor() != Triple::UnknownVendor && 7132aff2ebSGabor Marton Rhs.getVendor() != Triple::UnknownVendor && 7232aff2ebSGabor Marton Lhs.getVendor() != Rhs.getVendor()) 7332aff2ebSGabor Marton return false; 7432aff2ebSGabor Marton if (!Lhs.isOSUnknown() && !Rhs.isOSUnknown() && 7532aff2ebSGabor Marton Lhs.getOS() != Rhs.getOS()) 7632aff2ebSGabor Marton return false; 7732aff2ebSGabor Marton if (Lhs.getEnvironment() != Triple::UnknownEnvironment && 7832aff2ebSGabor Marton Rhs.getEnvironment() != Triple::UnknownEnvironment && 7932aff2ebSGabor Marton Lhs.getEnvironment() != Rhs.getEnvironment()) 8032aff2ebSGabor Marton return false; 8132aff2ebSGabor Marton if (Lhs.getObjectFormat() != Triple::UnknownObjectFormat && 8232aff2ebSGabor Marton Rhs.getObjectFormat() != Triple::UnknownObjectFormat && 8332aff2ebSGabor Marton Lhs.getObjectFormat() != Rhs.getObjectFormat()) 8432aff2ebSGabor Marton return false; 8532aff2ebSGabor Marton return true; 8632aff2ebSGabor Marton } 87700a29a1SGabor Marton 88e350b0a1SGabor Horvath // FIXME: This class is will be removed after the transition to llvm::Error. 89e350b0a1SGabor Horvath class IndexErrorCategory : public std::error_category { 90e350b0a1SGabor Horvath public: 91e350b0a1SGabor Horvath const char *name() const noexcept override { return "clang.index"; } 92e350b0a1SGabor Horvath 93e350b0a1SGabor Horvath std::string message(int Condition) const override { 94e350b0a1SGabor Horvath switch (static_cast<index_error_code>(Condition)) { 95d59b4acfSElla Ma case index_error_code::success: 96d59b4acfSElla Ma // There should not be a success error. Jump to unreachable directly. 97d59b4acfSElla Ma // Add this case to make the compiler stop complaining. 98d59b4acfSElla Ma break; 99e350b0a1SGabor Horvath case index_error_code::unspecified: 100e350b0a1SGabor Horvath return "An unknown error has occurred."; 101e350b0a1SGabor Horvath case index_error_code::missing_index_file: 102e350b0a1SGabor Horvath return "The index file is missing."; 103e350b0a1SGabor Horvath case index_error_code::invalid_index_format: 104e350b0a1SGabor Horvath return "Invalid index file format."; 105e350b0a1SGabor Horvath case index_error_code::multiple_definitions: 106e350b0a1SGabor Horvath return "Multiple definitions in the index file."; 107e350b0a1SGabor Horvath case index_error_code::missing_definition: 108e350b0a1SGabor Horvath return "Missing definition from the index file."; 109e350b0a1SGabor Horvath case index_error_code::failed_import: 110e350b0a1SGabor Horvath return "Failed to import the definition."; 111e350b0a1SGabor Horvath case index_error_code::failed_to_get_external_ast: 112e350b0a1SGabor Horvath return "Failed to load external AST source."; 113e350b0a1SGabor Horvath case index_error_code::failed_to_generate_usr: 114e350b0a1SGabor Horvath return "Failed to generate USR."; 11532aff2ebSGabor Marton case index_error_code::triple_mismatch: 11632aff2ebSGabor Marton return "Triple mismatch"; 11732aff2ebSGabor Marton case index_error_code::lang_mismatch: 11832aff2ebSGabor Marton return "Language mismatch"; 119a006b80aSGabor Marton case index_error_code::lang_dialect_mismatch: 120a006b80aSGabor Marton return "Language dialect mismatch"; 1210752d12cSEndre Fulop case index_error_code::load_threshold_reached: 1220752d12cSEndre Fulop return "Load threshold reached"; 1235cc18516SEndre Fülöp case index_error_code::invocation_list_ambiguous: 1245cc18516SEndre Fülöp return "Invocation list file contains multiple references to the same " 1255cc18516SEndre Fülöp "source file."; 1265cc18516SEndre Fülöp case index_error_code::invocation_list_file_not_found: 1275cc18516SEndre Fülöp return "Invocation list file is not found."; 1285cc18516SEndre Fülöp case index_error_code::invocation_list_empty: 1295cc18516SEndre Fülöp return "Invocation list file is empty."; 1305cc18516SEndre Fülöp case index_error_code::invocation_list_wrong_format: 1315cc18516SEndre Fülöp return "Invocation list file is in wrong format."; 1325cc18516SEndre Fülöp case index_error_code::invocation_list_lookup_unsuccessful: 1335cc18516SEndre Fülöp return "Invocation list file does not contain the requested source file."; 134e350b0a1SGabor Horvath } 135e350b0a1SGabor Horvath llvm_unreachable("Unrecognized index_error_code."); 136e350b0a1SGabor Horvath } 137e350b0a1SGabor Horvath }; 138e350b0a1SGabor Horvath 139e350b0a1SGabor Horvath static llvm::ManagedStatic<IndexErrorCategory> Category; 140e350b0a1SGabor Horvath } // end anonymous namespace 141e350b0a1SGabor Horvath 142e350b0a1SGabor Horvath char IndexError::ID; 143e350b0a1SGabor Horvath 144e350b0a1SGabor Horvath void IndexError::log(raw_ostream &OS) const { 145e350b0a1SGabor Horvath OS << Category->message(static_cast<int>(Code)) << '\n'; 146e350b0a1SGabor Horvath } 147e350b0a1SGabor Horvath 148e350b0a1SGabor Horvath std::error_code IndexError::convertToErrorCode() const { 149e350b0a1SGabor Horvath return std::error_code(static_cast<int>(Code), *Category); 150e350b0a1SGabor Horvath } 151e350b0a1SGabor Horvath 1529f902542SElla Ma /// Parse one line of the input CTU index file. 1539f902542SElla Ma /// 1549f902542SElla Ma /// @param[in] LineRef The input CTU index item in format 1559f902542SElla Ma /// "<USR-Length>:<USR> <File-Path>". 1569f902542SElla Ma /// @param[out] LookupName The lookup name in format "<USR-Length>:<USR>". 1579f902542SElla Ma /// @param[out] FilePath The file path "<File-Path>". 1589f902542SElla Ma static bool parseCrossTUIndexItem(StringRef LineRef, StringRef &LookupName, 1599f902542SElla Ma StringRef &FilePath) { 1609f902542SElla Ma // `LineRef` is "<USR-Length>:<USR> <File-Path>" now. 1619f902542SElla Ma 1629f902542SElla Ma size_t USRLength = 0; 1639f902542SElla Ma if (LineRef.consumeInteger(10, USRLength)) 1649f902542SElla Ma return false; 1659f902542SElla Ma assert(USRLength && "USRLength should be greater than zero."); 1669f902542SElla Ma 1679f902542SElla Ma if (!LineRef.consume_front(":")) 1689f902542SElla Ma return false; 1699f902542SElla Ma 1709f902542SElla Ma // `LineRef` is now just "<USR> <File-Path>". 1719f902542SElla Ma 1729f902542SElla Ma // Check LookupName length out of bound and incorrect delimiter. 1739f902542SElla Ma if (USRLength >= LineRef.size() || ' ' != LineRef[USRLength]) 1749f902542SElla Ma return false; 1759f902542SElla Ma 1769f902542SElla Ma LookupName = LineRef.substr(0, USRLength); 1779f902542SElla Ma FilePath = LineRef.substr(USRLength + 1); 1789f902542SElla Ma return true; 1799f902542SElla Ma } 1809f902542SElla Ma 181e350b0a1SGabor Horvath llvm::Expected<llvm::StringMap<std::string>> 1825cc18516SEndre Fülöp parseCrossTUIndex(StringRef IndexPath) { 183adcd0268SBenjamin Kramer std::ifstream ExternalMapFile{std::string(IndexPath)}; 1848c48705aSRafael Stahl if (!ExternalMapFile) 185e350b0a1SGabor Horvath return llvm::make_error<IndexError>(index_error_code::missing_index_file, 186e350b0a1SGabor Horvath IndexPath.str()); 187e350b0a1SGabor Horvath 188e350b0a1SGabor Horvath llvm::StringMap<std::string> Result; 189e350b0a1SGabor Horvath std::string Line; 190e350b0a1SGabor Horvath unsigned LineNo = 1; 1918c48705aSRafael Stahl while (std::getline(ExternalMapFile, Line)) { 1929f902542SElla Ma // Split lookup name and file path 1939f902542SElla Ma StringRef LookupName, FilePathInIndex; 1949f902542SElla Ma if (!parseCrossTUIndexItem(Line, LookupName, FilePathInIndex)) 1959f902542SElla Ma return llvm::make_error<IndexError>( 1969f902542SElla Ma index_error_code::invalid_index_format, IndexPath.str(), LineNo); 1975cc18516SEndre Fülöp 1985cc18516SEndre Fülöp // Store paths with posix-style directory separator. 1999f902542SElla Ma SmallString<32> FilePath(FilePathInIndex); 2005cc18516SEndre Fülöp llvm::sys::path::native(FilePath, llvm::sys::path::Style::posix); 2015cc18516SEndre Fülöp 2025cc18516SEndre Fülöp bool InsertionOccured; 2035cc18516SEndre Fülöp std::tie(std::ignore, InsertionOccured) = 2045cc18516SEndre Fülöp Result.try_emplace(LookupName, FilePath.begin(), FilePath.end()); 2055cc18516SEndre Fülöp if (!InsertionOccured) 206e350b0a1SGabor Horvath return llvm::make_error<IndexError>( 207e350b0a1SGabor Horvath index_error_code::multiple_definitions, IndexPath.str(), LineNo); 2089f902542SElla Ma 2095cc18516SEndre Fülöp ++LineNo; 210e350b0a1SGabor Horvath } 211e350b0a1SGabor Horvath return Result; 212e350b0a1SGabor Horvath } 213e350b0a1SGabor Horvath 214e350b0a1SGabor Horvath std::string 215e350b0a1SGabor Horvath createCrossTUIndexString(const llvm::StringMap<std::string> &Index) { 216e350b0a1SGabor Horvath std::ostringstream Result; 217e350b0a1SGabor Horvath for (const auto &E : Index) 2189f902542SElla Ma Result << E.getKey().size() << ':' << E.getKey().str() << ' ' 2199f902542SElla Ma << E.getValue() << '\n'; 220e350b0a1SGabor Horvath return Result.str(); 221e350b0a1SGabor Horvath } 222e350b0a1SGabor Horvath 223e63b81d1SGabor Marton bool shouldImport(const VarDecl *VD, const ASTContext &ACtx) { 224850361f6SRafael Stahl CanQualType CT = ACtx.getCanonicalType(VD->getType()); 225e63b81d1SGabor Marton return CT.isConstQualified() && VD->getType().isTrivialType(ACtx); 226850361f6SRafael Stahl } 227850361f6SRafael Stahl 228850361f6SRafael Stahl static bool hasBodyOrInit(const FunctionDecl *D, const FunctionDecl *&DefD) { 229850361f6SRafael Stahl return D->hasBody(DefD); 230850361f6SRafael Stahl } 231850361f6SRafael Stahl static bool hasBodyOrInit(const VarDecl *D, const VarDecl *&DefD) { 232850361f6SRafael Stahl return D->getAnyInitializer(DefD); 233850361f6SRafael Stahl } 234850361f6SRafael Stahl template <typename T> static bool hasBodyOrInit(const T *D) { 235850361f6SRafael Stahl const T *Unused; 236850361f6SRafael Stahl return hasBodyOrInit(D, Unused); 237850361f6SRafael Stahl } 238850361f6SRafael Stahl 239e350b0a1SGabor Horvath CrossTranslationUnitContext::CrossTranslationUnitContext(CompilerInstance &CI) 2404b9d2000SBalazs Keri : Context(CI.getASTContext()), ASTStorage(CI) {} 241e350b0a1SGabor Horvath 242e350b0a1SGabor Horvath CrossTranslationUnitContext::~CrossTranslationUnitContext() {} 243e350b0a1SGabor Horvath 2446ad0788cSKazu Hirata std::optional<std::string> 2454e79097dSBalazs Keri CrossTranslationUnitContext::getLookupName(const NamedDecl *ND) { 246e350b0a1SGabor Horvath SmallString<128> DeclUSR; 247850361f6SRafael Stahl bool Ret = index::generateUSRForDecl(ND, DeclUSR); 2484e79097dSBalazs Keri if (Ret) 2494e79097dSBalazs Keri return {}; 2509b2c25c7SKazu Hirata return std::string(DeclUSR); 251e350b0a1SGabor Horvath } 252e350b0a1SGabor Horvath 253850361f6SRafael Stahl /// Recursively visits the decls of a DeclContext, and returns one with the 254850361f6SRafael Stahl /// given USR. 255850361f6SRafael Stahl template <typename T> 256850361f6SRafael Stahl const T * 257850361f6SRafael Stahl CrossTranslationUnitContext::findDefInDeclContext(const DeclContext *DC, 258850361f6SRafael Stahl StringRef LookupName) { 259e350b0a1SGabor Horvath assert(DC && "Declaration Context must not be null"); 260e350b0a1SGabor Horvath for (const Decl *D : DC->decls()) { 261e350b0a1SGabor Horvath const auto *SubDC = dyn_cast<DeclContext>(D); 262e350b0a1SGabor Horvath if (SubDC) 263850361f6SRafael Stahl if (const auto *ND = findDefInDeclContext<T>(SubDC, LookupName)) 264850361f6SRafael Stahl return ND; 265e350b0a1SGabor Horvath 266850361f6SRafael Stahl const auto *ND = dyn_cast<T>(D); 267850361f6SRafael Stahl const T *ResultDecl; 268850361f6SRafael Stahl if (!ND || !hasBodyOrInit(ND, ResultDecl)) 269e350b0a1SGabor Horvath continue; 2706ad0788cSKazu Hirata std::optional<std::string> ResultLookupName = getLookupName(ResultDecl); 2714e79097dSBalazs Keri if (!ResultLookupName || *ResultLookupName != LookupName) 272e350b0a1SGabor Horvath continue; 273e350b0a1SGabor Horvath return ResultDecl; 274e350b0a1SGabor Horvath } 275e350b0a1SGabor Horvath return nullptr; 276e350b0a1SGabor Horvath } 277e350b0a1SGabor Horvath 278850361f6SRafael Stahl template <typename T> 279850361f6SRafael Stahl llvm::Expected<const T *> CrossTranslationUnitContext::getCrossTUDefinitionImpl( 280850361f6SRafael Stahl const T *D, StringRef CrossTUDir, StringRef IndexName, 2819419eb42SGabor Marton bool DisplayCTUProgress) { 282850361f6SRafael Stahl assert(D && "D is missing, bad call to this function!"); 283850361f6SRafael Stahl assert(!hasBodyOrInit(D) && 284850361f6SRafael Stahl "D has a body or init in current translation unit!"); 285700a29a1SGabor Marton ++NumGetCTUCalled; 2866ad0788cSKazu Hirata const std::optional<std::string> LookupName = getLookupName(D); 2874e79097dSBalazs Keri if (!LookupName) 288e350b0a1SGabor Horvath return llvm::make_error<IndexError>( 289e350b0a1SGabor Horvath index_error_code::failed_to_generate_usr); 2900492fd41SEndre Fulop llvm::Expected<ASTUnit *> ASTUnitOrError = 2914e79097dSBalazs Keri loadExternalAST(*LookupName, CrossTUDir, IndexName, DisplayCTUProgress); 292e350b0a1SGabor Horvath if (!ASTUnitOrError) 293e350b0a1SGabor Horvath return ASTUnitOrError.takeError(); 294e350b0a1SGabor Horvath ASTUnit *Unit = *ASTUnitOrError; 295e350b0a1SGabor Horvath assert(&Unit->getFileManager() == 296e350b0a1SGabor Horvath &Unit->getASTContext().getSourceManager().getFileManager()); 297e350b0a1SGabor Horvath 29832aff2ebSGabor Marton const llvm::Triple &TripleTo = Context.getTargetInfo().getTriple(); 29932aff2ebSGabor Marton const llvm::Triple &TripleFrom = 30032aff2ebSGabor Marton Unit->getASTContext().getTargetInfo().getTriple(); 30132aff2ebSGabor Marton // The imported AST had been generated for a different target. 30232aff2ebSGabor Marton // Some parts of the triple in the loaded ASTContext can be unknown while the 30332aff2ebSGabor Marton // very same parts in the target ASTContext are known. Thus we check for the 30432aff2ebSGabor Marton // known parts only. 30532aff2ebSGabor Marton if (!hasEqualKnownFields(TripleTo, TripleFrom)) { 30632aff2ebSGabor Marton // TODO: Pass the SourceLocation of the CallExpression for more precise 30732aff2ebSGabor Marton // diagnostics. 30832aff2ebSGabor Marton ++NumTripleMismatch; 30932aff2ebSGabor Marton return llvm::make_error<IndexError>(index_error_code::triple_mismatch, 310adcd0268SBenjamin Kramer std::string(Unit->getMainFileName()), 311adcd0268SBenjamin Kramer TripleTo.str(), TripleFrom.str()); 31232aff2ebSGabor Marton } 31332aff2ebSGabor Marton 31432aff2ebSGabor Marton const auto &LangTo = Context.getLangOpts(); 31532aff2ebSGabor Marton const auto &LangFrom = Unit->getASTContext().getLangOpts(); 316a006b80aSGabor Marton 31732aff2ebSGabor Marton // FIXME: Currenty we do not support CTU across C++ and C and across 31832aff2ebSGabor Marton // different dialects of C++. 31932aff2ebSGabor Marton if (LangTo.CPlusPlus != LangFrom.CPlusPlus) { 32032aff2ebSGabor Marton ++NumLangMismatch; 32132aff2ebSGabor Marton return llvm::make_error<IndexError>(index_error_code::lang_mismatch); 32232aff2ebSGabor Marton } 32332aff2ebSGabor Marton 324a006b80aSGabor Marton // If CPP dialects are different then return with error. 325a006b80aSGabor Marton // 326a006b80aSGabor Marton // Consider this STL code: 327a006b80aSGabor Marton // template<typename _Alloc> 328a006b80aSGabor Marton // struct __alloc_traits 329a006b80aSGabor Marton // #if __cplusplus >= 201103L 330a006b80aSGabor Marton // : std::allocator_traits<_Alloc> 331a006b80aSGabor Marton // #endif 332a006b80aSGabor Marton // { // ... 333a006b80aSGabor Marton // }; 334a006b80aSGabor Marton // This class template would create ODR errors during merging the two units, 335a006b80aSGabor Marton // since in one translation unit the class template has a base class, however 336a006b80aSGabor Marton // in the other unit it has none. 337a006b80aSGabor Marton if (LangTo.CPlusPlus11 != LangFrom.CPlusPlus11 || 338a006b80aSGabor Marton LangTo.CPlusPlus14 != LangFrom.CPlusPlus14 || 339a006b80aSGabor Marton LangTo.CPlusPlus17 != LangFrom.CPlusPlus17 || 3406a308943SAaron Ballman LangTo.CPlusPlus20 != LangFrom.CPlusPlus20) { 341a006b80aSGabor Marton ++NumLangDialectMismatch; 342a006b80aSGabor Marton return llvm::make_error<IndexError>( 343a006b80aSGabor Marton index_error_code::lang_dialect_mismatch); 344a006b80aSGabor Marton } 345a006b80aSGabor Marton 346e350b0a1SGabor Horvath TranslationUnitDecl *TU = Unit->getASTContext().getTranslationUnitDecl(); 3474e79097dSBalazs Keri if (const T *ResultDecl = findDefInDeclContext<T>(TU, *LookupName)) 348d22f8773SBalazs Keri return importDefinition(ResultDecl, Unit); 349e350b0a1SGabor Horvath return llvm::make_error<IndexError>(index_error_code::failed_import); 350e350b0a1SGabor Horvath } 351e350b0a1SGabor Horvath 352850361f6SRafael Stahl llvm::Expected<const FunctionDecl *> 353850361f6SRafael Stahl CrossTranslationUnitContext::getCrossTUDefinition(const FunctionDecl *FD, 354850361f6SRafael Stahl StringRef CrossTUDir, 355850361f6SRafael Stahl StringRef IndexName, 356850361f6SRafael Stahl bool DisplayCTUProgress) { 357850361f6SRafael Stahl return getCrossTUDefinitionImpl(FD, CrossTUDir, IndexName, 358850361f6SRafael Stahl DisplayCTUProgress); 359850361f6SRafael Stahl } 360850361f6SRafael Stahl 361850361f6SRafael Stahl llvm::Expected<const VarDecl *> 362850361f6SRafael Stahl CrossTranslationUnitContext::getCrossTUDefinition(const VarDecl *VD, 363850361f6SRafael Stahl StringRef CrossTUDir, 364850361f6SRafael Stahl StringRef IndexName, 365850361f6SRafael Stahl bool DisplayCTUProgress) { 366850361f6SRafael Stahl return getCrossTUDefinitionImpl(VD, CrossTUDir, IndexName, 367850361f6SRafael Stahl DisplayCTUProgress); 368850361f6SRafael Stahl } 369850361f6SRafael Stahl 370e350b0a1SGabor Horvath void CrossTranslationUnitContext::emitCrossTUDiagnostics(const IndexError &IE) { 371e350b0a1SGabor Horvath switch (IE.getCode()) { 372e350b0a1SGabor Horvath case index_error_code::missing_index_file: 3730f25c747SRichard Trieu Context.getDiagnostics().Report(diag::err_ctu_error_opening) 3740f25c747SRichard Trieu << IE.getFileName(); 375e350b0a1SGabor Horvath break; 376e350b0a1SGabor Horvath case index_error_code::invalid_index_format: 3778c48705aSRafael Stahl Context.getDiagnostics().Report(diag::err_extdefmap_parsing) 378e350b0a1SGabor Horvath << IE.getFileName() << IE.getLineNum(); 379554ab538SSimon Pilgrim break; 380e350b0a1SGabor Horvath case index_error_code::multiple_definitions: 381e350b0a1SGabor Horvath Context.getDiagnostics().Report(diag::err_multiple_def_index) 382e350b0a1SGabor Horvath << IE.getLineNum(); 383e350b0a1SGabor Horvath break; 38432aff2ebSGabor Marton case index_error_code::triple_mismatch: 38532aff2ebSGabor Marton Context.getDiagnostics().Report(diag::warn_ctu_incompat_triple) 38632aff2ebSGabor Marton << IE.getFileName() << IE.getTripleToName() << IE.getTripleFromName(); 38732aff2ebSGabor Marton break; 388e350b0a1SGabor Horvath default: 389e350b0a1SGabor Horvath break; 390e350b0a1SGabor Horvath } 391e350b0a1SGabor Horvath } 392e350b0a1SGabor Horvath 3930492fd41SEndre Fulop CrossTranslationUnitContext::ASTUnitStorage::ASTUnitStorage( 3945cc18516SEndre Fülöp CompilerInstance &CI) 3958e0c9bb9SJan Svoboda : Loader(CI, CI.getAnalyzerOpts().CTUDir, 3968e0c9bb9SJan Svoboda CI.getAnalyzerOpts().CTUInvocationList), 397d12d0b73SGabor Marton LoadGuard(CI.getASTContext().getLangOpts().CPlusPlus 3988e0c9bb9SJan Svoboda ? CI.getAnalyzerOpts().CTUImportCppThreshold 3998e0c9bb9SJan Svoboda : CI.getAnalyzerOpts().CTUImportThreshold) {} 4000492fd41SEndre Fulop 4010492fd41SEndre Fulop llvm::Expected<ASTUnit *> 4024b9d2000SBalazs Keri CrossTranslationUnitContext::ASTUnitStorage::getASTUnitForFile( 4034b9d2000SBalazs Keri StringRef FileName, bool DisplayCTUProgress) { 4040492fd41SEndre Fulop // Try the cache first. 4050492fd41SEndre Fulop auto ASTCacheEntry = FileASTUnitMap.find(FileName); 4060492fd41SEndre Fulop if (ASTCacheEntry == FileASTUnitMap.end()) { 4074b9d2000SBalazs Keri 4084b9d2000SBalazs Keri // Do not load if the limit is reached. 4094b9d2000SBalazs Keri if (!LoadGuard) { 4104b9d2000SBalazs Keri ++NumASTLoadThresholdReached; 4114b9d2000SBalazs Keri return llvm::make_error<IndexError>( 4124b9d2000SBalazs Keri index_error_code::load_threshold_reached); 4134b9d2000SBalazs Keri } 4144b9d2000SBalazs Keri 4155cc18516SEndre Fülöp auto LoadAttempt = Loader.load(FileName); 4165cc18516SEndre Fülöp 4175cc18516SEndre Fülöp if (!LoadAttempt) 4185cc18516SEndre Fülöp return LoadAttempt.takeError(); 4195cc18516SEndre Fülöp 4205cc18516SEndre Fülöp std::unique_ptr<ASTUnit> LoadedUnit = std::move(LoadAttempt.get()); 4210492fd41SEndre Fulop 4220492fd41SEndre Fulop // Need the raw pointer and the unique_ptr as well. 4230492fd41SEndre Fulop ASTUnit *Unit = LoadedUnit.get(); 4240492fd41SEndre Fulop 4250492fd41SEndre Fulop // Update the cache. 4260492fd41SEndre Fulop FileASTUnitMap[FileName] = std::move(LoadedUnit); 4274b9d2000SBalazs Keri 4284b9d2000SBalazs Keri LoadGuard.indicateLoadSuccess(); 4294b9d2000SBalazs Keri 4304b9d2000SBalazs Keri if (DisplayCTUProgress) 4314b9d2000SBalazs Keri llvm::errs() << "CTU loaded AST file: " << FileName << "\n"; 4324b9d2000SBalazs Keri 4330492fd41SEndre Fulop return Unit; 4340492fd41SEndre Fulop 4350492fd41SEndre Fulop } else { 4360492fd41SEndre Fulop // Found in the cache. 4370492fd41SEndre Fulop return ASTCacheEntry->second.get(); 4380492fd41SEndre Fulop } 4390492fd41SEndre Fulop } 4400492fd41SEndre Fulop 4410492fd41SEndre Fulop llvm::Expected<ASTUnit *> 4420492fd41SEndre Fulop CrossTranslationUnitContext::ASTUnitStorage::getASTUnitForFunction( 4434b9d2000SBalazs Keri StringRef FunctionName, StringRef CrossTUDir, StringRef IndexName, 4444b9d2000SBalazs Keri bool DisplayCTUProgress) { 4450492fd41SEndre Fulop // Try the cache first. 4460492fd41SEndre Fulop auto ASTCacheEntry = NameASTUnitMap.find(FunctionName); 4470492fd41SEndre Fulop if (ASTCacheEntry == NameASTUnitMap.end()) { 4480492fd41SEndre Fulop // Load the ASTUnit from the pre-dumped AST file specified by ASTFileName. 4490492fd41SEndre Fulop 4500492fd41SEndre Fulop // Ensure that the Index is loaded, as we need to search in it. 4510492fd41SEndre Fulop if (llvm::Error IndexLoadError = 4520492fd41SEndre Fulop ensureCTUIndexLoaded(CrossTUDir, IndexName)) 4530492fd41SEndre Fulop return std::move(IndexLoadError); 4540492fd41SEndre Fulop 4559f902542SElla Ma // Check if there is an entry in the index for the function. 4560492fd41SEndre Fulop if (!NameFileMap.count(FunctionName)) { 4570492fd41SEndre Fulop ++NumNotInOtherTU; 4580492fd41SEndre Fulop return llvm::make_error<IndexError>(index_error_code::missing_definition); 4590492fd41SEndre Fulop } 4600492fd41SEndre Fulop 4615674a3c8SGabriel Ravier // Search in the index for the filename where the definition of FunctionName 4620492fd41SEndre Fulop // resides. 4630492fd41SEndre Fulop if (llvm::Expected<ASTUnit *> FoundForFile = 4644b9d2000SBalazs Keri getASTUnitForFile(NameFileMap[FunctionName], DisplayCTUProgress)) { 4650492fd41SEndre Fulop 4660492fd41SEndre Fulop // Update the cache. 4670492fd41SEndre Fulop NameASTUnitMap[FunctionName] = *FoundForFile; 4680492fd41SEndre Fulop return *FoundForFile; 4690492fd41SEndre Fulop 4700492fd41SEndre Fulop } else { 4710492fd41SEndre Fulop return FoundForFile.takeError(); 4720492fd41SEndre Fulop } 4730492fd41SEndre Fulop } else { 4740492fd41SEndre Fulop // Found in the cache. 4750492fd41SEndre Fulop return ASTCacheEntry->second; 4760492fd41SEndre Fulop } 4770492fd41SEndre Fulop } 4780492fd41SEndre Fulop 4790492fd41SEndre Fulop llvm::Expected<std::string> 4800492fd41SEndre Fulop CrossTranslationUnitContext::ASTUnitStorage::getFileForFunction( 4810492fd41SEndre Fulop StringRef FunctionName, StringRef CrossTUDir, StringRef IndexName) { 4820492fd41SEndre Fulop if (llvm::Error IndexLoadError = ensureCTUIndexLoaded(CrossTUDir, IndexName)) 4830492fd41SEndre Fulop return std::move(IndexLoadError); 4840492fd41SEndre Fulop return NameFileMap[FunctionName]; 4850492fd41SEndre Fulop } 4860492fd41SEndre Fulop 4870492fd41SEndre Fulop llvm::Error CrossTranslationUnitContext::ASTUnitStorage::ensureCTUIndexLoaded( 4880492fd41SEndre Fulop StringRef CrossTUDir, StringRef IndexName) { 4890492fd41SEndre Fulop // Dont initialize if the map is filled. 4900492fd41SEndre Fulop if (!NameFileMap.empty()) 4910492fd41SEndre Fulop return llvm::Error::success(); 4920492fd41SEndre Fulop 4930492fd41SEndre Fulop // Get the absolute path to the index file. 4940492fd41SEndre Fulop SmallString<256> IndexFile = CrossTUDir; 4950492fd41SEndre Fulop if (llvm::sys::path::is_absolute(IndexName)) 4960492fd41SEndre Fulop IndexFile = IndexName; 4970492fd41SEndre Fulop else 4980492fd41SEndre Fulop llvm::sys::path::append(IndexFile, IndexName); 4990492fd41SEndre Fulop 5005cc18516SEndre Fülöp if (auto IndexMapping = parseCrossTUIndex(IndexFile)) { 5010492fd41SEndre Fulop // Initialize member map. 5020492fd41SEndre Fulop NameFileMap = *IndexMapping; 5030492fd41SEndre Fulop return llvm::Error::success(); 5040492fd41SEndre Fulop } else { 5050492fd41SEndre Fulop // Error while parsing CrossTU index file. 5060492fd41SEndre Fulop return IndexMapping.takeError(); 5070492fd41SEndre Fulop }; 5080492fd41SEndre Fulop } 5090492fd41SEndre Fulop 510e350b0a1SGabor Horvath llvm::Expected<ASTUnit *> CrossTranslationUnitContext::loadExternalAST( 5119419eb42SGabor Marton StringRef LookupName, StringRef CrossTUDir, StringRef IndexName, 5129419eb42SGabor Marton bool DisplayCTUProgress) { 513850361f6SRafael Stahl // FIXME: The current implementation only supports loading decls with 514e350b0a1SGabor Horvath // a lookup name from a single translation unit. If multiple 515850361f6SRafael Stahl // translation units contains decls with the same lookup name an 516e350b0a1SGabor Horvath // error will be returned. 5170752d12cSEndre Fulop 5180492fd41SEndre Fulop // Try to get the value from the heavily cached storage. 5194b9d2000SBalazs Keri llvm::Expected<ASTUnit *> Unit = ASTStorage.getASTUnitForFunction( 5204b9d2000SBalazs Keri LookupName, CrossTUDir, IndexName, DisplayCTUProgress); 521e350b0a1SGabor Horvath 5223081690cSGabor Marton if (!Unit) 5230492fd41SEndre Fulop return Unit.takeError(); 5240492fd41SEndre Fulop 5250492fd41SEndre Fulop // Check whether the backing pointer of the Expected is a nullptr. 5260492fd41SEndre Fulop if (!*Unit) 5273081690cSGabor Marton return llvm::make_error<IndexError>( 5283081690cSGabor Marton index_error_code::failed_to_get_external_ast); 5290492fd41SEndre Fulop 530e350b0a1SGabor Horvath return Unit; 531e350b0a1SGabor Horvath } 532e350b0a1SGabor Horvath 5335cc18516SEndre Fülöp CrossTranslationUnitContext::ASTLoader::ASTLoader( 5345cc18516SEndre Fülöp CompilerInstance &CI, StringRef CTUDir, StringRef InvocationListFilePath) 5355cc18516SEndre Fülöp : CI(CI), CTUDir(CTUDir), InvocationListFilePath(InvocationListFilePath) {} 5365cc18516SEndre Fülöp 5375cc18516SEndre Fülöp CrossTranslationUnitContext::LoadResultTy 5385cc18516SEndre Fülöp CrossTranslationUnitContext::ASTLoader::load(StringRef Identifier) { 5395cc18516SEndre Fülöp llvm::SmallString<256> Path; 5405cc18516SEndre Fülöp if (llvm::sys::path::is_absolute(Identifier, PathStyle)) { 5415cc18516SEndre Fülöp Path = Identifier; 5425cc18516SEndre Fülöp } else { 5435cc18516SEndre Fülöp Path = CTUDir; 5445cc18516SEndre Fülöp llvm::sys::path::append(Path, PathStyle, Identifier); 5455cc18516SEndre Fülöp } 5465cc18516SEndre Fülöp 5475cc18516SEndre Fülöp // The path is stored in the InvocationList member in posix style. To 5485cc18516SEndre Fülöp // successfully lookup an entry based on filepath, it must be converted. 5495cc18516SEndre Fülöp llvm::sys::path::native(Path, PathStyle); 5505cc18516SEndre Fülöp 5515cc18516SEndre Fülöp // Normalize by removing relative path components. 5525cc18516SEndre Fülöp llvm::sys::path::remove_dots(Path, /*remove_dot_dot*/ true, PathStyle); 5535cc18516SEndre Fülöp 554cc4ecfd6SKazu Hirata if (Path.ends_with(".ast")) 5555cc18516SEndre Fülöp return loadFromDump(Path); 5565cc18516SEndre Fülöp else 5575cc18516SEndre Fülöp return loadFromSource(Path); 5585cc18516SEndre Fülöp } 5595cc18516SEndre Fülöp 5605cc18516SEndre Fülöp CrossTranslationUnitContext::LoadResultTy 5615cc18516SEndre Fülöp CrossTranslationUnitContext::ASTLoader::loadFromDump(StringRef ASTDumpPath) { 5625cc18516SEndre Fülöp IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions(); 5635cc18516SEndre Fülöp TextDiagnosticPrinter *DiagClient = 5645cc18516SEndre Fülöp new TextDiagnosticPrinter(llvm::errs(), &*DiagOpts); 5655cc18516SEndre Fülöp IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs()); 5665cc18516SEndre Fülöp IntrusiveRefCntPtr<DiagnosticsEngine> Diags( 5675cc18516SEndre Fülöp new DiagnosticsEngine(DiagID, &*DiagOpts, DiagClient)); 5685cc18516SEndre Fülöp return ASTUnit::LoadFromASTFile( 569*3cd3202bSKazu Hirata ASTDumpPath, CI.getPCHContainerOperations()->getRawReader(), 570*3cd3202bSKazu Hirata ASTUnit::LoadEverything, Diags, CI.getFileSystemOpts(), 571*3cd3202bSKazu Hirata CI.getHeaderSearchOptsPtr()); 5725cc18516SEndre Fülöp } 5735cc18516SEndre Fülöp 5745cc18516SEndre Fülöp /// Load the AST from a source-file, which is supposed to be located inside the 5755cc18516SEndre Fülöp /// YAML formatted invocation list file under the filesystem path specified by 5765cc18516SEndre Fülöp /// \p InvocationList. The invocation list should contain absolute paths. 5775cc18516SEndre Fülöp /// \p SourceFilePath is the absolute path of the source file that contains the 5785cc18516SEndre Fülöp /// function definition the analysis is looking for. The Index is built by the 5795cc18516SEndre Fülöp /// \p clang-extdef-mapping tool, which is also supposed to be generating 5805cc18516SEndre Fülöp /// absolute paths. 5815cc18516SEndre Fülöp /// 5825cc18516SEndre Fülöp /// Proper diagnostic emission requires absolute paths, so even if a future 5835cc18516SEndre Fülöp /// change introduces the handling of relative paths, this must be taken into 5845cc18516SEndre Fülöp /// consideration. 5855cc18516SEndre Fülöp CrossTranslationUnitContext::LoadResultTy 5865cc18516SEndre Fülöp CrossTranslationUnitContext::ASTLoader::loadFromSource( 5875cc18516SEndre Fülöp StringRef SourceFilePath) { 5885cc18516SEndre Fülöp 5895cc18516SEndre Fülöp if (llvm::Error InitError = lazyInitInvocationList()) 5905cc18516SEndre Fülöp return std::move(InitError); 5915cc18516SEndre Fülöp assert(InvocationList); 5925cc18516SEndre Fülöp 5935cc18516SEndre Fülöp auto Invocation = InvocationList->find(SourceFilePath); 5945cc18516SEndre Fülöp if (Invocation == InvocationList->end()) 5955cc18516SEndre Fülöp return llvm::make_error<IndexError>( 5965cc18516SEndre Fülöp index_error_code::invocation_list_lookup_unsuccessful); 5975cc18516SEndre Fülöp 5985cc18516SEndre Fülöp const InvocationListTy::mapped_type &InvocationCommand = Invocation->second; 5995cc18516SEndre Fülöp 6005cc18516SEndre Fülöp SmallVector<const char *, 32> CommandLineArgs(InvocationCommand.size()); 6015cc18516SEndre Fülöp std::transform(InvocationCommand.begin(), InvocationCommand.end(), 6025cc18516SEndre Fülöp CommandLineArgs.begin(), 6035cc18516SEndre Fülöp [](auto &&CmdPart) { return CmdPart.c_str(); }); 6045cc18516SEndre Fülöp 6055cc18516SEndre Fülöp IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts{&CI.getDiagnosticOpts()}; 6065cc18516SEndre Fülöp auto *DiagClient = new ForwardingDiagnosticConsumer{CI.getDiagnosticClient()}; 6075cc18516SEndre Fülöp IntrusiveRefCntPtr<DiagnosticIDs> DiagID{ 6085cc18516SEndre Fülöp CI.getDiagnostics().getDiagnosticIDs()}; 6095cc18516SEndre Fülöp IntrusiveRefCntPtr<DiagnosticsEngine> Diags( 6105cc18516SEndre Fülöp new DiagnosticsEngine{DiagID, &*DiagOpts, DiagClient}); 6115cc18516SEndre Fülöp 612a57bdc8fSHamish Knight return ASTUnit::LoadFromCommandLine(CommandLineArgs.begin(), 613a57bdc8fSHamish Knight (CommandLineArgs.end()), 6145cc18516SEndre Fülöp CI.getPCHContainerOperations(), Diags, 615a57bdc8fSHamish Knight CI.getHeaderSearchOpts().ResourceDir); 6165cc18516SEndre Fülöp } 6175cc18516SEndre Fülöp 6185cc18516SEndre Fülöp llvm::Expected<InvocationListTy> 6195cc18516SEndre Fülöp parseInvocationList(StringRef FileContent, llvm::sys::path::Style PathStyle) { 6205cc18516SEndre Fülöp InvocationListTy InvocationList; 6215cc18516SEndre Fülöp 6225cc18516SEndre Fülöp /// LLVM YAML parser is used to extract information from invocation list file. 6235cc18516SEndre Fülöp llvm::SourceMgr SM; 6245cc18516SEndre Fülöp llvm::yaml::Stream InvocationFile(FileContent, SM); 6255cc18516SEndre Fülöp 6265cc18516SEndre Fülöp /// Only the first document is processed. 6275cc18516SEndre Fülöp llvm::yaml::document_iterator FirstInvocationFile = InvocationFile.begin(); 6285cc18516SEndre Fülöp 6295cc18516SEndre Fülöp /// There has to be at least one document available. 6305cc18516SEndre Fülöp if (FirstInvocationFile == InvocationFile.end()) 6315cc18516SEndre Fülöp return llvm::make_error<IndexError>( 6325cc18516SEndre Fülöp index_error_code::invocation_list_empty); 6335cc18516SEndre Fülöp 6345cc18516SEndre Fülöp llvm::yaml::Node *DocumentRoot = FirstInvocationFile->getRoot(); 6355cc18516SEndre Fülöp if (!DocumentRoot) 6365cc18516SEndre Fülöp return llvm::make_error<IndexError>( 6375cc18516SEndre Fülöp index_error_code::invocation_list_wrong_format); 6385cc18516SEndre Fülöp 6395cc18516SEndre Fülöp /// According to the format specified the document must be a mapping, where 6405cc18516SEndre Fülöp /// the keys are paths to source files, and values are sequences of invocation 6415cc18516SEndre Fülöp /// parts. 6425cc18516SEndre Fülöp auto *Mappings = dyn_cast<llvm::yaml::MappingNode>(DocumentRoot); 6435cc18516SEndre Fülöp if (!Mappings) 6445cc18516SEndre Fülöp return llvm::make_error<IndexError>( 6455cc18516SEndre Fülöp index_error_code::invocation_list_wrong_format); 6465cc18516SEndre Fülöp 6475cc18516SEndre Fülöp for (auto &NextMapping : *Mappings) { 6485cc18516SEndre Fülöp /// The keys should be strings, which represent a source-file path. 6495cc18516SEndre Fülöp auto *Key = dyn_cast<llvm::yaml::ScalarNode>(NextMapping.getKey()); 6505cc18516SEndre Fülöp if (!Key) 6515cc18516SEndre Fülöp return llvm::make_error<IndexError>( 6525cc18516SEndre Fülöp index_error_code::invocation_list_wrong_format); 6535cc18516SEndre Fülöp 654d44edfc1SNathan James SmallString<32> ValueStorage; 6555cc18516SEndre Fülöp StringRef SourcePath = Key->getValue(ValueStorage); 6565cc18516SEndre Fülöp 6575cc18516SEndre Fülöp // Store paths with PathStyle directory separator. 658d44edfc1SNathan James SmallString<32> NativeSourcePath(SourcePath); 6595cc18516SEndre Fülöp llvm::sys::path::native(NativeSourcePath, PathStyle); 6605cc18516SEndre Fülöp 6611def2579SDavid Blaikie StringRef InvocationKey = NativeSourcePath; 6625cc18516SEndre Fülöp 663ea9d4040SKazu Hirata if (InvocationList.contains(InvocationKey)) 6645cc18516SEndre Fülöp return llvm::make_error<IndexError>( 6655cc18516SEndre Fülöp index_error_code::invocation_list_ambiguous); 6665cc18516SEndre Fülöp 6675cc18516SEndre Fülöp /// The values should be sequences of strings, each representing a part of 6685cc18516SEndre Fülöp /// the invocation. 6695cc18516SEndre Fülöp auto *Args = dyn_cast<llvm::yaml::SequenceNode>(NextMapping.getValue()); 6705cc18516SEndre Fülöp if (!Args) 6715cc18516SEndre Fülöp return llvm::make_error<IndexError>( 6725cc18516SEndre Fülöp index_error_code::invocation_list_wrong_format); 6735cc18516SEndre Fülöp 6745cc18516SEndre Fülöp for (auto &Arg : *Args) { 6755cc18516SEndre Fülöp auto *CmdString = dyn_cast<llvm::yaml::ScalarNode>(&Arg); 6765cc18516SEndre Fülöp if (!CmdString) 6775cc18516SEndre Fülöp return llvm::make_error<IndexError>( 6785cc18516SEndre Fülöp index_error_code::invocation_list_wrong_format); 6795cc18516SEndre Fülöp /// Every conversion starts with an empty working storage, as it is not 6805cc18516SEndre Fülöp /// clear if this is a requirement of the YAML parser. 6815cc18516SEndre Fülöp ValueStorage.clear(); 6825cc18516SEndre Fülöp InvocationList[InvocationKey].emplace_back( 6835cc18516SEndre Fülöp CmdString->getValue(ValueStorage)); 6845cc18516SEndre Fülöp } 6855cc18516SEndre Fülöp 6865cc18516SEndre Fülöp if (InvocationList[InvocationKey].empty()) 6875cc18516SEndre Fülöp return llvm::make_error<IndexError>( 6885cc18516SEndre Fülöp index_error_code::invocation_list_wrong_format); 6895cc18516SEndre Fülöp } 6905cc18516SEndre Fülöp 6915cc18516SEndre Fülöp return InvocationList; 6925cc18516SEndre Fülöp } 6935cc18516SEndre Fülöp 6945cc18516SEndre Fülöp llvm::Error CrossTranslationUnitContext::ASTLoader::lazyInitInvocationList() { 6955cc18516SEndre Fülöp /// Lazily initialize the invocation list member used for on-demand parsing. 6965cc18516SEndre Fülöp if (InvocationList) 6975cc18516SEndre Fülöp return llvm::Error::success(); 698d59b4acfSElla Ma if (index_error_code::success != PreviousParsingResult) 699d59b4acfSElla Ma return llvm::make_error<IndexError>(PreviousParsingResult); 7005cc18516SEndre Fülöp 7015cc18516SEndre Fülöp llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> FileContent = 7025cc18516SEndre Fülöp llvm::MemoryBuffer::getFile(InvocationListFilePath); 703d59b4acfSElla Ma if (!FileContent) { 704d59b4acfSElla Ma PreviousParsingResult = index_error_code::invocation_list_file_not_found; 705d59b4acfSElla Ma return llvm::make_error<IndexError>(PreviousParsingResult); 706d59b4acfSElla Ma } 7075cc18516SEndre Fülöp std::unique_ptr<llvm::MemoryBuffer> ContentBuffer = std::move(*FileContent); 7085cc18516SEndre Fülöp assert(ContentBuffer && "If no error was produced after loading, the pointer " 7095cc18516SEndre Fülöp "should not be nullptr."); 7105cc18516SEndre Fülöp 7115cc18516SEndre Fülöp llvm::Expected<InvocationListTy> ExpectedInvocationList = 7125cc18516SEndre Fülöp parseInvocationList(ContentBuffer->getBuffer(), PathStyle); 7135cc18516SEndre Fülöp 714d59b4acfSElla Ma // Handle the error to store the code for next call to this function. 715d59b4acfSElla Ma if (!ExpectedInvocationList) { 716d59b4acfSElla Ma llvm::handleAllErrors( 717d59b4acfSElla Ma ExpectedInvocationList.takeError(), 718d59b4acfSElla Ma [&](const IndexError &E) { PreviousParsingResult = E.getCode(); }); 719d59b4acfSElla Ma return llvm::make_error<IndexError>(PreviousParsingResult); 720d59b4acfSElla Ma } 7215cc18516SEndre Fülöp 7225cc18516SEndre Fülöp InvocationList = *ExpectedInvocationList; 7235cc18516SEndre Fülöp 7245cc18516SEndre Fülöp return llvm::Error::success(); 7255cc18516SEndre Fülöp } 7265cc18516SEndre Fülöp 727850361f6SRafael Stahl template <typename T> 728850361f6SRafael Stahl llvm::Expected<const T *> 729d22f8773SBalazs Keri CrossTranslationUnitContext::importDefinitionImpl(const T *D, ASTUnit *Unit) { 730850361f6SRafael Stahl assert(hasBodyOrInit(D) && "Decls to be imported should have body or init."); 731b7f30ddaSGabor Marton 732d22f8773SBalazs Keri assert(&D->getASTContext() == &Unit->getASTContext() && 733d22f8773SBalazs Keri "ASTContext of Decl and the unit should match."); 734d22f8773SBalazs Keri ASTImporter &Importer = getOrCreateASTImporter(Unit); 735d22f8773SBalazs Keri 7365ac6d490SGabor Marton auto ToDeclOrError = Importer.Import(D); 737a1f6b103SBalazs Keri if (!ToDeclOrError) { 7389d637956SphyBrackets handleAllErrors(ToDeclOrError.takeError(), [&](const ASTImportError &IE) { 739a1f6b103SBalazs Keri switch (IE.Error) { 7409d637956SphyBrackets case ASTImportError::NameConflict: 7418ab8a60aSGabor Marton ++NumNameConflicts; 742a1f6b103SBalazs Keri break; 7439d637956SphyBrackets case ASTImportError::UnsupportedConstruct: 7448ab8a60aSGabor Marton ++NumUnsupportedNodeFound; 745a1f6b103SBalazs Keri break; 7469d637956SphyBrackets case ASTImportError::Unknown: 747a1f6b103SBalazs Keri llvm_unreachable("Unknown import error happened."); 748a1f6b103SBalazs Keri break; 749a1f6b103SBalazs Keri } 750a1f6b103SBalazs Keri }); 751b87251d0SGabor Marton return llvm::make_error<IndexError>(index_error_code::failed_import); 752a1f6b103SBalazs Keri } 753850361f6SRafael Stahl auto *ToDecl = cast<T>(*ToDeclOrError); 754850361f6SRafael Stahl assert(hasBodyOrInit(ToDecl) && "Imported Decl should have body or init."); 755700a29a1SGabor Marton ++NumGetCTUSuccess; 756a1f6b103SBalazs Keri 757f3b34466SBalázs Kéri // Parent map is invalidated after changing the AST. 758f3b34466SBalázs Kéri ToDecl->getASTContext().getParentMapContext().clear(); 759f3b34466SBalázs Kéri 760e350b0a1SGabor Horvath return ToDecl; 761e350b0a1SGabor Horvath } 762e350b0a1SGabor Horvath 763850361f6SRafael Stahl llvm::Expected<const FunctionDecl *> 764d22f8773SBalazs Keri CrossTranslationUnitContext::importDefinition(const FunctionDecl *FD, 765d22f8773SBalazs Keri ASTUnit *Unit) { 766d22f8773SBalazs Keri return importDefinitionImpl(FD, Unit); 767850361f6SRafael Stahl } 768850361f6SRafael Stahl 769850361f6SRafael Stahl llvm::Expected<const VarDecl *> 770d22f8773SBalazs Keri CrossTranslationUnitContext::importDefinition(const VarDecl *VD, 771d22f8773SBalazs Keri ASTUnit *Unit) { 772d22f8773SBalazs Keri return importDefinitionImpl(VD, Unit); 773850361f6SRafael Stahl } 774850361f6SRafael Stahl 7752afbfb6bSGabor Marton void CrossTranslationUnitContext::lazyInitImporterSharedSt( 77654058b50SGabor Marton TranslationUnitDecl *ToTU) { 7772afbfb6bSGabor Marton if (!ImporterSharedSt) 7782afbfb6bSGabor Marton ImporterSharedSt = std::make_shared<ASTImporterSharedState>(*ToTU); 77954058b50SGabor Marton } 78054058b50SGabor Marton 781e350b0a1SGabor Horvath ASTImporter & 782d22f8773SBalazs Keri CrossTranslationUnitContext::getOrCreateASTImporter(ASTUnit *Unit) { 783d22f8773SBalazs Keri ASTContext &From = Unit->getASTContext(); 784d22f8773SBalazs Keri 785e350b0a1SGabor Horvath auto I = ASTUnitImporterMap.find(From.getTranslationUnitDecl()); 786e350b0a1SGabor Horvath if (I != ASTUnitImporterMap.end()) 787e350b0a1SGabor Horvath return *I->second; 7882afbfb6bSGabor Marton lazyInitImporterSharedSt(Context.getTranslationUnitDecl()); 789abc744d2SIlya Biryukov ASTImporter *NewImporter = new ASTImporter( 790abc744d2SIlya Biryukov Context, Context.getSourceManager().getFileManager(), From, 791abc744d2SIlya Biryukov From.getSourceManager().getFileManager(), false, ImporterSharedSt); 792e350b0a1SGabor Horvath ASTUnitImporterMap[From.getTranslationUnitDecl()].reset(NewImporter); 793e350b0a1SGabor Horvath return *NewImporter; 794e350b0a1SGabor Horvath } 795e350b0a1SGabor Horvath 7966ad0788cSKazu Hirata std::optional<clang::MacroExpansionContext> 79738b18583SBalazs Benics CrossTranslationUnitContext::getMacroExpansionContextForSourceLocation( 7989c4b2225SAlexander Belyaev const clang::SourceLocation &ToLoc) const { 79938b18583SBalazs Benics // FIXME: Implement: Record such a context for every imported ASTUnit; lookup. 8005891420eSKazu Hirata return std::nullopt; 801d22f8773SBalazs Keri } 802d22f8773SBalazs Keri 80356b9b97cSGabor Marton bool CrossTranslationUnitContext::isImportedAsNew(const Decl *ToDecl) const { 80456b9b97cSGabor Marton if (!ImporterSharedSt) 80556b9b97cSGabor Marton return false; 80656b9b97cSGabor Marton return ImporterSharedSt->isNewDecl(const_cast<Decl *>(ToDecl)); 80756b9b97cSGabor Marton } 80856b9b97cSGabor Marton 80956b9b97cSGabor Marton bool CrossTranslationUnitContext::hasError(const Decl *ToDecl) const { 81056b9b97cSGabor Marton if (!ImporterSharedSt) 81156b9b97cSGabor Marton return false; 81256b9b97cSGabor Marton return static_cast<bool>( 81356b9b97cSGabor Marton ImporterSharedSt->getImportDeclErrorIfAny(const_cast<Decl *>(ToDecl))); 81456b9b97cSGabor Marton } 81556b9b97cSGabor Marton 816e350b0a1SGabor Horvath } // namespace cross_tu 817e350b0a1SGabor Horvath } // namespace clang 818