Coverage Report

Created: 2019-07-24 05:18

/Users/buildslave/jenkins/workspace/clang-stage2-coverage-R/llvm/tools/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/Basic/TargetInfo.h"
16
#include "clang/CrossTU/CrossTUDiagnostic.h"
17
#include "clang/Frontend/ASTUnit.h"
18
#include "clang/Frontend/CompilerInstance.h"
19
#include "clang/Frontend/TextDiagnosticPrinter.h"
20
#include "clang/Index/USRGeneration.h"
21
#include "llvm/ADT/Triple.h"
22
#include "llvm/ADT/Statistic.h"
23
#include "llvm/Support/ErrorHandling.h"
24
#include "llvm/Support/ManagedStatic.h"
25
#include "llvm/Support/Path.h"
26
#include "llvm/Support/raw_ostream.h"
27
#include <fstream>
28
#include <sstream>
29
30
namespace clang {
31
namespace cross_tu {
32
33
namespace {
34
35
#define DEBUG_TYPE "CrossTranslationUnit"
36
STATISTIC(NumGetCTUCalled, "The # of getCTUDefinition function called");
37
STATISTIC(
38
    NumNotInOtherTU,
39
    "The # of getCTUDefinition called but the function is not in any other TU");
40
STATISTIC(NumGetCTUSuccess,
41
          "The # of getCTUDefinition successfully returned the "
42
          "requested function's body");
43
STATISTIC(NumUnsupportedNodeFound, "The # of imports when the ASTImporter "
44
                                   "encountered an unsupported AST Node");
45
STATISTIC(NumNameConflicts, "The # of imports when the ASTImporter "
46
                            "encountered an ODR error");
47
STATISTIC(NumTripleMismatch, "The # of triple mismatches");
48
STATISTIC(NumLangMismatch, "The # of language mismatches");
49
STATISTIC(NumLangDialectMismatch, "The # of language dialect mismatches");
50
STATISTIC(NumASTLoadThresholdReached,
51
          "The # of ASTs not loaded because of threshold");
52
53
// Same as Triple's equality operator, but we check a field only if that is
54
// known in both instances.
55
57
bool hasEqualKnownFields(const llvm::Triple &Lhs, const llvm::Triple &Rhs) {
56
57
  using llvm::Triple;
57
57
  if (Lhs.getArch() != Triple::UnknownArch &&
58
57
      Rhs.getArch() != Triple::UnknownArch && Lhs.getArch() != Rhs.getArch())
59
1
    return false;
60
56
  if (Lhs.getSubArch() != Triple::NoSubArch &&
61
56
      
Rhs.getSubArch() != Triple::NoSubArch0
&&
62
56
      
Lhs.getSubArch() != Rhs.getSubArch()0
)
63
0
    return false;
64
56
  if (Lhs.getVendor() != Triple::UnknownVendor &&
65
56
      
Rhs.getVendor() != Triple::UnknownVendor55
&&
66
56
      
Lhs.getVendor() != Rhs.getVendor()55
)
67
0
    return false;
68
56
  if (!Lhs.isOSUnknown() && !Rhs.isOSUnknown() &&
69
56
      Lhs.getOS() != Rhs.getOS())
70
0
    return false;
71
56
  if (Lhs.getEnvironment() != Triple::UnknownEnvironment &&
72
56
      
Rhs.getEnvironment() != Triple::UnknownEnvironment55
&&
73
56
      
Lhs.getEnvironment() != Rhs.getEnvironment()55
)
74
0
    return false;
75
56
  if (Lhs.getObjectFormat() != Triple::UnknownObjectFormat &&
76
56
      Rhs.getObjectFormat() != Triple::UnknownObjectFormat &&
77
56
      Lhs.getObjectFormat() != Rhs.getObjectFormat())
78
0
    return false;
79
56
  return true;
80
56
}
81
82
// FIXME: This class is will be removed after the transition to llvm::Error.
83
class IndexErrorCategory : public std::error_category {
84
public:
85
0
  const char *name() const noexcept override { return "clang.index"; }
86
87
0
  std::string message(int Condition) const override {
88
0
    switch (static_cast<index_error_code>(Condition)) {
89
0
    case index_error_code::unspecified:
90
0
      return "An unknown error has occurred.";
91
0
    case index_error_code::missing_index_file:
92
0
      return "The index file is missing.";
93
0
    case index_error_code::invalid_index_format:
94
0
      return "Invalid index file format.";
95
0
    case index_error_code::multiple_definitions:
96
0
      return "Multiple definitions in the index file.";
97
0
    case index_error_code::missing_definition:
98
0
      return "Missing definition from the index file.";
99
0
    case index_error_code::failed_import:
100
0
      return "Failed to import the definition.";
101
0
    case index_error_code::failed_to_get_external_ast:
102
0
      return "Failed to load external AST source.";
103
0
    case index_error_code::failed_to_generate_usr:
104
0
      return "Failed to generate USR.";
105
0
    case index_error_code::triple_mismatch:
106
0
      return "Triple mismatch";
107
0
    case index_error_code::lang_mismatch:
108
0
      return "Language mismatch";
109
0
    case index_error_code::lang_dialect_mismatch:
110
0
      return "Language dialect mismatch";
111
0
    case index_error_code::load_threshold_reached:
112
0
      return "Load threshold reached";
113
0
    }
114
0
    llvm_unreachable("Unrecognized index_error_code.");
115
0
  }
116
};
117
118
static llvm::ManagedStatic<IndexErrorCategory> Category;
119
} // end anonymous namespace
120
121
char IndexError::ID;
122
123
0
void IndexError::log(raw_ostream &OS) const {
124
0
  OS << Category->message(static_cast<int>(Code)) << '\n';
125
0
}
126
127
0
std::error_code IndexError::convertToErrorCode() const {
128
0
  return std::error_code(static_cast<int>(Code), *Category);
129
0
}
130
131
llvm::Expected<llvm::StringMap<std::string>>
132
8
parseCrossTUIndex(StringRef IndexPath, StringRef CrossTUDir) {
133
8
  std::ifstream ExternalMapFile(IndexPath);
134
8
  if (!ExternalMapFile)
135
0
    return llvm::make_error<IndexError>(index_error_code::missing_index_file,
136
0
                                        IndexPath.str());
137
8
138
8
  llvm::StringMap<std::string> Result;
139
8
  std::string Line;
140
8
  unsigned LineNo = 1;
141
127
  while (std::getline(ExternalMapFile, Line)) {
142
119
    const size_t Pos = Line.find(" ");
143
119
    if (Pos > 0 && Pos != std::string::npos) {
144
119
      StringRef LineRef{Line};
145
119
      StringRef LookupName = LineRef.substr(0, Pos);
146
119
      if (Result.count(LookupName))
147
0
        return llvm::make_error<IndexError>(
148
0
            index_error_code::multiple_definitions, IndexPath.str(), LineNo);
149
119
      StringRef FileName = LineRef.substr(Pos + 1);
150
119
      SmallString<256> FilePath = CrossTUDir;
151
119
      llvm::sys::path::append(FilePath, FileName);
152
119
      Result[LookupName] = FilePath.str().str();
153
119
    } else
154
0
      return llvm::make_error<IndexError>(
155
0
          index_error_code::invalid_index_format, IndexPath.str(), LineNo);
156
119
    LineNo++;
157
119
  }
158
8
  return Result;
159
8
}
160
161
std::string
162
3
createCrossTUIndexString(const llvm::StringMap<std::string> &Index) {
163
3
  std::ostringstream Result;
164
3
  for (const auto &E : Index)
165
11
    Result << E.getKey().str() << " " << E.getValue() << '\n';
166
3
  return Result.str();
167
3
}
168
169
38
bool containsConst(const VarDecl *VD, const ASTContext &ACtx) {
170
38
  CanQualType CT = ACtx.getCanonicalType(VD->getType());
171
38
  if (!CT.isConstQualified()) {
172
18
    const RecordType *RTy = CT->getAs<RecordType>();
173
18
    if (!RTy || 
!RTy->hasConstFields()17
)
174
2
      return false;
175
36
  }
176
36
  return true;
177
36
}
178
179
439
static bool hasBodyOrInit(const FunctionDecl *D, const FunctionDecl *&DefD) {
180
439
  return D->hasBody(DefD);
181
439
}
182
454
static bool hasBodyOrInit(const VarDecl *D, const VarDecl *&DefD) {
183
454
  return D->getAnyInitializer(DefD);
184
454
}
185
template <typename T> static bool hasBodyOrInit(const T *D) {
186
  const T *Unused;
187
  return hasBodyOrInit(D, Unused);
188
}
189
190
CrossTranslationUnitContext::CrossTranslationUnitContext(CompilerInstance &CI)
191
    : CI(CI), Context(CI.getASTContext()),
192
920
      CTULoadThreshold(CI.getAnalyzerOpts()->CTUImportThreshold) {}
193
194
920
CrossTranslationUnitContext::~CrossTranslationUnitContext() {}
195
196
503
std::string CrossTranslationUnitContext::getLookupName(const NamedDecl *ND) {
197
503
  SmallString<128> DeclUSR;
198
503
  bool Ret = index::generateUSRForDecl(ND, DeclUSR);
199
503
  (void)Ret;
200
503
  assert(!Ret && "Unable to generate USR");
201
503
  return DeclUSR.str();
202
503
}
203
204
/// Recursively visits the decls of a DeclContext, and returns one with the
205
/// given USR.
206
template <typename T>
207
const T *
208
CrossTranslationUnitContext::findDefInDeclContext(const DeclContext *DC,
209
1.93k
                                                  StringRef LookupName) {
210
1.93k
  assert(DC && "Declaration Context must not be null");
211
3.11k
  for (const Decl *D : DC->decls()) {
212
3.11k
    const auto *SubDC = dyn_cast<DeclContext>(D);
213
3.11k
    if (SubDC)
214
1.88k
      if (const auto *ND = findDefInDeclContext<T>(SubDC, LookupName))
215
24
        return ND;
216
3.09k
217
3.09k
    const auto *ND = dyn_cast<T>(D);
218
3.09k
    const T *ResultDecl;
219
3.09k
    if (!ND || 
!hasBodyOrInit(ND, ResultDecl)893
)
220
2.66k
      continue;
221
431
    if (getLookupName(ResultDecl) != LookupName)
222
375
      continue;
223
56
    return ResultDecl;
224
56
  }
225
1.93k
  
return nullptr1.85k
;
226
1.93k
}
clang::FunctionDecl const* clang::cross_tu::CrossTranslationUnitContext::findDefInDeclContext<clang::FunctionDecl>(clang::DeclContext const*, llvm::StringRef)
Line
Count
Source
209
649
                                                  StringRef LookupName) {
210
649
  assert(DC && "Declaration Context must not be null");
211
1.10k
  for (const Decl *D : DC->decls()) {
212
1.10k
    const auto *SubDC = dyn_cast<DeclContext>(D);
213
1.10k
    if (SubDC)
214
613
      if (const auto *ND = findDefInDeclContext<T>(SubDC, LookupName))
215
18
        return ND;
216
1.08k
217
1.08k
    const auto *ND = dyn_cast<T>(D);
218
1.08k
    const T *ResultDecl;
219
1.08k
    if (!ND || 
!hasBodyOrInit(ND, ResultDecl)439
)
220
802
      continue;
221
281
    if (getLookupName(ResultDecl) != LookupName)
222
245
      continue;
223
36
    return ResultDecl;
224
36
  }
225
649
  
return nullptr595
;
226
649
}
clang::VarDecl const* clang::cross_tu::CrossTranslationUnitContext::findDefInDeclContext<clang::VarDecl>(clang::DeclContext const*, llvm::StringRef)
Line
Count
Source
209
1.29k
                                                  StringRef LookupName) {
210
1.29k
  assert(DC && "Declaration Context must not be null");
211
2.01k
  for (const Decl *D : DC->decls()) {
212
2.01k
    const auto *SubDC = dyn_cast<DeclContext>(D);
213
2.01k
    if (SubDC)
214
1.27k
      if (const auto *ND = findDefInDeclContext<T>(SubDC, LookupName))
215
6
        return ND;
216
2.01k
217
2.01k
    const auto *ND = dyn_cast<T>(D);
218
2.01k
    const T *ResultDecl;
219
2.01k
    if (!ND || 
!hasBodyOrInit(ND, ResultDecl)454
)
220
1.86k
      continue;
221
150
    if (getLookupName(ResultDecl) != LookupName)
222
130
      continue;
223
20
    return ResultDecl;
224
20
  }
225
1.29k
  
return nullptr1.26k
;
226
1.29k
}
227
228
template <typename T>
229
llvm::Expected<const T *> CrossTranslationUnitContext::getCrossTUDefinitionImpl(
230
    const T *D, StringRef CrossTUDir, StringRef IndexName,
231
64
    bool DisplayCTUProgress) {
232
64
  assert(D && "D is missing, bad call to this function!");
233
64
  assert(!hasBodyOrInit(D) &&
234
64
         "D has a body or init in current translation unit!");
235
64
  ++NumGetCTUCalled;
236
64
  const std::string LookupName = getLookupName(D);
237
64
  if (LookupName.empty())
238
0
    return llvm::make_error<IndexError>(
239
0
        index_error_code::failed_to_generate_usr);
240
64
  llvm::Expected<ASTUnit *> ASTUnitOrError = loadExternalAST(
241
64
      LookupName, CrossTUDir, IndexName, DisplayCTUProgress);
242
64
  if (!ASTUnitOrError)
243
7
    return ASTUnitOrError.takeError();
244
57
  ASTUnit *Unit = *ASTUnitOrError;
245
57
  assert(&Unit->getFileManager() ==
246
57
         &Unit->getASTContext().getSourceManager().getFileManager());
247
57
248
57
  const llvm::Triple &TripleTo = Context.getTargetInfo().getTriple();
249
57
  const llvm::Triple &TripleFrom =
250
57
      Unit->getASTContext().getTargetInfo().getTriple();
251
57
  // The imported AST had been generated for a different target.
252
57
  // Some parts of the triple in the loaded ASTContext can be unknown while the
253
57
  // very same parts in the target ASTContext are known. Thus we check for the
254
57
  // known parts only.
255
57
  if (!hasEqualKnownFields(TripleTo, TripleFrom)) {
256
1
    // TODO: Pass the SourceLocation of the CallExpression for more precise
257
1
    // diagnostics.
258
1
    ++NumTripleMismatch;
259
1
    return llvm::make_error<IndexError>(index_error_code::triple_mismatch,
260
1
                                        Unit->getMainFileName(), TripleTo.str(),
261
1
                                        TripleFrom.str());
262
1
  }
263
56
264
56
  const auto &LangTo = Context.getLangOpts();
265
56
  const auto &LangFrom = Unit->getASTContext().getLangOpts();
266
56
267
56
  // FIXME: Currenty we do not support CTU across C++ and C and across
268
56
  // different dialects of C++.
269
56
  if (LangTo.CPlusPlus != LangFrom.CPlusPlus) {
270
0
    ++NumLangMismatch;
271
0
    return llvm::make_error<IndexError>(index_error_code::lang_mismatch);
272
0
  }
273
56
274
56
  // If CPP dialects are different then return with error.
275
56
  //
276
56
  // Consider this STL code:
277
56
  //   template<typename _Alloc>
278
56
  //     struct __alloc_traits
279
56
  //   #if __cplusplus >= 201103L
280
56
  //     : std::allocator_traits<_Alloc>
281
56
  //   #endif
282
56
  //     { // ...
283
56
  //     };
284
56
  // This class template would create ODR errors during merging the two units,
285
56
  // since in one translation unit the class template has a base class, however
286
56
  // in the other unit it has none.
287
56
  if (LangTo.CPlusPlus11 != LangFrom.CPlusPlus11 ||
288
56
      LangTo.CPlusPlus14 != LangFrom.CPlusPlus14 ||
289
56
      LangTo.CPlusPlus17 != LangFrom.CPlusPlus17 ||
290
56
      LangTo.CPlusPlus2a != LangFrom.CPlusPlus2a) {
291
0
    ++NumLangDialectMismatch;
292
0
    return llvm::make_error<IndexError>(
293
0
        index_error_code::lang_dialect_mismatch);
294
0
  }
295
56
296
56
  TranslationUnitDecl *TU = Unit->getASTContext().getTranslationUnitDecl();
297
56
  if (const T *ResultDecl = findDefInDeclContext<T>(TU, LookupName))
298
56
    return importDefinition(ResultDecl);
299
0
  return llvm::make_error<IndexError>(index_error_code::failed_import);
300
0
}
llvm::Expected<clang::FunctionDecl const*> clang::cross_tu::CrossTranslationUnitContext::getCrossTUDefinitionImpl<clang::FunctionDecl>(clang::FunctionDecl const*, llvm::StringRef, llvm::StringRef, bool)
Line
Count
Source
231
44
    bool DisplayCTUProgress) {
232
44
  assert(D && "D is missing, bad call to this function!");
233
44
  assert(!hasBodyOrInit(D) &&
234
44
         "D has a body or init in current translation unit!");
235
44
  ++NumGetCTUCalled;
236
44
  const std::string LookupName = getLookupName(D);
237
44
  if (LookupName.empty())
238
0
    return llvm::make_error<IndexError>(
239
0
        index_error_code::failed_to_generate_usr);
240
44
  llvm::Expected<ASTUnit *> ASTUnitOrError = loadExternalAST(
241
44
      LookupName, CrossTUDir, IndexName, DisplayCTUProgress);
242
44
  if (!ASTUnitOrError)
243
7
    return ASTUnitOrError.takeError();
244
37
  ASTUnit *Unit = *ASTUnitOrError;
245
37
  assert(&Unit->getFileManager() ==
246
37
         &Unit->getASTContext().getSourceManager().getFileManager());
247
37
248
37
  const llvm::Triple &TripleTo = Context.getTargetInfo().getTriple();
249
37
  const llvm::Triple &TripleFrom =
250
37
      Unit->getASTContext().getTargetInfo().getTriple();
251
37
  // The imported AST had been generated for a different target.
252
37
  // Some parts of the triple in the loaded ASTContext can be unknown while the
253
37
  // very same parts in the target ASTContext are known. Thus we check for the
254
37
  // known parts only.
255
37
  if (!hasEqualKnownFields(TripleTo, TripleFrom)) {
256
1
    // TODO: Pass the SourceLocation of the CallExpression for more precise
257
1
    // diagnostics.
258
1
    ++NumTripleMismatch;
259
1
    return llvm::make_error<IndexError>(index_error_code::triple_mismatch,
260
1
                                        Unit->getMainFileName(), TripleTo.str(),
261
1
                                        TripleFrom.str());
262
1
  }
263
36
264
36
  const auto &LangTo = Context.getLangOpts();
265
36
  const auto &LangFrom = Unit->getASTContext().getLangOpts();
266
36
267
36
  // FIXME: Currenty we do not support CTU across C++ and C and across
268
36
  // different dialects of C++.
269
36
  if (LangTo.CPlusPlus != LangFrom.CPlusPlus) {
270
0
    ++NumLangMismatch;
271
0
    return llvm::make_error<IndexError>(index_error_code::lang_mismatch);
272
0
  }
273
36
274
36
  // If CPP dialects are different then return with error.
275
36
  //
276
36
  // Consider this STL code:
277
36
  //   template<typename _Alloc>
278
36
  //     struct __alloc_traits
279
36
  //   #if __cplusplus >= 201103L
280
36
  //     : std::allocator_traits<_Alloc>
281
36
  //   #endif
282
36
  //     { // ...
283
36
  //     };
284
36
  // This class template would create ODR errors during merging the two units,
285
36
  // since in one translation unit the class template has a base class, however
286
36
  // in the other unit it has none.
287
36
  if (LangTo.CPlusPlus11 != LangFrom.CPlusPlus11 ||
288
36
      LangTo.CPlusPlus14 != LangFrom.CPlusPlus14 ||
289
36
      LangTo.CPlusPlus17 != LangFrom.CPlusPlus17 ||
290
36
      LangTo.CPlusPlus2a != LangFrom.CPlusPlus2a) {
291
0
    ++NumLangDialectMismatch;
292
0
    return llvm::make_error<IndexError>(
293
0
        index_error_code::lang_dialect_mismatch);
294
0
  }
295
36
296
36
  TranslationUnitDecl *TU = Unit->getASTContext().getTranslationUnitDecl();
297
36
  if (const T *ResultDecl = findDefInDeclContext<T>(TU, LookupName))
298
36
    return importDefinition(ResultDecl);
299
0
  return llvm::make_error<IndexError>(index_error_code::failed_import);
300
0
}
llvm::Expected<clang::VarDecl const*> clang::cross_tu::CrossTranslationUnitContext::getCrossTUDefinitionImpl<clang::VarDecl>(clang::VarDecl const*, llvm::StringRef, llvm::StringRef, bool)
Line
Count
Source
231
20
    bool DisplayCTUProgress) {
232
20
  assert(D && "D is missing, bad call to this function!");
233
20
  assert(!hasBodyOrInit(D) &&
234
20
         "D has a body or init in current translation unit!");
235
20
  ++NumGetCTUCalled;
236
20
  const std::string LookupName = getLookupName(D);
237
20
  if (LookupName.empty())
238
0
    return llvm::make_error<IndexError>(
239
0
        index_error_code::failed_to_generate_usr);
240
20
  llvm::Expected<ASTUnit *> ASTUnitOrError = loadExternalAST(
241
20
      LookupName, CrossTUDir, IndexName, DisplayCTUProgress);
242
20
  if (!ASTUnitOrError)
243
0
    return ASTUnitOrError.takeError();
244
20
  ASTUnit *Unit = *ASTUnitOrError;
245
20
  assert(&Unit->getFileManager() ==
246
20
         &Unit->getASTContext().getSourceManager().getFileManager());
247
20
248
20
  const llvm::Triple &TripleTo = Context.getTargetInfo().getTriple();
249
20
  const llvm::Triple &TripleFrom =
250
20
      Unit->getASTContext().getTargetInfo().getTriple();
251
20
  // The imported AST had been generated for a different target.
252
20
  // Some parts of the triple in the loaded ASTContext can be unknown while the
253
20
  // very same parts in the target ASTContext are known. Thus we check for the
254
20
  // known parts only.
255
20
  if (!hasEqualKnownFields(TripleTo, TripleFrom)) {
256
0
    // TODO: Pass the SourceLocation of the CallExpression for more precise
257
0
    // diagnostics.
258
0
    ++NumTripleMismatch;
259
0
    return llvm::make_error<IndexError>(index_error_code::triple_mismatch,
260
0
                                        Unit->getMainFileName(), TripleTo.str(),
261
0
                                        TripleFrom.str());
262
0
  }
263
20
264
20
  const auto &LangTo = Context.getLangOpts();
265
20
  const auto &LangFrom = Unit->getASTContext().getLangOpts();
266
20
267
20
  // FIXME: Currenty we do not support CTU across C++ and C and across
268
20
  // different dialects of C++.
269
20
  if (LangTo.CPlusPlus != LangFrom.CPlusPlus) {
270
0
    ++NumLangMismatch;
271
0
    return llvm::make_error<IndexError>(index_error_code::lang_mismatch);
272
0
  }
273
20
274
20
  // If CPP dialects are different then return with error.
275
20
  //
276
20
  // Consider this STL code:
277
20
  //   template<typename _Alloc>
278
20
  //     struct __alloc_traits
279
20
  //   #if __cplusplus >= 201103L
280
20
  //     : std::allocator_traits<_Alloc>
281
20
  //   #endif
282
20
  //     { // ...
283
20
  //     };
284
20
  // This class template would create ODR errors during merging the two units,
285
20
  // since in one translation unit the class template has a base class, however
286
20
  // in the other unit it has none.
287
20
  if (LangTo.CPlusPlus11 != LangFrom.CPlusPlus11 ||
288
20
      LangTo.CPlusPlus14 != LangFrom.CPlusPlus14 ||
289
20
      LangTo.CPlusPlus17 != LangFrom.CPlusPlus17 ||
290
20
      LangTo.CPlusPlus2a != LangFrom.CPlusPlus2a) {
291
0
    ++NumLangDialectMismatch;
292
0
    return llvm::make_error<IndexError>(
293
0
        index_error_code::lang_dialect_mismatch);
294
0
  }
295
20
296
20
  TranslationUnitDecl *TU = Unit->getASTContext().getTranslationUnitDecl();
297
20
  if (const T *ResultDecl = findDefInDeclContext<T>(TU, LookupName))
298
20
    return importDefinition(ResultDecl);
299
0
  return llvm::make_error<IndexError>(index_error_code::failed_import);
300
0
}
301
302
llvm::Expected<const FunctionDecl *>
303
CrossTranslationUnitContext::getCrossTUDefinition(const FunctionDecl *FD,
304
                                                  StringRef CrossTUDir,
305
                                                  StringRef IndexName,
306
44
                                                  bool DisplayCTUProgress) {
307
44
  return getCrossTUDefinitionImpl(FD, CrossTUDir, IndexName,
308
44
                                  DisplayCTUProgress);
309
44
}
310
311
llvm::Expected<const VarDecl *>
312
CrossTranslationUnitContext::getCrossTUDefinition(const VarDecl *VD,
313
                                                  StringRef CrossTUDir,
314
                                                  StringRef IndexName,
315
20
                                                  bool DisplayCTUProgress) {
316
20
  return getCrossTUDefinitionImpl(VD, CrossTUDir, IndexName,
317
20
                                  DisplayCTUProgress);
318
20
}
319
320
8
void CrossTranslationUnitContext::emitCrossTUDiagnostics(const IndexError &IE) {
321
8
  switch (IE.getCode()) {
322
8
  case index_error_code::missing_index_file:
323
0
    Context.getDiagnostics().Report(diag::err_ctu_error_opening)
324
0
        << IE.getFileName();
325
0
    break;
326
8
  case index_error_code::invalid_index_format:
327
0
    Context.getDiagnostics().Report(diag::err_extdefmap_parsing)
328
0
        << IE.getFileName() << IE.getLineNum();
329
0
    break;
330
8
  case index_error_code::multiple_definitions:
331
0
    Context.getDiagnostics().Report(diag::err_multiple_def_index)
332
0
        << IE.getLineNum();
333
0
    break;
334
8
  case index_error_code::triple_mismatch:
335
1
    Context.getDiagnostics().Report(diag::warn_ctu_incompat_triple)
336
1
        << IE.getFileName() << IE.getTripleToName() << IE.getTripleFromName();
337
1
    break;
338
8
  default:
339
7
    break;
340
8
  }
341
8
}
342
343
llvm::Expected<ASTUnit *> CrossTranslationUnitContext::loadExternalAST(
344
    StringRef LookupName, StringRef CrossTUDir, StringRef IndexName,
345
64
    bool DisplayCTUProgress) {
346
64
  // FIXME: The current implementation only supports loading decls with
347
64
  //        a lookup name from a single translation unit. If multiple
348
64
  //        translation units contains decls with the same lookup name an
349
64
  //        error will be returned.
350
64
351
64
  if (NumASTLoaded >= CTULoadThreshold) {
352
1
    ++NumASTLoadThresholdReached;
353
1
    return llvm::make_error<IndexError>(
354
1
        index_error_code::load_threshold_reached);
355
1
  }
356
63
357
63
  ASTUnit *Unit = nullptr;
358
63
  auto NameUnitCacheEntry = NameASTUnitMap.find(LookupName);
359
63
  if (NameUnitCacheEntry == NameASTUnitMap.end()) {
360
63
    if (NameFileMap.empty()) {
361
6
      SmallString<256> IndexFile = CrossTUDir;
362
6
      if (llvm::sys::path::is_absolute(IndexName))
363
1
        IndexFile = IndexName;
364
5
      else
365
5
        llvm::sys::path::append(IndexFile, IndexName);
366
6
      llvm::Expected<llvm::StringMap<std::string>> IndexOrErr =
367
6
          parseCrossTUIndex(IndexFile, CrossTUDir);
368
6
      if (IndexOrErr)
369
6
        NameFileMap = *IndexOrErr;
370
0
      else
371
0
        return IndexOrErr.takeError();
372
63
    }
373
63
374
63
    auto It = NameFileMap.find(LookupName);
375
63
    if (It == NameFileMap.end()) {
376
6
      ++NumNotInOtherTU;
377
6
      return llvm::make_error<IndexError>(index_error_code::missing_definition);
378
6
    }
379
57
    StringRef ASTFileName = It->second;
380
57
    auto ASTCacheEntry = FileASTUnitMap.find(ASTFileName);
381
57
    if (ASTCacheEntry == FileASTUnitMap.end()) {
382
8
      IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
383
8
      TextDiagnosticPrinter *DiagClient =
384
8
          new TextDiagnosticPrinter(llvm::errs(), &*DiagOpts);
385
8
      IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
386
8
      IntrusiveRefCntPtr<DiagnosticsEngine> Diags(
387
8
          new DiagnosticsEngine(DiagID, &*DiagOpts, DiagClient));
388
8
389
8
      std::unique_ptr<ASTUnit> LoadedUnit(ASTUnit::LoadFromASTFile(
390
8
          ASTFileName, CI.getPCHContainerOperations()->getRawReader(),
391
8
          ASTUnit::LoadEverything, Diags, CI.getFileSystemOpts()));
392
8
      Unit = LoadedUnit.get();
393
8
      FileASTUnitMap[ASTFileName] = std::move(LoadedUnit);
394
8
      ++NumASTLoaded;
395
8
      if (DisplayCTUProgress) {
396
2
        llvm::errs() << "CTU loaded AST file: "
397
2
                     << ASTFileName << "\n";
398
2
      }
399
49
    } else {
400
49
      Unit = ASTCacheEntry->second.get();
401
49
    }
402
57
    NameASTUnitMap[LookupName] = Unit;
403
57
  } else {
404
0
    Unit = NameUnitCacheEntry->second;
405
0
  }
406
63
  
if (57
!Unit57
)
407
0
    return llvm::make_error<IndexError>(
408
0
        index_error_code::failed_to_get_external_ast);
409
57
  return Unit;
410
57
}
411
412
template <typename T>
413
llvm::Expected<const T *>
414
56
CrossTranslationUnitContext::importDefinitionImpl(const T *D) {
415
56
  assert(hasBodyOrInit(D) && "Decls to be imported should have body or init.");
416
56
417
56
  ASTImporter &Importer = getOrCreateASTImporter(D->getASTContext());
418
56
  auto ToDeclOrError = Importer.Import(D);
419
56
  if (!ToDeclOrError) {
420
1
    handleAllErrors(ToDeclOrError.takeError(),
421
1
                    [&](const ImportError &IE) {
422
1
                      switch (IE.Error) {
423
1
                      case ImportError::NameConflict:
424
0
                        ++NumNameConflicts;
425
0
                         break;
426
1
                      case ImportError::UnsupportedConstruct:
427
1
                        ++NumUnsupportedNodeFound;
428
1
                        break;
429
1
                      case ImportError::Unknown:
430
0
                        llvm_unreachable("Unknown import error happened.");
431
1
                        
break0
;
432
1
                      }
433
1
                    });
llvm::Expected<clang::FunctionDecl const*> clang::cross_tu::CrossTranslationUnitContext::importDefinitionImpl<clang::FunctionDecl>(clang::FunctionDecl const*)::'lambda'(clang::ImportError const&)::operator()(clang::ImportError const&) const
Line
Count
Source
421
1
                    [&](const ImportError &IE) {
422
1
                      switch (IE.Error) {
423
1
                      case ImportError::NameConflict:
424
0
                        ++NumNameConflicts;
425
0
                         break;
426
1
                      case ImportError::UnsupportedConstruct:
427
1
                        ++NumUnsupportedNodeFound;
428
1
                        break;
429
1
                      case ImportError::Unknown:
430
0
                        llvm_unreachable("Unknown import error happened.");
431
1
                        
break0
;
432
1
                      }
433
1
                    });
Unexecuted instantiation: llvm::Expected<clang::VarDecl const*> clang::cross_tu::CrossTranslationUnitContext::importDefinitionImpl<clang::VarDecl>(clang::VarDecl const*)::'lambda'(clang::ImportError const&)::operator()(clang::ImportError const&) const
434
1
    return llvm::make_error<IndexError>(index_error_code::failed_import);
435
1
  }
436
55
  auto *ToDecl = cast<T>(*ToDeclOrError);
437
55
  assert(hasBodyOrInit(ToDecl) && "Imported Decl should have body or init.");
438
55
  ++NumGetCTUSuccess;
439
55
440
55
  return ToDecl;
441
55
}
llvm::Expected<clang::FunctionDecl const*> clang::cross_tu::CrossTranslationUnitContext::importDefinitionImpl<clang::FunctionDecl>(clang::FunctionDecl const*)
Line
Count
Source
414
36
CrossTranslationUnitContext::importDefinitionImpl(const T *D) {
415
36
  assert(hasBodyOrInit(D) && "Decls to be imported should have body or init.");
416
36
417
36
  ASTImporter &Importer = getOrCreateASTImporter(D->getASTContext());
418
36
  auto ToDeclOrError = Importer.Import(D);
419
36
  if (!ToDeclOrError) {
420
1
    handleAllErrors(ToDeclOrError.takeError(),
421
1
                    [&](const ImportError &IE) {
422
1
                      switch (IE.Error) {
423
1
                      case ImportError::NameConflict:
424
1
                        ++NumNameConflicts;
425
1
                         break;
426
1
                      case ImportError::UnsupportedConstruct:
427
1
                        ++NumUnsupportedNodeFound;
428
1
                        break;
429
1
                      case ImportError::Unknown:
430
1
                        llvm_unreachable("Unknown import error happened.");
431
1
                        break;
432
1
                      }
433
1
                    });
434
1
    return llvm::make_error<IndexError>(index_error_code::failed_import);
435
1
  }
436
35
  auto *ToDecl = cast<T>(*ToDeclOrError);
437
35
  assert(hasBodyOrInit(ToDecl) && "Imported Decl should have body or init.");
438
35
  ++NumGetCTUSuccess;
439
35
440
35
  return ToDecl;
441
35
}
llvm::Expected<clang::VarDecl const*> clang::cross_tu::CrossTranslationUnitContext::importDefinitionImpl<clang::VarDecl>(clang::VarDecl const*)
Line
Count
Source
414
20
CrossTranslationUnitContext::importDefinitionImpl(const T *D) {
415
20
  assert(hasBodyOrInit(D) && "Decls to be imported should have body or init.");
416
20
417
20
  ASTImporter &Importer = getOrCreateASTImporter(D->getASTContext());
418
20
  auto ToDeclOrError = Importer.Import(D);
419
20
  if (!ToDeclOrError) {
420
0
    handleAllErrors(ToDeclOrError.takeError(),
421
0
                    [&](const ImportError &IE) {
422
0
                      switch (IE.Error) {
423
0
                      case ImportError::NameConflict:
424
0
                        ++NumNameConflicts;
425
0
                         break;
426
0
                      case ImportError::UnsupportedConstruct:
427
0
                        ++NumUnsupportedNodeFound;
428
0
                        break;
429
0
                      case ImportError::Unknown:
430
0
                        llvm_unreachable("Unknown import error happened.");
431
0
                        break;
432
0
                      }
433
0
                    });
434
0
    return llvm::make_error<IndexError>(index_error_code::failed_import);
435
0
  }
436
20
  auto *ToDecl = cast<T>(*ToDeclOrError);
437
20
  assert(hasBodyOrInit(ToDecl) && "Imported Decl should have body or init.");
438
20
  ++NumGetCTUSuccess;
439
20
440
20
  return ToDecl;
441
20
}
442
443
llvm::Expected<const FunctionDecl *>
444
36
CrossTranslationUnitContext::importDefinition(const FunctionDecl *FD) {
445
36
  return importDefinitionImpl(FD);
446
36
}
447
448
llvm::Expected<const VarDecl *>
449
20
CrossTranslationUnitContext::importDefinition(const VarDecl *VD) {
450
20
  return importDefinitionImpl(VD);
451
20
}
452
453
void CrossTranslationUnitContext::lazyInitImporterSharedSt(
454
7
    TranslationUnitDecl *ToTU) {
455
7
  if (!ImporterSharedSt)
456
5
    ImporterSharedSt = std::make_shared<ASTImporterSharedState>(*ToTU);
457
7
}
458
459
ASTImporter &
460
56
CrossTranslationUnitContext::getOrCreateASTImporter(ASTContext &From) {
461
56
  auto I = ASTUnitImporterMap.find(From.getTranslationUnitDecl());
462
56
  if (I != ASTUnitImporterMap.end())
463
49
    return *I->second;
464
7
  lazyInitImporterSharedSt(Context.getTranslationUnitDecl());
465
7
  ASTImporter *NewImporter = new ASTImporter(
466
7
      Context, Context.getSourceManager().getFileManager(), From,
467
7
      From.getSourceManager().getFileManager(), false, ImporterSharedSt);
468
7
  ASTUnitImporterMap[From.getTranslationUnitDecl()].reset(NewImporter);
469
7
  return *NewImporter;
470
7
}
471
472
} // namespace cross_tu
473
} // namespace clang