summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--clang/include/clang/AST/ExternalASTMerger.h51
-rw-r--r--clang/lib/AST/CMakeLists.txt1
-rw-r--r--clang/lib/AST/ExternalASTMerger.cpp183
-rw-r--r--clang/test/Import/forward-declared-struct/Inputs/S1.c1
-rw-r--r--clang/test/Import/forward-declared-struct/Inputs/S2.c3
-rw-r--r--clang/test/Import/forward-declared-struct/test.c5
-rw-r--r--clang/test/Import/member-in-struct/Inputs/S.c3
-rw-r--r--clang/test/Import/member-in-struct/test.c5
-rw-r--r--clang/test/Import/multiple-forward-declarations/Inputs/S1.c1
-rw-r--r--clang/test/Import/multiple-forward-declarations/Inputs/S2.c1
-rw-r--r--clang/test/Import/multiple-forward-declarations/test.c4
-rw-r--r--clang/test/Import/overloaded-function/Inputs/F1.c1
-rw-r--r--clang/test/Import/overloaded-function/Inputs/F2.c4
-rw-r--r--clang/test/Import/overloaded-function/test.c7
-rw-r--r--clang/test/Import/struct-in-namespace/Inputs/N1.cpp11
-rw-r--r--clang/test/Import/struct-in-namespace/Inputs/N2.cpp5
-rw-r--r--clang/test/Import/struct-in-namespace/Inputs/N3.cpp5
-rw-r--r--clang/test/Import/struct-in-namespace/test.cpp7
-rw-r--r--clang/test/Import/template-specialization/Inputs/T.cpp14
-rw-r--r--clang/test/Import/template-specialization/test.cpp7
-rw-r--r--clang/tools/clang-import-test/clang-import-test.cpp64
21 files changed, 331 insertions, 52 deletions
diff --git a/clang/include/clang/AST/ExternalASTMerger.h b/clang/include/clang/AST/ExternalASTMerger.h
new file mode 100644
index 00000000000..51d0c30ad23
--- /dev/null
+++ b/clang/include/clang/AST/ExternalASTMerger.h
@@ -0,0 +1,51 @@
+//===--- ExternalASTMerger.h - Merging External AST Interface ---*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file declares the ExternalASTMerger, which vends a combination of ASTs
+// from several different ASTContext/FileManager pairs
+//
+//===----------------------------------------------------------------------===//
+#ifndef LLVM_CLANG_AST_EXTERNALASTMERGER_H
+#define LLVM_CLANG_AST_EXTERNALASTMERGER_H
+
+#include "clang/AST/ASTImporter.h"
+#include "clang/AST/ExternalASTSource.h"
+
+namespace clang {
+
+class ExternalASTMerger : public ExternalASTSource {
+public:
+ struct ImporterPair {
+ std::unique_ptr<ASTImporter> Forward;
+ std::unique_ptr<ASTImporter> Reverse;
+ };
+
+private:
+ std::vector<ImporterPair> Importers;
+
+public:
+ struct ImporterEndpoint {
+ ASTContext &AST;
+ FileManager &FM;
+ };
+ ExternalASTMerger(const ImporterEndpoint &Target,
+ llvm::ArrayRef<ImporterEndpoint> Sources);
+
+ bool FindExternalVisibleDeclsByName(const DeclContext *DC,
+ DeclarationName Name) override;
+
+ void
+ FindExternalLexicalDecls(const DeclContext *DC,
+ llvm::function_ref<bool(Decl::Kind)> IsKindWeWant,
+ SmallVectorImpl<Decl *> &Result) override;
+};
+
+} // end namespace clang
+
+#endif
diff --git a/clang/lib/AST/CMakeLists.txt b/clang/lib/AST/CMakeLists.txt
index 2e98f524da8..13bf352c2f2 100644
--- a/clang/lib/AST/CMakeLists.txt
+++ b/clang/lib/AST/CMakeLists.txt
@@ -31,6 +31,7 @@ add_clang_library(clangAST
ExprConstant.cpp
ExprCXX.cpp
ExprObjC.cpp
+ ExternalASTMerger.cpp
ExternalASTSource.cpp
InheritViz.cpp
ItaniumCXXABI.cpp
diff --git a/clang/lib/AST/ExternalASTMerger.cpp b/clang/lib/AST/ExternalASTMerger.cpp
new file mode 100644
index 00000000000..1d144047bd1
--- /dev/null
+++ b/clang/lib/AST/ExternalASTMerger.cpp
@@ -0,0 +1,183 @@
+//===- ExternalASTMerger.cpp - Merging External AST Interface ---*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements the ExternalASTMerger, which vends a combination of
+// ASTs from several different ASTContext/FileManager pairs
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclObjC.h"
+#include "clang/AST/ExternalASTMerger.h"
+
+using namespace clang;
+
+namespace {
+
+template <typename T> struct Source {
+ T t;
+ Source(T &&t) : t(std::move(t)) {}
+ operator T() { return t; }
+ template <typename U = T> U &get() { return t; }
+ template <typename U = T> const U &get() const { return t; }
+ template <typename U> operator Source<U>() { return Source<U>(t); }
+};
+
+typedef std::pair<Source<NamedDecl *>, ASTImporter *> Candidate;
+
+class LazyASTImporter : public ASTImporter {
+public:
+ LazyASTImporter(ASTContext &ToContext, FileManager &ToFileManager,
+ ASTContext &FromContext, FileManager &FromFileManager)
+ : ASTImporter(ToContext, ToFileManager, FromContext, FromFileManager,
+ /*MinimalImport=*/true) {}
+ Decl *Imported(Decl *From, Decl *To) override {
+ if (auto ToTag = dyn_cast<TagDecl>(To)) {
+ ToTag->setHasExternalLexicalStorage();
+ } else if (auto ToNamespace = dyn_cast<NamespaceDecl>(To)) {
+ ToNamespace->setHasExternalVisibleStorage();
+ }
+ return ASTImporter::Imported(From, To);
+ }
+};
+
+Source<const DeclContext *>
+LookupSameContext(Source<TranslationUnitDecl *> SourceTU, const DeclContext *DC,
+ ASTImporter &ReverseImporter) {
+ if (DC->isTranslationUnit()) {
+ return SourceTU;
+ }
+ Source<const DeclContext *> SourceParentDC =
+ LookupSameContext(SourceTU, DC->getParent(), ReverseImporter);
+ if (!SourceParentDC) {
+ // If we couldn't find the parent DC in this TranslationUnit, give up.
+ return nullptr;
+ }
+ auto ND = cast<NamedDecl>(DC);
+ DeclarationName Name = ND->getDeclName();
+ Source<DeclarationName> SourceName = ReverseImporter.Import(Name);
+ DeclContext::lookup_result SearchResult =
+ SourceParentDC.get()->lookup(SourceName.get());
+ size_t SearchResultSize = SearchResult.size();
+ // Handle multiple candidates once we have a test for it.
+ // This may turn up when we import template specializations correctly.
+ assert(SearchResultSize < 2);
+ if (SearchResultSize == 0) {
+ // couldn't find the name, so we have to give up
+ return nullptr;
+ } else {
+ NamedDecl *SearchResultDecl = SearchResult[0];
+ return dyn_cast<DeclContext>(SearchResultDecl);
+ }
+}
+
+bool IsForwardDeclaration(Decl *D) {
+ assert(!isa<ObjCInterfaceDecl>(D)); // TODO handle this case
+ if (auto TD = dyn_cast<TagDecl>(D)) {
+ return !TD->isThisDeclarationADefinition();
+ } else if (auto FD = dyn_cast<FunctionDecl>(D)) {
+ return !FD->isThisDeclarationADefinition();
+ } else {
+ return false;
+ }
+}
+
+void ForEachMatchingDC(
+ const DeclContext *DC,
+ llvm::ArrayRef<ExternalASTMerger::ImporterPair> Importers,
+ std::function<void(const ExternalASTMerger::ImporterPair &IP,
+ Source<const DeclContext *> SourceDC)>
+ Callback) {
+ for (const ExternalASTMerger::ImporterPair &IP : Importers) {
+ Source<TranslationUnitDecl *> SourceTU(
+ IP.Forward->getFromContext().getTranslationUnitDecl());
+ Source<const DeclContext *> SourceDC =
+ LookupSameContext(SourceTU, DC, *IP.Reverse);
+ if (SourceDC.get()) {
+ Callback(IP, SourceDC);
+ }
+ }
+}
+
+bool HasDeclOfSameType(llvm::ArrayRef<Candidate> Decls, const Candidate &C) {
+ return std::any_of(Decls.begin(), Decls.end(), [&C](const Candidate &D) {
+ return C.first.get()->getKind() == D.first.get()->getKind();
+ });
+}
+} // end namespace
+
+ExternalASTMerger::ExternalASTMerger(const ImporterEndpoint &Target,
+ llvm::ArrayRef<ImporterEndpoint> Sources) {
+ for (const ImporterEndpoint &S : Sources) {
+ Importers.push_back(
+ {llvm::make_unique<LazyASTImporter>(Target.AST, Target.FM, S.AST, S.FM),
+ llvm::make_unique<ASTImporter>(S.AST, S.FM, Target.AST, Target.FM,
+ /*MinimalImport=*/true)});
+ }
+}
+
+bool ExternalASTMerger::FindExternalVisibleDeclsByName(const DeclContext *DC,
+ DeclarationName Name) {
+ llvm::SmallVector<NamedDecl *, 1> Decls;
+ llvm::SmallVector<Candidate, 4> CompleteDecls;
+ llvm::SmallVector<Candidate, 4> ForwardDecls;
+
+ auto FilterFoundDecl = [&CompleteDecls, &ForwardDecls](const Candidate &C) {
+ if (IsForwardDeclaration(C.first.get())) {
+ if (!HasDeclOfSameType(ForwardDecls, C)) {
+ ForwardDecls.push_back(C);
+ }
+ } else {
+ CompleteDecls.push_back(C);
+ }
+ };
+
+ ForEachMatchingDC(DC, Importers, [Name, &FilterFoundDecl](
+ const ImporterPair &IP,
+ Source<const DeclContext *> SourceDC) {
+ DeclarationName FromName = IP.Reverse->Import(Name);
+ DeclContextLookupResult Result = SourceDC.get()->lookup(FromName);
+ for (NamedDecl *FromD : Result) {
+ FilterFoundDecl(std::make_pair(FromD, IP.Forward.get()));
+ }
+ });
+
+ llvm::ArrayRef<Candidate> DeclsToReport =
+ CompleteDecls.empty() ? ForwardDecls : CompleteDecls;
+
+ if (DeclsToReport.empty()) {
+ return false;
+ }
+
+ Decls.reserve(DeclsToReport.size());
+ for (const Candidate &C : DeclsToReport) {
+ NamedDecl *d = cast<NamedDecl>(C.second->Import(C.first.get()));
+ assert(d);
+ Decls.push_back(d);
+ }
+ SetExternalVisibleDeclsForName(DC, Name, Decls);
+ return true;
+}
+
+void ExternalASTMerger::FindExternalLexicalDecls(
+ const DeclContext *DC, llvm::function_ref<bool(Decl::Kind)> IsKindWeWant,
+ SmallVectorImpl<Decl *> &Result) {
+ ForEachMatchingDC(
+ DC, Importers, [DC, IsKindWeWant](const ImporterPair &IP,
+ Source<const DeclContext *> SourceDC) {
+ for (Source<const Decl *> SourceDecl : SourceDC.get()->decls()) {
+ if (IsKindWeWant(SourceDecl.get()->getKind())) {
+ Decl *ImportedDecl =
+ IP.Forward->Import(const_cast<Decl *>(SourceDecl.get()));
+ assert(ImportedDecl->getDeclContext() == DC);
+ }
+ }
+ });
+}
diff --git a/clang/test/Import/forward-declared-struct/Inputs/S1.c b/clang/test/Import/forward-declared-struct/Inputs/S1.c
new file mode 100644
index 00000000000..28377c2760b
--- /dev/null
+++ b/clang/test/Import/forward-declared-struct/Inputs/S1.c
@@ -0,0 +1 @@
+struct S;
diff --git a/clang/test/Import/forward-declared-struct/Inputs/S2.c b/clang/test/Import/forward-declared-struct/Inputs/S2.c
new file mode 100644
index 00000000000..b0876d27df4
--- /dev/null
+++ b/clang/test/Import/forward-declared-struct/Inputs/S2.c
@@ -0,0 +1,3 @@
+struct S {
+ int a;
+};
diff --git a/clang/test/Import/forward-declared-struct/test.c b/clang/test/Import/forward-declared-struct/test.c
new file mode 100644
index 00000000000..7ccdcf9e97d
--- /dev/null
+++ b/clang/test/Import/forward-declared-struct/test.c
@@ -0,0 +1,5 @@
+// RUN: clang-import-test -import %S/Inputs/S1.c --import %S/Inputs/S2.c -expression %s
+void expr() {
+ struct S MyS;
+ MyS.a = 3;
+}
diff --git a/clang/test/Import/member-in-struct/Inputs/S.c b/clang/test/Import/member-in-struct/Inputs/S.c
new file mode 100644
index 00000000000..b0876d27df4
--- /dev/null
+++ b/clang/test/Import/member-in-struct/Inputs/S.c
@@ -0,0 +1,3 @@
+struct S {
+ int a;
+};
diff --git a/clang/test/Import/member-in-struct/test.c b/clang/test/Import/member-in-struct/test.c
new file mode 100644
index 00000000000..bde2b60d275
--- /dev/null
+++ b/clang/test/Import/member-in-struct/test.c
@@ -0,0 +1,5 @@
+// RUN: clang-import-test -import %S/Inputs/S.c -expression %s
+void expr() {
+ struct S MyS;
+ MyS.a = 3;
+}
diff --git a/clang/test/Import/multiple-forward-declarations/Inputs/S1.c b/clang/test/Import/multiple-forward-declarations/Inputs/S1.c
new file mode 100644
index 00000000000..28377c2760b
--- /dev/null
+++ b/clang/test/Import/multiple-forward-declarations/Inputs/S1.c
@@ -0,0 +1 @@
+struct S;
diff --git a/clang/test/Import/multiple-forward-declarations/Inputs/S2.c b/clang/test/Import/multiple-forward-declarations/Inputs/S2.c
new file mode 100644
index 00000000000..28377c2760b
--- /dev/null
+++ b/clang/test/Import/multiple-forward-declarations/Inputs/S2.c
@@ -0,0 +1 @@
+struct S;
diff --git a/clang/test/Import/multiple-forward-declarations/test.c b/clang/test/Import/multiple-forward-declarations/test.c
new file mode 100644
index 00000000000..fdaaaf61143
--- /dev/null
+++ b/clang/test/Import/multiple-forward-declarations/test.c
@@ -0,0 +1,4 @@
+// RUN: clang-import-test -import %S/Inputs/S1.c --import %S/Inputs/S2.c -expression %s
+void expr() {
+ struct S *MySPtr;
+}
diff --git a/clang/test/Import/overloaded-function/Inputs/F1.c b/clang/test/Import/overloaded-function/Inputs/F1.c
new file mode 100644
index 00000000000..fb548b464f2
--- /dev/null
+++ b/clang/test/Import/overloaded-function/Inputs/F1.c
@@ -0,0 +1 @@
+void f(int arg) { }
diff --git a/clang/test/Import/overloaded-function/Inputs/F2.c b/clang/test/Import/overloaded-function/Inputs/F2.c
new file mode 100644
index 00000000000..937efe54d84
--- /dev/null
+++ b/clang/test/Import/overloaded-function/Inputs/F2.c
@@ -0,0 +1,4 @@
+struct S { int a; };
+
+void f(const char *arg) { }
+void f(S arg) { }
diff --git a/clang/test/Import/overloaded-function/test.c b/clang/test/Import/overloaded-function/test.c
new file mode 100644
index 00000000000..4f7781bc8e6
--- /dev/null
+++ b/clang/test/Import/overloaded-function/test.c
@@ -0,0 +1,7 @@
+// RUN: clang-import-test -import %S/Inputs/F1.c -import %S/Inputs/F2.c -expression %s
+void expr() {
+ f(2);
+ f("world");
+ S s;
+ f(s);
+}
diff --git a/clang/test/Import/struct-in-namespace/Inputs/N1.cpp b/clang/test/Import/struct-in-namespace/Inputs/N1.cpp
new file mode 100644
index 00000000000..ddb67a51621
--- /dev/null
+++ b/clang/test/Import/struct-in-namespace/Inputs/N1.cpp
@@ -0,0 +1,11 @@
+namespace N {
+ struct S {
+ int a;
+ };
+}
+
+namespace N {
+ struct T {
+ int b;
+ };
+}
diff --git a/clang/test/Import/struct-in-namespace/Inputs/N2.cpp b/clang/test/Import/struct-in-namespace/Inputs/N2.cpp
new file mode 100644
index 00000000000..ad97d5dd52e
--- /dev/null
+++ b/clang/test/Import/struct-in-namespace/Inputs/N2.cpp
@@ -0,0 +1,5 @@
+namespace N {
+ struct U {
+ int c;
+ };
+}
diff --git a/clang/test/Import/struct-in-namespace/Inputs/N3.cpp b/clang/test/Import/struct-in-namespace/Inputs/N3.cpp
new file mode 100644
index 00000000000..e0ec4146747
--- /dev/null
+++ b/clang/test/Import/struct-in-namespace/Inputs/N3.cpp
@@ -0,0 +1,5 @@
+namespace M {
+ struct V {
+ int d;
+ };
+}
diff --git a/clang/test/Import/struct-in-namespace/test.cpp b/clang/test/Import/struct-in-namespace/test.cpp
new file mode 100644
index 00000000000..fd14d82d178
--- /dev/null
+++ b/clang/test/Import/struct-in-namespace/test.cpp
@@ -0,0 +1,7 @@
+// RUN: clang-import-test -import %S/Inputs/N1.cpp -import %S/Inputs/N2.cpp -import %S/Inputs/N3.cpp -expression %s
+void expr() {
+ N::S s;
+ N::T t;
+ N::U u;
+ int d = s.a + t.b + u.c;
+}
diff --git a/clang/test/Import/template-specialization/Inputs/T.cpp b/clang/test/Import/template-specialization/Inputs/T.cpp
new file mode 100644
index 00000000000..b31e2439efe
--- /dev/null
+++ b/clang/test/Import/template-specialization/Inputs/T.cpp
@@ -0,0 +1,14 @@
+template <typename T> struct A {
+};
+
+template <> struct A<int> {
+ struct B {
+ int f;
+ };
+};
+
+template <> struct A<bool> {
+ struct B {
+ int g;
+ };
+};
diff --git a/clang/test/Import/template-specialization/test.cpp b/clang/test/Import/template-specialization/test.cpp
new file mode 100644
index 00000000000..43996c53a77
--- /dev/null
+++ b/clang/test/Import/template-specialization/test.cpp
@@ -0,0 +1,7 @@
+// RUN: clang-import-test -import %S/Inputs/T.cpp -expression %s
+// XFAIL: *
+void expr() {
+ A<int>::B b1;
+ A<bool>::B b2;
+ b1.f + b2.g;
+}
diff --git a/clang/tools/clang-import-test/clang-import-test.cpp b/clang/tools/clang-import-test/clang-import-test.cpp
index 33190af4bf4..d7ab18478c3 100644
--- a/clang/tools/clang-import-test/clang-import-test.cpp
+++ b/clang/tools/clang-import-test/clang-import-test.cpp
@@ -9,6 +9,8 @@
#include "clang/AST/ASTContext.h"
#include "clang/AST/ASTImporter.h"
+#include "clang/AST/DeclObjC.h"
+#include "clang/AST/ExternalASTMerger.h"
#include "clang/Basic/Builtins.h"
#include "clang/Basic/IdentifierTable.h"
#include "clang/Basic/SourceLocation.h"
@@ -189,61 +191,18 @@ std::unique_ptr<CodeGenerator> BuildCodeGen(CompilerInstance &CI,
} // end namespace
namespace {
-class TestExternalASTSource : public ExternalASTSource {
-private:
- llvm::ArrayRef<std::unique_ptr<CompilerInstance>> ImportCIs;
- std::map<CompilerInstance *, std::unique_ptr<ASTImporter>> ForwardImporters;
- std::map<CompilerInstance *, std::unique_ptr<ASTImporter>> ReverseImporters;
-
-public:
- TestExternalASTSource(
- CompilerInstance &ExpressionCI,
- llvm::ArrayRef<std::unique_ptr<CompilerInstance>> ImportCIs)
- : ImportCIs(ImportCIs) {
- for (const std::unique_ptr<CompilerInstance> &ImportCI : ImportCIs) {
- ForwardImporters[ImportCI.get()] = llvm::make_unique<ASTImporter>(
- ExpressionCI.getASTContext(), ExpressionCI.getFileManager(),
- ImportCI->getASTContext(), ImportCI->getFileManager(),
- /*MinimalImport=*/true);
- ReverseImporters[ImportCI.get()] = llvm::make_unique<ASTImporter>(
- ImportCI->getASTContext(), ImportCI->getFileManager(),
- ExpressionCI.getASTContext(), ExpressionCI.getFileManager(),
- /*MinimalImport=*/true);
- }
- }
-
- bool FindExternalVisibleDeclsByName(const DeclContext *DC,
- DeclarationName Name) override {
- llvm::SmallVector<NamedDecl *, 1> Decls;
-
- if (isa<TranslationUnitDecl>(DC)) {
- for (const std::unique_ptr<CompilerInstance> &I : ImportCIs) {
- DeclarationName FromName = ReverseImporters[I.get()]->Import(Name);
- DeclContextLookupResult Result =
- I->getASTContext().getTranslationUnitDecl()->lookup(FromName);
- for (NamedDecl *FromD : Result) {
- NamedDecl *D =
- llvm::cast<NamedDecl>(ForwardImporters[I.get()]->Import(FromD));
- Decls.push_back(D);
- }
- }
- }
- if (Decls.empty()) {
- return false;
- } else {
- SetExternalVisibleDeclsForName(DC, Name, Decls);
- return true;
- }
- }
-};
-
+
void AddExternalSource(
CompilerInstance &CI,
llvm::ArrayRef<std::unique_ptr<CompilerInstance>> Imports) {
- ASTContext &AST = CI.getASTContext();
- auto ES = llvm::make_unique<TestExternalASTSource>(CI, Imports);
- AST.setExternalSource(ES.release());
- AST.getTranslationUnitDecl()->setHasExternalVisibleStorage();
+ ExternalASTMerger::ImporterEndpoint Target({CI.getASTContext(), CI.getFileManager()});
+ llvm::SmallVector<ExternalASTMerger::ImporterEndpoint, 3> Sources;
+ for (const std::unique_ptr<CompilerInstance> &CI : Imports) {
+ Sources.push_back({CI->getASTContext(), CI->getFileManager()});
+ }
+ auto ES = llvm::make_unique<ExternalASTMerger>(Target, Sources);
+ CI.getASTContext().setExternalSource(ES.release());
+ CI.getASTContext().getTranslationUnitDecl()->setHasExternalVisibleStorage();
}
llvm::Error ParseSource(const std::string &Path, CompilerInstance &CI,
@@ -292,6 +251,7 @@ Parse(const std::string &Path,
return std::move(CI);
}
}
+
} // end namespace
int main(int argc, const char **argv) {
OpenPOWER on IntegriCloud