21 #include "llvm/ADT/Triple.h" 22 #include "llvm/ADT/Statistic.h" 23 #include "llvm/Support/ErrorHandling.h" 24 #include "llvm/Support/ManagedStatic.h" 25 #include "llvm/Support/Path.h" 26 #include "llvm/Support/raw_ostream.h" 35 #define DEBUG_TYPE "CrossTranslationUnit" 36 STATISTIC(NumGetCTUCalled,
"The # of getCTUDefinition function called");
39 "The # of getCTUDefinition called but the function is not in any other TU");
41 "The # of getCTUDefinition successfully returned the " 42 "requested function's body");
43 STATISTIC(NumUnsupportedNodeFound,
"The # of imports when the ASTImporter " 44 "encountered an unsupported AST Node");
45 STATISTIC(NumNameConflicts,
"The # of imports when the ASTImporter " 46 "encountered an ODR error");
47 STATISTIC(NumTripleMismatch,
"The # of triple mismatches");
48 STATISTIC(NumLangMismatch,
"The # of language mismatches");
49 STATISTIC(NumLangDialectMismatch,
"The # of language dialect mismatches");
51 "The # of ASTs not loaded because of threshold");
55 bool hasEqualKnownFields(
const llvm::Triple &Lhs,
const llvm::Triple &Rhs) {
57 if (Lhs.getArch() != Triple::UnknownArch &&
58 Rhs.getArch() != Triple::UnknownArch && Lhs.getArch() != Rhs.getArch())
60 if (Lhs.getSubArch() != Triple::NoSubArch &&
61 Rhs.getSubArch() != Triple::NoSubArch &&
62 Lhs.getSubArch() != Rhs.getSubArch())
64 if (Lhs.getVendor() != Triple::UnknownVendor &&
65 Rhs.getVendor() != Triple::UnknownVendor &&
66 Lhs.getVendor() != Rhs.getVendor())
68 if (!Lhs.isOSUnknown() && !Rhs.isOSUnknown() &&
69 Lhs.getOS() != Rhs.getOS())
71 if (Lhs.getEnvironment() != Triple::UnknownEnvironment &&
72 Rhs.getEnvironment() != Triple::UnknownEnvironment &&
73 Lhs.getEnvironment() != Rhs.getEnvironment())
75 if (Lhs.getObjectFormat() != Triple::UnknownObjectFormat &&
76 Rhs.getObjectFormat() != Triple::UnknownObjectFormat &&
77 Lhs.getObjectFormat() != Rhs.getObjectFormat())
83 class IndexErrorCategory :
public std::error_category {
85 const char *
name() const noexcept
override {
return "clang.index"; }
87 std::string message(
int Condition)
const override {
88 switch (static_cast<index_error_code>(Condition)) {
90 return "An unknown error has occurred.";
92 return "The index file is missing.";
94 return "Invalid index file format.";
96 return "Multiple definitions in the index file.";
98 return "Missing definition from the index file.";
100 return "Failed to import the definition.";
102 return "Failed to load external AST source.";
104 return "Failed to generate USR.";
106 return "Triple mismatch";
108 return "Language mismatch";
110 return "Language dialect mismatch";
112 return "Load threshold reached";
114 llvm_unreachable(
"Unrecognized index_error_code.");
118 static llvm::ManagedStatic<IndexErrorCategory>
Category;
124 OS <<
Category->message(static_cast<int>(Code)) <<
'\n';
128 return std::error_code(static_cast<int>(Code), *
Category);
133 std::ifstream ExternalMapFile(IndexPath);
134 if (!ExternalMapFile)
138 llvm::StringMap<std::string> Result;
141 while (std::getline(ExternalMapFile, Line)) {
142 const size_t Pos = Line.find(
" ");
143 if (Pos > 0 && Pos != std::string::npos) {
144 StringRef LineRef{Line};
145 StringRef LookupName = LineRef.substr(0, Pos);
146 if (Result.count(LookupName))
147 return llvm::make_error<IndexError>(
149 StringRef FileName = LineRef.substr(Pos + 1);
151 llvm::sys::path::append(FilePath, FileName);
152 Result[LookupName] = FilePath.str().str();
154 return llvm::make_error<IndexError>(
163 std::ostringstream Result;
164 for (
const auto &E : Index)
165 Result << E.getKey().str() <<
" " << E.getValue() <<
'\n';
191 : CI(CI), Context(CI.getASTContext()),
192 CTULoadThreshold(CI.getAnalyzerOpts()->CTUImportThreshold) {}
200 assert(!Ret &&
"Unable to generate USR");
201 return DeclUSR.str();
206 template <
typename T>
208 CrossTranslationUnitContext::findDefInDeclContext(
const DeclContext *DC,
209 StringRef LookupName) {
210 assert(DC &&
"Declaration Context must not be null");
214 if (
const auto *ND = findDefInDeclContext<T>(SubDC, LookupName))
217 const auto *ND = dyn_cast<T>(D);
228 template <
typename T>
230 const T *D, StringRef CrossTUDir, StringRef IndexName,
231 bool DisplayCTUProgress) {
232 assert(D &&
"D is missing, bad call to this function!");
234 "D has a body or init in current translation unit!");
237 if (LookupName.empty())
238 return llvm::make_error<IndexError>(
241 LookupName, CrossTUDir, IndexName, DisplayCTUProgress);
243 return ASTUnitOrError.takeError();
244 ASTUnit *Unit = *ASTUnitOrError;
249 const llvm::Triple &TripleFrom =
255 if (!hasEqualKnownFields(TripleTo, TripleFrom)) {
269 if (LangTo.CPlusPlus != LangFrom.CPlusPlus) {
287 if (LangTo.CPlusPlus11 != LangFrom.CPlusPlus11 ||
288 LangTo.CPlusPlus14 != LangFrom.CPlusPlus14 ||
289 LangTo.CPlusPlus17 != LangFrom.CPlusPlus17 ||
290 LangTo.CPlusPlus2a != LangFrom.CPlusPlus2a) {
291 ++NumLangDialectMismatch;
292 return llvm::make_error<IndexError>(
297 if (
const T *ResultDecl = findDefInDeclContext<T>(TU, LookupName))
304 StringRef CrossTUDir,
306 bool DisplayCTUProgress) {
307 return getCrossTUDefinitionImpl(FD, CrossTUDir, IndexName,
313 StringRef CrossTUDir,
315 bool DisplayCTUProgress) {
316 return getCrossTUDefinitionImpl(VD, CrossTUDir, IndexName,
344 StringRef LookupName, StringRef CrossTUDir, StringRef IndexName,
345 bool DisplayCTUProgress) {
351 if (NumASTLoaded >= CTULoadThreshold) {
352 ++NumASTLoadThresholdReached;
353 return llvm::make_error<IndexError>(
358 auto NameUnitCacheEntry = NameASTUnitMap.find(LookupName);
359 if (NameUnitCacheEntry == NameASTUnitMap.end()) {
360 if (NameFileMap.empty()) {
362 if (llvm::sys::path::is_absolute(IndexName))
363 IndexFile = IndexName;
365 llvm::sys::path::append(IndexFile, IndexName);
369 NameFileMap = *IndexOrErr;
371 return IndexOrErr.takeError();
374 auto It = NameFileMap.find(LookupName);
375 if (It == NameFileMap.end()) {
379 StringRef ASTFileName = It->second;
380 auto ASTCacheEntry = FileASTUnitMap.find(ASTFileName);
381 if (ASTCacheEntry == FileASTUnitMap.end()) {
392 Unit = LoadedUnit.get();
393 FileASTUnitMap[ASTFileName] = std::move(LoadedUnit);
395 if (DisplayCTUProgress) {
396 llvm::errs() <<
"CTU loaded AST file: " 397 << ASTFileName <<
"\n";
400 Unit = ASTCacheEntry->second.get();
402 NameASTUnitMap[LookupName] = Unit;
404 Unit = NameUnitCacheEntry->second;
407 return llvm::make_error<IndexError>(
412 template <
typename T>
414 CrossTranslationUnitContext::importDefinitionImpl(
const T *D) {
415 assert(
hasBodyOrInit(D) &&
"Decls to be imported should have body or init.");
417 ASTImporter &Importer = getOrCreateASTImporter(D->getASTContext());
418 auto ToDeclOrError = Importer.
Import(D);
419 if (!ToDeclOrError) {
420 handleAllErrors(ToDeclOrError.takeError(),
427 ++NumUnsupportedNodeFound;
430 llvm_unreachable(
"Unknown import error happened.");
436 auto *ToDecl = cast<T>(*ToDeclOrError);
437 assert(
hasBodyOrInit(ToDecl) &&
"Imported Decl should have body or init.");
445 return importDefinitionImpl(FD);
450 return importDefinitionImpl(VD);
453 void CrossTranslationUnitContext::lazyInitImporterSharedSt(
455 if (!ImporterSharedSt)
456 ImporterSharedSt = std::make_shared<ASTImporterSharedState>(*ToTU);
460 CrossTranslationUnitContext::getOrCreateASTImporter(
ASTContext &From) {
462 if (I != ASTUnitImporterMap.end())
Represents a function declaration or definition.
CrossTranslationUnitContext(CompilerInstance &CI)
bool isConstQualified() const
const llvm::Triple & getTriple() const
Returns the target triple of the primary target.
Load everything, including Sema.
std::shared_ptr< PCHContainerOperations > getPCHContainerOperations() const
Decl - This represents one declaration (or definition), e.g.
const FileManager & getFileManager() const
llvm::Expected< ASTUnit * > loadExternalAST(StringRef LookupName, StringRef CrossTUDir, StringRef IndexName, bool DisplayCTUProgress=false)
This function loads a definition from an external AST file.
void log(raw_ostream &OS) const override
DiagnosticsEngine & getDiagnostics() const
DiagnosticBuilder Report(SourceLocation Loc, unsigned DiagID)
Issue the message to the client.
const TargetInfo & getTargetInfo() const
const Expr * getAnyInitializer() const
Get the initializer for this variable, no matter which declaration it is attached to...
Not supported node or case.
Represents a variable declaration or definition.
decl_range decls() const
decls_begin/decls_end - Iterate over the declarations stored in this context.
FileManager & getFileManager() const
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
Utility class for loading a ASTContext from an AST file.
StringRef getMainFileName() const
static std::unique_ptr< ASTUnit > LoadFromASTFile(const std::string &Filename, const PCHContainerReader &PCHContainerRdr, WhatToLoad ToLoad, IntrusiveRefCntPtr< DiagnosticsEngine > Diags, const FileSystemOptions &FileSystemOpts, bool UseDebugInfo=false, bool OnlyLocalDecls=false, ArrayRef< RemappedFile > RemappedFiles=None, CaptureDiagsKind CaptureDiagnostics=CaptureDiagsKind::None, bool AllowPCHWithCompilerErrors=false, bool UserFilesAreVolatile=false)
Create a ASTUnit from an AST file.
Concrete class used by the front-end to report problems and issues.
bool containsConst(const VarDecl *VD, const ASTContext &ACtx)
STATISTIC(NumObjCCallEdges, "Number of Objective-C method call edges")
const AnnotatedLine * Line
std::string createCrossTUIndexString(const llvm::StringMap< std::string > &Index)
bool hasBody(const FunctionDecl *&Definition) const
Returns true if the function has a body.
std::string getFileName() const
llvm::Expected< llvm::StringMap< std::string > > parseCrossTUIndex(StringRef IndexPath, StringRef CrossTUDir)
This function parses an index file that determines which translation unit contains which definition...
~CrossTranslationUnitContext()
FileSystemOptions & getFileSystemOpts()
CompilerInstance - Helper class for managing a single instance of the Clang compiler.
Options for controlling the compiler diagnostics engine.
llvm::Expected< QualType > Import(QualType FromT)
Import the given type from the "from" context into the "to" context.
static bool hasBodyOrInit(const FunctionDecl *D, const FunctionDecl *&DefD)
Naming ambiguity (likely ODR violation).
bool hasConstFields() const
Recursively check all fields in the record for const-ness.
CanProxy< U > getAs() const
Retrieve a canonical type pointer with a different static type, upcasting or downcasting as needed...
Dataflow Directional Tag Classes.
DeclContext - This is used only as base class of specific decl types that can act as declaration cont...
Used for handling and querying diagnostic IDs.
A helper class that allows the use of isa/cast/dyncast to detect TagType objects of structs/unions/cl...
index_error_code getCode() const
Imports selected nodes from one AST context into another context, merging AST nodes where appropriate...
llvm::Expected< const FunctionDecl * > importDefinition(const FunctionDecl *FD)
This function merges a definition from a separate AST Unit into the current one which was created by ...
const ASTContext & getASTContext() const
SourceManager & getSourceManager()
CanQualType getCanonicalType(QualType T) const
Return the canonical (structural) type corresponding to the specified potentially non-canonical type ...
llvm::Expected< const FunctionDecl * > getCrossTUDefinition(const FunctionDecl *FD, StringRef CrossTUDir, StringRef IndexName, bool DisplayCTUProgress=false)
This function loads a function or variable definition from an external AST file and merges it into th...
std::error_code convertToErrorCode() const override
TranslationUnitDecl * getTranslationUnitDecl() const
Defines the clang::TargetInfo interface.
static std::string getLookupName(const NamedDecl *ND)
Get a name to identify a named decl.
void emitCrossTUDiagnostics(const IndexError &IE)
Emit diagnostics for the user for potential configuration errors.
The top declaration context.
bool generateUSRForDecl(const Decl *D, SmallVectorImpl< char > &Buf)
Generate a USR for a Decl, including the USR prefix.
This represents a decl that may have a name.
std::string getTripleToName() const
const LangOptions & getLangOpts() const
std::string getTripleFromName() const