diff options
Diffstat (limited to 'contrib/llvm-project/clang/lib/CrossTU/CrossTranslationUnit.cpp')
-rw-r--r-- | contrib/llvm-project/clang/lib/CrossTU/CrossTranslationUnit.cpp | 261 |
1 files changed, 188 insertions, 73 deletions
diff --git a/contrib/llvm-project/clang/lib/CrossTU/CrossTranslationUnit.cpp b/contrib/llvm-project/clang/lib/CrossTU/CrossTranslationUnit.cpp index 977fd4b8dd30..7391d7132daf 100644 --- a/contrib/llvm-project/clang/lib/CrossTU/CrossTranslationUnit.cpp +++ b/contrib/llvm-project/clang/lib/CrossTU/CrossTranslationUnit.cpp @@ -188,17 +188,17 @@ template <typename T> static bool hasBodyOrInit(const T *D) { } CrossTranslationUnitContext::CrossTranslationUnitContext(CompilerInstance &CI) - : CI(CI), Context(CI.getASTContext()), - CTULoadThreshold(CI.getAnalyzerOpts()->CTUImportThreshold) {} + : Context(CI.getASTContext()), ASTStorage(CI) {} CrossTranslationUnitContext::~CrossTranslationUnitContext() {} -std::string CrossTranslationUnitContext::getLookupName(const NamedDecl *ND) { +llvm::Optional<std::string> +CrossTranslationUnitContext::getLookupName(const NamedDecl *ND) { SmallString<128> DeclUSR; bool Ret = index::generateUSRForDecl(ND, DeclUSR); - (void)Ret; - assert(!Ret && "Unable to generate USR"); - return DeclUSR.str(); + if (Ret) + return {}; + return std::string(DeclUSR.str()); } /// Recursively visits the decls of a DeclContext, and returns one with the @@ -218,7 +218,8 @@ CrossTranslationUnitContext::findDefInDeclContext(const DeclContext *DC, const T *ResultDecl; if (!ND || !hasBodyOrInit(ND, ResultDecl)) continue; - if (getLookupName(ResultDecl) != LookupName) + llvm::Optional<std::string> ResultLookupName = getLookupName(ResultDecl); + if (!ResultLookupName || *ResultLookupName != LookupName) continue; return ResultDecl; } @@ -233,12 +234,12 @@ llvm::Expected<const T *> CrossTranslationUnitContext::getCrossTUDefinitionImpl( assert(!hasBodyOrInit(D) && "D has a body or init in current translation unit!"); ++NumGetCTUCalled; - const std::string LookupName = getLookupName(D); - if (LookupName.empty()) + const llvm::Optional<std::string> LookupName = getLookupName(D); + if (!LookupName) return llvm::make_error<IndexError>( index_error_code::failed_to_generate_usr); - llvm::Expected<ASTUnit *> ASTUnitOrError = loadExternalAST( - LookupName, CrossTUDir, IndexName, DisplayCTUProgress); + llvm::Expected<ASTUnit *> ASTUnitOrError = + loadExternalAST(*LookupName, CrossTUDir, IndexName, DisplayCTUProgress); if (!ASTUnitOrError) return ASTUnitOrError.takeError(); ASTUnit *Unit = *ASTUnitOrError; @@ -294,8 +295,8 @@ llvm::Expected<const T *> CrossTranslationUnitContext::getCrossTUDefinitionImpl( } TranslationUnitDecl *TU = Unit->getASTContext().getTranslationUnitDecl(); - if (const T *ResultDecl = findDefInDeclContext<T>(TU, LookupName)) - return importDefinition(ResultDecl); + if (const T *ResultDecl = findDefInDeclContext<T>(TU, *LookupName)) + return importDefinition(ResultDecl, Unit); return llvm::make_error<IndexError>(index_error_code::failed_import); } @@ -340,81 +341,168 @@ 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 decls with - // a lookup name from a single translation unit. If multiple - // 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); - } +CrossTranslationUnitContext::ASTFileLoader::ASTFileLoader( + const CompilerInstance &CI) + : CI(CI) {} + +std::unique_ptr<ASTUnit> +CrossTranslationUnitContext::ASTFileLoader::operator()(StringRef ASTFilePath) { + // Load AST from ast-dump. + IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions(); + TextDiagnosticPrinter *DiagClient = + new TextDiagnosticPrinter(llvm::errs(), &*DiagOpts); + IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs()); + IntrusiveRefCntPtr<DiagnosticsEngine> Diags( + new DiagnosticsEngine(DiagID, &*DiagOpts, DiagClient)); + + return ASTUnit::LoadFromASTFile( + ASTFilePath, CI.getPCHContainerOperations()->getRawReader(), + ASTUnit::LoadEverything, Diags, CI.getFileSystemOpts()); +} - ASTUnit *Unit = nullptr; - 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; - else - llvm::sys::path::append(IndexFile, IndexName); - llvm::Expected<llvm::StringMap<std::string>> IndexOrErr = - parseCrossTUIndex(IndexFile, CrossTUDir); - if (IndexOrErr) - NameFileMap = *IndexOrErr; - else - return IndexOrErr.takeError(); +CrossTranslationUnitContext::ASTUnitStorage::ASTUnitStorage( + const CompilerInstance &CI) + : FileAccessor(CI), LoadGuard(const_cast<CompilerInstance &>(CI) + .getAnalyzerOpts() + ->CTUImportThreshold) {} + +llvm::Expected<ASTUnit *> +CrossTranslationUnitContext::ASTUnitStorage::getASTUnitForFile( + StringRef FileName, bool DisplayCTUProgress) { + // Try the cache first. + auto ASTCacheEntry = FileASTUnitMap.find(FileName); + if (ASTCacheEntry == FileASTUnitMap.end()) { + + // Do not load if the limit is reached. + if (!LoadGuard) { + ++NumASTLoadThresholdReached; + return llvm::make_error<IndexError>( + index_error_code::load_threshold_reached); } - auto It = NameFileMap.find(LookupName); - if (It == NameFileMap.end()) { + // Load the ASTUnit from the pre-dumped AST file specified by ASTFileName. + std::unique_ptr<ASTUnit> LoadedUnit = FileAccessor(FileName); + + // Need the raw pointer and the unique_ptr as well. + ASTUnit *Unit = LoadedUnit.get(); + + // Update the cache. + FileASTUnitMap[FileName] = std::move(LoadedUnit); + + LoadGuard.indicateLoadSuccess(); + + if (DisplayCTUProgress) + llvm::errs() << "CTU loaded AST file: " << FileName << "\n"; + + return Unit; + + } else { + // Found in the cache. + return ASTCacheEntry->second.get(); + } +} + +llvm::Expected<ASTUnit *> +CrossTranslationUnitContext::ASTUnitStorage::getASTUnitForFunction( + StringRef FunctionName, StringRef CrossTUDir, StringRef IndexName, + bool DisplayCTUProgress) { + // Try the cache first. + auto ASTCacheEntry = NameASTUnitMap.find(FunctionName); + if (ASTCacheEntry == NameASTUnitMap.end()) { + // Load the ASTUnit from the pre-dumped AST file specified by ASTFileName. + + // Ensure that the Index is loaded, as we need to search in it. + if (llvm::Error IndexLoadError = + ensureCTUIndexLoaded(CrossTUDir, IndexName)) + return std::move(IndexLoadError); + + // Check if there is and entry in the index for the function. + if (!NameFileMap.count(FunctionName)) { ++NumNotInOtherTU; return llvm::make_error<IndexError>(index_error_code::missing_definition); } - StringRef ASTFileName = It->second; - auto ASTCacheEntry = FileASTUnitMap.find(ASTFileName); - if (ASTCacheEntry == FileASTUnitMap.end()) { - IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions(); - TextDiagnosticPrinter *DiagClient = - new TextDiagnosticPrinter(llvm::errs(), &*DiagOpts); - IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs()); - IntrusiveRefCntPtr<DiagnosticsEngine> Diags( - new DiagnosticsEngine(DiagID, &*DiagOpts, DiagClient)); - - std::unique_ptr<ASTUnit> LoadedUnit(ASTUnit::LoadFromASTFile( - ASTFileName, CI.getPCHContainerOperations()->getRawReader(), - ASTUnit::LoadEverything, Diags, CI.getFileSystemOpts())); - Unit = LoadedUnit.get(); - FileASTUnitMap[ASTFileName] = std::move(LoadedUnit); - ++NumASTLoaded; - if (DisplayCTUProgress) { - llvm::errs() << "CTU loaded AST file: " - << ASTFileName << "\n"; - } + + // Search in the index for the filename where the definition of FuncitonName + // resides. + if (llvm::Expected<ASTUnit *> FoundForFile = + getASTUnitForFile(NameFileMap[FunctionName], DisplayCTUProgress)) { + + // Update the cache. + NameASTUnitMap[FunctionName] = *FoundForFile; + return *FoundForFile; + } else { - Unit = ASTCacheEntry->second.get(); + return FoundForFile.takeError(); } - NameASTUnitMap[LookupName] = Unit; } else { - Unit = NameUnitCacheEntry->second; + // Found in the cache. + return ASTCacheEntry->second; } +} + +llvm::Expected<std::string> +CrossTranslationUnitContext::ASTUnitStorage::getFileForFunction( + StringRef FunctionName, StringRef CrossTUDir, StringRef IndexName) { + if (llvm::Error IndexLoadError = ensureCTUIndexLoaded(CrossTUDir, IndexName)) + return std::move(IndexLoadError); + return NameFileMap[FunctionName]; +} + +llvm::Error CrossTranslationUnitContext::ASTUnitStorage::ensureCTUIndexLoaded( + StringRef CrossTUDir, StringRef IndexName) { + // Dont initialize if the map is filled. + if (!NameFileMap.empty()) + return llvm::Error::success(); + + // Get the absolute path to the index file. + SmallString<256> IndexFile = CrossTUDir; + if (llvm::sys::path::is_absolute(IndexName)) + IndexFile = IndexName; + else + llvm::sys::path::append(IndexFile, IndexName); + + if (auto IndexMapping = parseCrossTUIndex(IndexFile, CrossTUDir)) { + // Initialize member map. + NameFileMap = *IndexMapping; + return llvm::Error::success(); + } else { + // Error while parsing CrossTU index file. + return IndexMapping.takeError(); + }; +} + +llvm::Expected<ASTUnit *> CrossTranslationUnitContext::loadExternalAST( + StringRef LookupName, StringRef CrossTUDir, StringRef IndexName, + bool DisplayCTUProgress) { + // FIXME: The current implementation only supports loading decls with + // a lookup name from a single translation unit. If multiple + // translation units contains decls with the same lookup name an + // error will be returned. + + // Try to get the value from the heavily cached storage. + llvm::Expected<ASTUnit *> Unit = ASTStorage.getASTUnitForFunction( + LookupName, CrossTUDir, IndexName, DisplayCTUProgress); + if (!Unit) + return Unit.takeError(); + + // Check whether the backing pointer of the Expected is a nullptr. + if (!*Unit) return llvm::make_error<IndexError>( index_error_code::failed_to_get_external_ast); + return Unit; } template <typename T> llvm::Expected<const T *> -CrossTranslationUnitContext::importDefinitionImpl(const T *D) { +CrossTranslationUnitContext::importDefinitionImpl(const T *D, ASTUnit *Unit) { assert(hasBodyOrInit(D) && "Decls to be imported should have body or init."); - ASTImporter &Importer = getOrCreateASTImporter(D->getASTContext()); + assert(&D->getASTContext() == &Unit->getASTContext() && + "ASTContext of Decl and the unit should match."); + ASTImporter &Importer = getOrCreateASTImporter(Unit); + auto ToDeclOrError = Importer.Import(D); if (!ToDeclOrError) { handleAllErrors(ToDeclOrError.takeError(), @@ -441,13 +529,15 @@ CrossTranslationUnitContext::importDefinitionImpl(const T *D) { } llvm::Expected<const FunctionDecl *> -CrossTranslationUnitContext::importDefinition(const FunctionDecl *FD) { - return importDefinitionImpl(FD); +CrossTranslationUnitContext::importDefinition(const FunctionDecl *FD, + ASTUnit *Unit) { + return importDefinitionImpl(FD, Unit); } llvm::Expected<const VarDecl *> -CrossTranslationUnitContext::importDefinition(const VarDecl *VD) { - return importDefinitionImpl(VD); +CrossTranslationUnitContext::importDefinition(const VarDecl *VD, + ASTUnit *Unit) { + return importDefinitionImpl(VD, Unit); } void CrossTranslationUnitContext::lazyInitImporterSharedSt( @@ -457,7 +547,9 @@ void CrossTranslationUnitContext::lazyInitImporterSharedSt( } ASTImporter & -CrossTranslationUnitContext::getOrCreateASTImporter(ASTContext &From) { +CrossTranslationUnitContext::getOrCreateASTImporter(ASTUnit *Unit) { + ASTContext &From = Unit->getASTContext(); + auto I = ASTUnitImporterMap.find(From.getTranslationUnitDecl()); if (I != ASTUnitImporterMap.end()) return *I->second; @@ -465,9 +557,32 @@ CrossTranslationUnitContext::getOrCreateASTImporter(ASTContext &From) { ASTImporter *NewImporter = new ASTImporter( Context, Context.getSourceManager().getFileManager(), From, From.getSourceManager().getFileManager(), false, ImporterSharedSt); + NewImporter->setFileIDImportHandler([this, Unit](FileID ToID, FileID FromID) { + assert(ImportedFileIDs.find(ToID) == ImportedFileIDs.end() && + "FileID already imported, should not happen."); + ImportedFileIDs[ToID] = std::make_pair(FromID, Unit); + }); ASTUnitImporterMap[From.getTranslationUnitDecl()].reset(NewImporter); return *NewImporter; } +llvm::Optional<std::pair<SourceLocation, ASTUnit *>> +CrossTranslationUnitContext::getImportedFromSourceLocation( + const clang::SourceLocation &ToLoc) const { + const SourceManager &SM = Context.getSourceManager(); + auto DecToLoc = SM.getDecomposedLoc(ToLoc); + + auto I = ImportedFileIDs.find(DecToLoc.first); + if (I == ImportedFileIDs.end()) + return {}; + + FileID FromID = I->second.first; + clang::ASTUnit *Unit = I->second.second; + SourceLocation FromLoc = + Unit->getSourceManager().getComposedLoc(FromID, DecToLoc.second); + + return std::make_pair(FromLoc, Unit); +} + } // namespace cross_tu } // namespace clang |