ExternalASTMerger.cpp revision 321369
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/DeclObjC.h"
18#include "clang/AST/ExternalASTMerger.h"
19
20using namespace clang;
21
22namespace {
23
24template <typename T> struct Source {
25  T t;
26  Source(T t) : t(t) {}
27  operator T() { return t; }
28  template <typename U = T> U &get() { return t; }
29  template <typename U = T> const U &get() const { return t; }
30  template <typename U> operator Source<U>() { return Source<U>(t); }
31};
32
33typedef std::pair<Source<NamedDecl *>, ASTImporter *> Candidate;
34
35class LazyASTImporter : public ASTImporter {
36public:
37  LazyASTImporter(ASTContext &ToContext, FileManager &ToFileManager,
38                  ASTContext &FromContext, FileManager &FromFileManager)
39      : ASTImporter(ToContext, ToFileManager, FromContext, FromFileManager,
40                    /*MinimalImport=*/true) {}
41  Decl *Imported(Decl *From, Decl *To) override {
42    if (auto ToTag = dyn_cast<TagDecl>(To)) {
43      ToTag->setHasExternalLexicalStorage();
44      ToTag->setMustBuildLookupTable();
45    } else if (auto ToNamespace = dyn_cast<NamespaceDecl>(To)) {
46      ToNamespace->setHasExternalVisibleStorage();
47    }
48    return ASTImporter::Imported(From, To);
49  }
50};
51
52Source<const DeclContext *>
53LookupSameContext(Source<TranslationUnitDecl *> SourceTU, const DeclContext *DC,
54                  ASTImporter &ReverseImporter) {
55  if (DC->isTranslationUnit()) {
56    return SourceTU;
57  }
58  Source<const DeclContext *> SourceParentDC =
59      LookupSameContext(SourceTU, DC->getParent(), ReverseImporter);
60  if (!SourceParentDC) {
61    // If we couldn't find the parent DC in this TranslationUnit, give up.
62    return nullptr;
63  }
64  auto ND = cast<NamedDecl>(DC);
65  DeclarationName Name = ND->getDeclName();
66  Source<DeclarationName> SourceName = ReverseImporter.Import(Name);
67  DeclContext::lookup_result SearchResult =
68      SourceParentDC.get()->lookup(SourceName.get());
69  size_t SearchResultSize = SearchResult.size();
70  // Handle multiple candidates once we have a test for it.
71  // This may turn up when we import template specializations correctly.
72  assert(SearchResultSize < 2);
73  if (SearchResultSize == 0) {
74    // couldn't find the name, so we have to give up
75    return nullptr;
76  } else {
77    NamedDecl *SearchResultDecl = SearchResult[0];
78    return dyn_cast<DeclContext>(SearchResultDecl);
79  }
80}
81
82bool IsForwardDeclaration(Decl *D) {
83  assert(!isa<ObjCInterfaceDecl>(D)); // TODO handle this case
84  if (auto TD = dyn_cast<TagDecl>(D)) {
85    return !TD->isThisDeclarationADefinition();
86  } else if (auto FD = dyn_cast<FunctionDecl>(D)) {
87    return !FD->isThisDeclarationADefinition();
88  } else {
89    return false;
90  }
91}
92
93template <typename CallbackType>
94void ForEachMatchingDC(
95    const DeclContext *DC,
96    llvm::ArrayRef<ExternalASTMerger::ImporterPair> Importers,
97    CallbackType Callback) {
98  for (const ExternalASTMerger::ImporterPair &IP : Importers) {
99    Source<TranslationUnitDecl *> SourceTU =
100        IP.Forward->getFromContext().getTranslationUnitDecl();
101    if (auto SourceDC = LookupSameContext(SourceTU, DC, *IP.Reverse))
102      Callback(IP, SourceDC);
103  }
104}
105
106bool HasDeclOfSameType(llvm::ArrayRef<Candidate> Decls, const Candidate &C) {
107  return llvm::any_of(Decls, [&](const Candidate &D) {
108    return C.first.get()->getKind() == D.first.get()->getKind();
109  });
110}
111} // end namespace
112
113ExternalASTMerger::ExternalASTMerger(const ImporterEndpoint &Target,
114                                     llvm::ArrayRef<ImporterEndpoint> Sources) {
115  for (const ImporterEndpoint &S : Sources) {
116    Importers.push_back(
117        {llvm::make_unique<LazyASTImporter>(Target.AST, Target.FM, S.AST, S.FM),
118         llvm::make_unique<ASTImporter>(S.AST, S.FM, Target.AST, Target.FM,
119                                        /*MinimalImport=*/true)});
120  }
121}
122
123bool ExternalASTMerger::FindExternalVisibleDeclsByName(const DeclContext *DC,
124                                                       DeclarationName Name) {
125  llvm::SmallVector<NamedDecl *, 1> Decls;
126  llvm::SmallVector<Candidate, 4> CompleteDecls;
127  llvm::SmallVector<Candidate, 4> ForwardDecls;
128
129  auto FilterFoundDecl = [&CompleteDecls, &ForwardDecls](const Candidate &C) {
130    if (IsForwardDeclaration(C.first.get())) {
131      if (!HasDeclOfSameType(ForwardDecls, C)) {
132        ForwardDecls.push_back(C);
133      }
134    } else {
135      CompleteDecls.push_back(C);
136    }
137  };
138
139  ForEachMatchingDC(
140      DC, Importers,
141      [&](const ImporterPair &IP, Source<const DeclContext *> SourceDC) {
142        DeclarationName FromName = IP.Reverse->Import(Name);
143        DeclContextLookupResult Result = SourceDC.get()->lookup(FromName);
144        for (NamedDecl *FromD : Result) {
145          FilterFoundDecl(std::make_pair(FromD, IP.Forward.get()));
146        }
147      });
148
149  llvm::ArrayRef<Candidate> DeclsToReport =
150      CompleteDecls.empty() ? ForwardDecls : CompleteDecls;
151
152  if (DeclsToReport.empty()) {
153    return false;
154  }
155
156  Decls.reserve(DeclsToReport.size());
157  for (const Candidate &C : DeclsToReport) {
158    NamedDecl *d = cast<NamedDecl>(C.second->Import(C.first.get()));
159    assert(d);
160    Decls.push_back(d);
161  }
162  SetExternalVisibleDeclsForName(DC, Name, Decls);
163  return true;
164}
165
166void ExternalASTMerger::FindExternalLexicalDecls(
167    const DeclContext *DC, llvm::function_ref<bool(Decl::Kind)> IsKindWeWant,
168    SmallVectorImpl<Decl *> &Result) {
169  ForEachMatchingDC(
170      DC, Importers,
171      [&](const ImporterPair &IP, Source<const DeclContext *> SourceDC) {
172        for (const Decl *SourceDecl : SourceDC.get()->decls()) {
173          if (IsKindWeWant(SourceDecl->getKind())) {
174            Decl *ImportedDecl =
175                IP.Forward->Import(const_cast<Decl *>(SourceDecl));
176            assert(ImportedDecl->getDeclContext() == DC);
177            (void)ImportedDecl;
178          }
179        }
180      });
181}
182
183