clang  6.0.0svn
CrossTranslationUnit.cpp
Go to the documentation of this file.
1 //===--- CrossTranslationUnit.cpp - -----------------------------*- C++ -*-===//
2 //
3 // The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 // This file implements the CrossTranslationUnit interface.
11 //
12 //===----------------------------------------------------------------------===//
14 #include "clang/AST/ASTImporter.h"
15 #include "clang/AST/Decl.h"
16 #include "clang/Basic/TargetInfo.h"
18 #include "clang/Frontend/ASTUnit.h"
23 #include "llvm/ADT/Triple.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"
28 #include <fstream>
29 #include <sstream>
30 
31 namespace clang {
32 namespace cross_tu {
33 
34 namespace {
35 // FIXME: This class is will be removed after the transition to llvm::Error.
36 class IndexErrorCategory : public std::error_category {
37 public:
38  const char *name() const noexcept override { return "clang.index"; }
39 
40  std::string message(int Condition) const override {
41  switch (static_cast<index_error_code>(Condition)) {
43  return "An unknown error has occurred.";
45  return "The index file is missing.";
47  return "Invalid index file format.";
49  return "Multiple definitions in the index file.";
51  return "Missing definition from the index file.";
53  return "Failed to import the definition.";
55  return "Failed to load external AST source.";
57  return "Failed to generate USR.";
58  }
59  llvm_unreachable("Unrecognized index_error_code.");
60  }
61 };
62 
63 static llvm::ManagedStatic<IndexErrorCategory> Category;
64 } // end anonymous namespace
65 
66 char IndexError::ID;
67 
68 void IndexError::log(raw_ostream &OS) const {
69  OS << Category->message(static_cast<int>(Code)) << '\n';
70 }
71 
72 std::error_code IndexError::convertToErrorCode() const {
73  return std::error_code(static_cast<int>(Code), *Category);
74 }
75 
77 parseCrossTUIndex(StringRef IndexPath, StringRef CrossTUDir) {
78  std::ifstream ExternalFnMapFile(IndexPath);
79  if (!ExternalFnMapFile)
80  return llvm::make_error<IndexError>(index_error_code::missing_index_file,
81  IndexPath.str());
82 
83  llvm::StringMap<std::string> Result;
84  std::string Line;
85  unsigned LineNo = 1;
86  while (std::getline(ExternalFnMapFile, Line)) {
87  const size_t Pos = Line.find(" ");
88  if (Pos > 0 && Pos != std::string::npos) {
89  StringRef LineRef{Line};
90  StringRef FunctionLookupName = LineRef.substr(0, Pos);
91  if (Result.count(FunctionLookupName))
92  return llvm::make_error<IndexError>(
93  index_error_code::multiple_definitions, IndexPath.str(), LineNo);
94  StringRef FileName = LineRef.substr(Pos + 1);
95  SmallString<256> FilePath = CrossTUDir;
96  llvm::sys::path::append(FilePath, FileName);
97  Result[FunctionLookupName] = FilePath.str().str();
98  } else
99  return llvm::make_error<IndexError>(
100  index_error_code::invalid_index_format, IndexPath.str(), LineNo);
101  LineNo++;
102  }
103  return Result;
104 }
105 
106 std::string
107 createCrossTUIndexString(const llvm::StringMap<std::string> &Index) {
108  std::ostringstream Result;
109  for (const auto &E : Index)
110  Result << E.getKey().str() << " " << E.getValue() << '\n';
111  return Result.str();
112 }
113 
115  : CI(CI), Context(CI.getASTContext()) {}
116 
118 
120  SmallString<128> DeclUSR;
121  bool Ret = index::generateUSRForDecl(ND, DeclUSR); (void)Ret;
122  assert(!Ret && "Unable to generate USR");
123  return DeclUSR.str();
124 }
125 
126 /// Recursively visits the function decls of a DeclContext, and looks up a
127 /// function based on USRs.
128 const FunctionDecl *
129 CrossTranslationUnitContext::findFunctionInDeclContext(const DeclContext *DC,
130  StringRef LookupFnName) {
131  assert(DC && "Declaration Context must not be null");
132  for (const Decl *D : DC->decls()) {
133  const auto *SubDC = dyn_cast<DeclContext>(D);
134  if (SubDC)
135  if (const auto *FD = findFunctionInDeclContext(SubDC, LookupFnName))
136  return FD;
137 
138  const auto *ND = dyn_cast<FunctionDecl>(D);
139  const FunctionDecl *ResultDecl;
140  if (!ND || !ND->hasBody(ResultDecl))
141  continue;
142  if (getLookupName(ResultDecl) != LookupFnName)
143  continue;
144  return ResultDecl;
145  }
146  return nullptr;
147 }
148 
151  StringRef CrossTUDir,
152  StringRef IndexName) {
153  assert(!FD->hasBody() && "FD has a definition in current translation unit!");
154  const std::string LookupFnName = getLookupName(FD);
155  if (LookupFnName.empty())
156  return llvm::make_error<IndexError>(
158  llvm::Expected<ASTUnit *> ASTUnitOrError =
159  loadExternalAST(LookupFnName, CrossTUDir, IndexName);
160  if (!ASTUnitOrError)
161  return ASTUnitOrError.takeError();
162  ASTUnit *Unit = *ASTUnitOrError;
163  if (!Unit)
164  return llvm::make_error<IndexError>(
166  assert(&Unit->getFileManager() ==
168 
170  if (const FunctionDecl *ResultDecl =
171  findFunctionInDeclContext(TU, LookupFnName))
172  return importDefinition(ResultDecl);
173  return llvm::make_error<IndexError>(index_error_code::failed_import);
174 }
175 
177  switch (IE.getCode()) {
179  Context.getDiagnostics().Report(diag::err_fe_error_opening)
180  << IE.getFileName() << "required by the CrossTU functionality";
181  break;
183  Context.getDiagnostics().Report(diag::err_fnmap_parsing)
184  << IE.getFileName() << IE.getLineNum();
185  break;
187  Context.getDiagnostics().Report(diag::err_multiple_def_index)
188  << IE.getLineNum();
189  break;
190  default:
191  break;
192  }
193 }
194 
196  StringRef LookupName, StringRef CrossTUDir, StringRef IndexName) {
197  // FIXME: The current implementation only supports loading functions with
198  // a lookup name from a single translation unit. If multiple
199  // translation units contains functions with the same lookup name an
200  // error will be returned.
201  ASTUnit *Unit = nullptr;
202  auto FnUnitCacheEntry = FunctionASTUnitMap.find(LookupName);
203  if (FnUnitCacheEntry == FunctionASTUnitMap.end()) {
204  if (FunctionFileMap.empty()) {
205  SmallString<256> IndexFile = CrossTUDir;
206  if (llvm::sys::path::is_absolute(IndexName))
207  IndexFile = IndexName;
208  else
209  llvm::sys::path::append(IndexFile, IndexName);
211  parseCrossTUIndex(IndexFile, CrossTUDir);
212  if (IndexOrErr)
213  FunctionFileMap = *IndexOrErr;
214  else
215  return IndexOrErr.takeError();
216  }
217 
218  auto It = FunctionFileMap.find(LookupName);
219  if (It == FunctionFileMap.end())
220  return llvm::make_error<IndexError>(index_error_code::missing_definition);
221  StringRef ASTFileName = It->second;
222  auto ASTCacheEntry = FileASTUnitMap.find(ASTFileName);
223  if (ASTCacheEntry == FileASTUnitMap.end()) {
225  TextDiagnosticPrinter *DiagClient =
226  new TextDiagnosticPrinter(llvm::errs(), &*DiagOpts);
229  new DiagnosticsEngine(DiagID, &*DiagOpts, DiagClient));
230 
231  std::unique_ptr<ASTUnit> LoadedUnit(ASTUnit::LoadFromASTFile(
232  ASTFileName, CI.getPCHContainerOperations()->getRawReader(),
234  Unit = LoadedUnit.get();
235  FileASTUnitMap[ASTFileName] = std::move(LoadedUnit);
236  } else {
237  Unit = ASTCacheEntry->second.get();
238  }
239  FunctionASTUnitMap[LookupName] = Unit;
240  } else {
241  Unit = FnUnitCacheEntry->second;
242  }
243  return Unit;
244 }
245 
248  ASTImporter &Importer = getOrCreateASTImporter(FD->getASTContext());
249  auto *ToDecl =
250  cast<FunctionDecl>(Importer.Import(const_cast<FunctionDecl *>(FD)));
251  assert(ToDecl->hasBody());
252  assert(FD->hasBody() && "Functions already imported should have body.");
253  return ToDecl;
254 }
255 
256 ASTImporter &
257 CrossTranslationUnitContext::getOrCreateASTImporter(ASTContext &From) {
258  auto I = ASTUnitImporterMap.find(From.getTranslationUnitDecl());
259  if (I != ASTUnitImporterMap.end())
260  return *I->second;
261  ASTImporter *NewImporter =
262  new ASTImporter(Context, Context.getSourceManager().getFileManager(),
263  From, From.getSourceManager().getFileManager(), false);
264  ASTUnitImporterMap[From.getTranslationUnitDecl()].reset(NewImporter);
265  return *NewImporter;
266 }
267 
268 } // namespace cross_tu
269 } // namespace clang
FunctionDecl - An instance of this class is created to represent a function declaration or definition...
Definition: Decl.h:1698
Load everything, including Sema.
Definition: ASTUnit.h:637
std::shared_ptr< PCHContainerOperations > getPCHContainerOperations() const
Decl - This represents one declaration (or definition), e.g.
Definition: DeclBase.h:86
const FileManager & getFileManager() const
Definition: ASTUnit.h:444
void log(raw_ostream &OS) const override
DiagnosticsEngine & getDiagnostics() const
DiagnosticBuilder Report(SourceLocation Loc, unsigned DiagID)
Issue the message to the client.
Definition: Diagnostic.h:1207
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.
Definition: ASTUnit.cpp:683
decl_range decls() const
decls_begin/decls_end - Iterate over the declarations stored in this context.
Definition: DeclBase.h:1576
QualType Import(QualType FromT)
Import the given type from the "from" context into the "to" context.
llvm::Expected< ASTUnit * > loadExternalAST(StringRef LookupName, StringRef CrossTUDir, StringRef IndexName)
This function loads a function definition from an external AST file.
FileManager & getFileManager() const
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
Definition: ASTContext.h:149
Utility class for loading a ASTContext from an AST file.
Definition: ASTUnit.h:71
int Category
Definition: Format.cpp:1348
Concrete class used by the front-end to report problems and issues.
Definition: Diagnostic.h:147
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 (definition).
Definition: Decl.cpp:2576
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...
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
Definition: DeclBase.cpp:365
llvm::Expected< const FunctionDecl * > getCrossTUDefinition(const FunctionDecl *FD, StringRef CrossTUDir, StringRef IndexName)
This function loads a function definition from an external AST file and merge it into the original AS...
Dataflow Directional Tag Classes.
DeclContext - This is used only as base class of specific decl types that can act as declaration cont...
Definition: DeclBase.h:1252
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...
Definition: ASTImporter.h:40
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
Definition: ASTUnit.h:417
SourceManager & getSourceManager()
Definition: ASTContext.h:643
std::error_code convertToErrorCode() const override
TranslationUnitDecl * getTranslationUnitDecl() const
Definition: ASTContext.h:989
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.
TranslationUnitDecl - The top declaration context.
Definition: Decl.h:107
bool generateUSRForDecl(const Decl *D, SmallVectorImpl< char > &Buf)
Generate a USR for a Decl, including the USR prefix.
NamedDecl - This represents a decl with a name.
Definition: Decl.h:245