diff options
Diffstat (limited to 'lib/CrossTU/CrossTranslationUnit.cpp')
-rw-r--r-- | lib/CrossTU/CrossTranslationUnit.cpp | 216 |
1 files changed, 162 insertions, 54 deletions
diff --git a/lib/CrossTU/CrossTranslationUnit.cpp b/lib/CrossTU/CrossTranslationUnit.cpp index 7c97beb498a5..977fd4b8dd30 100644 --- a/lib/CrossTU/CrossTranslationUnit.cpp +++ b/lib/CrossTU/CrossTranslationUnit.cpp @@ -1,9 +1,8 @@ //===--- CrossTranslationUnit.cpp - -----------------------------*- C++ -*-===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // @@ -41,8 +40,15 @@ STATISTIC( STATISTIC(NumGetCTUSuccess, "The # of getCTUDefinition successfully returned the " "requested function's body"); +STATISTIC(NumUnsupportedNodeFound, "The # of imports when the ASTImporter " + "encountered an unsupported AST Node"); +STATISTIC(NumNameConflicts, "The # of imports when the ASTImporter " + "encountered an ODR error"); STATISTIC(NumTripleMismatch, "The # of triple mismatches"); STATISTIC(NumLangMismatch, "The # of language mismatches"); +STATISTIC(NumLangDialectMismatch, "The # of language dialect mismatches"); +STATISTIC(NumASTLoadThresholdReached, + "The # of ASTs not loaded because of threshold"); // Same as Triple's equality operator, but we check a field only if that is // known in both instances. @@ -100,6 +106,10 @@ public: return "Triple mismatch"; case index_error_code::lang_mismatch: return "Language mismatch"; + case index_error_code::lang_dialect_mismatch: + return "Language dialect mismatch"; + case index_error_code::load_threshold_reached: + return "Load threshold reached"; } llvm_unreachable("Unrecognized index_error_code."); } @@ -156,55 +166,79 @@ createCrossTUIndexString(const llvm::StringMap<std::string> &Index) { return Result.str(); } +bool containsConst(const VarDecl *VD, const ASTContext &ACtx) { + CanQualType CT = ACtx.getCanonicalType(VD->getType()); + if (!CT.isConstQualified()) { + const RecordType *RTy = CT->getAs<RecordType>(); + if (!RTy || !RTy->hasConstFields()) + return false; + } + return true; +} + +static bool hasBodyOrInit(const FunctionDecl *D, const FunctionDecl *&DefD) { + return D->hasBody(DefD); +} +static bool hasBodyOrInit(const VarDecl *D, const VarDecl *&DefD) { + return D->getAnyInitializer(DefD); +} +template <typename T> static bool hasBodyOrInit(const T *D) { + const T *Unused; + return hasBodyOrInit(D, Unused); +} + CrossTranslationUnitContext::CrossTranslationUnitContext(CompilerInstance &CI) - : CI(CI), Context(CI.getASTContext()) {} + : CI(CI), Context(CI.getASTContext()), + CTULoadThreshold(CI.getAnalyzerOpts()->CTUImportThreshold) {} CrossTranslationUnitContext::~CrossTranslationUnitContext() {} std::string CrossTranslationUnitContext::getLookupName(const NamedDecl *ND) { SmallString<128> DeclUSR; - bool Ret = index::generateUSRForDecl(ND, DeclUSR); (void)Ret; + bool Ret = index::generateUSRForDecl(ND, DeclUSR); + (void)Ret; assert(!Ret && "Unable to generate USR"); return DeclUSR.str(); } -/// Recursively visits the function decls of a DeclContext, and looks up a -/// function based on USRs. -const FunctionDecl * -CrossTranslationUnitContext::findFunctionInDeclContext(const DeclContext *DC, - StringRef LookupFnName) { +/// Recursively visits the decls of a DeclContext, and returns one with the +/// given USR. +template <typename T> +const T * +CrossTranslationUnitContext::findDefInDeclContext(const DeclContext *DC, + StringRef LookupName) { assert(DC && "Declaration Context must not be null"); for (const Decl *D : DC->decls()) { const auto *SubDC = dyn_cast<DeclContext>(D); if (SubDC) - if (const auto *FD = findFunctionInDeclContext(SubDC, LookupFnName)) - return FD; + if (const auto *ND = findDefInDeclContext<T>(SubDC, LookupName)) + return ND; - const auto *ND = dyn_cast<FunctionDecl>(D); - const FunctionDecl *ResultDecl; - if (!ND || !ND->hasBody(ResultDecl)) + const auto *ND = dyn_cast<T>(D); + const T *ResultDecl; + if (!ND || !hasBodyOrInit(ND, ResultDecl)) continue; - if (getLookupName(ResultDecl) != LookupFnName) + if (getLookupName(ResultDecl) != LookupName) continue; return ResultDecl; } return nullptr; } -llvm::Expected<const FunctionDecl *> -CrossTranslationUnitContext::getCrossTUDefinition(const FunctionDecl *FD, - StringRef CrossTUDir, - StringRef IndexName, - bool DisplayCTUProgress) { - assert(FD && "FD is missing, bad call to this function!"); - assert(!FD->hasBody() && "FD has a definition in current translation unit!"); +template <typename T> +llvm::Expected<const T *> CrossTranslationUnitContext::getCrossTUDefinitionImpl( + const T *D, StringRef CrossTUDir, StringRef IndexName, + bool DisplayCTUProgress) { + assert(D && "D is missing, bad call to this function!"); + assert(!hasBodyOrInit(D) && + "D has a body or init in current translation unit!"); ++NumGetCTUCalled; - const std::string LookupFnName = getLookupName(FD); - if (LookupFnName.empty()) + const std::string LookupName = getLookupName(D); + if (LookupName.empty()) return llvm::make_error<IndexError>( index_error_code::failed_to_generate_usr); - llvm::Expected<ASTUnit *> ASTUnitOrError = - loadExternalAST(LookupFnName, CrossTUDir, IndexName, DisplayCTUProgress); + llvm::Expected<ASTUnit *> ASTUnitOrError = loadExternalAST( + LookupName, CrossTUDir, IndexName, DisplayCTUProgress); if (!ASTUnitOrError) return ASTUnitOrError.takeError(); ASTUnit *Unit = *ASTUnitOrError; @@ -229,6 +263,7 @@ CrossTranslationUnitContext::getCrossTUDefinition(const FunctionDecl *FD, const auto &LangTo = Context.getLangOpts(); const auto &LangFrom = Unit->getASTContext().getLangOpts(); + // FIXME: Currenty we do not support CTU across C++ and C and across // different dialects of C++. if (LangTo.CPlusPlus != LangFrom.CPlusPlus) { @@ -236,13 +271,52 @@ CrossTranslationUnitContext::getCrossTUDefinition(const FunctionDecl *FD, return llvm::make_error<IndexError>(index_error_code::lang_mismatch); } + // If CPP dialects are different then return with error. + // + // Consider this STL code: + // template<typename _Alloc> + // struct __alloc_traits + // #if __cplusplus >= 201103L + // : std::allocator_traits<_Alloc> + // #endif + // { // ... + // }; + // This class template would create ODR errors during merging the two units, + // since in one translation unit the class template has a base class, however + // in the other unit it has none. + if (LangTo.CPlusPlus11 != LangFrom.CPlusPlus11 || + LangTo.CPlusPlus14 != LangFrom.CPlusPlus14 || + LangTo.CPlusPlus17 != LangFrom.CPlusPlus17 || + LangTo.CPlusPlus2a != LangFrom.CPlusPlus2a) { + ++NumLangDialectMismatch; + return llvm::make_error<IndexError>( + index_error_code::lang_dialect_mismatch); + } + TranslationUnitDecl *TU = Unit->getASTContext().getTranslationUnitDecl(); - if (const FunctionDecl *ResultDecl = - findFunctionInDeclContext(TU, LookupFnName)) + if (const T *ResultDecl = findDefInDeclContext<T>(TU, LookupName)) return importDefinition(ResultDecl); return llvm::make_error<IndexError>(index_error_code::failed_import); } +llvm::Expected<const FunctionDecl *> +CrossTranslationUnitContext::getCrossTUDefinition(const FunctionDecl *FD, + StringRef CrossTUDir, + StringRef IndexName, + bool DisplayCTUProgress) { + return getCrossTUDefinitionImpl(FD, CrossTUDir, IndexName, + DisplayCTUProgress); +} + +llvm::Expected<const VarDecl *> +CrossTranslationUnitContext::getCrossTUDefinition(const VarDecl *VD, + StringRef CrossTUDir, + StringRef IndexName, + bool DisplayCTUProgress) { + return getCrossTUDefinitionImpl(VD, CrossTUDir, IndexName, + DisplayCTUProgress); +} + void CrossTranslationUnitContext::emitCrossTUDiagnostics(const IndexError &IE) { switch (IE.getCode()) { case index_error_code::missing_index_file: @@ -269,14 +343,21 @@ void CrossTranslationUnitContext::emitCrossTUDiagnostics(const IndexError &IE) { llvm::Expected<ASTUnit *> CrossTranslationUnitContext::loadExternalAST( StringRef LookupName, StringRef CrossTUDir, StringRef IndexName, bool DisplayCTUProgress) { - // FIXME: The current implementation only supports loading functions with + // FIXME: The current implementation only supports loading decls with // a lookup name from a single translation unit. If multiple - // translation units contains functions with the same lookup name an + // translation units contains decls with the same lookup name an // error will be returned. + + if (NumASTLoaded >= CTULoadThreshold) { + ++NumASTLoadThresholdReached; + return llvm::make_error<IndexError>( + index_error_code::load_threshold_reached); + } + ASTUnit *Unit = nullptr; - auto FnUnitCacheEntry = FunctionASTUnitMap.find(LookupName); - if (FnUnitCacheEntry == FunctionASTUnitMap.end()) { - if (FunctionFileMap.empty()) { + auto NameUnitCacheEntry = NameASTUnitMap.find(LookupName); + if (NameUnitCacheEntry == NameASTUnitMap.end()) { + if (NameFileMap.empty()) { SmallString<256> IndexFile = CrossTUDir; if (llvm::sys::path::is_absolute(IndexName)) IndexFile = IndexName; @@ -285,13 +366,13 @@ llvm::Expected<ASTUnit *> CrossTranslationUnitContext::loadExternalAST( llvm::Expected<llvm::StringMap<std::string>> IndexOrErr = parseCrossTUIndex(IndexFile, CrossTUDir); if (IndexOrErr) - FunctionFileMap = *IndexOrErr; + NameFileMap = *IndexOrErr; else return IndexOrErr.takeError(); } - auto It = FunctionFileMap.find(LookupName); - if (It == FunctionFileMap.end()) { + auto It = NameFileMap.find(LookupName); + if (It == NameFileMap.end()) { ++NumNotInOtherTU; return llvm::make_error<IndexError>(index_error_code::missing_definition); } @@ -310,6 +391,7 @@ llvm::Expected<ASTUnit *> CrossTranslationUnitContext::loadExternalAST( ASTUnit::LoadEverything, Diags, CI.getFileSystemOpts())); Unit = LoadedUnit.get(); FileASTUnitMap[ASTFileName] = std::move(LoadedUnit); + ++NumASTLoaded; if (DisplayCTUProgress) { llvm::errs() << "CTU loaded AST file: " << ASTFileName << "\n"; @@ -317,9 +399,9 @@ llvm::Expected<ASTUnit *> CrossTranslationUnitContext::loadExternalAST( } else { Unit = ASTCacheEntry->second.get(); } - FunctionASTUnitMap[LookupName] = Unit; + NameASTUnitMap[LookupName] = Unit; } else { - Unit = FnUnitCacheEntry->second; + Unit = NameUnitCacheEntry->second; } if (!Unit) return llvm::make_error<IndexError>( @@ -327,25 +409,51 @@ llvm::Expected<ASTUnit *> CrossTranslationUnitContext::loadExternalAST( return Unit; } -llvm::Expected<const FunctionDecl *> -CrossTranslationUnitContext::importDefinition(const FunctionDecl *FD) { - assert(FD->hasBody() && "Functions to be imported should have body."); +template <typename T> +llvm::Expected<const T *> +CrossTranslationUnitContext::importDefinitionImpl(const T *D) { + assert(hasBodyOrInit(D) && "Decls to be imported should have body or init."); - ASTImporter &Importer = getOrCreateASTImporter(FD->getASTContext()); - auto *ToDecl = - cast_or_null<FunctionDecl>(Importer.Import(const_cast<FunctionDecl *>(FD))); - if (!ToDecl) + ASTImporter &Importer = getOrCreateASTImporter(D->getASTContext()); + auto ToDeclOrError = Importer.Import(D); + if (!ToDeclOrError) { + handleAllErrors(ToDeclOrError.takeError(), + [&](const ImportError &IE) { + switch (IE.Error) { + case ImportError::NameConflict: + ++NumNameConflicts; + break; + case ImportError::UnsupportedConstruct: + ++NumUnsupportedNodeFound; + break; + case ImportError::Unknown: + llvm_unreachable("Unknown import error happened."); + break; + } + }); return llvm::make_error<IndexError>(index_error_code::failed_import); - assert(ToDecl->hasBody()); - assert(FD->hasBody() && "Functions already imported should have body."); + } + auto *ToDecl = cast<T>(*ToDeclOrError); + assert(hasBodyOrInit(ToDecl) && "Imported Decl should have body or init."); ++NumGetCTUSuccess; + return ToDecl; } -void CrossTranslationUnitContext::lazyInitLookupTable( +llvm::Expected<const FunctionDecl *> +CrossTranslationUnitContext::importDefinition(const FunctionDecl *FD) { + return importDefinitionImpl(FD); +} + +llvm::Expected<const VarDecl *> +CrossTranslationUnitContext::importDefinition(const VarDecl *VD) { + return importDefinitionImpl(VD); +} + +void CrossTranslationUnitContext::lazyInitImporterSharedSt( TranslationUnitDecl *ToTU) { - if (!LookupTable) - LookupTable = llvm::make_unique<ASTImporterLookupTable>(*ToTU); + if (!ImporterSharedSt) + ImporterSharedSt = std::make_shared<ASTImporterSharedState>(*ToTU); } ASTImporter & @@ -353,10 +461,10 @@ CrossTranslationUnitContext::getOrCreateASTImporter(ASTContext &From) { auto I = ASTUnitImporterMap.find(From.getTranslationUnitDecl()); if (I != ASTUnitImporterMap.end()) return *I->second; - lazyInitLookupTable(Context.getTranslationUnitDecl()); + lazyInitImporterSharedSt(Context.getTranslationUnitDecl()); ASTImporter *NewImporter = new ASTImporter( Context, Context.getSourceManager().getFileManager(), From, - From.getSourceManager().getFileManager(), false, LookupTable.get()); + From.getSourceManager().getFileManager(), false, ImporterSharedSt); ASTUnitImporterMap[From.getTranslationUnitDecl()].reset(NewImporter); return *NewImporter; } |