Coverage Report

Created: 2021-08-24 07:12

/Users/buildslave/jenkins/workspace/coverage/llvm-project/clang/lib/CrossTU/CrossTranslationUnit.cpp
Line
Count
Source (jump to first uncovered line)
1
//===--- CrossTranslationUnit.cpp - -----------------------------*- C++ -*-===//
2
//
3
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4
// See https://llvm.org/LICENSE.txt for license information.
5
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6
//
7
//===----------------------------------------------------------------------===//
8
//
9
//  This file implements the CrossTranslationUnit interface.
10
//
11
//===----------------------------------------------------------------------===//
12
#include "clang/CrossTU/CrossTranslationUnit.h"
13
#include "clang/AST/ASTImporter.h"
14
#include "clang/AST/Decl.h"
15
#include "clang/AST/ParentMapContext.h"
16
#include "clang/Basic/TargetInfo.h"
17
#include "clang/CrossTU/CrossTUDiagnostic.h"
18
#include "clang/Frontend/ASTUnit.h"
19
#include "clang/Frontend/CompilerInstance.h"
20
#include "clang/Frontend/TextDiagnosticPrinter.h"
21
#include "clang/Index/USRGeneration.h"
22
#include "llvm/ADT/Optional.h"
23
#include "llvm/ADT/Statistic.h"
24
#include "llvm/ADT/Triple.h"
25
#include "llvm/Option/ArgList.h"
26
#include "llvm/Support/ErrorHandling.h"
27
#include "llvm/Support/ManagedStatic.h"
28
#include "llvm/Support/Path.h"
29
#include "llvm/Support/YAMLParser.h"
30
#include "llvm/Support/raw_ostream.h"
31
#include <algorithm>
32
#include <fstream>
33
#include <sstream>
34
#include <tuple>
35
36
namespace clang {
37
namespace cross_tu {
38
39
namespace {
40
41
#define DEBUG_TYPE "CrossTranslationUnit"
42
STATISTIC(NumGetCTUCalled, "The # of getCTUDefinition function called");
43
STATISTIC(
44
    NumNotInOtherTU,
45
    "The # of getCTUDefinition called but the function is not in any other TU");
46
STATISTIC(NumGetCTUSuccess,
47
          "The # of getCTUDefinition successfully returned the "
48
          "requested function's body");
49
STATISTIC(NumUnsupportedNodeFound, "The # of imports when the ASTImporter "
50
                                   "encountered an unsupported AST Node");
51
STATISTIC(NumNameConflicts, "The # of imports when the ASTImporter "
52
                            "encountered an ODR error");
53
STATISTIC(NumTripleMismatch, "The # of triple mismatches");
54
STATISTIC(NumLangMismatch, "The # of language mismatches");
55
STATISTIC(NumLangDialectMismatch, "The # of language dialect mismatches");
56
STATISTIC(NumASTLoadThresholdReached,
57
          "The # of ASTs not loaded because of threshold");
58
59
// Same as Triple's equality operator, but we check a field only if that is
60
// known in both instances.
61
70
bool hasEqualKnownFields(const llvm::Triple &Lhs, const llvm::Triple &Rhs) {
62
70
  using llvm::Triple;
63
70
  if (Lhs.getArch() != Triple::UnknownArch &&
64
70
      Rhs.getArch() != Triple::UnknownArch && Lhs.getArch() != Rhs.getArch())
65
1
    return false;
66
69
  if (Lhs.getSubArch() != Triple::NoSubArch &&
67
69
      
Rhs.getSubArch() != Triple::NoSubArch0
&&
68
69
      
Lhs.getSubArch() != Rhs.getSubArch()0
)
69
0
    return false;
70
69
  if (Lhs.getVendor() != Triple::UnknownVendor &&
71
69
      
Rhs.getVendor() != Triple::UnknownVendor68
&&
72
69
      
Lhs.getVendor() != Rhs.getVendor()68
)
73
0
    return false;
74
69
  if (!Lhs.isOSUnknown() && !Rhs.isOSUnknown() &&
75
69
      Lhs.getOS() != Rhs.getOS())
76
0
    return false;
77
69
  if (Lhs.getEnvironment() != Triple::UnknownEnvironment &&
78
69
      
Rhs.getEnvironment() != Triple::UnknownEnvironment63
&&
79
69
      
Lhs.getEnvironment() != Rhs.getEnvironment()63
)
80
0
    return false;
81
69
  if (Lhs.getObjectFormat() != Triple::UnknownObjectFormat &&
82
69
      Rhs.getObjectFormat() != Triple::UnknownObjectFormat &&
83
69
      Lhs.getObjectFormat() != Rhs.getObjectFormat())
84
0
    return false;
85
69
  return true;
86
69
}
87
88
// FIXME: This class is will be removed after the transition to llvm::Error.
89
class IndexErrorCategory : public std::error_category {
90
public:
91
0
  const char *name() const noexcept override { return "clang.index"; }
92
93
0
  std::string message(int Condition) const override {
94
0
    switch (static_cast<index_error_code>(Condition)) {
95
0
    case index_error_code::success:
96
      // There should not be a success error. Jump to unreachable directly.
97
      // Add this case to make the compiler stop complaining.
98
0
      break;
99
0
    case index_error_code::unspecified:
100
0
      return "An unknown error has occurred.";
101
0
    case index_error_code::missing_index_file:
102
0
      return "The index file is missing.";
103
0
    case index_error_code::invalid_index_format:
104
0
      return "Invalid index file format.";
105
0
    case index_error_code::multiple_definitions:
106
0
      return "Multiple definitions in the index file.";
107
0
    case index_error_code::missing_definition:
108
0
      return "Missing definition from the index file.";
109
0
    case index_error_code::failed_import:
110
0
      return "Failed to import the definition.";
111
0
    case index_error_code::failed_to_get_external_ast:
112
0
      return "Failed to load external AST source.";
113
0
    case index_error_code::failed_to_generate_usr:
114
0
      return "Failed to generate USR.";
115
0
    case index_error_code::triple_mismatch:
116
0
      return "Triple mismatch";
117
0
    case index_error_code::lang_mismatch:
118
0
      return "Language mismatch";
119
0
    case index_error_code::lang_dialect_mismatch:
120
0
      return "Language dialect mismatch";
121
0
    case index_error_code::load_threshold_reached:
122
0
      return "Load threshold reached";
123
0
    case index_error_code::invocation_list_ambiguous:
124
0
      return "Invocation list file contains multiple references to the same "
125
0
             "source file.";
126
0
    case index_error_code::invocation_list_file_not_found:
127
0
      return "Invocation list file is not found.";
128
0
    case index_error_code::invocation_list_empty:
129
0
      return "Invocation list file is empty.";
130
0
    case index_error_code::invocation_list_wrong_format:
131
0
      return "Invocation list file is in wrong format.";
132
0
    case index_error_code::invocation_list_lookup_unsuccessful:
133
0
      return "Invocation list file does not contain the requested source file.";
134
0
    }
135
0
    llvm_unreachable("Unrecognized index_error_code.");
136
0
  }
137
};
138
139
static llvm::ManagedStatic<IndexErrorCategory> Category;
140
} // end anonymous namespace
141
142
char IndexError::ID;
143
144
0
void IndexError::log(raw_ostream &OS) const {
145
0
  OS << Category->message(static_cast<int>(Code)) << '\n';
146
0
}
147
148
0
std::error_code IndexError::convertToErrorCode() const {
149
0
  return std::error_code(static_cast<int>(Code), *Category);
150
0
}
151
152
llvm::Expected<llvm::StringMap<std::string>>
153
11
parseCrossTUIndex(StringRef IndexPath) {
154
11
  std::ifstream ExternalMapFile{std::string(IndexPath)};
155
11
  if (!ExternalMapFile)
156
0
    return llvm::make_error<IndexError>(index_error_code::missing_index_file,
157
0
                                        IndexPath.str());
158
159
11
  llvm::StringMap<std::string> Result;
160
11
  std::string Line;
161
11
  unsigned LineNo = 1;
162
149
  while (std::getline(ExternalMapFile, Line)) {
163
138
    StringRef LineRef{Line};
164
138
    const size_t Delimiter = LineRef.find(' ');
165
138
    if (Delimiter > 0 && Delimiter != std::string::npos) {
166
138
      StringRef LookupName = LineRef.substr(0, Delimiter);
167
168
      // Store paths with posix-style directory separator.
169
138
      SmallString<32> FilePath(LineRef.substr(Delimiter + 1));
170
138
      llvm::sys::path::native(FilePath, llvm::sys::path::Style::posix);
171
172
138
      bool InsertionOccured;
173
138
      std::tie(std::ignore, InsertionOccured) =
174
138
          Result.try_emplace(LookupName, FilePath.begin(), FilePath.end());
175
138
      if (!InsertionOccured)
176
0
        return llvm::make_error<IndexError>(
177
0
            index_error_code::multiple_definitions, IndexPath.str(), LineNo);
178
138
    } else
179
0
      return llvm::make_error<IndexError>(
180
0
          index_error_code::invalid_index_format, IndexPath.str(), LineNo);
181
138
    ++LineNo;
182
138
  }
183
11
  return Result;
184
11
}
185
186
std::string
187
2
createCrossTUIndexString(const llvm::StringMap<std::string> &Index) {
188
2
  std::ostringstream Result;
189
2
  for (const auto &E : Index)
190
10
    Result << E.getKey().str() << " " << E.getValue() << '\n';
191
2
  return Result.str();
192
2
}
193
194
45
bool containsConst(const VarDecl *VD, const ASTContext &ACtx) {
195
45
  CanQualType CT = ACtx.getCanonicalType(VD->getType());
196
45
  if (!CT.isConstQualified()) {
197
19
    const RecordType *RTy = CT->getAs<RecordType>();
198
19
    if (!RTy || 
!RTy->hasConstFields()18
)
199
2
      return false;
200
19
  }
201
43
  return true;
202
45
}
203
204
834
static bool hasBodyOrInit(const FunctionDecl *D, const FunctionDecl *&DefD) {
205
834
  return D->hasBody(DefD);
206
834
}
207
588
static bool hasBodyOrInit(const VarDecl *D, const VarDecl *&DefD) {
208
588
  return D->getAnyInitializer(DefD);
209
588
}
210
214
template <typename T> static bool hasBodyOrInit(const T *D) {
211
214
  const T *Unused;
212
214
  return hasBodyOrInit(D, Unused);
213
214
}
CrossTranslationUnit.cpp:bool clang::cross_tu::hasBodyOrInit<clang::FunctionDecl>(clang::FunctionDecl const*)
Line
Count
Source
210
145
template <typename T> static bool hasBodyOrInit(const T *D) {
211
145
  const T *Unused;
212
145
  return hasBodyOrInit(D, Unused);
213
145
}
CrossTranslationUnit.cpp:bool clang::cross_tu::hasBodyOrInit<clang::VarDecl>(clang::VarDecl const*)
Line
Count
Source
210
69
template <typename T> static bool hasBodyOrInit(const T *D) {
211
69
  const T *Unused;
212
69
  return hasBodyOrInit(D, Unused);
213
69
}
214
215
CrossTranslationUnitContext::CrossTranslationUnitContext(CompilerInstance &CI)
216
1.39k
    : Context(CI.getASTContext()), ASTStorage(CI) {}
217
218
1.39k
CrossTranslationUnitContext::~CrossTranslationUnitContext() {}
219
220
llvm::Optional<std::string>
221
688
CrossTranslationUnitContext::getLookupName(const NamedDecl *ND) {
222
688
  SmallString<128> DeclUSR;
223
688
  bool Ret = index::generateUSRForDecl(ND, DeclUSR);
224
688
  if (Ret)
225
3
    return {};
226
685
  return std::string(DeclUSR.str());
227
688
}
228
229
/// Recursively visits the decls of a DeclContext, and returns one with the
230
/// given USR.
231
template <typename T>
232
const T *
233
CrossTranslationUnitContext::findDefInDeclContext(const DeclContext *DC,
234
2.54k
                                                  StringRef LookupName) {
235
2.54k
  assert(DC && "Declaration Context must not be null");
236
4.13k
  for (const Decl *D : DC->decls()) {
237
4.13k
    const auto *SubDC = dyn_cast<DeclContext>(D);
238
4.13k
    if (SubDC)
239
2.47k
      if (const auto *ND = findDefInDeclContext<T>(SubDC, LookupName))
240
28
        return ND;
241
242
4.11k
    const auto *ND = dyn_cast<T>(D);
243
4.11k
    const T *ResultDecl;
244
4.11k
    if (!ND || 
!hasBodyOrInit(ND, ResultDecl)1.20k
)
245
3.50k
      continue;
246
601
    llvm::Optional<std::string> ResultLookupName = getLookupName(ResultDecl);
247
601
    if (!ResultLookupName || 
*ResultLookupName != LookupName599
)
248
532
      continue;
249
69
    return ResultDecl;
250
601
  }
251
2.44k
  return nullptr;
252
2.54k
}
clang::FunctionDecl const* clang::cross_tu::CrossTranslationUnitContext::findDefInDeclContext<clang::FunctionDecl>(clang::DeclContext const*, llvm::StringRef)
Line
Count
Source
234
1.06k
                                                  StringRef LookupName) {
235
1.06k
  assert(DC && "Declaration Context must not be null");
236
1.80k
  for (const Decl *D : DC->decls()) {
237
1.80k
    const auto *SubDC = dyn_cast<DeclContext>(D);
238
1.80k
    if (SubDC)
239
1.01k
      if (const auto *ND = findDefInDeclContext<T>(SubDC, LookupName))
240
18
        return ND;
241
242
1.79k
    const auto *ND = dyn_cast<T>(D);
243
1.79k
    const T *ResultDecl;
244
1.79k
    if (!ND || 
!hasBodyOrInit(ND, ResultDecl)689
)
245
1.37k
      continue;
246
420
    llvm::Optional<std::string> ResultLookupName = getLookupName(ResultDecl);
247
420
    if (!ResultLookupName || *ResultLookupName != LookupName)
248
374
      continue;
249
46
    return ResultDecl;
250
420
  }
251
997
  return nullptr;
252
1.06k
}
clang::VarDecl const* clang::cross_tu::CrossTranslationUnitContext::findDefInDeclContext<clang::VarDecl>(clang::DeclContext const*, llvm::StringRef)
Line
Count
Source
234
1.48k
                                                  StringRef LookupName) {
235
1.48k
  assert(DC && "Declaration Context must not be null");
236
2.32k
  for (const Decl *D : DC->decls()) {
237
2.32k
    const auto *SubDC = dyn_cast<DeclContext>(D);
238
2.32k
    if (SubDC)
239
1.46k
      if (const auto *ND = findDefInDeclContext<T>(SubDC, LookupName))
240
10
        return ND;
241
242
2.31k
    const auto *ND = dyn_cast<T>(D);
243
2.31k
    const T *ResultDecl;
244
2.31k
    if (!ND || 
!hasBodyOrInit(ND, ResultDecl)519
)
245
2.13k
      continue;
246
181
    llvm::Optional<std::string> ResultLookupName = getLookupName(ResultDecl);
247
181
    if (!ResultLookupName || 
*ResultLookupName != LookupName179
)
248
158
      continue;
249
23
    return ResultDecl;
250
181
  }
251
1.45k
  return nullptr;
252
1.48k
}
253
254
template <typename T>
255
llvm::Expected<const T *> CrossTranslationUnitContext::getCrossTUDefinitionImpl(
256
    const T *D, StringRef CrossTUDir, StringRef IndexName,
257
77
    bool DisplayCTUProgress) {
258
77
  assert(D && "D is missing, bad call to this function!");
259
0
  assert(!hasBodyOrInit(D) &&
260
77
         "D has a body or init in current translation unit!");
261
0
  ++NumGetCTUCalled;
262
77
  const llvm::Optional<std::string> LookupName = getLookupName(D);
263
77
  if (!LookupName)
264
0
    return llvm::make_error<IndexError>(
265
0
        index_error_code::failed_to_generate_usr);
266
77
  llvm::Expected<ASTUnit *> ASTUnitOrError =
267
77
      loadExternalAST(*LookupName, CrossTUDir, IndexName, DisplayCTUProgress);
268
77
  if (!ASTUnitOrError)
269
7
    return ASTUnitOrError.takeError();
270
70
  ASTUnit *Unit = *ASTUnitOrError;
271
70
  assert(&Unit->getFileManager() ==
272
70
         &Unit->getASTContext().getSourceManager().getFileManager());
273
274
0
  const llvm::Triple &TripleTo = Context.getTargetInfo().getTriple();
275
70
  const llvm::Triple &TripleFrom =
276
70
      Unit->getASTContext().getTargetInfo().getTriple();
277
  // The imported AST had been generated for a different target.
278
  // Some parts of the triple in the loaded ASTContext can be unknown while the
279
  // very same parts in the target ASTContext are known. Thus we check for the
280
  // known parts only.
281
70
  if (!hasEqualKnownFields(TripleTo, TripleFrom)) {
282
    // TODO: Pass the SourceLocation of the CallExpression for more precise
283
    // diagnostics.
284
1
    ++NumTripleMismatch;
285
1
    return llvm::make_error<IndexError>(index_error_code::triple_mismatch,
286
1
                                        std::string(Unit->getMainFileName()),
287
1
                                        TripleTo.str(), TripleFrom.str());
288
1
  }
289
290
69
  const auto &LangTo = Context.getLangOpts();
291
69
  const auto &LangFrom = Unit->getASTContext().getLangOpts();
292
293
  // FIXME: Currenty we do not support CTU across C++ and C and across
294
  // different dialects of C++.
295
69
  if (LangTo.CPlusPlus != LangFrom.CPlusPlus) {
296
0
    ++NumLangMismatch;
297
0
    return llvm::make_error<IndexError>(index_error_code::lang_mismatch);
298
0
  }
299
300
  // If CPP dialects are different then return with error.
301
  //
302
  // Consider this STL code:
303
  //   template<typename _Alloc>
304
  //     struct __alloc_traits
305
  //   #if __cplusplus >= 201103L
306
  //     : std::allocator_traits<_Alloc>
307
  //   #endif
308
  //     { // ...
309
  //     };
310
  // This class template would create ODR errors during merging the two units,
311
  // since in one translation unit the class template has a base class, however
312
  // in the other unit it has none.
313
69
  if (LangTo.CPlusPlus11 != LangFrom.CPlusPlus11 ||
314
69
      LangTo.CPlusPlus14 != LangFrom.CPlusPlus14 ||
315
69
      LangTo.CPlusPlus17 != LangFrom.CPlusPlus17 ||
316
69
      LangTo.CPlusPlus20 != LangFrom.CPlusPlus20) {
317
0
    ++NumLangDialectMismatch;
318
0
    return llvm::make_error<IndexError>(
319
0
        index_error_code::lang_dialect_mismatch);
320
0
  }
321
322
69
  TranslationUnitDecl *TU = Unit->getASTContext().getTranslationUnitDecl();
323
69
  if (const T *ResultDecl = findDefInDeclContext<T>(TU, *LookupName))
324
69
    return importDefinition(ResultDecl, Unit);
325
0
  return llvm::make_error<IndexError>(index_error_code::failed_import);
326
69
}
llvm::Expected<clang::FunctionDecl const*> clang::cross_tu::CrossTranslationUnitContext::getCrossTUDefinitionImpl<clang::FunctionDecl>(clang::FunctionDecl const*, llvm::StringRef, llvm::StringRef, bool)
Line
Count
Source
257
54
    bool DisplayCTUProgress) {
258
54
  assert(D && "D is missing, bad call to this function!");
259
0
  assert(!hasBodyOrInit(D) &&
260
54
         "D has a body or init in current translation unit!");
261
0
  ++NumGetCTUCalled;
262
54
  const llvm::Optional<std::string> LookupName = getLookupName(D);
263
54
  if (!LookupName)
264
0
    return llvm::make_error<IndexError>(
265
0
        index_error_code::failed_to_generate_usr);
266
54
  llvm::Expected<ASTUnit *> ASTUnitOrError =
267
54
      loadExternalAST(*LookupName, CrossTUDir, IndexName, DisplayCTUProgress);
268
54
  if (!ASTUnitOrError)
269
7
    return ASTUnitOrError.takeError();
270
47
  ASTUnit *Unit = *ASTUnitOrError;
271
47
  assert(&Unit->getFileManager() ==
272
47
         &Unit->getASTContext().getSourceManager().getFileManager());
273
274
0
  const llvm::Triple &TripleTo = Context.getTargetInfo().getTriple();
275
47
  const llvm::Triple &TripleFrom =
276
47
      Unit->getASTContext().getTargetInfo().getTriple();
277
  // The imported AST had been generated for a different target.
278
  // Some parts of the triple in the loaded ASTContext can be unknown while the
279
  // very same parts in the target ASTContext are known. Thus we check for the
280
  // known parts only.
281
47
  if (!hasEqualKnownFields(TripleTo, TripleFrom)) {
282
    // TODO: Pass the SourceLocation of the CallExpression for more precise
283
    // diagnostics.
284
1
    ++NumTripleMismatch;
285
1
    return llvm::make_error<IndexError>(index_error_code::triple_mismatch,
286
1
                                        std::string(Unit->getMainFileName()),
287
1
                                        TripleTo.str(), TripleFrom.str());
288
1
  }
289
290
46
  const auto &LangTo = Context.getLangOpts();
291
46
  const auto &LangFrom = Unit->getASTContext().getLangOpts();
292
293
  // FIXME: Currenty we do not support CTU across C++ and C and across
294
  // different dialects of C++.
295
46
  if (LangTo.CPlusPlus != LangFrom.CPlusPlus) {
296
0
    ++NumLangMismatch;
297
0
    return llvm::make_error<IndexError>(index_error_code::lang_mismatch);
298
0
  }
299
300
  // If CPP dialects are different then return with error.
301
  //
302
  // Consider this STL code:
303
  //   template<typename _Alloc>
304
  //     struct __alloc_traits
305
  //   #if __cplusplus >= 201103L
306
  //     : std::allocator_traits<_Alloc>
307
  //   #endif
308
  //     { // ...
309
  //     };
310
  // This class template would create ODR errors during merging the two units,
311
  // since in one translation unit the class template has a base class, however
312
  // in the other unit it has none.
313
46
  if (LangTo.CPlusPlus11 != LangFrom.CPlusPlus11 ||
314
46
      LangTo.CPlusPlus14 != LangFrom.CPlusPlus14 ||
315
46
      LangTo.CPlusPlus17 != LangFrom.CPlusPlus17 ||
316
46
      LangTo.CPlusPlus20 != LangFrom.CPlusPlus20) {
317
0
    ++NumLangDialectMismatch;
318
0
    return llvm::make_error<IndexError>(
319
0
        index_error_code::lang_dialect_mismatch);
320
0
  }
321
322
46
  TranslationUnitDecl *TU = Unit->getASTContext().getTranslationUnitDecl();
323
46
  if (const T *ResultDecl = findDefInDeclContext<T>(TU, *LookupName))
324
46
    return importDefinition(ResultDecl, Unit);
325
0
  return llvm::make_error<IndexError>(index_error_code::failed_import);
326
46
}
llvm::Expected<clang::VarDecl const*> clang::cross_tu::CrossTranslationUnitContext::getCrossTUDefinitionImpl<clang::VarDecl>(clang::VarDecl const*, llvm::StringRef, llvm::StringRef, bool)
Line
Count
Source
257
23
    bool DisplayCTUProgress) {
258
23
  assert(D && "D is missing, bad call to this function!");
259
0
  assert(!hasBodyOrInit(D) &&
260
23
         "D has a body or init in current translation unit!");
261
0
  ++NumGetCTUCalled;
262
23
  const llvm::Optional<std::string> LookupName = getLookupName(D);
263
23
  if (!LookupName)
264
0
    return llvm::make_error<IndexError>(
265
0
        index_error_code::failed_to_generate_usr);
266
23
  llvm::Expected<ASTUnit *> ASTUnitOrError =
267
23
      loadExternalAST(*LookupName, CrossTUDir, IndexName, DisplayCTUProgress);
268
23
  if (!ASTUnitOrError)
269
0
    return ASTUnitOrError.takeError();
270
23
  ASTUnit *Unit = *ASTUnitOrError;
271
23
  assert(&Unit->getFileManager() ==
272
23
         &Unit->getASTContext().getSourceManager().getFileManager());
273
274
0
  const llvm::Triple &TripleTo = Context.getTargetInfo().getTriple();
275
23
  const llvm::Triple &TripleFrom =
276
23
      Unit->getASTContext().getTargetInfo().getTriple();
277
  // The imported AST had been generated for a different target.
278
  // Some parts of the triple in the loaded ASTContext can be unknown while the
279
  // very same parts in the target ASTContext are known. Thus we check for the
280
  // known parts only.
281
23
  if (!hasEqualKnownFields(TripleTo, TripleFrom)) {
282
    // TODO: Pass the SourceLocation of the CallExpression for more precise
283
    // diagnostics.
284
0
    ++NumTripleMismatch;
285
0
    return llvm::make_error<IndexError>(index_error_code::triple_mismatch,
286
0
                                        std::string(Unit->getMainFileName()),
287
0
                                        TripleTo.str(), TripleFrom.str());
288
0
  }
289
290
23
  const auto &LangTo = Context.getLangOpts();
291
23
  const auto &LangFrom = Unit->getASTContext().getLangOpts();
292
293
  // FIXME: Currenty we do not support CTU across C++ and C and across
294
  // different dialects of C++.
295
23
  if (LangTo.CPlusPlus != LangFrom.CPlusPlus) {
296
0
    ++NumLangMismatch;
297
0
    return llvm::make_error<IndexError>(index_error_code::lang_mismatch);
298
0
  }
299
300
  // If CPP dialects are different then return with error.
301
  //
302
  // Consider this STL code:
303
  //   template<typename _Alloc>
304
  //     struct __alloc_traits
305
  //   #if __cplusplus >= 201103L
306
  //     : std::allocator_traits<_Alloc>
307
  //   #endif
308
  //     { // ...
309
  //     };
310
  // This class template would create ODR errors during merging the two units,
311
  // since in one translation unit the class template has a base class, however
312
  // in the other unit it has none.
313
23
  if (LangTo.CPlusPlus11 != LangFrom.CPlusPlus11 ||
314
23
      LangTo.CPlusPlus14 != LangFrom.CPlusPlus14 ||
315
23
      LangTo.CPlusPlus17 != LangFrom.CPlusPlus17 ||
316
23
      LangTo.CPlusPlus20 != LangFrom.CPlusPlus20) {
317
0
    ++NumLangDialectMismatch;
318
0
    return llvm::make_error<IndexError>(
319
0
        index_error_code::lang_dialect_mismatch);
320
0
  }
321
322
23
  TranslationUnitDecl *TU = Unit->getASTContext().getTranslationUnitDecl();
323
23
  if (const T *ResultDecl = findDefInDeclContext<T>(TU, *LookupName))
324
23
    return importDefinition(ResultDecl, Unit);
325
0
  return llvm::make_error<IndexError>(index_error_code::failed_import);
326
23
}
327
328
llvm::Expected<const FunctionDecl *>
329
CrossTranslationUnitContext::getCrossTUDefinition(const FunctionDecl *FD,
330
                                                  StringRef CrossTUDir,
331
                                                  StringRef IndexName,
332
54
                                                  bool DisplayCTUProgress) {
333
54
  return getCrossTUDefinitionImpl(FD, CrossTUDir, IndexName,
334
54
                                  DisplayCTUProgress);
335
54
}
336
337
llvm::Expected<const VarDecl *>
338
CrossTranslationUnitContext::getCrossTUDefinition(const VarDecl *VD,
339
                                                  StringRef CrossTUDir,
340
                                                  StringRef IndexName,
341
23
                                                  bool DisplayCTUProgress) {
342
23
  return getCrossTUDefinitionImpl(VD, CrossTUDir, IndexName,
343
23
                                  DisplayCTUProgress);
344
23
}
345
346
8
void CrossTranslationUnitContext::emitCrossTUDiagnostics(const IndexError &IE) {
347
8
  switch (IE.getCode()) {
348
0
  case index_error_code::missing_index_file:
349
0
    Context.getDiagnostics().Report(diag::err_ctu_error_opening)
350
0
        << IE.getFileName();
351
0
    break;
352
0
  case index_error_code::invalid_index_format:
353
0
    Context.getDiagnostics().Report(diag::err_extdefmap_parsing)
354
0
        << IE.getFileName() << IE.getLineNum();
355
0
    break;
356
0
  case index_error_code::multiple_definitions:
357
0
    Context.getDiagnostics().Report(diag::err_multiple_def_index)
358
0
        << IE.getLineNum();
359
0
    break;
360
1
  case index_error_code::triple_mismatch:
361
1
    Context.getDiagnostics().Report(diag::warn_ctu_incompat_triple)
362
1
        << IE.getFileName() << IE.getTripleToName() << IE.getTripleFromName();
363
1
    break;
364
7
  default:
365
7
    break;
366
8
  }
367
8
}
368
369
CrossTranslationUnitContext::ASTUnitStorage::ASTUnitStorage(
370
    CompilerInstance &CI)
371
    : Loader(CI, CI.getAnalyzerOpts()->CTUDir,
372
             CI.getAnalyzerOpts()->CTUInvocationList),
373
      LoadGuard(CI.getASTContext().getLangOpts().CPlusPlus
374
                    ? CI.getAnalyzerOpts()->CTUImportCppThreshold
375
1.39k
                    : CI.getAnalyzerOpts()->CTUImportThreshold) {}
376
377
llvm::Expected<ASTUnit *>
378
CrossTranslationUnitContext::ASTUnitStorage::getASTUnitForFile(
379
71
    StringRef FileName, bool DisplayCTUProgress) {
380
  // Try the cache first.
381
71
  auto ASTCacheEntry = FileASTUnitMap.find(FileName);
382
71
  if (ASTCacheEntry == FileASTUnitMap.end()) {
383
384
    // Do not load if the limit is reached.
385
12
    if (!LoadGuard) {
386
1
      ++NumASTLoadThresholdReached;
387
1
      return llvm::make_error<IndexError>(
388
1
          index_error_code::load_threshold_reached);
389
1
    }
390
391
11
    auto LoadAttempt = Loader.load(FileName);
392
393
11
    if (!LoadAttempt)
394
0
      return LoadAttempt.takeError();
395
396
11
    std::unique_ptr<ASTUnit> LoadedUnit = std::move(LoadAttempt.get());
397
398
    // Need the raw pointer and the unique_ptr as well.
399
11
    ASTUnit *Unit = LoadedUnit.get();
400
401
    // Update the cache.
402
11
    FileASTUnitMap[FileName] = std::move(LoadedUnit);
403
404
11
    LoadGuard.indicateLoadSuccess();
405
406
11
    if (DisplayCTUProgress)
407
4
      llvm::errs() << "CTU loaded AST file: " << FileName << "\n";
408
409
11
    return Unit;
410
411
59
  } else {
412
    // Found in the cache.
413
59
    return ASTCacheEntry->second.get();
414
59
  }
415
71
}
416
417
llvm::Expected<ASTUnit *>
418
CrossTranslationUnitContext::ASTUnitStorage::getASTUnitForFunction(
419
    StringRef FunctionName, StringRef CrossTUDir, StringRef IndexName,
420
77
    bool DisplayCTUProgress) {
421
  // Try the cache first.
422
77
  auto ASTCacheEntry = NameASTUnitMap.find(FunctionName);
423
77
  if (ASTCacheEntry == NameASTUnitMap.end()) {
424
    // Load the ASTUnit from the pre-dumped AST file specified by ASTFileName.
425
426
    // Ensure that the Index is loaded, as we need to search in it.
427
77
    if (llvm::Error IndexLoadError =
428
77
            ensureCTUIndexLoaded(CrossTUDir, IndexName))
429
0
      return std::move(IndexLoadError);
430
431
    // Check if there is and entry in the index for the function.
432
77
    if (!NameFileMap.count(FunctionName)) {
433
6
      ++NumNotInOtherTU;
434
6
      return llvm::make_error<IndexError>(index_error_code::missing_definition);
435
6
    }
436
437
    // Search in the index for the filename where the definition of FuncitonName
438
    // resides.
439
71
    if (llvm::Expected<ASTUnit *> FoundForFile =
440
71
            getASTUnitForFile(NameFileMap[FunctionName], DisplayCTUProgress)) {
441
442
      // Update the cache.
443
70
      NameASTUnitMap[FunctionName] = *FoundForFile;
444
70
      return *FoundForFile;
445
446
70
    } else {
447
1
      return FoundForFile.takeError();
448
1
    }
449
71
  } else {
450
    // Found in the cache.
451
0
    return ASTCacheEntry->second;
452
0
  }
453
77
}
454
455
llvm::Expected<std::string>
456
CrossTranslationUnitContext::ASTUnitStorage::getFileForFunction(
457
0
    StringRef FunctionName, StringRef CrossTUDir, StringRef IndexName) {
458
0
  if (llvm::Error IndexLoadError = ensureCTUIndexLoaded(CrossTUDir, IndexName))
459
0
    return std::move(IndexLoadError);
460
0
  return NameFileMap[FunctionName];
461
0
}
462
463
llvm::Error CrossTranslationUnitContext::ASTUnitStorage::ensureCTUIndexLoaded(
464
77
    StringRef CrossTUDir, StringRef IndexName) {
465
  // Dont initialize if the map is filled.
466
77
  if (!NameFileMap.empty())
467
67
    return llvm::Error::success();
468
469
  // Get the absolute path to the index file.
470
10
  SmallString<256> IndexFile = CrossTUDir;
471
10
  if (llvm::sys::path::is_absolute(IndexName))
472
2
    IndexFile = IndexName;
473
8
  else
474
8
    llvm::sys::path::append(IndexFile, IndexName);
475
476
10
  if (auto IndexMapping = parseCrossTUIndex(IndexFile)) {
477
    // Initialize member map.
478
10
    NameFileMap = *IndexMapping;
479
10
    return llvm::Error::success();
480
10
  } else {
481
    // Error while parsing CrossTU index file.
482
0
    return IndexMapping.takeError();
483
0
  };
484
0
}
485
486
llvm::Expected<ASTUnit *> CrossTranslationUnitContext::loadExternalAST(
487
    StringRef LookupName, StringRef CrossTUDir, StringRef IndexName,
488
77
    bool DisplayCTUProgress) {
489
  // FIXME: The current implementation only supports loading decls with
490
  //        a lookup name from a single translation unit. If multiple
491
  //        translation units contains decls with the same lookup name an
492
  //        error will be returned.
493
494
  // Try to get the value from the heavily cached storage.
495
77
  llvm::Expected<ASTUnit *> Unit = ASTStorage.getASTUnitForFunction(
496
77
      LookupName, CrossTUDir, IndexName, DisplayCTUProgress);
497
498
77
  if (!Unit)
499
7
    return Unit.takeError();
500
501
  // Check whether the backing pointer of the Expected is a nullptr.
502
70
  if (!*Unit)
503
0
    return llvm::make_error<IndexError>(
504
0
        index_error_code::failed_to_get_external_ast);
505
506
70
  return Unit;
507
70
}
508
509
CrossTranslationUnitContext::ASTLoader::ASTLoader(
510
    CompilerInstance &CI, StringRef CTUDir, StringRef InvocationListFilePath)
511
1.39k
    : CI(CI), CTUDir(CTUDir), InvocationListFilePath(InvocationListFilePath) {}
512
513
CrossTranslationUnitContext::LoadResultTy
514
11
CrossTranslationUnitContext::ASTLoader::load(StringRef Identifier) {
515
11
  llvm::SmallString<256> Path;
516
11
  if (llvm::sys::path::is_absolute(Identifier, PathStyle)) {
517
1
    Path = Identifier;
518
10
  } else {
519
10
    Path = CTUDir;
520
10
    llvm::sys::path::append(Path, PathStyle, Identifier);
521
10
  }
522
523
  // The path is stored in the InvocationList member in posix style. To
524
  // successfully lookup an entry based on filepath, it must be converted.
525
11
  llvm::sys::path::native(Path, PathStyle);
526
527
  // Normalize by removing relative path components.
528
11
  llvm::sys::path::remove_dots(Path, /*remove_dot_dot*/ true, PathStyle);
529
530
11
  if (Path.endswith(".ast"))
531
11
    return loadFromDump(Path);
532
0
  else
533
0
    return loadFromSource(Path);
534
11
}
535
536
CrossTranslationUnitContext::LoadResultTy
537
11
CrossTranslationUnitContext::ASTLoader::loadFromDump(StringRef ASTDumpPath) {
538
11
  IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
539
11
  TextDiagnosticPrinter *DiagClient =
540
11
      new TextDiagnosticPrinter(llvm::errs(), &*DiagOpts);
541
11
  IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
542
11
  IntrusiveRefCntPtr<DiagnosticsEngine> Diags(
543
11
      new DiagnosticsEngine(DiagID, &*DiagOpts, DiagClient));
544
11
  return ASTUnit::LoadFromASTFile(
545
11
      std::string(ASTDumpPath.str()),
546
11
      CI.getPCHContainerOperations()->getRawReader(), ASTUnit::LoadEverything,
547
11
      Diags, CI.getFileSystemOpts());
548
11
}
549
550
/// Load the AST from a source-file, which is supposed to be located inside the
551
/// YAML formatted invocation list file under the filesystem path specified by
552
/// \p InvocationList. The invocation list should contain absolute paths.
553
/// \p SourceFilePath is the absolute path of the source file that contains the
554
/// function definition the analysis is looking for. The Index is built by the
555
/// \p clang-extdef-mapping tool, which is also supposed to be generating
556
/// absolute paths.
557
///
558
/// Proper diagnostic emission requires absolute paths, so even if a future
559
/// change introduces the handling of relative paths, this must be taken into
560
/// consideration.
561
CrossTranslationUnitContext::LoadResultTy
562
CrossTranslationUnitContext::ASTLoader::loadFromSource(
563
0
    StringRef SourceFilePath) {
564
565
0
  if (llvm::Error InitError = lazyInitInvocationList())
566
0
    return std::move(InitError);
567
0
  assert(InvocationList);
568
569
0
  auto Invocation = InvocationList->find(SourceFilePath);
570
0
  if (Invocation == InvocationList->end())
571
0
    return llvm::make_error<IndexError>(
572
0
        index_error_code::invocation_list_lookup_unsuccessful);
573
574
0
  const InvocationListTy::mapped_type &InvocationCommand = Invocation->second;
575
576
0
  SmallVector<const char *, 32> CommandLineArgs(InvocationCommand.size());
577
0
  std::transform(InvocationCommand.begin(), InvocationCommand.end(),
578
0
                 CommandLineArgs.begin(),
579
0
                 [](auto &&CmdPart) { return CmdPart.c_str(); });
580
581
0
  IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts{&CI.getDiagnosticOpts()};
582
0
  auto *DiagClient = new ForwardingDiagnosticConsumer{CI.getDiagnosticClient()};
583
0
  IntrusiveRefCntPtr<DiagnosticIDs> DiagID{
584
0
      CI.getDiagnostics().getDiagnosticIDs()};
585
0
  IntrusiveRefCntPtr<DiagnosticsEngine> Diags(
586
0
      new DiagnosticsEngine{DiagID, &*DiagOpts, DiagClient});
587
588
0
  return std::unique_ptr<ASTUnit>(ASTUnit::LoadFromCommandLine(
589
0
      CommandLineArgs.begin(), (CommandLineArgs.end()),
590
0
      CI.getPCHContainerOperations(), Diags,
591
0
      CI.getHeaderSearchOpts().ResourceDir));
592
0
}
593
594
llvm::Expected<InvocationListTy>
595
4
parseInvocationList(StringRef FileContent, llvm::sys::path::Style PathStyle) {
596
4
  InvocationListTy InvocationList;
597
598
  /// LLVM YAML parser is used to extract information from invocation list file.
599
4
  llvm::SourceMgr SM;
600
4
  llvm::yaml::Stream InvocationFile(FileContent, SM);
601
602
  /// Only the first document is processed.
603
4
  llvm::yaml::document_iterator FirstInvocationFile = InvocationFile.begin();
604
605
  /// There has to be at least one document available.
606
4
  if (FirstInvocationFile == InvocationFile.end())
607
0
    return llvm::make_error<IndexError>(
608
0
        index_error_code::invocation_list_empty);
609
610
4
  llvm::yaml::Node *DocumentRoot = FirstInvocationFile->getRoot();
611
4
  if (!DocumentRoot)
612
0
    return llvm::make_error<IndexError>(
613
0
        index_error_code::invocation_list_wrong_format);
614
615
  /// According to the format specified the document must be a mapping, where
616
  /// the keys are paths to source files, and values are sequences of invocation
617
  /// parts.
618
4
  auto *Mappings = dyn_cast<llvm::yaml::MappingNode>(DocumentRoot);
619
4
  if (!Mappings)
620
1
    return llvm::make_error<IndexError>(
621
1
        index_error_code::invocation_list_wrong_format);
622
623
5
  
for (auto &NextMapping : *Mappings)3
{
624
    /// The keys should be strings, which represent a source-file path.
625
5
    auto *Key = dyn_cast<llvm::yaml::ScalarNode>(NextMapping.getKey());
626
5
    if (!Key)
627
0
      return llvm::make_error<IndexError>(
628
0
          index_error_code::invocation_list_wrong_format);
629
630
5
    SmallString<32> ValueStorage;
631
5
    StringRef SourcePath = Key->getValue(ValueStorage);
632
633
    // Store paths with PathStyle directory separator.
634
5
    SmallString<32> NativeSourcePath(SourcePath);
635
5
    llvm::sys::path::native(NativeSourcePath, PathStyle);
636
637
5
    StringRef InvocationKey = NativeSourcePath;
638
639
5
    if (InvocationList.find(InvocationKey) != InvocationList.end())
640
1
      return llvm::make_error<IndexError>(
641
1
          index_error_code::invocation_list_ambiguous);
642
643
    /// The values should be sequences of strings, each representing a part of
644
    /// the invocation.
645
4
    auto *Args = dyn_cast<llvm::yaml::SequenceNode>(NextMapping.getValue());
646
4
    if (!Args)
647
0
      return llvm::make_error<IndexError>(
648
0
          index_error_code::invocation_list_wrong_format);
649
650
16
    
for (auto &Arg : *Args)4
{
651
16
      auto *CmdString = dyn_cast<llvm::yaml::ScalarNode>(&Arg);
652
16
      if (!CmdString)
653
0
        return llvm::make_error<IndexError>(
654
0
            index_error_code::invocation_list_wrong_format);
655
      /// Every conversion starts with an empty working storage, as it is not
656
      /// clear if this is a requirement of the YAML parser.
657
16
      ValueStorage.clear();
658
16
      InvocationList[InvocationKey].emplace_back(
659
16
          CmdString->getValue(ValueStorage));
660
16
    }
661
662
4
    if (InvocationList[InvocationKey].empty())
663
0
      return llvm::make_error<IndexError>(
664
0
          index_error_code::invocation_list_wrong_format);
665
4
  }
666
667
2
  return InvocationList;
668
3
}
669
670
0
llvm::Error CrossTranslationUnitContext::ASTLoader::lazyInitInvocationList() {
671
  /// Lazily initialize the invocation list member used for on-demand parsing.
672
0
  if (InvocationList)
673
0
    return llvm::Error::success();
674
0
  if (index_error_code::success != PreviousParsingResult)
675
0
    return llvm::make_error<IndexError>(PreviousParsingResult);
676
677
0
  llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> FileContent =
678
0
      llvm::MemoryBuffer::getFile(InvocationListFilePath);
679
0
  if (!FileContent) {
680
0
    PreviousParsingResult = index_error_code::invocation_list_file_not_found;
681
0
    return llvm::make_error<IndexError>(PreviousParsingResult);
682
0
  }
683
0
  std::unique_ptr<llvm::MemoryBuffer> ContentBuffer = std::move(*FileContent);
684
0
  assert(ContentBuffer && "If no error was produced after loading, the pointer "
685
0
                          "should not be nullptr.");
686
687
0
  llvm::Expected<InvocationListTy> ExpectedInvocationList =
688
0
      parseInvocationList(ContentBuffer->getBuffer(), PathStyle);
689
690
  // Handle the error to store the code for next call to this function.
691
0
  if (!ExpectedInvocationList) {
692
0
    llvm::handleAllErrors(
693
0
        ExpectedInvocationList.takeError(),
694
0
        [&](const IndexError &E) { PreviousParsingResult = E.getCode(); });
695
0
    return llvm::make_error<IndexError>(PreviousParsingResult);
696
0
  }
697
698
0
  InvocationList = *ExpectedInvocationList;
699
700
0
  return llvm::Error::success();
701
0
}
702
703
template <typename T>
704
llvm::Expected<const T *>
705
69
CrossTranslationUnitContext::importDefinitionImpl(const T *D, ASTUnit *Unit) {
706
69
  assert(hasBodyOrInit(D) && "Decls to be imported should have body or init.");
707
708
0
  assert(&D->getASTContext() == &Unit->getASTContext() &&
709
69
         "ASTContext of Decl and the unit should match.");
710
0
  ASTImporter &Importer = getOrCreateASTImporter(Unit);
711
712
69
  auto ToDeclOrError = Importer.Import(D);
713
69
  if (!ToDeclOrError) {
714
1
    handleAllErrors(ToDeclOrError.takeError(),
715
1
                    [&](const ImportError &IE) {
716
1
                      switch (IE.Error) {
717
0
                      case ImportError::NameConflict:
718
0
                        ++NumNameConflicts;
719
0
                         break;
720
1
                      case ImportError::UnsupportedConstruct:
721
1
                        ++NumUnsupportedNodeFound;
722
1
                        break;
723
0
                      case ImportError::Unknown:
724
0
                        llvm_unreachable("Unknown import error happened.");
725
0
                        break;
726
1
                      }
727
1
                    });
llvm::Expected<clang::FunctionDecl const*> clang::cross_tu::CrossTranslationUnitContext::importDefinitionImpl<clang::FunctionDecl>(clang::FunctionDecl const*, clang::ASTUnit*)::'lambda'(clang::ImportError const&)::operator()(clang::ImportError const&) const
Line
Count
Source
715
1
                    [&](const ImportError &IE) {
716
1
                      switch (IE.Error) {
717
0
                      case ImportError::NameConflict:
718
0
                        ++NumNameConflicts;
719
0
                         break;
720
1
                      case ImportError::UnsupportedConstruct:
721
1
                        ++NumUnsupportedNodeFound;
722
1
                        break;
723
0
                      case ImportError::Unknown:
724
0
                        llvm_unreachable("Unknown import error happened.");
725
0
                        break;
726
1
                      }
727
1
                    });
Unexecuted instantiation: llvm::Expected<clang::VarDecl const*> clang::cross_tu::CrossTranslationUnitContext::importDefinitionImpl<clang::VarDecl>(clang::VarDecl const*, clang::ASTUnit*)::'lambda'(clang::ImportError const&)::operator()(clang::ImportError const&) const
728
1
    return llvm::make_error<IndexError>(index_error_code::failed_import);
729
1
  }
730
68
  auto *ToDecl = cast<T>(*ToDeclOrError);
731
68
  assert(hasBodyOrInit(ToDecl) && "Imported Decl should have body or init.");
732
0
  ++NumGetCTUSuccess;
733
734
  // Parent map is invalidated after changing the AST.
735
68
  ToDecl->getASTContext().getParentMapContext().clear();
736
737
68
  return ToDecl;
738
69
}
llvm::Expected<clang::FunctionDecl const*> clang::cross_tu::CrossTranslationUnitContext::importDefinitionImpl<clang::FunctionDecl>(clang::FunctionDecl const*, clang::ASTUnit*)
Line
Count
Source
705
46
CrossTranslationUnitContext::importDefinitionImpl(const T *D, ASTUnit *Unit) {
706
46
  assert(hasBodyOrInit(D) && "Decls to be imported should have body or init.");
707
708
0
  assert(&D->getASTContext() == &Unit->getASTContext() &&
709
46
         "ASTContext of Decl and the unit should match.");
710
0
  ASTImporter &Importer = getOrCreateASTImporter(Unit);
711
712
46
  auto ToDeclOrError = Importer.Import(D);
713
46
  if (!ToDeclOrError) {
714
1
    handleAllErrors(ToDeclOrError.takeError(),
715
1
                    [&](const ImportError &IE) {
716
1
                      switch (IE.Error) {
717
1
                      case ImportError::NameConflict:
718
1
                        ++NumNameConflicts;
719
1
                         break;
720
1
                      case ImportError::UnsupportedConstruct:
721
1
                        ++NumUnsupportedNodeFound;
722
1
                        break;
723
1
                      case ImportError::Unknown:
724
1
                        llvm_unreachable("Unknown import error happened.");
725
1
                        break;
726
1
                      }
727
1
                    });
728
1
    return llvm::make_error<IndexError>(index_error_code::failed_import);
729
1
  }
730
45
  auto *ToDecl = cast<T>(*ToDeclOrError);
731
45
  assert(hasBodyOrInit(ToDecl) && "Imported Decl should have body or init.");
732
0
  ++NumGetCTUSuccess;
733
734
  // Parent map is invalidated after changing the AST.
735
45
  ToDecl->getASTContext().getParentMapContext().clear();
736
737
45
  return ToDecl;
738
46
}
llvm::Expected<clang::VarDecl const*> clang::cross_tu::CrossTranslationUnitContext::importDefinitionImpl<clang::VarDecl>(clang::VarDecl const*, clang::ASTUnit*)
Line
Count
Source
705
23
CrossTranslationUnitContext::importDefinitionImpl(const T *D, ASTUnit *Unit) {
706
23
  assert(hasBodyOrInit(D) && "Decls to be imported should have body or init.");
707
708
0
  assert(&D->getASTContext() == &Unit->getASTContext() &&
709
23
         "ASTContext of Decl and the unit should match.");
710
0
  ASTImporter &Importer = getOrCreateASTImporter(Unit);
711
712
23
  auto ToDeclOrError = Importer.Import(D);
713
23
  if (!ToDeclOrError) {
714
0
    handleAllErrors(ToDeclOrError.takeError(),
715
0
                    [&](const ImportError &IE) {
716
0
                      switch (IE.Error) {
717
0
                      case ImportError::NameConflict:
718
0
                        ++NumNameConflicts;
719
0
                         break;
720
0
                      case ImportError::UnsupportedConstruct:
721
0
                        ++NumUnsupportedNodeFound;
722
0
                        break;
723
0
                      case ImportError::Unknown:
724
0
                        llvm_unreachable("Unknown import error happened.");
725
0
                        break;
726
0
                      }
727
0
                    });
728
0
    return llvm::make_error<IndexError>(index_error_code::failed_import);
729
0
  }
730
23
  auto *ToDecl = cast<T>(*ToDeclOrError);
731
23
  assert(hasBodyOrInit(ToDecl) && "Imported Decl should have body or init.");
732
0
  ++NumGetCTUSuccess;
733
734
  // Parent map is invalidated after changing the AST.
735
23
  ToDecl->getASTContext().getParentMapContext().clear();
736
737
23
  return ToDecl;
738
23
}
739
740
llvm::Expected<const FunctionDecl *>
741
CrossTranslationUnitContext::importDefinition(const FunctionDecl *FD,
742
46
                                              ASTUnit *Unit) {
743
46
  return importDefinitionImpl(FD, Unit);
744
46
}
745
746
llvm::Expected<const VarDecl *>
747
CrossTranslationUnitContext::importDefinition(const VarDecl *VD,
748
23
                                              ASTUnit *Unit) {
749
23
  return importDefinitionImpl(VD, Unit);
750
23
}
751
752
void CrossTranslationUnitContext::lazyInitImporterSharedSt(
753
10
    TranslationUnitDecl *ToTU) {
754
10
  if (!ImporterSharedSt)
755
8
    ImporterSharedSt = std::make_shared<ASTImporterSharedState>(*ToTU);
756
10
}
757
758
ASTImporter &
759
69
CrossTranslationUnitContext::getOrCreateASTImporter(ASTUnit *Unit) {
760
69
  ASTContext &From = Unit->getASTContext();
761
762
69
  auto I = ASTUnitImporterMap.find(From.getTranslationUnitDecl());
763
69
  if (I != ASTUnitImporterMap.end())
764
59
    return *I->second;
765
10
  lazyInitImporterSharedSt(Context.getTranslationUnitDecl());
766
10
  ASTImporter *NewImporter = new ASTImporter(
767
10
      Context, Context.getSourceManager().getFileManager(), From,
768
10
      From.getSourceManager().getFileManager(), false, ImporterSharedSt);
769
10
  ASTUnitImporterMap[From.getTranslationUnitDecl()].reset(NewImporter);
770
10
  return *NewImporter;
771
69
}
772
773
llvm::Optional<clang::MacroExpansionContext>
774
CrossTranslationUnitContext::getMacroExpansionContextForSourceLocation(
775
46
    const clang::SourceLocation &ToLoc) const {
776
  // FIXME: Implement: Record such a context for every imported ASTUnit; lookup.
777
46
  return llvm::None;
778
46
}
779
780
} // namespace cross_tu
781
} // namespace clang