summaryrefslogtreecommitdiffstats
path: root/clang/lib/AST/ExternalASTMerger.cpp
diff options
context:
space:
mode:
authorSean Callanan <scallanan@apple.com>2017-04-11 19:33:35 +0000
committerSean Callanan <scallanan@apple.com>2017-04-11 19:33:35 +0000
commitb7160ca466175d21a01de50894df47f7c4612e67 (patch)
tree28603dd87d598ec66586831ac76790f3dd082f2f /clang/lib/AST/ExternalASTMerger.cpp
parent20dd36a48a76bb4227e19ad5da26066db5a466fa (diff)
downloadbcm5719-llvm-b7160ca466175d21a01de50894df47f7c4612e67.tar.gz
bcm5719-llvm-b7160ca466175d21a01de50894df47f7c4612e67.zip
[clang-import-test] Lookup inside contexts
clang-import-test has until now been only able to report top-level Decls. This is clearly insufficient; we should be able to look inside structs and namespaces also. This patch adds new test cases for a variety of lookups inside existing ASTContexts, and adds the functionality necessar to make most of these testcases work. (One testcase is known to fail because of ASTImporter limitations when importing templates; I'll look into that separately.) This patch also separates the core functionality out into ExternalASTMerger, an interface that allows clients like LLDB to make use of it. clang-import-test now only has the machinery necessary to set up the tests. Differential revision: https://reviews.llvm.org/D30435 llvm-svn: 299976
Diffstat (limited to 'clang/lib/AST/ExternalASTMerger.cpp')
-rw-r--r--clang/lib/AST/ExternalASTMerger.cpp183
1 files changed, 183 insertions, 0 deletions
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);
+ }
+ }
+ });
+}
OpenPOWER on IntegriCloud