22 #include "llvm/ADT/Triple.h" 23 #include "llvm/ADT/Statistic.h" 24 #include "llvm/Support/ErrorHandling.h" 25 #include "llvm/Support/ManagedStatic.h" 26 #include "llvm/Support/Path.h" 27 #include "llvm/Support/raw_ostream.h" 36 #define DEBUG_TYPE "CrossTranslationUnit" 37 STATISTIC(NumGetCTUCalled,
"The # of getCTUDefinition function called");
40 "The # of getCTUDefinition called but the function is not in any other TU");
42 "The # of getCTUDefinition successfully returned the " 43 "requested function's body");
44 STATISTIC(NumTripleMismatch,
"The # of triple mismatches");
45 STATISTIC(NumLangMismatch,
"The # of language mismatches");
49 bool hasEqualKnownFields(
const llvm::Triple &Lhs,
const llvm::Triple &Rhs) {
51 if (Lhs.getArch() != Triple::UnknownArch &&
52 Rhs.getArch() != Triple::UnknownArch && Lhs.getArch() != Rhs.getArch())
54 if (Lhs.getSubArch() != Triple::NoSubArch &&
55 Rhs.getSubArch() != Triple::NoSubArch &&
56 Lhs.getSubArch() != Rhs.getSubArch())
58 if (Lhs.getVendor() != Triple::UnknownVendor &&
59 Rhs.getVendor() != Triple::UnknownVendor &&
60 Lhs.getVendor() != Rhs.getVendor())
62 if (!Lhs.isOSUnknown() && !Rhs.isOSUnknown() &&
63 Lhs.getOS() != Rhs.getOS())
65 if (Lhs.getEnvironment() != Triple::UnknownEnvironment &&
66 Rhs.getEnvironment() != Triple::UnknownEnvironment &&
67 Lhs.getEnvironment() != Rhs.getEnvironment())
69 if (Lhs.getObjectFormat() != Triple::UnknownObjectFormat &&
70 Rhs.getObjectFormat() != Triple::UnknownObjectFormat &&
71 Lhs.getObjectFormat() != Rhs.getObjectFormat())
77 class IndexErrorCategory :
public std::error_category {
79 const char *name() const noexcept
override {
return "clang.index"; }
81 std::string message(
int Condition)
const override {
82 switch (static_cast<index_error_code>(Condition)) {
84 return "An unknown error has occurred.";
86 return "The index file is missing.";
88 return "Invalid index file format.";
90 return "Multiple definitions in the index file.";
92 return "Missing definition from the index file.";
94 return "Failed to import the definition.";
96 return "Failed to load external AST source.";
98 return "Failed to generate USR.";
100 return "Triple mismatch";
102 return "Language mismatch";
104 llvm_unreachable(
"Unrecognized index_error_code.");
108 static llvm::ManagedStatic<IndexErrorCategory>
Category;
114 OS <<
Category->message(static_cast<int>(Code)) <<
'\n';
118 return std::error_code(static_cast<int>(Code), *
Category);
123 std::ifstream ExternalMapFile(IndexPath);
124 if (!ExternalMapFile)
128 llvm::StringMap<std::string> Result;
131 while (std::getline(ExternalMapFile, Line)) {
132 const size_t Pos = Line.find(
" ");
133 if (Pos > 0 && Pos != std::string::npos) {
134 StringRef LineRef{Line};
135 StringRef LookupName = LineRef.substr(0, Pos);
136 if (Result.count(LookupName))
137 return llvm::make_error<IndexError>(
139 StringRef FileName = LineRef.substr(Pos + 1);
141 llvm::sys::path::append(FilePath, FileName);
142 Result[LookupName] = FilePath.str().str();
144 return llvm::make_error<IndexError>(
153 std::ostringstream Result;
154 for (
const auto &E : Index)
155 Result << E.getKey().str() <<
" " << E.getValue() <<
'\n';
160 : CI(CI), Context(CI.getASTContext()) {}
167 assert(!Ret &&
"Unable to generate USR");
168 return DeclUSR.str();
174 CrossTranslationUnitContext::findFunctionInDeclContext(
const DeclContext *DC,
175 StringRef LookupFnName) {
176 assert(DC &&
"Declaration Context must not be null");
180 if (
const auto *FD = findFunctionInDeclContext(SubDC, LookupFnName))
185 if (!ND || !ND->hasBody(ResultDecl))
196 StringRef CrossTUDir,
198 bool DisplayCTUProgress) {
199 assert(FD &&
"FD is missing, bad call to this function!");
200 assert(!FD->
hasBody() &&
"FD has a definition in current translation unit!");
203 if (LookupFnName.empty())
204 return llvm::make_error<IndexError>(
207 loadExternalAST(LookupFnName, CrossTUDir, IndexName, DisplayCTUProgress);
209 return ASTUnitOrError.takeError();
210 ASTUnit *Unit = *ASTUnitOrError;
215 const llvm::Triple &TripleFrom =
221 if (!hasEqualKnownFields(TripleTo, TripleFrom)) {
234 if (LangTo.CPlusPlus != LangFrom.CPlusPlus) {
241 findFunctionInDeclContext(TU, LookupFnName))
270 StringRef LookupName, StringRef CrossTUDir, StringRef IndexName,
271 bool DisplayCTUProgress) {
277 auto FnUnitCacheEntry = FunctionASTUnitMap.find(LookupName);
278 if (FnUnitCacheEntry == FunctionASTUnitMap.end()) {
279 if (FunctionFileMap.empty()) {
281 if (llvm::sys::path::is_absolute(IndexName))
282 IndexFile = IndexName;
284 llvm::sys::path::append(IndexFile, IndexName);
288 FunctionFileMap = *IndexOrErr;
290 return IndexOrErr.takeError();
293 auto It = FunctionFileMap.find(LookupName);
294 if (It == FunctionFileMap.end()) {
298 StringRef ASTFileName = It->second;
299 auto ASTCacheEntry = FileASTUnitMap.find(ASTFileName);
300 if (ASTCacheEntry == FileASTUnitMap.end()) {
311 Unit = LoadedUnit.get();
312 FileASTUnitMap[ASTFileName] = std::move(LoadedUnit);
313 if (DisplayCTUProgress) {
314 llvm::errs() <<
"CTU loaded AST file: " 315 << ASTFileName <<
"\n";
318 Unit = ASTCacheEntry->second.get();
320 FunctionASTUnitMap[LookupName] = Unit;
322 Unit = FnUnitCacheEntry->second;
325 return llvm::make_error<IndexError>(
332 assert(FD->
hasBody() &&
"Functions to be imported should have body.");
336 cast_or_null<FunctionDecl>(Importer.Import(const_cast<FunctionDecl *>(FD)));
339 assert(ToDecl->hasBody());
340 assert(FD->
hasBody() &&
"Functions already imported should have body.");
345 void CrossTranslationUnitContext::lazyInitLookupTable(
348 LookupTable = llvm::make_unique<ASTImporterLookupTable>(*ToTU);
352 CrossTranslationUnitContext::getOrCreateASTImporter(
ASTContext &From) {
354 if (I != ASTUnitImporterMap.end())
Represents a function declaration or definition.
CrossTranslationUnitContext(CompilerInstance &CI)
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 function 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
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, bool CaptureDiagnostics=false, bool AllowPCHWithCompilerErrors=false, bool UserFilesAreVolatile=false)
Create a ASTUnit from an AST file.
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
Concrete class used by the front-end to report problems and issues.
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.
ASTContext & getASTContext() const LLVM_READONLY
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.
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()
llvm::Expected< const FunctionDecl * > getCrossTUDefinition(const FunctionDecl *FD, StringRef CrossTUDir, StringRef IndexName, bool DisplayCTUProgress=false)
This function loads a function definition from an external AST file and merge it into the original AS...
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 function.
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