annotate clang/lib/CrossTU/CrossTranslationUnit.cpp @ 176:de4ac79aef9d

...
author Shinji KONO <kono@ie.u-ryukyu.ac.jp>
date Mon, 25 May 2020 17:13:11 +0900
parents 0572611fdcc8
children 2e18cbf3894f
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
150
anatofuz
parents:
diff changeset
1 //===--- CrossTranslationUnit.cpp - -----------------------------*- C++ -*-===//
anatofuz
parents:
diff changeset
2 //
anatofuz
parents:
diff changeset
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
anatofuz
parents:
diff changeset
4 // See https://llvm.org/LICENSE.txt for license information.
anatofuz
parents:
diff changeset
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
anatofuz
parents:
diff changeset
6 //
anatofuz
parents:
diff changeset
7 //===----------------------------------------------------------------------===//
anatofuz
parents:
diff changeset
8 //
anatofuz
parents:
diff changeset
9 // This file implements the CrossTranslationUnit interface.
anatofuz
parents:
diff changeset
10 //
anatofuz
parents:
diff changeset
11 //===----------------------------------------------------------------------===//
anatofuz
parents:
diff changeset
12 #include "clang/CrossTU/CrossTranslationUnit.h"
anatofuz
parents:
diff changeset
13 #include "clang/AST/ASTImporter.h"
anatofuz
parents:
diff changeset
14 #include "clang/AST/Decl.h"
anatofuz
parents:
diff changeset
15 #include "clang/Basic/TargetInfo.h"
anatofuz
parents:
diff changeset
16 #include "clang/CrossTU/CrossTUDiagnostic.h"
anatofuz
parents:
diff changeset
17 #include "clang/Frontend/ASTUnit.h"
anatofuz
parents:
diff changeset
18 #include "clang/Frontend/CompilerInstance.h"
anatofuz
parents:
diff changeset
19 #include "clang/Frontend/TextDiagnosticPrinter.h"
anatofuz
parents:
diff changeset
20 #include "clang/Index/USRGeneration.h"
anatofuz
parents:
diff changeset
21 #include "llvm/ADT/Triple.h"
anatofuz
parents:
diff changeset
22 #include "llvm/ADT/Statistic.h"
anatofuz
parents:
diff changeset
23 #include "llvm/Support/ErrorHandling.h"
anatofuz
parents:
diff changeset
24 #include "llvm/Support/ManagedStatic.h"
anatofuz
parents:
diff changeset
25 #include "llvm/Support/Path.h"
anatofuz
parents:
diff changeset
26 #include "llvm/Support/raw_ostream.h"
anatofuz
parents:
diff changeset
27 #include <fstream>
anatofuz
parents:
diff changeset
28 #include <sstream>
anatofuz
parents:
diff changeset
29
anatofuz
parents:
diff changeset
30 namespace clang {
anatofuz
parents:
diff changeset
31 namespace cross_tu {
anatofuz
parents:
diff changeset
32
anatofuz
parents:
diff changeset
33 namespace {
anatofuz
parents:
diff changeset
34
anatofuz
parents:
diff changeset
35 #define DEBUG_TYPE "CrossTranslationUnit"
anatofuz
parents:
diff changeset
36 STATISTIC(NumGetCTUCalled, "The # of getCTUDefinition function called");
anatofuz
parents:
diff changeset
37 STATISTIC(
anatofuz
parents:
diff changeset
38 NumNotInOtherTU,
anatofuz
parents:
diff changeset
39 "The # of getCTUDefinition called but the function is not in any other TU");
anatofuz
parents:
diff changeset
40 STATISTIC(NumGetCTUSuccess,
anatofuz
parents:
diff changeset
41 "The # of getCTUDefinition successfully returned the "
anatofuz
parents:
diff changeset
42 "requested function's body");
anatofuz
parents:
diff changeset
43 STATISTIC(NumUnsupportedNodeFound, "The # of imports when the ASTImporter "
anatofuz
parents:
diff changeset
44 "encountered an unsupported AST Node");
anatofuz
parents:
diff changeset
45 STATISTIC(NumNameConflicts, "The # of imports when the ASTImporter "
anatofuz
parents:
diff changeset
46 "encountered an ODR error");
anatofuz
parents:
diff changeset
47 STATISTIC(NumTripleMismatch, "The # of triple mismatches");
anatofuz
parents:
diff changeset
48 STATISTIC(NumLangMismatch, "The # of language mismatches");
anatofuz
parents:
diff changeset
49 STATISTIC(NumLangDialectMismatch, "The # of language dialect mismatches");
anatofuz
parents:
diff changeset
50 STATISTIC(NumASTLoadThresholdReached,
anatofuz
parents:
diff changeset
51 "The # of ASTs not loaded because of threshold");
anatofuz
parents:
diff changeset
52
anatofuz
parents:
diff changeset
53 // Same as Triple's equality operator, but we check a field only if that is
anatofuz
parents:
diff changeset
54 // known in both instances.
anatofuz
parents:
diff changeset
55 bool hasEqualKnownFields(const llvm::Triple &Lhs, const llvm::Triple &Rhs) {
anatofuz
parents:
diff changeset
56 using llvm::Triple;
anatofuz
parents:
diff changeset
57 if (Lhs.getArch() != Triple::UnknownArch &&
anatofuz
parents:
diff changeset
58 Rhs.getArch() != Triple::UnknownArch && Lhs.getArch() != Rhs.getArch())
anatofuz
parents:
diff changeset
59 return false;
anatofuz
parents:
diff changeset
60 if (Lhs.getSubArch() != Triple::NoSubArch &&
anatofuz
parents:
diff changeset
61 Rhs.getSubArch() != Triple::NoSubArch &&
anatofuz
parents:
diff changeset
62 Lhs.getSubArch() != Rhs.getSubArch())
anatofuz
parents:
diff changeset
63 return false;
anatofuz
parents:
diff changeset
64 if (Lhs.getVendor() != Triple::UnknownVendor &&
anatofuz
parents:
diff changeset
65 Rhs.getVendor() != Triple::UnknownVendor &&
anatofuz
parents:
diff changeset
66 Lhs.getVendor() != Rhs.getVendor())
anatofuz
parents:
diff changeset
67 return false;
anatofuz
parents:
diff changeset
68 if (!Lhs.isOSUnknown() && !Rhs.isOSUnknown() &&
anatofuz
parents:
diff changeset
69 Lhs.getOS() != Rhs.getOS())
anatofuz
parents:
diff changeset
70 return false;
anatofuz
parents:
diff changeset
71 if (Lhs.getEnvironment() != Triple::UnknownEnvironment &&
anatofuz
parents:
diff changeset
72 Rhs.getEnvironment() != Triple::UnknownEnvironment &&
anatofuz
parents:
diff changeset
73 Lhs.getEnvironment() != Rhs.getEnvironment())
anatofuz
parents:
diff changeset
74 return false;
anatofuz
parents:
diff changeset
75 if (Lhs.getObjectFormat() != Triple::UnknownObjectFormat &&
anatofuz
parents:
diff changeset
76 Rhs.getObjectFormat() != Triple::UnknownObjectFormat &&
anatofuz
parents:
diff changeset
77 Lhs.getObjectFormat() != Rhs.getObjectFormat())
anatofuz
parents:
diff changeset
78 return false;
anatofuz
parents:
diff changeset
79 return true;
anatofuz
parents:
diff changeset
80 }
anatofuz
parents:
diff changeset
81
anatofuz
parents:
diff changeset
82 // FIXME: This class is will be removed after the transition to llvm::Error.
anatofuz
parents:
diff changeset
83 class IndexErrorCategory : public std::error_category {
anatofuz
parents:
diff changeset
84 public:
anatofuz
parents:
diff changeset
85 const char *name() const noexcept override { return "clang.index"; }
anatofuz
parents:
diff changeset
86
anatofuz
parents:
diff changeset
87 std::string message(int Condition) const override {
anatofuz
parents:
diff changeset
88 switch (static_cast<index_error_code>(Condition)) {
anatofuz
parents:
diff changeset
89 case index_error_code::unspecified:
anatofuz
parents:
diff changeset
90 return "An unknown error has occurred.";
anatofuz
parents:
diff changeset
91 case index_error_code::missing_index_file:
anatofuz
parents:
diff changeset
92 return "The index file is missing.";
anatofuz
parents:
diff changeset
93 case index_error_code::invalid_index_format:
anatofuz
parents:
diff changeset
94 return "Invalid index file format.";
anatofuz
parents:
diff changeset
95 case index_error_code::multiple_definitions:
anatofuz
parents:
diff changeset
96 return "Multiple definitions in the index file.";
anatofuz
parents:
diff changeset
97 case index_error_code::missing_definition:
anatofuz
parents:
diff changeset
98 return "Missing definition from the index file.";
anatofuz
parents:
diff changeset
99 case index_error_code::failed_import:
anatofuz
parents:
diff changeset
100 return "Failed to import the definition.";
anatofuz
parents:
diff changeset
101 case index_error_code::failed_to_get_external_ast:
anatofuz
parents:
diff changeset
102 return "Failed to load external AST source.";
anatofuz
parents:
diff changeset
103 case index_error_code::failed_to_generate_usr:
anatofuz
parents:
diff changeset
104 return "Failed to generate USR.";
anatofuz
parents:
diff changeset
105 case index_error_code::triple_mismatch:
anatofuz
parents:
diff changeset
106 return "Triple mismatch";
anatofuz
parents:
diff changeset
107 case index_error_code::lang_mismatch:
anatofuz
parents:
diff changeset
108 return "Language mismatch";
anatofuz
parents:
diff changeset
109 case index_error_code::lang_dialect_mismatch:
anatofuz
parents:
diff changeset
110 return "Language dialect mismatch";
anatofuz
parents:
diff changeset
111 case index_error_code::load_threshold_reached:
anatofuz
parents:
diff changeset
112 return "Load threshold reached";
anatofuz
parents:
diff changeset
113 }
anatofuz
parents:
diff changeset
114 llvm_unreachable("Unrecognized index_error_code.");
anatofuz
parents:
diff changeset
115 }
anatofuz
parents:
diff changeset
116 };
anatofuz
parents:
diff changeset
117
anatofuz
parents:
diff changeset
118 static llvm::ManagedStatic<IndexErrorCategory> Category;
anatofuz
parents:
diff changeset
119 } // end anonymous namespace
anatofuz
parents:
diff changeset
120
anatofuz
parents:
diff changeset
121 char IndexError::ID;
anatofuz
parents:
diff changeset
122
anatofuz
parents:
diff changeset
123 void IndexError::log(raw_ostream &OS) const {
anatofuz
parents:
diff changeset
124 OS << Category->message(static_cast<int>(Code)) << '\n';
anatofuz
parents:
diff changeset
125 }
anatofuz
parents:
diff changeset
126
anatofuz
parents:
diff changeset
127 std::error_code IndexError::convertToErrorCode() const {
anatofuz
parents:
diff changeset
128 return std::error_code(static_cast<int>(Code), *Category);
anatofuz
parents:
diff changeset
129 }
anatofuz
parents:
diff changeset
130
anatofuz
parents:
diff changeset
131 llvm::Expected<llvm::StringMap<std::string>>
anatofuz
parents:
diff changeset
132 parseCrossTUIndex(StringRef IndexPath, StringRef CrossTUDir) {
anatofuz
parents:
diff changeset
133 std::ifstream ExternalMapFile{std::string(IndexPath)};
anatofuz
parents:
diff changeset
134 if (!ExternalMapFile)
anatofuz
parents:
diff changeset
135 return llvm::make_error<IndexError>(index_error_code::missing_index_file,
anatofuz
parents:
diff changeset
136 IndexPath.str());
anatofuz
parents:
diff changeset
137
anatofuz
parents:
diff changeset
138 llvm::StringMap<std::string> Result;
anatofuz
parents:
diff changeset
139 std::string Line;
anatofuz
parents:
diff changeset
140 unsigned LineNo = 1;
anatofuz
parents:
diff changeset
141 while (std::getline(ExternalMapFile, Line)) {
anatofuz
parents:
diff changeset
142 const size_t Pos = Line.find(" ");
anatofuz
parents:
diff changeset
143 if (Pos > 0 && Pos != std::string::npos) {
anatofuz
parents:
diff changeset
144 StringRef LineRef{Line};
anatofuz
parents:
diff changeset
145 StringRef LookupName = LineRef.substr(0, Pos);
anatofuz
parents:
diff changeset
146 if (Result.count(LookupName))
anatofuz
parents:
diff changeset
147 return llvm::make_error<IndexError>(
anatofuz
parents:
diff changeset
148 index_error_code::multiple_definitions, IndexPath.str(), LineNo);
anatofuz
parents:
diff changeset
149 StringRef FileName = LineRef.substr(Pos + 1);
anatofuz
parents:
diff changeset
150 SmallString<256> FilePath = CrossTUDir;
anatofuz
parents:
diff changeset
151 llvm::sys::path::append(FilePath, FileName);
anatofuz
parents:
diff changeset
152 Result[LookupName] = std::string(FilePath);
anatofuz
parents:
diff changeset
153 } else
anatofuz
parents:
diff changeset
154 return llvm::make_error<IndexError>(
anatofuz
parents:
diff changeset
155 index_error_code::invalid_index_format, IndexPath.str(), LineNo);
anatofuz
parents:
diff changeset
156 LineNo++;
anatofuz
parents:
diff changeset
157 }
anatofuz
parents:
diff changeset
158 return Result;
anatofuz
parents:
diff changeset
159 }
anatofuz
parents:
diff changeset
160
anatofuz
parents:
diff changeset
161 std::string
anatofuz
parents:
diff changeset
162 createCrossTUIndexString(const llvm::StringMap<std::string> &Index) {
anatofuz
parents:
diff changeset
163 std::ostringstream Result;
anatofuz
parents:
diff changeset
164 for (const auto &E : Index)
anatofuz
parents:
diff changeset
165 Result << E.getKey().str() << " " << E.getValue() << '\n';
anatofuz
parents:
diff changeset
166 return Result.str();
anatofuz
parents:
diff changeset
167 }
anatofuz
parents:
diff changeset
168
anatofuz
parents:
diff changeset
169 bool containsConst(const VarDecl *VD, const ASTContext &ACtx) {
anatofuz
parents:
diff changeset
170 CanQualType CT = ACtx.getCanonicalType(VD->getType());
anatofuz
parents:
diff changeset
171 if (!CT.isConstQualified()) {
anatofuz
parents:
diff changeset
172 const RecordType *RTy = CT->getAs<RecordType>();
anatofuz
parents:
diff changeset
173 if (!RTy || !RTy->hasConstFields())
anatofuz
parents:
diff changeset
174 return false;
anatofuz
parents:
diff changeset
175 }
anatofuz
parents:
diff changeset
176 return true;
anatofuz
parents:
diff changeset
177 }
anatofuz
parents:
diff changeset
178
anatofuz
parents:
diff changeset
179 static bool hasBodyOrInit(const FunctionDecl *D, const FunctionDecl *&DefD) {
anatofuz
parents:
diff changeset
180 return D->hasBody(DefD);
anatofuz
parents:
diff changeset
181 }
anatofuz
parents:
diff changeset
182 static bool hasBodyOrInit(const VarDecl *D, const VarDecl *&DefD) {
anatofuz
parents:
diff changeset
183 return D->getAnyInitializer(DefD);
anatofuz
parents:
diff changeset
184 }
anatofuz
parents:
diff changeset
185 template <typename T> static bool hasBodyOrInit(const T *D) {
anatofuz
parents:
diff changeset
186 const T *Unused;
anatofuz
parents:
diff changeset
187 return hasBodyOrInit(D, Unused);
anatofuz
parents:
diff changeset
188 }
anatofuz
parents:
diff changeset
189
anatofuz
parents:
diff changeset
190 CrossTranslationUnitContext::CrossTranslationUnitContext(CompilerInstance &CI)
anatofuz
parents:
diff changeset
191 : Context(CI.getASTContext()), ASTStorage(CI) {}
anatofuz
parents:
diff changeset
192
anatofuz
parents:
diff changeset
193 CrossTranslationUnitContext::~CrossTranslationUnitContext() {}
anatofuz
parents:
diff changeset
194
anatofuz
parents:
diff changeset
195 llvm::Optional<std::string>
anatofuz
parents:
diff changeset
196 CrossTranslationUnitContext::getLookupName(const NamedDecl *ND) {
anatofuz
parents:
diff changeset
197 SmallString<128> DeclUSR;
anatofuz
parents:
diff changeset
198 bool Ret = index::generateUSRForDecl(ND, DeclUSR);
anatofuz
parents:
diff changeset
199 if (Ret)
anatofuz
parents:
diff changeset
200 return {};
anatofuz
parents:
diff changeset
201 return std::string(DeclUSR.str());
anatofuz
parents:
diff changeset
202 }
anatofuz
parents:
diff changeset
203
anatofuz
parents:
diff changeset
204 /// Recursively visits the decls of a DeclContext, and returns one with the
anatofuz
parents:
diff changeset
205 /// given USR.
anatofuz
parents:
diff changeset
206 template <typename T>
anatofuz
parents:
diff changeset
207 const T *
anatofuz
parents:
diff changeset
208 CrossTranslationUnitContext::findDefInDeclContext(const DeclContext *DC,
anatofuz
parents:
diff changeset
209 StringRef LookupName) {
anatofuz
parents:
diff changeset
210 assert(DC && "Declaration Context must not be null");
anatofuz
parents:
diff changeset
211 for (const Decl *D : DC->decls()) {
anatofuz
parents:
diff changeset
212 const auto *SubDC = dyn_cast<DeclContext>(D);
anatofuz
parents:
diff changeset
213 if (SubDC)
anatofuz
parents:
diff changeset
214 if (const auto *ND = findDefInDeclContext<T>(SubDC, LookupName))
anatofuz
parents:
diff changeset
215 return ND;
anatofuz
parents:
diff changeset
216
anatofuz
parents:
diff changeset
217 const auto *ND = dyn_cast<T>(D);
anatofuz
parents:
diff changeset
218 const T *ResultDecl;
anatofuz
parents:
diff changeset
219 if (!ND || !hasBodyOrInit(ND, ResultDecl))
anatofuz
parents:
diff changeset
220 continue;
anatofuz
parents:
diff changeset
221 llvm::Optional<std::string> ResultLookupName = getLookupName(ResultDecl);
anatofuz
parents:
diff changeset
222 if (!ResultLookupName || *ResultLookupName != LookupName)
anatofuz
parents:
diff changeset
223 continue;
anatofuz
parents:
diff changeset
224 return ResultDecl;
anatofuz
parents:
diff changeset
225 }
anatofuz
parents:
diff changeset
226 return nullptr;
anatofuz
parents:
diff changeset
227 }
anatofuz
parents:
diff changeset
228
anatofuz
parents:
diff changeset
229 template <typename T>
anatofuz
parents:
diff changeset
230 llvm::Expected<const T *> CrossTranslationUnitContext::getCrossTUDefinitionImpl(
anatofuz
parents:
diff changeset
231 const T *D, StringRef CrossTUDir, StringRef IndexName,
anatofuz
parents:
diff changeset
232 bool DisplayCTUProgress) {
anatofuz
parents:
diff changeset
233 assert(D && "D is missing, bad call to this function!");
anatofuz
parents:
diff changeset
234 assert(!hasBodyOrInit(D) &&
anatofuz
parents:
diff changeset
235 "D has a body or init in current translation unit!");
anatofuz
parents:
diff changeset
236 ++NumGetCTUCalled;
anatofuz
parents:
diff changeset
237 const llvm::Optional<std::string> LookupName = getLookupName(D);
anatofuz
parents:
diff changeset
238 if (!LookupName)
anatofuz
parents:
diff changeset
239 return llvm::make_error<IndexError>(
anatofuz
parents:
diff changeset
240 index_error_code::failed_to_generate_usr);
anatofuz
parents:
diff changeset
241 llvm::Expected<ASTUnit *> ASTUnitOrError =
anatofuz
parents:
diff changeset
242 loadExternalAST(*LookupName, CrossTUDir, IndexName, DisplayCTUProgress);
anatofuz
parents:
diff changeset
243 if (!ASTUnitOrError)
anatofuz
parents:
diff changeset
244 return ASTUnitOrError.takeError();
anatofuz
parents:
diff changeset
245 ASTUnit *Unit = *ASTUnitOrError;
anatofuz
parents:
diff changeset
246 assert(&Unit->getFileManager() ==
anatofuz
parents:
diff changeset
247 &Unit->getASTContext().getSourceManager().getFileManager());
anatofuz
parents:
diff changeset
248
anatofuz
parents:
diff changeset
249 const llvm::Triple &TripleTo = Context.getTargetInfo().getTriple();
anatofuz
parents:
diff changeset
250 const llvm::Triple &TripleFrom =
anatofuz
parents:
diff changeset
251 Unit->getASTContext().getTargetInfo().getTriple();
anatofuz
parents:
diff changeset
252 // The imported AST had been generated for a different target.
anatofuz
parents:
diff changeset
253 // Some parts of the triple in the loaded ASTContext can be unknown while the
anatofuz
parents:
diff changeset
254 // very same parts in the target ASTContext are known. Thus we check for the
anatofuz
parents:
diff changeset
255 // known parts only.
anatofuz
parents:
diff changeset
256 if (!hasEqualKnownFields(TripleTo, TripleFrom)) {
anatofuz
parents:
diff changeset
257 // TODO: Pass the SourceLocation of the CallExpression for more precise
anatofuz
parents:
diff changeset
258 // diagnostics.
anatofuz
parents:
diff changeset
259 ++NumTripleMismatch;
anatofuz
parents:
diff changeset
260 return llvm::make_error<IndexError>(index_error_code::triple_mismatch,
anatofuz
parents:
diff changeset
261 std::string(Unit->getMainFileName()),
anatofuz
parents:
diff changeset
262 TripleTo.str(), TripleFrom.str());
anatofuz
parents:
diff changeset
263 }
anatofuz
parents:
diff changeset
264
anatofuz
parents:
diff changeset
265 const auto &LangTo = Context.getLangOpts();
anatofuz
parents:
diff changeset
266 const auto &LangFrom = Unit->getASTContext().getLangOpts();
anatofuz
parents:
diff changeset
267
anatofuz
parents:
diff changeset
268 // FIXME: Currenty we do not support CTU across C++ and C and across
anatofuz
parents:
diff changeset
269 // different dialects of C++.
anatofuz
parents:
diff changeset
270 if (LangTo.CPlusPlus != LangFrom.CPlusPlus) {
anatofuz
parents:
diff changeset
271 ++NumLangMismatch;
anatofuz
parents:
diff changeset
272 return llvm::make_error<IndexError>(index_error_code::lang_mismatch);
anatofuz
parents:
diff changeset
273 }
anatofuz
parents:
diff changeset
274
anatofuz
parents:
diff changeset
275 // If CPP dialects are different then return with error.
anatofuz
parents:
diff changeset
276 //
anatofuz
parents:
diff changeset
277 // Consider this STL code:
anatofuz
parents:
diff changeset
278 // template<typename _Alloc>
anatofuz
parents:
diff changeset
279 // struct __alloc_traits
anatofuz
parents:
diff changeset
280 // #if __cplusplus >= 201103L
anatofuz
parents:
diff changeset
281 // : std::allocator_traits<_Alloc>
anatofuz
parents:
diff changeset
282 // #endif
anatofuz
parents:
diff changeset
283 // { // ...
anatofuz
parents:
diff changeset
284 // };
anatofuz
parents:
diff changeset
285 // This class template would create ODR errors during merging the two units,
anatofuz
parents:
diff changeset
286 // since in one translation unit the class template has a base class, however
anatofuz
parents:
diff changeset
287 // in the other unit it has none.
anatofuz
parents:
diff changeset
288 if (LangTo.CPlusPlus11 != LangFrom.CPlusPlus11 ||
anatofuz
parents:
diff changeset
289 LangTo.CPlusPlus14 != LangFrom.CPlusPlus14 ||
anatofuz
parents:
diff changeset
290 LangTo.CPlusPlus17 != LangFrom.CPlusPlus17 ||
173
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
291 LangTo.CPlusPlus20 != LangFrom.CPlusPlus20) {
150
anatofuz
parents:
diff changeset
292 ++NumLangDialectMismatch;
anatofuz
parents:
diff changeset
293 return llvm::make_error<IndexError>(
anatofuz
parents:
diff changeset
294 index_error_code::lang_dialect_mismatch);
anatofuz
parents:
diff changeset
295 }
anatofuz
parents:
diff changeset
296
anatofuz
parents:
diff changeset
297 TranslationUnitDecl *TU = Unit->getASTContext().getTranslationUnitDecl();
anatofuz
parents:
diff changeset
298 if (const T *ResultDecl = findDefInDeclContext<T>(TU, *LookupName))
anatofuz
parents:
diff changeset
299 return importDefinition(ResultDecl, Unit);
anatofuz
parents:
diff changeset
300 return llvm::make_error<IndexError>(index_error_code::failed_import);
anatofuz
parents:
diff changeset
301 }
anatofuz
parents:
diff changeset
302
anatofuz
parents:
diff changeset
303 llvm::Expected<const FunctionDecl *>
anatofuz
parents:
diff changeset
304 CrossTranslationUnitContext::getCrossTUDefinition(const FunctionDecl *FD,
anatofuz
parents:
diff changeset
305 StringRef CrossTUDir,
anatofuz
parents:
diff changeset
306 StringRef IndexName,
anatofuz
parents:
diff changeset
307 bool DisplayCTUProgress) {
anatofuz
parents:
diff changeset
308 return getCrossTUDefinitionImpl(FD, CrossTUDir, IndexName,
anatofuz
parents:
diff changeset
309 DisplayCTUProgress);
anatofuz
parents:
diff changeset
310 }
anatofuz
parents:
diff changeset
311
anatofuz
parents:
diff changeset
312 llvm::Expected<const VarDecl *>
anatofuz
parents:
diff changeset
313 CrossTranslationUnitContext::getCrossTUDefinition(const VarDecl *VD,
anatofuz
parents:
diff changeset
314 StringRef CrossTUDir,
anatofuz
parents:
diff changeset
315 StringRef IndexName,
anatofuz
parents:
diff changeset
316 bool DisplayCTUProgress) {
anatofuz
parents:
diff changeset
317 return getCrossTUDefinitionImpl(VD, CrossTUDir, IndexName,
anatofuz
parents:
diff changeset
318 DisplayCTUProgress);
anatofuz
parents:
diff changeset
319 }
anatofuz
parents:
diff changeset
320
anatofuz
parents:
diff changeset
321 void CrossTranslationUnitContext::emitCrossTUDiagnostics(const IndexError &IE) {
anatofuz
parents:
diff changeset
322 switch (IE.getCode()) {
anatofuz
parents:
diff changeset
323 case index_error_code::missing_index_file:
anatofuz
parents:
diff changeset
324 Context.getDiagnostics().Report(diag::err_ctu_error_opening)
anatofuz
parents:
diff changeset
325 << IE.getFileName();
anatofuz
parents:
diff changeset
326 break;
anatofuz
parents:
diff changeset
327 case index_error_code::invalid_index_format:
anatofuz
parents:
diff changeset
328 Context.getDiagnostics().Report(diag::err_extdefmap_parsing)
anatofuz
parents:
diff changeset
329 << IE.getFileName() << IE.getLineNum();
anatofuz
parents:
diff changeset
330 break;
anatofuz
parents:
diff changeset
331 case index_error_code::multiple_definitions:
anatofuz
parents:
diff changeset
332 Context.getDiagnostics().Report(diag::err_multiple_def_index)
anatofuz
parents:
diff changeset
333 << IE.getLineNum();
anatofuz
parents:
diff changeset
334 break;
anatofuz
parents:
diff changeset
335 case index_error_code::triple_mismatch:
anatofuz
parents:
diff changeset
336 Context.getDiagnostics().Report(diag::warn_ctu_incompat_triple)
anatofuz
parents:
diff changeset
337 << IE.getFileName() << IE.getTripleToName() << IE.getTripleFromName();
anatofuz
parents:
diff changeset
338 break;
anatofuz
parents:
diff changeset
339 default:
anatofuz
parents:
diff changeset
340 break;
anatofuz
parents:
diff changeset
341 }
anatofuz
parents:
diff changeset
342 }
anatofuz
parents:
diff changeset
343
anatofuz
parents:
diff changeset
344 CrossTranslationUnitContext::ASTFileLoader::ASTFileLoader(
anatofuz
parents:
diff changeset
345 const CompilerInstance &CI)
anatofuz
parents:
diff changeset
346 : CI(CI) {}
anatofuz
parents:
diff changeset
347
anatofuz
parents:
diff changeset
348 std::unique_ptr<ASTUnit>
anatofuz
parents:
diff changeset
349 CrossTranslationUnitContext::ASTFileLoader::operator()(StringRef ASTFilePath) {
anatofuz
parents:
diff changeset
350 // Load AST from ast-dump.
anatofuz
parents:
diff changeset
351 IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
anatofuz
parents:
diff changeset
352 TextDiagnosticPrinter *DiagClient =
anatofuz
parents:
diff changeset
353 new TextDiagnosticPrinter(llvm::errs(), &*DiagOpts);
anatofuz
parents:
diff changeset
354 IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
anatofuz
parents:
diff changeset
355 IntrusiveRefCntPtr<DiagnosticsEngine> Diags(
anatofuz
parents:
diff changeset
356 new DiagnosticsEngine(DiagID, &*DiagOpts, DiagClient));
anatofuz
parents:
diff changeset
357
anatofuz
parents:
diff changeset
358 return ASTUnit::LoadFromASTFile(
anatofuz
parents:
diff changeset
359 std::string(ASTFilePath), CI.getPCHContainerOperations()->getRawReader(),
anatofuz
parents:
diff changeset
360 ASTUnit::LoadEverything, Diags, CI.getFileSystemOpts());
anatofuz
parents:
diff changeset
361 }
anatofuz
parents:
diff changeset
362
anatofuz
parents:
diff changeset
363 CrossTranslationUnitContext::ASTUnitStorage::ASTUnitStorage(
anatofuz
parents:
diff changeset
364 const CompilerInstance &CI)
anatofuz
parents:
diff changeset
365 : FileAccessor(CI), LoadGuard(const_cast<CompilerInstance &>(CI)
anatofuz
parents:
diff changeset
366 .getAnalyzerOpts()
anatofuz
parents:
diff changeset
367 ->CTUImportThreshold) {}
anatofuz
parents:
diff changeset
368
anatofuz
parents:
diff changeset
369 llvm::Expected<ASTUnit *>
anatofuz
parents:
diff changeset
370 CrossTranslationUnitContext::ASTUnitStorage::getASTUnitForFile(
anatofuz
parents:
diff changeset
371 StringRef FileName, bool DisplayCTUProgress) {
anatofuz
parents:
diff changeset
372 // Try the cache first.
anatofuz
parents:
diff changeset
373 auto ASTCacheEntry = FileASTUnitMap.find(FileName);
anatofuz
parents:
diff changeset
374 if (ASTCacheEntry == FileASTUnitMap.end()) {
anatofuz
parents:
diff changeset
375
anatofuz
parents:
diff changeset
376 // Do not load if the limit is reached.
anatofuz
parents:
diff changeset
377 if (!LoadGuard) {
anatofuz
parents:
diff changeset
378 ++NumASTLoadThresholdReached;
anatofuz
parents:
diff changeset
379 return llvm::make_error<IndexError>(
anatofuz
parents:
diff changeset
380 index_error_code::load_threshold_reached);
anatofuz
parents:
diff changeset
381 }
anatofuz
parents:
diff changeset
382
anatofuz
parents:
diff changeset
383 // Load the ASTUnit from the pre-dumped AST file specified by ASTFileName.
anatofuz
parents:
diff changeset
384 std::unique_ptr<ASTUnit> LoadedUnit = FileAccessor(FileName);
anatofuz
parents:
diff changeset
385
anatofuz
parents:
diff changeset
386 // Need the raw pointer and the unique_ptr as well.
anatofuz
parents:
diff changeset
387 ASTUnit *Unit = LoadedUnit.get();
anatofuz
parents:
diff changeset
388
anatofuz
parents:
diff changeset
389 // Update the cache.
anatofuz
parents:
diff changeset
390 FileASTUnitMap[FileName] = std::move(LoadedUnit);
anatofuz
parents:
diff changeset
391
anatofuz
parents:
diff changeset
392 LoadGuard.indicateLoadSuccess();
anatofuz
parents:
diff changeset
393
anatofuz
parents:
diff changeset
394 if (DisplayCTUProgress)
anatofuz
parents:
diff changeset
395 llvm::errs() << "CTU loaded AST file: " << FileName << "\n";
anatofuz
parents:
diff changeset
396
anatofuz
parents:
diff changeset
397 return Unit;
anatofuz
parents:
diff changeset
398
anatofuz
parents:
diff changeset
399 } else {
anatofuz
parents:
diff changeset
400 // Found in the cache.
anatofuz
parents:
diff changeset
401 return ASTCacheEntry->second.get();
anatofuz
parents:
diff changeset
402 }
anatofuz
parents:
diff changeset
403 }
anatofuz
parents:
diff changeset
404
anatofuz
parents:
diff changeset
405 llvm::Expected<ASTUnit *>
anatofuz
parents:
diff changeset
406 CrossTranslationUnitContext::ASTUnitStorage::getASTUnitForFunction(
anatofuz
parents:
diff changeset
407 StringRef FunctionName, StringRef CrossTUDir, StringRef IndexName,
anatofuz
parents:
diff changeset
408 bool DisplayCTUProgress) {
anatofuz
parents:
diff changeset
409 // Try the cache first.
anatofuz
parents:
diff changeset
410 auto ASTCacheEntry = NameASTUnitMap.find(FunctionName);
anatofuz
parents:
diff changeset
411 if (ASTCacheEntry == NameASTUnitMap.end()) {
anatofuz
parents:
diff changeset
412 // Load the ASTUnit from the pre-dumped AST file specified by ASTFileName.
anatofuz
parents:
diff changeset
413
anatofuz
parents:
diff changeset
414 // Ensure that the Index is loaded, as we need to search in it.
anatofuz
parents:
diff changeset
415 if (llvm::Error IndexLoadError =
anatofuz
parents:
diff changeset
416 ensureCTUIndexLoaded(CrossTUDir, IndexName))
anatofuz
parents:
diff changeset
417 return std::move(IndexLoadError);
anatofuz
parents:
diff changeset
418
anatofuz
parents:
diff changeset
419 // Check if there is and entry in the index for the function.
anatofuz
parents:
diff changeset
420 if (!NameFileMap.count(FunctionName)) {
anatofuz
parents:
diff changeset
421 ++NumNotInOtherTU;
anatofuz
parents:
diff changeset
422 return llvm::make_error<IndexError>(index_error_code::missing_definition);
anatofuz
parents:
diff changeset
423 }
anatofuz
parents:
diff changeset
424
anatofuz
parents:
diff changeset
425 // Search in the index for the filename where the definition of FuncitonName
anatofuz
parents:
diff changeset
426 // resides.
anatofuz
parents:
diff changeset
427 if (llvm::Expected<ASTUnit *> FoundForFile =
anatofuz
parents:
diff changeset
428 getASTUnitForFile(NameFileMap[FunctionName], DisplayCTUProgress)) {
anatofuz
parents:
diff changeset
429
anatofuz
parents:
diff changeset
430 // Update the cache.
anatofuz
parents:
diff changeset
431 NameASTUnitMap[FunctionName] = *FoundForFile;
anatofuz
parents:
diff changeset
432 return *FoundForFile;
anatofuz
parents:
diff changeset
433
anatofuz
parents:
diff changeset
434 } else {
anatofuz
parents:
diff changeset
435 return FoundForFile.takeError();
anatofuz
parents:
diff changeset
436 }
anatofuz
parents:
diff changeset
437 } else {
anatofuz
parents:
diff changeset
438 // Found in the cache.
anatofuz
parents:
diff changeset
439 return ASTCacheEntry->second;
anatofuz
parents:
diff changeset
440 }
anatofuz
parents:
diff changeset
441 }
anatofuz
parents:
diff changeset
442
anatofuz
parents:
diff changeset
443 llvm::Expected<std::string>
anatofuz
parents:
diff changeset
444 CrossTranslationUnitContext::ASTUnitStorage::getFileForFunction(
anatofuz
parents:
diff changeset
445 StringRef FunctionName, StringRef CrossTUDir, StringRef IndexName) {
anatofuz
parents:
diff changeset
446 if (llvm::Error IndexLoadError = ensureCTUIndexLoaded(CrossTUDir, IndexName))
anatofuz
parents:
diff changeset
447 return std::move(IndexLoadError);
anatofuz
parents:
diff changeset
448 return NameFileMap[FunctionName];
anatofuz
parents:
diff changeset
449 }
anatofuz
parents:
diff changeset
450
anatofuz
parents:
diff changeset
451 llvm::Error CrossTranslationUnitContext::ASTUnitStorage::ensureCTUIndexLoaded(
anatofuz
parents:
diff changeset
452 StringRef CrossTUDir, StringRef IndexName) {
anatofuz
parents:
diff changeset
453 // Dont initialize if the map is filled.
anatofuz
parents:
diff changeset
454 if (!NameFileMap.empty())
anatofuz
parents:
diff changeset
455 return llvm::Error::success();
anatofuz
parents:
diff changeset
456
anatofuz
parents:
diff changeset
457 // Get the absolute path to the index file.
anatofuz
parents:
diff changeset
458 SmallString<256> IndexFile = CrossTUDir;
anatofuz
parents:
diff changeset
459 if (llvm::sys::path::is_absolute(IndexName))
anatofuz
parents:
diff changeset
460 IndexFile = IndexName;
anatofuz
parents:
diff changeset
461 else
anatofuz
parents:
diff changeset
462 llvm::sys::path::append(IndexFile, IndexName);
anatofuz
parents:
diff changeset
463
anatofuz
parents:
diff changeset
464 if (auto IndexMapping = parseCrossTUIndex(IndexFile, CrossTUDir)) {
anatofuz
parents:
diff changeset
465 // Initialize member map.
anatofuz
parents:
diff changeset
466 NameFileMap = *IndexMapping;
anatofuz
parents:
diff changeset
467 return llvm::Error::success();
anatofuz
parents:
diff changeset
468 } else {
anatofuz
parents:
diff changeset
469 // Error while parsing CrossTU index file.
anatofuz
parents:
diff changeset
470 return IndexMapping.takeError();
anatofuz
parents:
diff changeset
471 };
anatofuz
parents:
diff changeset
472 }
anatofuz
parents:
diff changeset
473
anatofuz
parents:
diff changeset
474 llvm::Expected<ASTUnit *> CrossTranslationUnitContext::loadExternalAST(
anatofuz
parents:
diff changeset
475 StringRef LookupName, StringRef CrossTUDir, StringRef IndexName,
anatofuz
parents:
diff changeset
476 bool DisplayCTUProgress) {
anatofuz
parents:
diff changeset
477 // FIXME: The current implementation only supports loading decls with
anatofuz
parents:
diff changeset
478 // a lookup name from a single translation unit. If multiple
anatofuz
parents:
diff changeset
479 // translation units contains decls with the same lookup name an
anatofuz
parents:
diff changeset
480 // error will be returned.
anatofuz
parents:
diff changeset
481
anatofuz
parents:
diff changeset
482 // Try to get the value from the heavily cached storage.
anatofuz
parents:
diff changeset
483 llvm::Expected<ASTUnit *> Unit = ASTStorage.getASTUnitForFunction(
anatofuz
parents:
diff changeset
484 LookupName, CrossTUDir, IndexName, DisplayCTUProgress);
anatofuz
parents:
diff changeset
485
anatofuz
parents:
diff changeset
486 if (!Unit)
anatofuz
parents:
diff changeset
487 return Unit.takeError();
anatofuz
parents:
diff changeset
488
anatofuz
parents:
diff changeset
489 // Check whether the backing pointer of the Expected is a nullptr.
anatofuz
parents:
diff changeset
490 if (!*Unit)
anatofuz
parents:
diff changeset
491 return llvm::make_error<IndexError>(
anatofuz
parents:
diff changeset
492 index_error_code::failed_to_get_external_ast);
anatofuz
parents:
diff changeset
493
anatofuz
parents:
diff changeset
494 return Unit;
anatofuz
parents:
diff changeset
495 }
anatofuz
parents:
diff changeset
496
anatofuz
parents:
diff changeset
497 template <typename T>
anatofuz
parents:
diff changeset
498 llvm::Expected<const T *>
anatofuz
parents:
diff changeset
499 CrossTranslationUnitContext::importDefinitionImpl(const T *D, ASTUnit *Unit) {
anatofuz
parents:
diff changeset
500 assert(hasBodyOrInit(D) && "Decls to be imported should have body or init.");
anatofuz
parents:
diff changeset
501
anatofuz
parents:
diff changeset
502 assert(&D->getASTContext() == &Unit->getASTContext() &&
anatofuz
parents:
diff changeset
503 "ASTContext of Decl and the unit should match.");
anatofuz
parents:
diff changeset
504 ASTImporter &Importer = getOrCreateASTImporter(Unit);
anatofuz
parents:
diff changeset
505
anatofuz
parents:
diff changeset
506 auto ToDeclOrError = Importer.Import(D);
anatofuz
parents:
diff changeset
507 if (!ToDeclOrError) {
anatofuz
parents:
diff changeset
508 handleAllErrors(ToDeclOrError.takeError(),
anatofuz
parents:
diff changeset
509 [&](const ImportError &IE) {
anatofuz
parents:
diff changeset
510 switch (IE.Error) {
anatofuz
parents:
diff changeset
511 case ImportError::NameConflict:
anatofuz
parents:
diff changeset
512 ++NumNameConflicts;
anatofuz
parents:
diff changeset
513 break;
anatofuz
parents:
diff changeset
514 case ImportError::UnsupportedConstruct:
anatofuz
parents:
diff changeset
515 ++NumUnsupportedNodeFound;
anatofuz
parents:
diff changeset
516 break;
anatofuz
parents:
diff changeset
517 case ImportError::Unknown:
anatofuz
parents:
diff changeset
518 llvm_unreachable("Unknown import error happened.");
anatofuz
parents:
diff changeset
519 break;
anatofuz
parents:
diff changeset
520 }
anatofuz
parents:
diff changeset
521 });
anatofuz
parents:
diff changeset
522 return llvm::make_error<IndexError>(index_error_code::failed_import);
anatofuz
parents:
diff changeset
523 }
anatofuz
parents:
diff changeset
524 auto *ToDecl = cast<T>(*ToDeclOrError);
anatofuz
parents:
diff changeset
525 assert(hasBodyOrInit(ToDecl) && "Imported Decl should have body or init.");
anatofuz
parents:
diff changeset
526 ++NumGetCTUSuccess;
anatofuz
parents:
diff changeset
527
anatofuz
parents:
diff changeset
528 return ToDecl;
anatofuz
parents:
diff changeset
529 }
anatofuz
parents:
diff changeset
530
anatofuz
parents:
diff changeset
531 llvm::Expected<const FunctionDecl *>
anatofuz
parents:
diff changeset
532 CrossTranslationUnitContext::importDefinition(const FunctionDecl *FD,
anatofuz
parents:
diff changeset
533 ASTUnit *Unit) {
anatofuz
parents:
diff changeset
534 return importDefinitionImpl(FD, Unit);
anatofuz
parents:
diff changeset
535 }
anatofuz
parents:
diff changeset
536
anatofuz
parents:
diff changeset
537 llvm::Expected<const VarDecl *>
anatofuz
parents:
diff changeset
538 CrossTranslationUnitContext::importDefinition(const VarDecl *VD,
anatofuz
parents:
diff changeset
539 ASTUnit *Unit) {
anatofuz
parents:
diff changeset
540 return importDefinitionImpl(VD, Unit);
anatofuz
parents:
diff changeset
541 }
anatofuz
parents:
diff changeset
542
anatofuz
parents:
diff changeset
543 void CrossTranslationUnitContext::lazyInitImporterSharedSt(
anatofuz
parents:
diff changeset
544 TranslationUnitDecl *ToTU) {
anatofuz
parents:
diff changeset
545 if (!ImporterSharedSt)
anatofuz
parents:
diff changeset
546 ImporterSharedSt = std::make_shared<ASTImporterSharedState>(*ToTU);
anatofuz
parents:
diff changeset
547 }
anatofuz
parents:
diff changeset
548
anatofuz
parents:
diff changeset
549 ASTImporter &
anatofuz
parents:
diff changeset
550 CrossTranslationUnitContext::getOrCreateASTImporter(ASTUnit *Unit) {
anatofuz
parents:
diff changeset
551 ASTContext &From = Unit->getASTContext();
anatofuz
parents:
diff changeset
552
anatofuz
parents:
diff changeset
553 auto I = ASTUnitImporterMap.find(From.getTranslationUnitDecl());
anatofuz
parents:
diff changeset
554 if (I != ASTUnitImporterMap.end())
anatofuz
parents:
diff changeset
555 return *I->second;
anatofuz
parents:
diff changeset
556 lazyInitImporterSharedSt(Context.getTranslationUnitDecl());
anatofuz
parents:
diff changeset
557 ASTImporter *NewImporter = new ASTImporter(
anatofuz
parents:
diff changeset
558 Context, Context.getSourceManager().getFileManager(), From,
anatofuz
parents:
diff changeset
559 From.getSourceManager().getFileManager(), false, ImporterSharedSt);
anatofuz
parents:
diff changeset
560 NewImporter->setFileIDImportHandler([this, Unit](FileID ToID, FileID FromID) {
anatofuz
parents:
diff changeset
561 assert(ImportedFileIDs.find(ToID) == ImportedFileIDs.end() &&
anatofuz
parents:
diff changeset
562 "FileID already imported, should not happen.");
anatofuz
parents:
diff changeset
563 ImportedFileIDs[ToID] = std::make_pair(FromID, Unit);
anatofuz
parents:
diff changeset
564 });
anatofuz
parents:
diff changeset
565 ASTUnitImporterMap[From.getTranslationUnitDecl()].reset(NewImporter);
anatofuz
parents:
diff changeset
566 return *NewImporter;
anatofuz
parents:
diff changeset
567 }
anatofuz
parents:
diff changeset
568
anatofuz
parents:
diff changeset
569 llvm::Optional<std::pair<SourceLocation, ASTUnit *>>
anatofuz
parents:
diff changeset
570 CrossTranslationUnitContext::getImportedFromSourceLocation(
anatofuz
parents:
diff changeset
571 const clang::SourceLocation &ToLoc) const {
anatofuz
parents:
diff changeset
572 const SourceManager &SM = Context.getSourceManager();
anatofuz
parents:
diff changeset
573 auto DecToLoc = SM.getDecomposedLoc(ToLoc);
anatofuz
parents:
diff changeset
574
anatofuz
parents:
diff changeset
575 auto I = ImportedFileIDs.find(DecToLoc.first);
anatofuz
parents:
diff changeset
576 if (I == ImportedFileIDs.end())
anatofuz
parents:
diff changeset
577 return {};
anatofuz
parents:
diff changeset
578
anatofuz
parents:
diff changeset
579 FileID FromID = I->second.first;
anatofuz
parents:
diff changeset
580 clang::ASTUnit *Unit = I->second.second;
anatofuz
parents:
diff changeset
581 SourceLocation FromLoc =
anatofuz
parents:
diff changeset
582 Unit->getSourceManager().getComposedLoc(FromID, DecToLoc.second);
anatofuz
parents:
diff changeset
583
anatofuz
parents:
diff changeset
584 return std::make_pair(FromLoc, Unit);
anatofuz
parents:
diff changeset
585 }
anatofuz
parents:
diff changeset
586
anatofuz
parents:
diff changeset
587 } // namespace cross_tu
anatofuz
parents:
diff changeset
588 } // namespace clang