clang  7.0.0svn
ExternalASTMerger.cpp
Go to the documentation of this file.
1 //===- ExternalASTMerger.cpp - Merging External AST Interface ---*- C++ -*-===//
2 //
3 // The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 // This file implements the ExternalASTMerger, which vends a combination of
11 // ASTs from several different ASTContext/FileManager pairs
12 //
13 //===----------------------------------------------------------------------===//
14 
15 #include "clang/AST/ASTContext.h"
16 #include "clang/AST/Decl.h"
17 #include "clang/AST/DeclCXX.h"
18 #include "clang/AST/DeclObjC.h"
19 #include "clang/AST/DeclTemplate.h"
21 
22 using namespace clang;
23 
24 namespace {
25 
26 template <typename T> struct Source {
27  T t;
28  Source(T t) : t(t) {}
29  operator T() { return t; }
30  template <typename U = T> U &get() { return t; }
31  template <typename U = T> const U &get() const { return t; }
32  template <typename U> operator Source<U>() { return Source<U>(t); }
33 };
34 
35 typedef std::pair<Source<NamedDecl *>, ASTImporter *> Candidate;
36 
37 /// For the given DC, return the DC that is safe to perform lookups on. This is
38 /// the DC we actually want to work with most of the time.
39 const DeclContext *CanonicalizeDC(const DeclContext *DC) {
40  if (isa<LinkageSpecDecl>(DC))
41  return DC->getRedeclContext();
42  return DC;
43 }
44 
45 Source<const DeclContext *>
46 LookupSameContext(Source<TranslationUnitDecl *> SourceTU, const DeclContext *DC,
47  ASTImporter &ReverseImporter) {
48  DC = CanonicalizeDC(DC);
49  if (DC->isTranslationUnit()) {
50  return SourceTU;
51  }
52  Source<const DeclContext *> SourceParentDC =
53  LookupSameContext(SourceTU, DC->getParent(), ReverseImporter);
54  if (!SourceParentDC) {
55  // If we couldn't find the parent DC in this TranslationUnit, give up.
56  return nullptr;
57  }
58  auto *ND = cast<NamedDecl>(DC);
59  DeclarationName Name = ND->getDeclName();
60  Source<DeclarationName> SourceName = ReverseImporter.Import(Name);
61  DeclContext::lookup_result SearchResult =
62  SourceParentDC.get()->lookup(SourceName.get());
63  size_t SearchResultSize = SearchResult.size();
64  if (SearchResultSize == 0 || SearchResultSize > 1) {
65  // There are two cases here. First, we might not find the name.
66  // We might also find multiple copies, in which case we have no
67  // guarantee that the one we wanted is the one we pick. (E.g.,
68  // if we have two specializations of the same template it is
69  // very hard to determine which is the one you want.)
70  //
71  // The Origins map fixes this problem by allowing the origin to be
72  // explicitly recorded, so we trigger that recording by returning
73  // nothing (rather than a possibly-inaccurate guess) here.
74  return nullptr;
75  } else {
76  NamedDecl *SearchResultDecl = SearchResult[0];
77  if (isa<DeclContext>(SearchResultDecl) &&
78  SearchResultDecl->getKind() == DC->getDeclKind())
79  return cast<DeclContext>(SearchResultDecl)->getPrimaryContext();
80  return nullptr; // This type of lookup is unsupported
81  }
82 }
83 
84 /// A custom implementation of ASTImporter, for ExternalASTMerger's purposes.
85 ///
86 /// There are several modifications:
87 ///
88 /// - It enables lazy lookup (via the HasExternalLexicalStorage flag and a few
89 /// others), which instructs Clang to refer to ExternalASTMerger. Also, it
90 /// forces MinimalImport to true, which is necessary to make this work.
91 /// - It maintains a reverse importer for use with names. This allows lookup of
92 /// arbitrary names in the source context.
93 /// - It updates the ExternalASTMerger's origin map as needed whenever a
94 /// it sees a DeclContext.
95 class LazyASTImporter : public ASTImporter {
96 private:
98  ASTImporter Reverse;
99  const ExternalASTMerger::OriginMap &FromOrigins;
100 
101  llvm::raw_ostream &logs() { return Parent.logs(); }
102 public:
103  LazyASTImporter(ExternalASTMerger &_Parent, ASTContext &ToContext,
104  FileManager &ToFileManager, ASTContext &FromContext,
105  FileManager &FromFileManager,
106  const ExternalASTMerger::OriginMap &_FromOrigins)
107  : ASTImporter(ToContext, ToFileManager, FromContext, FromFileManager,
108  /*MinimalImport=*/true),
109  Parent(_Parent), Reverse(FromContext, FromFileManager, ToContext,
110  ToFileManager, /*MinimalImport=*/true), FromOrigins(_FromOrigins) {}
111 
112  /// Whenever a DeclContext is imported, ensure that ExternalASTSource's origin
113  /// map is kept up to date. Also set the appropriate flags.
114  Decl *Imported(Decl *From, Decl *To) override {
115  if (auto *ToDC = dyn_cast<DeclContext>(To)) {
116  const bool LoggingEnabled = Parent.LoggingEnabled();
117  if (LoggingEnabled)
118  logs() << "(ExternalASTMerger*)" << (void*)&Parent
119  << " imported (DeclContext*)" << (void*)ToDC
120  << ", (ASTContext*)" << (void*)&getToContext()
121  << " from (DeclContext*)" << (void*)llvm::cast<DeclContext>(From)
122  << ", (ASTContext*)" << (void*)&getFromContext()
123  << "\n";
124  Source<DeclContext *> FromDC(
125  cast<DeclContext>(From)->getPrimaryContext());
126  if (FromOrigins.count(FromDC) &&
127  Parent.HasImporterForOrigin(*FromOrigins.at(FromDC).AST)) {
128  if (LoggingEnabled)
129  logs() << "(ExternalASTMerger*)" << (void*)&Parent
130  << " forced origin (DeclContext*)"
131  << (void*)FromOrigins.at(FromDC).DC
132  << ", (ASTContext*)"
133  << (void*)FromOrigins.at(FromDC).AST
134  << "\n";
135  Parent.ForceRecordOrigin(ToDC, FromOrigins.at(FromDC));
136  } else {
137  if (LoggingEnabled)
138  logs() << "(ExternalASTMerger*)" << (void*)&Parent
139  << " maybe recording origin (DeclContext*)" << (void*)FromDC
140  << ", (ASTContext*)" << (void*)&getFromContext()
141  << "\n";
142  Parent.MaybeRecordOrigin(ToDC, {FromDC, &getFromContext()});
143  }
144  }
145  if (auto *ToTag = dyn_cast<TagDecl>(To)) {
146  ToTag->setHasExternalLexicalStorage();
147  ToTag->setMustBuildLookupTable();
148  assert(Parent.CanComplete(ToTag));
149  } else if (auto *ToNamespace = dyn_cast<NamespaceDecl>(To)) {
150  ToNamespace->setHasExternalVisibleStorage();
151  assert(Parent.CanComplete(ToNamespace));
152  } else if (auto *ToContainer = dyn_cast<ObjCContainerDecl>(To)) {
153  ToContainer->setHasExternalLexicalStorage();
154  ToContainer->setMustBuildLookupTable();
155  assert(Parent.CanComplete(ToContainer));
156  }
157  return ASTImporter::Imported(From, To);
158  }
159  ASTImporter &GetReverse() { return Reverse; }
160 };
161 
162 bool HasDeclOfSameType(llvm::ArrayRef<Candidate> Decls, const Candidate &C) {
163  if (isa<FunctionDecl>(C.first.get()))
164  return false;
165  return llvm::any_of(Decls, [&](const Candidate &D) {
166  return C.first.get()->getKind() == D.first.get()->getKind();
167  });
168 }
169 
170 } // end namespace
171 
173  for (const std::unique_ptr<ASTImporter> &I : Importers)
174  if (&I->getFromContext() == &OriginContext)
175  return *I;
176  llvm_unreachable("We should have an importer for this origin!");
177 }
178 
179 namespace {
180 LazyASTImporter &LazyImporterForOrigin(ExternalASTMerger &Merger,
181  ASTContext &OriginContext) {
182  return static_cast<LazyASTImporter &>(
183  Merger.ImporterForOrigin(OriginContext));
184 }
185 }
186 
188  for (const std::unique_ptr<ASTImporter> &I : Importers)
189  if (&I->getFromContext() == &OriginContext)
190  return true;
191  return false;
192 }
193 
194 template <typename CallbackType>
195 void ExternalASTMerger::ForEachMatchingDC(const DeclContext *DC,
196  CallbackType Callback) {
197  if (Origins.count(DC)) {
198  ExternalASTMerger::DCOrigin Origin = Origins[DC];
199  LazyASTImporter &Importer = LazyImporterForOrigin(*this, *Origin.AST);
200  Callback(Importer, Importer.GetReverse(), Origin.DC);
201  } else {
202  bool DidCallback = false;
203  for (const std::unique_ptr<ASTImporter> &Importer : Importers) {
204  Source<TranslationUnitDecl *> SourceTU =
205  Importer->getFromContext().getTranslationUnitDecl();
206  ASTImporter &Reverse =
207  static_cast<LazyASTImporter *>(Importer.get())->GetReverse();
208  if (auto SourceDC = LookupSameContext(SourceTU, DC, Reverse)) {
209  DidCallback = true;
210  if (Callback(*Importer, Reverse, SourceDC))
211  break;
212  }
213  }
214  if (!DidCallback && LoggingEnabled())
215  logs() << "(ExternalASTMerger*)" << (void*)this
216  << " asserting for (DeclContext*)" << (const void*)DC
217  << ", (ASTContext*)" << (void*)&Target.AST
218  << "\n";
219  assert(DidCallback && "Couldn't find a source context matching our DC");
220  }
221 }
222 
224  assert(Tag->hasExternalLexicalStorage());
225  ForEachMatchingDC(Tag, [&](ASTImporter &Forward, ASTImporter &Reverse,
226  Source<const DeclContext *> SourceDC) -> bool {
227  auto *SourceTag = const_cast<TagDecl *>(cast<TagDecl>(SourceDC.get()));
228  if (SourceTag->hasExternalLexicalStorage())
229  SourceTag->getASTContext().getExternalSource()->CompleteType(SourceTag);
230  if (!SourceTag->getDefinition())
231  return false;
232  Forward.Imported(SourceTag, Tag);
233  Forward.ImportDefinition(SourceTag);
234  Tag->setCompleteDefinition(SourceTag->isCompleteDefinition());
235  return true;
236  });
237 }
238 
240  assert(Interface->hasExternalLexicalStorage());
241  ForEachMatchingDC(
242  Interface, [&](ASTImporter &Forward, ASTImporter &Reverse,
243  Source<const DeclContext *> SourceDC) -> bool {
244  auto *SourceInterface = const_cast<ObjCInterfaceDecl *>(
245  cast<ObjCInterfaceDecl>(SourceDC.get()));
246  if (SourceInterface->hasExternalLexicalStorage())
247  SourceInterface->getASTContext().getExternalSource()->CompleteType(
248  SourceInterface);
249  if (!SourceInterface->getDefinition())
250  return false;
251  Forward.Imported(SourceInterface, Interface);
252  Forward.ImportDefinition(SourceInterface);
253  return true;
254  });
255 }
256 
258  assert(Interface->hasExternalLexicalStorage() ||
259  Interface->hasExternalVisibleStorage());
260  bool FoundMatchingDC = false;
261  ForEachMatchingDC(Interface,
262  [&](ASTImporter &Forward, ASTImporter &Reverse,
263  Source<const DeclContext *> SourceDC) -> bool {
264  FoundMatchingDC = true;
265  return true;
266  });
267  return FoundMatchingDC;
268 }
269 
270 namespace {
271 bool IsSameDC(const DeclContext *D1, const DeclContext *D2) {
272  if (isa<ObjCContainerDecl>(D1) && isa<ObjCContainerDecl>(D2))
273  return true; // There are many cases where Objective-C is ambiguous.
274  if (auto *T1 = dyn_cast<TagDecl>(D1))
275  if (auto *T2 = dyn_cast<TagDecl>(D2))
276  if (T1->getFirstDecl() == T2->getFirstDecl())
277  return true;
278  return D1 == D2 || D1 == CanonicalizeDC(D2);
279 }
280 }
281 
283  DCOrigin Origin) {
284  LazyASTImporter &Importer = LazyImporterForOrigin(*this, *Origin.AST);
285  ASTImporter &Reverse = Importer.GetReverse();
286  Source<const DeclContext *> FoundFromDC =
287  LookupSameContext(Origin.AST->getTranslationUnitDecl(), ToDC, Reverse);
288  const bool DoRecord = !FoundFromDC || !IsSameDC(FoundFromDC.get(), Origin.DC);
289  if (DoRecord)
290  RecordOriginImpl(ToDC, Origin, Importer);
291  if (LoggingEnabled())
292  logs() << "(ExternalASTMerger*)" << (void*)this
293  << (DoRecord ? " decided " : " decided NOT")
294  << " to record origin (DeclContext*)" << (void*)Origin.DC
295  << ", (ASTContext*)" << (void*)&Origin.AST
296  << "\n";
297 }
298 
300  DCOrigin Origin) {
301  RecordOriginImpl(ToDC, Origin, ImporterForOrigin(*Origin.AST));
302 }
303 
304 void ExternalASTMerger::RecordOriginImpl(const DeclContext *ToDC, DCOrigin Origin,
305  ASTImporter &Importer) {
306  Origins[ToDC] = Origin;
307  Importer.ASTImporter::Imported(cast<Decl>(Origin.DC), const_cast<Decl*>(cast<Decl>(ToDC)));
308 }
309 
311  llvm::ArrayRef<ImporterSource> Sources) : LogStream(&llvm::nulls()), Target(Target) {
312  AddSources(Sources);
313 }
314 
316  for (const ImporterSource &S : Sources) {
317  assert(&S.AST != &Target.AST);
318  Importers.push_back(llvm::make_unique<LazyASTImporter>(
319  *this, Target.AST, Target.FM, S.AST, S.FM, S.OM));
320  }
321 }
322 
324  if (LoggingEnabled())
325  for (const ImporterSource &S : Sources)
326  logs() << "(ExternalASTMerger*)" << (void*)this
327  << " removing source (ASTContext*)" << (void*)&S.AST
328  << "\n";
329  Importers.erase(
330  std::remove_if(Importers.begin(), Importers.end(),
331  [&Sources](std::unique_ptr<ASTImporter> &Importer) -> bool {
332  for (const ImporterSource &S : Sources) {
333  if (&Importer->getFromContext() == &S.AST)
334  return true;
335  }
336  return false;
337  }),
338  Importers.end());
339  for (OriginMap::iterator OI = Origins.begin(), OE = Origins.end(); OI != OE; ) {
340  std::pair<const DeclContext *, DCOrigin> Origin = *OI;
341  bool Erase = false;
342  for (const ImporterSource &S : Sources) {
343  if (&S.AST == Origin.second.AST) {
344  Erase = true;
345  break;
346  }
347  }
348  if (Erase)
349  OI = Origins.erase(OI);
350  else
351  ++OI;
352  }
353 }
354 
355 template <typename DeclTy>
356 static bool importSpecializations(DeclTy *D, ASTImporter *Importer) {
357  for (auto *Spec : D->specializations())
358  if (!Importer->Import(Spec))
359  return true;
360  return false;
361 }
362 
363 /// Imports specializations from template declarations that can be specialized.
364 static bool importSpecializationsIfNeeded(Decl *D, ASTImporter *Importer) {
365  if (!isa<TemplateDecl>(D))
366  return false;
367  if (auto *FunctionTD = dyn_cast<FunctionTemplateDecl>(D))
368  return importSpecializations(FunctionTD, Importer);
369  else if (auto *ClassTD = dyn_cast<ClassTemplateDecl>(D))
370  return importSpecializations(ClassTD, Importer);
371  else if (auto *VarTD = dyn_cast<VarTemplateDecl>(D))
372  return importSpecializations(VarTD, Importer);
373  return false;
374 }
375 
377  DeclarationName Name) {
380 
381  auto FilterFoundDecl = [&Candidates](const Candidate &C) {
382  if (!HasDeclOfSameType(Candidates, C))
383  Candidates.push_back(C);
384  };
385 
386  ForEachMatchingDC(DC, [&](ASTImporter &Forward, ASTImporter &Reverse,
387  Source<const DeclContext *> SourceDC) -> bool {
388  DeclarationName FromName = Reverse.Import(Name);
389  DeclContextLookupResult Result = SourceDC.get()->lookup(FromName);
390  for (NamedDecl *FromD : Result) {
391  FilterFoundDecl(std::make_pair(FromD, &Forward));
392  }
393  return false;
394  });
395 
396  if (Candidates.empty())
397  return false;
398 
399  Decls.reserve(Candidates.size());
400  for (const Candidate &C : Candidates) {
401  Decl *LookupRes = C.first.get();
402  ASTImporter *Importer = C.second;
403  NamedDecl *ND = cast_or_null<NamedDecl>(Importer->Import(LookupRes));
404  assert(ND);
405  // If we don't import specialization, they are not available via lookup
406  // because the lookup result is imported TemplateDecl and it does not
407  // reference its specializations until they are imported explicitly.
408  bool IsSpecImportFailed =
409  importSpecializationsIfNeeded(LookupRes, Importer);
410  assert(!IsSpecImportFailed);
411  (void)IsSpecImportFailed;
412  Decls.push_back(ND);
413  }
414  SetExternalVisibleDeclsForName(DC, Name, Decls);
415  return true;
416 }
417 
419  const DeclContext *DC, llvm::function_ref<bool(Decl::Kind)> IsKindWeWant,
421  ForEachMatchingDC(DC, [&](ASTImporter &Forward, ASTImporter &Reverse,
422  Source<const DeclContext *> SourceDC) -> bool {
423  for (const Decl *SourceDecl : SourceDC.get()->decls()) {
424  if (IsKindWeWant(SourceDecl->getKind())) {
425  Decl *ImportedDecl = Forward.Import(const_cast<Decl *>(SourceDecl));
426  assert(!ImportedDecl || IsSameDC(ImportedDecl->getDeclContext(), DC));
427  (void)ImportedDecl;
428  }
429  }
430  return false;
431  });
432 }
433 
Defines the clang::ASTContext interface.
void MaybeRecordOrigin(const DeclContext *ToDC, DCOrigin Origin)
Records an origin in Origins only if name lookup would find something different or nothing at all...
Implements support for file system lookup, file system caching, and directory search management...
Definition: FileManager.h:116
DominatorTree GraphTraits specialization so the DominatorTree can be iterable by generic graph iterat...
Definition: Dominators.h:30
Decl - This represents one declaration (or definition), e.g.
Definition: DeclBase.h:86
Defines the C++ template declaration subclasses.
bool HasImporterForOrigin(ASTContext &OriginContext)
Returns true if Importers contains an ASTImporter whose source is OriginContext.
bool hasExternalVisibleStorage() const
Whether this DeclContext has external storage containing additional declarations that are visible in ...
Definition: DeclBase.h:1907
QualType Import(QualType FromT)
Import the given type from the "from" context into the "to" context.
static DeclContextLookupResult SetExternalVisibleDeclsForName(const DeclContext *DC, DeclarationName Name, ArrayRef< NamedDecl *> Decls)
Definition: DeclBase.cpp:1285
void setCompleteDefinition(bool V)
Definition: Decl.h:3206
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
Definition: ASTContext.h:150
The results of name lookup within a DeclContext.
Definition: DeclBase.h:1188
void AddSources(llvm::ArrayRef< ImporterSource > Sources)
Add a set of ASTContexts as possible origins.
The target for an ExternalASTMerger.
Represents an ObjC class declaration.
Definition: DeclObjC.h:1191
bool LoggingEnabled()
True if the log stream is not llvm::nulls();.
NodeId Parent
Definition: ASTDiff.cpp:192
A single origin for a DeclContext.
bool FindExternalVisibleDeclsByName(const DeclContext *DC, DeclarationName Name) override
Implementation of the ExternalASTSource API.
const FunctionProtoType * T
DeclContext * getDeclContext()
Definition: DeclBase.h:426
DeclContext * getParent()
getParent - Returns the containing DeclContext.
Definition: DeclBase.h:1341
The result type of a method or function.
Decl::Kind getDeclKind() const
Definition: DeclBase.h:1334
ASTImporter & ImporterForOrigin(ASTContext &OriginContext)
Returns a reference to the ASTRImporter from Importers whose origin is OriginContext.
Represents the declaration of a struct/union/class/enum.
Definition: Decl.h:3006
ASTContext & getASTContext() const LLVM_READONLY
Definition: DeclBase.cpp:376
bool hasExternalLexicalStorage() const
Whether this DeclContext has external storage containing additional declarations that are lexically i...
Definition: DeclBase.h:1897
std::map< const DeclContext *, DCOrigin > OriginMap
A source for an ExternalASTMerger.
Dataflow Directional Tag Classes.
DeclContext - This is used only as base class of specific decl types that can act as declaration cont...
Definition: DeclBase.h:1262
virtual Decl * Imported(Decl *From, Decl *To)
Note that we have imported the "from" declaration by mapping it to the (potentially-newly-created) "t...
bool CanComplete(DeclContext *DC)
Returns true if DC can be found in any source AST context.
static bool importSpecializations(DeclTy *D, ASTImporter *Importer)
DeclarationName - The name of a declaration.
void RemoveSources(llvm::ArrayRef< ImporterSource > Sources)
Remove a set of ASTContexts as possible origins.
llvm::raw_ostream & logs()
Log something if there is a logging callback installed.
Kind getKind() const
Definition: DeclBase.h:420
ExternalASTSource * getExternalSource() const
Retrieve a pointer to the external AST source associated with this AST context, if any...
Definition: ASTContext.h:1061
Imports selected nodes from one AST context into another context, merging AST nodes where appropriate...
Definition: ASTImporter.h:48
virtual void CompleteType(TagDecl *Tag)
Gives the external AST source an opportunity to complete an incomplete type.
DeclContext * getRedeclContext()
getRedeclContext - Retrieve the context in which an entity conflicts with other entities of the same ...
Definition: DeclBase.cpp:1669
void ImportDefinition(Decl *From)
Import the definition of the given declaration, including all of the declarations it contains...
void FindExternalLexicalDecls(const DeclContext *DC, llvm::function_ref< bool(Decl::Kind)> IsKindWeWant, SmallVectorImpl< Decl *> &Result) override
Implementation of the ExternalASTSource API.
Defines the C++ Decl subclasses, other than those for templates (found in DeclTemplate.h) and friends (in DeclFriend.h).
TranslationUnitDecl * getTranslationUnitDecl() const
Definition: ASTContext.h:990
void CompleteType(TagDecl *Tag) override
Implementation of the ExternalASTSource API.
ASTContext & getFromContext() const
Retrieve the context that AST nodes are being imported from.
Definition: ASTImporter.h:285
void ForceRecordOrigin(const DeclContext *ToDC, DCOrigin Origin)
Regardless of any checks, override the Origin for a DeclContext.
static bool importSpecializationsIfNeeded(Decl *D, ASTImporter *Importer)
Imports specializations from template declarations that can be specialized.
Kind
Lists the kind of concrete classes of Decl.
Definition: DeclBase.h:89
DeclContext * getPrimaryContext()
getPrimaryContext - There may be many different declarations of the same entity (including forward de...
Definition: DeclBase.cpp:1120
#define true
Definition: stdbool.h:32
This represents a decl that may have a name.
Definition: Decl.h:248
bool isTranslationUnit() const
Definition: DeclBase.h:1411
ExternalASTSource implementation that merges information from several ASTContexts.
ExternalASTMerger(const ImporterTarget &Target, llvm::ArrayRef< ImporterSource > Sources)