diff options
Diffstat (limited to 'lib/CrossTU/CrossTranslationUnit.cpp')
-rw-r--r-- | lib/CrossTU/CrossTranslationUnit.cpp | 138 |
1 files changed, 117 insertions, 21 deletions
diff --git a/lib/CrossTU/CrossTranslationUnit.cpp b/lib/CrossTU/CrossTranslationUnit.cpp index e20ea7702237c..7c97beb498a57 100644 --- a/lib/CrossTU/CrossTranslationUnit.cpp +++ b/lib/CrossTU/CrossTranslationUnit.cpp @@ -17,10 +17,10 @@ #include "clang/CrossTU/CrossTUDiagnostic.h" #include "clang/Frontend/ASTUnit.h" #include "clang/Frontend/CompilerInstance.h" -#include "clang/Frontend/FrontendDiagnostic.h" #include "clang/Frontend/TextDiagnosticPrinter.h" #include "clang/Index/USRGeneration.h" #include "llvm/ADT/Triple.h" +#include "llvm/ADT/Statistic.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/ManagedStatic.h" #include "llvm/Support/Path.h" @@ -32,6 +32,47 @@ namespace clang { namespace cross_tu { namespace { + +#define DEBUG_TYPE "CrossTranslationUnit" +STATISTIC(NumGetCTUCalled, "The # of getCTUDefinition function called"); +STATISTIC( + NumNotInOtherTU, + "The # of getCTUDefinition called but the function is not in any other TU"); +STATISTIC(NumGetCTUSuccess, + "The # of getCTUDefinition successfully returned the " + "requested function's body"); +STATISTIC(NumTripleMismatch, "The # of triple mismatches"); +STATISTIC(NumLangMismatch, "The # of language mismatches"); + +// Same as Triple's equality operator, but we check a field only if that is +// known in both instances. +bool hasEqualKnownFields(const llvm::Triple &Lhs, const llvm::Triple &Rhs) { + using llvm::Triple; + if (Lhs.getArch() != Triple::UnknownArch && + Rhs.getArch() != Triple::UnknownArch && Lhs.getArch() != Rhs.getArch()) + return false; + if (Lhs.getSubArch() != Triple::NoSubArch && + Rhs.getSubArch() != Triple::NoSubArch && + Lhs.getSubArch() != Rhs.getSubArch()) + return false; + if (Lhs.getVendor() != Triple::UnknownVendor && + Rhs.getVendor() != Triple::UnknownVendor && + Lhs.getVendor() != Rhs.getVendor()) + return false; + if (!Lhs.isOSUnknown() && !Rhs.isOSUnknown() && + Lhs.getOS() != Rhs.getOS()) + return false; + if (Lhs.getEnvironment() != Triple::UnknownEnvironment && + Rhs.getEnvironment() != Triple::UnknownEnvironment && + Lhs.getEnvironment() != Rhs.getEnvironment()) + return false; + if (Lhs.getObjectFormat() != Triple::UnknownObjectFormat && + Rhs.getObjectFormat() != Triple::UnknownObjectFormat && + Lhs.getObjectFormat() != Rhs.getObjectFormat()) + return false; + return true; +} + // FIXME: This class is will be removed after the transition to llvm::Error. class IndexErrorCategory : public std::error_category { public: @@ -55,6 +96,10 @@ public: return "Failed to load external AST source."; case index_error_code::failed_to_generate_usr: return "Failed to generate USR."; + case index_error_code::triple_mismatch: + return "Triple mismatch"; + case index_error_code::lang_mismatch: + return "Language mismatch"; } llvm_unreachable("Unrecognized index_error_code."); } @@ -75,26 +120,26 @@ std::error_code IndexError::convertToErrorCode() const { llvm::Expected<llvm::StringMap<std::string>> parseCrossTUIndex(StringRef IndexPath, StringRef CrossTUDir) { - std::ifstream ExternalFnMapFile(IndexPath); - if (!ExternalFnMapFile) + std::ifstream ExternalMapFile(IndexPath); + if (!ExternalMapFile) return llvm::make_error<IndexError>(index_error_code::missing_index_file, IndexPath.str()); llvm::StringMap<std::string> Result; std::string Line; unsigned LineNo = 1; - while (std::getline(ExternalFnMapFile, Line)) { + while (std::getline(ExternalMapFile, Line)) { const size_t Pos = Line.find(" "); if (Pos > 0 && Pos != std::string::npos) { StringRef LineRef{Line}; - StringRef FunctionLookupName = LineRef.substr(0, Pos); - if (Result.count(FunctionLookupName)) + StringRef LookupName = LineRef.substr(0, Pos); + if (Result.count(LookupName)) return llvm::make_error<IndexError>( index_error_code::multiple_definitions, IndexPath.str(), LineNo); StringRef FileName = LineRef.substr(Pos + 1); SmallString<256> FilePath = CrossTUDir; llvm::sys::path::append(FilePath, FileName); - Result[FunctionLookupName] = FilePath.str().str(); + Result[LookupName] = FilePath.str().str(); } else return llvm::make_error<IndexError>( index_error_code::invalid_index_format, IndexPath.str(), LineNo); @@ -149,23 +194,48 @@ CrossTranslationUnitContext::findFunctionInDeclContext(const DeclContext *DC, llvm::Expected<const FunctionDecl *> CrossTranslationUnitContext::getCrossTUDefinition(const FunctionDecl *FD, StringRef CrossTUDir, - StringRef IndexName) { + 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!"); + ++NumGetCTUCalled; const std::string LookupFnName = getLookupName(FD); if (LookupFnName.empty()) return llvm::make_error<IndexError>( index_error_code::failed_to_generate_usr); llvm::Expected<ASTUnit *> ASTUnitOrError = - loadExternalAST(LookupFnName, CrossTUDir, IndexName); + loadExternalAST(LookupFnName, CrossTUDir, IndexName, DisplayCTUProgress); if (!ASTUnitOrError) return ASTUnitOrError.takeError(); ASTUnit *Unit = *ASTUnitOrError; - if (!Unit) - return llvm::make_error<IndexError>( - index_error_code::failed_to_get_external_ast); assert(&Unit->getFileManager() == &Unit->getASTContext().getSourceManager().getFileManager()); + const llvm::Triple &TripleTo = Context.getTargetInfo().getTriple(); + const llvm::Triple &TripleFrom = + Unit->getASTContext().getTargetInfo().getTriple(); + // The imported AST had been generated for a different target. + // Some parts of the triple in the loaded ASTContext can be unknown while the + // very same parts in the target ASTContext are known. Thus we check for the + // known parts only. + if (!hasEqualKnownFields(TripleTo, TripleFrom)) { + // TODO: Pass the SourceLocation of the CallExpression for more precise + // diagnostics. + ++NumTripleMismatch; + return llvm::make_error<IndexError>(index_error_code::triple_mismatch, + Unit->getMainFileName(), TripleTo.str(), + TripleFrom.str()); + } + + 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) { + ++NumLangMismatch; + return llvm::make_error<IndexError>(index_error_code::lang_mismatch); + } + TranslationUnitDecl *TU = Unit->getASTContext().getTranslationUnitDecl(); if (const FunctionDecl *ResultDecl = findFunctionInDeclContext(TU, LookupFnName)) @@ -176,24 +246,29 @@ CrossTranslationUnitContext::getCrossTUDefinition(const FunctionDecl *FD, void CrossTranslationUnitContext::emitCrossTUDiagnostics(const IndexError &IE) { switch (IE.getCode()) { case index_error_code::missing_index_file: - Context.getDiagnostics().Report(diag::err_fe_error_opening) - << IE.getFileName() << "required by the CrossTU functionality"; + Context.getDiagnostics().Report(diag::err_ctu_error_opening) + << IE.getFileName(); break; case index_error_code::invalid_index_format: - Context.getDiagnostics().Report(diag::err_fnmap_parsing) + Context.getDiagnostics().Report(diag::err_extdefmap_parsing) << IE.getFileName() << IE.getLineNum(); break; case index_error_code::multiple_definitions: Context.getDiagnostics().Report(diag::err_multiple_def_index) << IE.getLineNum(); break; + case index_error_code::triple_mismatch: + Context.getDiagnostics().Report(diag::warn_ctu_incompat_triple) + << IE.getFileName() << IE.getTripleToName() << IE.getTripleFromName(); + break; default: break; } } llvm::Expected<ASTUnit *> CrossTranslationUnitContext::loadExternalAST( - StringRef LookupName, StringRef CrossTUDir, StringRef IndexName) { + StringRef LookupName, StringRef CrossTUDir, StringRef IndexName, + bool DisplayCTUProgress) { // FIXME: The current implementation only supports loading functions with // a lookup name from a single translation unit. If multiple // translation units contains functions with the same lookup name an @@ -216,8 +291,10 @@ llvm::Expected<ASTUnit *> CrossTranslationUnitContext::loadExternalAST( } auto It = FunctionFileMap.find(LookupName); - if (It == FunctionFileMap.end()) + if (It == FunctionFileMap.end()) { + ++NumNotInOtherTU; return llvm::make_error<IndexError>(index_error_code::missing_definition); + } StringRef ASTFileName = It->second; auto ASTCacheEntry = FileASTUnitMap.find(ASTFileName); if (ASTCacheEntry == FileASTUnitMap.end()) { @@ -233,6 +310,10 @@ llvm::Expected<ASTUnit *> CrossTranslationUnitContext::loadExternalAST( ASTUnit::LoadEverything, Diags, CI.getFileSystemOpts())); Unit = LoadedUnit.get(); FileASTUnitMap[ASTFileName] = std::move(LoadedUnit); + if (DisplayCTUProgress) { + llvm::errs() << "CTU loaded AST file: " + << ASTFileName << "\n"; + } } else { Unit = ASTCacheEntry->second.get(); } @@ -240,27 +321,42 @@ llvm::Expected<ASTUnit *> CrossTranslationUnitContext::loadExternalAST( } else { Unit = FnUnitCacheEntry->second; } + if (!Unit) + return llvm::make_error<IndexError>( + index_error_code::failed_to_get_external_ast); return Unit; } llvm::Expected<const FunctionDecl *> CrossTranslationUnitContext::importDefinition(const FunctionDecl *FD) { + assert(FD->hasBody() && "Functions to be imported should have body."); + ASTImporter &Importer = getOrCreateASTImporter(FD->getASTContext()); auto *ToDecl = - cast<FunctionDecl>(Importer.Import(const_cast<FunctionDecl *>(FD))); + cast_or_null<FunctionDecl>(Importer.Import(const_cast<FunctionDecl *>(FD))); + if (!ToDecl) + return llvm::make_error<IndexError>(index_error_code::failed_import); assert(ToDecl->hasBody()); assert(FD->hasBody() && "Functions already imported should have body."); + ++NumGetCTUSuccess; return ToDecl; } +void CrossTranslationUnitContext::lazyInitLookupTable( + TranslationUnitDecl *ToTU) { + if (!LookupTable) + LookupTable = llvm::make_unique<ASTImporterLookupTable>(*ToTU); +} + ASTImporter & CrossTranslationUnitContext::getOrCreateASTImporter(ASTContext &From) { auto I = ASTUnitImporterMap.find(From.getTranslationUnitDecl()); if (I != ASTUnitImporterMap.end()) return *I->second; - ASTImporter *NewImporter = - new ASTImporter(Context, Context.getSourceManager().getFileManager(), - From, From.getSourceManager().getFileManager(), false); + lazyInitLookupTable(Context.getTranslationUnitDecl()); + ASTImporter *NewImporter = new ASTImporter( + Context, Context.getSourceManager().getFileManager(), From, + From.getSourceManager().getFileManager(), false, LookupTable.get()); ASTUnitImporterMap[From.getTranslationUnitDecl()].reset(NewImporter); return *NewImporter; } |