clang  6.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"
20 
21 using namespace clang;
22 
23 namespace {
24 
25 template <typename T> struct Source {
26  T t;
27  Source(T t) : t(t) {}
28  operator T() { return t; }
29  template <typename U = T> U &get() { return t; }
30  template <typename U = T> const U &get() const { return t; }
31  template <typename U> operator Source<U>() { return Source<U>(t); }
32 };
33 
34 typedef std::pair<Source<NamedDecl *>, ASTImporter *> Candidate;
35 
36 /// For the given DC, return the DC that is safe to perform lookups on. This is
37 /// the DC we actually want to work with most of the time.
38 const DeclContext *CanonicalizeDC(const DeclContext *DC) {
39  if (isa<LinkageSpecDecl>(DC))
40  return DC->getRedeclContext();
41  return DC;
42 }
43 
44 Source<const DeclContext *>
45 LookupSameContext(Source<TranslationUnitDecl *> SourceTU, const DeclContext *DC,
46  ASTImporter &ReverseImporter) {
47  DC = CanonicalizeDC(DC);
48  if (DC->isTranslationUnit()) {
49  return SourceTU;
50  }
51  Source<const DeclContext *> SourceParentDC =
52  LookupSameContext(SourceTU, DC->getParent(), ReverseImporter);
53  if (!SourceParentDC) {
54  // If we couldn't find the parent DC in this TranslationUnit, give up.
55  return nullptr;
56  }
57  auto *ND = cast<NamedDecl>(DC);
58  DeclarationName Name = ND->getDeclName();
59  Source<DeclarationName> SourceName = ReverseImporter.Import(Name);
60  DeclContext::lookup_result SearchResult =
61  SourceParentDC.get()->lookup(SourceName.get());
62  size_t SearchResultSize = SearchResult.size();
63  if (SearchResultSize == 0 || SearchResultSize > 1) {
64  // There are two cases here. First, we might not find the name.
65  // We might also find multiple copies, in which case we have no
66  // guarantee that the one we wanted is the one we pick. (E.g.,
67  // if we have two specializations of the same template it is
68  // very hard to determine which is the one you want.)
69  //
70  // The Origins map fixes this problem by allowing the origin to be
71  // explicitly recorded, so we trigger that recording by returning
72  // nothing (rather than a possibly-inaccurate guess) here.
73  return nullptr;
74  } else {
75  NamedDecl *SearchResultDecl = SearchResult[0];
76  if (isa<DeclContext>(SearchResultDecl) &&
77  SearchResultDecl->getKind() == DC->getDeclKind())
78  return cast<DeclContext>(SearchResultDecl)->getPrimaryContext();
79  return nullptr; // This type of lookup is unsupported
80  }
81 }
82 
83 /// A custom implementation of ASTImporter, for ExternalASTMerger's purposes.
84 ///
85 /// There are several modifications:
86 ///
87 /// - It enables lazy lookup (via the HasExternalLexicalStorage flag and a few
88 /// others), which instructs Clang to refer to ExternalASTMerger. Also, it
89 /// forces MinimalImport to true, which is necessary to make this work.
90 /// - It maintains a reverse importer for use with names. This allows lookup of
91 /// arbitrary names in the source context.
92 /// - It updates the ExternalASTMerger's origin map as needed whenever a
93 /// it sees a DeclContext.
94 class LazyASTImporter : public ASTImporter {
95 private:
97  ASTImporter Reverse;
98  const ExternalASTMerger::OriginMap &FromOrigins;
99 
100  llvm::raw_ostream &logs() { return Parent.logs(); }
101 public:
102  LazyASTImporter(ExternalASTMerger &_Parent, ASTContext &ToContext,
103  FileManager &ToFileManager, ASTContext &FromContext,
104  FileManager &FromFileManager,
105  const ExternalASTMerger::OriginMap &_FromOrigins)
106  : ASTImporter(ToContext, ToFileManager, FromContext, FromFileManager,
107  /*MinimalImport=*/true),
108  Parent(_Parent), Reverse(FromContext, FromFileManager, ToContext,
109  ToFileManager, /*MinimalImport=*/true), FromOrigins(_FromOrigins) {}
110 
111  /// Whenever a DeclContext is imported, ensure that ExternalASTSource's origin
112  /// map is kept up to date. Also set the appropriate flags.
113  Decl *Imported(Decl *From, Decl *To) override {
114  if (auto *ToDC = dyn_cast<DeclContext>(To)) {
115  const bool LoggingEnabled = Parent.LoggingEnabled();
116  if (LoggingEnabled)
117  logs() << "(ExternalASTMerger*)" << (void*)&Parent
118  << " imported (DeclContext*)" << (void*)ToDC
119  << ", (ASTContext*)" << (void*)&getToContext()
120  << " from (DeclContext*)" << (void*)llvm::cast<DeclContext>(From)
121  << ", (ASTContext*)" << (void*)&getFromContext()
122  << "\n";
123  Source<DeclContext *> FromDC(
124  cast<DeclContext>(From)->getPrimaryContext());
125  if (FromOrigins.count(FromDC) &&
126  Parent.HasImporterForOrigin(*FromOrigins.at(FromDC).AST)) {
127  if (LoggingEnabled)
128  logs() << "(ExternalASTMerger*)" << (void*)&Parent
129  << " forced origin (DeclContext*)"
130  << (void*)FromOrigins.at(FromDC).DC
131  << ", (ASTContext*)"
132  << (void*)FromOrigins.at(FromDC).AST
133  << "\n";
134  Parent.ForceRecordOrigin(ToDC, FromOrigins.at(FromDC));
135  } else {
136  if (LoggingEnabled)
137  logs() << "(ExternalASTMerger*)" << (void*)&Parent
138  << " maybe recording origin (DeclContext*)" << (void*)FromDC
139  << ", (ASTContext*)" << (void*)&getFromContext()
140  << "\n";
141  Parent.MaybeRecordOrigin(ToDC, {FromDC, &getFromContext()});
142  }
143  }
144  if (auto *ToTag = dyn_cast<TagDecl>(To)) {
145  ToTag->setHasExternalLexicalStorage();
146  ToTag->setMustBuildLookupTable();
147  assert(Parent.CanComplete(ToTag));
148  } else if (auto *ToNamespace = dyn_cast<NamespaceDecl>(To)) {
149  ToNamespace->setHasExternalVisibleStorage();
150  assert(Parent.CanComplete(ToNamespace));
151  } else if (auto *ToContainer = dyn_cast<ObjCContainerDecl>(To)) {
152  ToContainer->setHasExternalLexicalStorage();
153  ToContainer->setMustBuildLookupTable();
154  assert(Parent.CanComplete(ToContainer));
155  }
156  return ASTImporter::Imported(From, To);
157  }
158  ASTImporter &GetReverse() { return Reverse; }
159 };
160 
161 bool HasDeclOfSameType(llvm::ArrayRef<Candidate> Decls, const Candidate &C) {
162  if (isa<FunctionDecl>(C.first.get()))
163  return false;
164  return llvm::any_of(Decls, [&](const Candidate &D) {
165  return C.first.get()->getKind() == D.first.get()->getKind();
166  });
167 }
168 
169 } // end namespace
170 
172  for (const std::unique_ptr<ASTImporter> &I : Importers)
173  if (&I->getFromContext() == &OriginContext)
174  return *I;
175  llvm_unreachable("We should have an importer for this origin!");
176 }
177 
178 namespace {
179 LazyASTImporter &LazyImporterForOrigin(ExternalASTMerger &Merger,
180  ASTContext &OriginContext) {
181  return static_cast<LazyASTImporter &>(
182  Merger.ImporterForOrigin(OriginContext));
183 }
184 }
185 
187  for (const std::unique_ptr<ASTImporter> &I : Importers)
188  if (&I->getFromContext() == &OriginContext)
189  return true;
190  return false;
191 }
192 
193 template <typename CallbackType>
194 void ExternalASTMerger::ForEachMatchingDC(const DeclContext *DC,
195  CallbackType Callback) {
196  if (Origins.count(DC)) {
197  ExternalASTMerger::DCOrigin Origin = Origins[DC];
198  LazyASTImporter &Importer = LazyImporterForOrigin(*this, *Origin.AST);
199  Callback(Importer, Importer.GetReverse(), Origin.DC);
200  } else {
201  bool DidCallback = false;
202  for (const std::unique_ptr<ASTImporter> &Importer : Importers) {
203  Source<TranslationUnitDecl *> SourceTU =
204  Importer->getFromContext().getTranslationUnitDecl();
205  ASTImporter &Reverse =
206  static_cast<LazyASTImporter *>(Importer.get())->GetReverse();
207  if (auto SourceDC = LookupSameContext(SourceTU, DC, Reverse)) {
208  DidCallback = true;
209  if (Callback(*Importer, Reverse, SourceDC))
210  break;
211  }
212  }
213  if (!DidCallback && LoggingEnabled())
214  logs() << "(ExternalASTMerger*)" << (void*)this
215  << " asserting for (DeclContext*)" << (const void*)DC
216  << ", (ASTContext*)" << (void*)&Target.AST
217  << "\n";
218  assert(DidCallback && "Couldn't find a source context matching our DC");
219  }
220 }
221 
223  assert(Tag->hasExternalLexicalStorage());
224  ForEachMatchingDC(Tag, [&](ASTImporter &Forward, ASTImporter &Reverse,
225  Source<const DeclContext *> SourceDC) -> bool {
226  auto *SourceTag = const_cast<TagDecl *>(cast<TagDecl>(SourceDC.get()));
227  if (SourceTag->hasExternalLexicalStorage())
228  SourceTag->getASTContext().getExternalSource()->CompleteType(SourceTag);
229  if (!SourceTag->getDefinition())
230  return false;
231  Forward.Imported(SourceTag, Tag);
232  Forward.ImportDefinition(SourceTag);
233  Tag->setCompleteDefinition(SourceTag->isCompleteDefinition());
234  return true;
235  });
236 }
237 
239  assert(Interface->hasExternalLexicalStorage());
240  ForEachMatchingDC(
241  Interface, [&](ASTImporter &Forward, ASTImporter &Reverse,
242  Source<const DeclContext *> SourceDC) -> bool {
243  auto *SourceInterface = const_cast<ObjCInterfaceDecl *>(
244  cast<ObjCInterfaceDecl>(SourceDC.get()));
245  if (SourceInterface->hasExternalLexicalStorage())
246  SourceInterface->getASTContext().getExternalSource()->CompleteType(
247  SourceInterface);
248  if (!SourceInterface->getDefinition())
249  return false;
250  Forward.Imported(SourceInterface, Interface);
251  Forward.ImportDefinition(SourceInterface);
252  return true;
253  });
254 }
255 
257  assert(Interface->hasExternalLexicalStorage() ||
258  Interface->hasExternalVisibleStorage());
259  bool FoundMatchingDC = false;
260  ForEachMatchingDC(Interface,
261  [&](ASTImporter &Forward, ASTImporter &Reverse,
262  Source<const DeclContext *> SourceDC) -> bool {
263  FoundMatchingDC = true;
264  return true;
265  });
266  return FoundMatchingDC;
267 }
268 
269 namespace {
270 bool IsSameDC(const DeclContext *D1, const DeclContext *D2) {
271  if (isa<ObjCContainerDecl>(D1) && isa<ObjCContainerDecl>(D2))
272  return true; // There are many cases where Objective-C is ambiguous.
273  if (auto *T1 = dyn_cast<TagDecl>(D1))
274  if (auto *T2 = dyn_cast<TagDecl>(D2))
275  if (T1->getFirstDecl() == T2->getFirstDecl())
276  return true;
277  return D1 == D2 || D1 == CanonicalizeDC(D2);
278 }
279 }
280 
282  DCOrigin Origin) {
283  LazyASTImporter &Importer = LazyImporterForOrigin(*this, *Origin.AST);
284  ASTImporter &Reverse = Importer.GetReverse();
285  Source<const DeclContext *> FoundFromDC =
286  LookupSameContext(Origin.AST->getTranslationUnitDecl(), ToDC, Reverse);
287  const bool DoRecord = !FoundFromDC || !IsSameDC(FoundFromDC.get(), Origin.DC);
288  if (DoRecord)
289  RecordOriginImpl(ToDC, Origin, Importer);
290  if (LoggingEnabled())
291  logs() << "(ExternalASTMerger*)" << (void*)this
292  << (DoRecord ? " decided " : " decided NOT")
293  << " to record origin (DeclContext*)" << (void*)Origin.DC
294  << ", (ASTContext*)" << (void*)&Origin.AST
295  << "\n";
296 }
297 
299  DCOrigin Origin) {
300  RecordOriginImpl(ToDC, Origin, ImporterForOrigin(*Origin.AST));
301 }
302 
303 void ExternalASTMerger::RecordOriginImpl(const DeclContext *ToDC, DCOrigin Origin,
304  ASTImporter &Importer) {
305  Origins[ToDC] = Origin;
306  Importer.ASTImporter::Imported(cast<Decl>(Origin.DC), const_cast<Decl*>(cast<Decl>(ToDC)));
307 }
308 
310  llvm::ArrayRef<ImporterSource> Sources) : LogStream(&llvm::nulls()), Target(Target) {
311  AddSources(Sources);
312 }
313 
315  for (const ImporterSource &S : Sources) {
316  assert(&S.AST != &Target.AST);
317  Importers.push_back(llvm::make_unique<LazyASTImporter>(
318  *this, Target.AST, Target.FM, S.AST, S.FM, S.OM));
319  }
320 }
321 
323  if (LoggingEnabled())
324  for (const ImporterSource &S : Sources)
325  logs() << "(ExternalASTMerger*)" << (void*)this
326  << " removing source (ASTContext*)" << (void*)&S.AST
327  << "\n";
328  Importers.erase(
329  std::remove_if(Importers.begin(), Importers.end(),
330  [&Sources](std::unique_ptr<ASTImporter> &Importer) -> bool {
331  for (const ImporterSource &S : Sources) {
332  if (&Importer->getFromContext() == &S.AST)
333  return true;
334  }
335  return false;
336  }),
337  Importers.end());
338  for (OriginMap::iterator OI = Origins.begin(), OE = Origins.end(); OI != OE; ) {
339  std::pair<const DeclContext *, DCOrigin> Origin = *OI;
340  bool Erase = false;
341  for (const ImporterSource &S : Sources) {
342  if (&S.AST == Origin.second.AST) {
343  Erase = true;
344  break;
345  }
346  }
347  if (Erase)
348  OI = Origins.erase(OI);
349  else
350  ++OI;
351  }
352 }
353 
355  DeclarationName Name) {
358 
359  auto FilterFoundDecl = [&Candidates](const Candidate &C) {
360  if (!HasDeclOfSameType(Candidates, C))
361  Candidates.push_back(C);
362  };
363 
364  ForEachMatchingDC(DC, [&](ASTImporter &Forward, ASTImporter &Reverse,
365  Source<const DeclContext *> SourceDC) -> bool {
366  DeclarationName FromName = Reverse.Import(Name);
367  DeclContextLookupResult Result = SourceDC.get()->lookup(FromName);
368  for (NamedDecl *FromD : Result) {
369  FilterFoundDecl(std::make_pair(FromD, &Forward));
370  }
371  return false;
372  });
373 
374  if (Candidates.empty())
375  return false;
376 
377  Decls.reserve(Candidates.size());
378  for (const Candidate &C : Candidates) {
379  NamedDecl *d = cast<NamedDecl>(C.second->Import(C.first.get()));
380  assert(d);
381  Decls.push_back(d);
382  }
383  SetExternalVisibleDeclsForName(DC, Name, Decls);
384  return true;
385 }
386 
388  const DeclContext *DC, llvm::function_ref<bool(Decl::Kind)> IsKindWeWant,
390  ForEachMatchingDC(DC, [&](ASTImporter &Forward, ASTImporter &Reverse,
391  Source<const DeclContext *> SourceDC) -> bool {
392  for (const Decl *SourceDecl : SourceDC.get()->decls()) {
393  if (IsKindWeWant(SourceDecl->getKind())) {
394  Decl *ImportedDecl = Forward.Import(const_cast<Decl *>(SourceDecl));
395  assert(!ImportedDecl || IsSameDC(ImportedDecl->getDeclContext(), DC));
396  (void)ImportedDecl;
397  }
398  }
399  return false;
400  });
401 }
402 
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:26
Decl - This represents one declaration (or definition), e.g.
Definition: DeclBase.h:86
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:1895
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:1272
void setCompleteDefinition(bool V)
Definition: Decl.h:3136
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
Definition: ASTContext.h:149
The results of name lookup within a DeclContext.
Definition: DeclBase.h:1178
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:425
DeclContext * getParent()
getParent - Returns the containing DeclContext.
Definition: DeclBase.h:1331
The result type of a method or function.
Decl::Kind getDeclKind() const
Definition: DeclBase.h:1324
ASTImporter & ImporterForOrigin(ASTContext &OriginContext)
Returns a reference to the ASTRImporter from Importers whose origin is OriginContext.
TagDecl - Represents the declaration of a struct/union/class/enum.
Definition: Decl.h:2934
ASTContext & getASTContext() const LLVM_READONLY
Definition: DeclBase.cpp:365
bool hasExternalLexicalStorage() const
Whether this DeclContext has external storage containing additional declarations that are lexically i...
Definition: DeclBase.h:1885
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:1252
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.
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:419
ExternalASTSource * getExternalSource() const
Retrieve a pointer to the external AST source associated with this AST context, if any...
Definition: ASTContext.h:1048
Imports selected nodes from one AST context into another context, merging AST nodes where appropriate...
Definition: ASTImporter.h:40
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:1648
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:989
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:272
void ForceRecordOrigin(const DeclContext *ToDC, DCOrigin Origin)
Regardless of any checks, override the Origin for a DeclContext.
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:1106
#define true
Definition: stdbool.h:32
NamedDecl - This represents a decl with a name.
Definition: Decl.h:245
bool isTranslationUnit() const
Definition: DeclBase.h:1401
ExternalASTSource implementation that merges information from several ASTContexts.
ExternalASTMerger(const ImporterTarget &Target, llvm::ArrayRef< ImporterSource > Sources)