Index: test/Import/forward-declared-struct/Inputs/S1.c =================================================================== --- test/Import/forward-declared-struct/Inputs/S1.c +++ test/Import/forward-declared-struct/Inputs/S1.c @@ -0,0 +1 @@ +struct S; Index: test/Import/forward-declared-struct/Inputs/S2.c =================================================================== --- test/Import/forward-declared-struct/Inputs/S2.c +++ test/Import/forward-declared-struct/Inputs/S2.c @@ -0,0 +1,3 @@ +struct S { + int a; +}; Index: test/Import/forward-declared-struct/test.c =================================================================== --- test/Import/forward-declared-struct/test.c +++ 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; +} Index: test/Import/member-in-struct/Inputs/S.c =================================================================== --- test/Import/member-in-struct/Inputs/S.c +++ test/Import/member-in-struct/Inputs/S.c @@ -0,0 +1,3 @@ +struct S { + int a; +}; Index: test/Import/member-in-struct/test.c =================================================================== --- test/Import/member-in-struct/test.c +++ 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; +} Index: test/Import/multiple-forward-declarations/Inputs/S1.c =================================================================== --- test/Import/multiple-forward-declarations/Inputs/S1.c +++ test/Import/multiple-forward-declarations/Inputs/S1.c @@ -0,0 +1 @@ +struct S; Index: test/Import/multiple-forward-declarations/Inputs/S2.c =================================================================== --- test/Import/multiple-forward-declarations/Inputs/S2.c +++ test/Import/multiple-forward-declarations/Inputs/S2.c @@ -0,0 +1 @@ +struct S; Index: test/Import/multiple-forward-declarations/test.c =================================================================== --- test/Import/multiple-forward-declarations/test.c +++ 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; +} Index: test/Import/overloaded-function/Inputs/F1.c =================================================================== --- test/Import/overloaded-function/Inputs/F1.c +++ test/Import/overloaded-function/Inputs/F1.c @@ -0,0 +1 @@ +void f(int arg) { } \ No newline at end of file Index: test/Import/overloaded-function/Inputs/F2.c =================================================================== --- test/Import/overloaded-function/Inputs/F2.c +++ test/Import/overloaded-function/Inputs/F2.c @@ -0,0 +1,4 @@ +struct S { int a; }; + +void f(const char *arg) { } +void f(S arg) { } \ No newline at end of file Index: test/Import/overloaded-function/test.c =================================================================== --- test/Import/overloaded-function/test.c +++ 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); +} Index: test/Import/struct-in-namespace/Inputs/N1.cpp =================================================================== --- test/Import/struct-in-namespace/Inputs/N1.cpp +++ test/Import/struct-in-namespace/Inputs/N1.cpp @@ -0,0 +1,11 @@ +namespace N { + struct S { + int a; + }; +} + +namespace N { + struct T { + int b; + }; +} \ No newline at end of file Index: test/Import/struct-in-namespace/Inputs/N2.cpp =================================================================== --- test/Import/struct-in-namespace/Inputs/N2.cpp +++ test/Import/struct-in-namespace/Inputs/N2.cpp @@ -0,0 +1,5 @@ +namespace N { + struct U { + int c; + }; +} \ No newline at end of file Index: test/Import/struct-in-namespace/test.cpp =================================================================== --- test/Import/struct-in-namespace/test.cpp +++ 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 -expression %s +void expr() { + N::S s; + N::T t; + N::U u; + int d = s.a + t.b + u.c; +} Index: test/Import/template-specialization/Inputs/T.cpp =================================================================== --- test/Import/template-specialization/Inputs/T.cpp +++ test/Import/template-specialization/Inputs/T.cpp @@ -0,0 +1,14 @@ +template struct A { +}; + +template <> struct A { + struct B { + int f; + }; +}; + +template <> struct A { + struct B { + int g; + }; +}; \ No newline at end of file Index: test/Import/template-specialization/test.cpp =================================================================== --- test/Import/template-specialization/test.cpp +++ 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::B b1; + A::B b2; + b1.f + b2.g; +} Index: tools/clang-import-test/clang-import-test.cpp =================================================================== --- tools/clang-import-test/clang-import-test.cpp +++ tools/clang-import-test/clang-import-test.cpp @@ -9,6 +9,7 @@ #include "clang/AST/ASTContext.h" #include "clang/AST/ASTImporter.h" +#include "clang/AST/DeclObjC.h" #include "clang/Basic/Builtins.h" #include "clang/Basic/IdentifierTable.h" #include "clang/Basic/SourceLocation.h" @@ -189,10 +190,71 @@ } // end namespace namespace { +class TestASTImporter : public ASTImporter { +public: + TestASTImporter(ASTContext &ToContext, FileManager &ToFileManager, + ASTContext &FromContext, FileManager &FromFileManager, + bool MinimalImport) + : ASTImporter(ToContext, ToFileManager, FromContext, FromFileManager, + MinimalImport) {} + Decl *Imported(Decl *From, Decl *To) override { + if (auto ToTag = llvm::dyn_cast(To)) { + ToTag->setHasExternalLexicalStorage(); + } else if (auto ToNamespace = llvm::dyn_cast(To)) { + ToNamespace->setHasExternalVisibleStorage(); + } + return ASTImporter::Imported(From, To); + } +}; + +const DeclContext *LookupSameContext(const TranslationUnitDecl *SearchTU, + const DeclContext *SourceDC, + ASTImporter &SourceToSearchImporter) { + if (SourceDC->isTranslationUnit()) { + return SearchTU; + } + const DeclContext *SearchParentDC = + LookupSameContext(SearchTU, SourceDC->getParent(), SourceToSearchImporter); + if (!SearchParentDC) { + return nullptr; + } + if (auto SourceNamedDecl = dyn_cast(SourceDC)) { + DeclarationName SourceName = SourceNamedDecl->getDeclName(); + DeclarationName SearchName = SourceToSearchImporter.Import(SourceName); + DeclContext::lookup_result SearchResult = + SearchParentDC->lookup(SearchName); + size_t SearchResultSize = SearchResult.size(); + if (SearchResultSize == 0) { + return nullptr; // couldn't find the name, so we have to give up + } else if (SearchResultSize > 1) { + return nullptr; // unhandled case; here we need to perform overload + // resolution + } else { + NamedDecl *SearchResultDecl = SearchResult[0]; + return dyn_cast(SearchResultDecl); + } + } else { + return nullptr; // unhandled case; here we need to handle e.g. + // NamespaceDecls + } +} + +bool IsForwardDeclaration(Decl *D) { + assert(!isa(D)); // TODO handle this case + if (auto TD = dyn_cast(D)) { + return !TD->isThisDeclarationADefinition(); + } else if (auto FD = dyn_cast(D)) { + return !FD->isThisDeclarationADefinition(); + } else { + return false; + } +} + class TestExternalASTSource : public ExternalASTSource { private: llvm::ArrayRef> ImportCIs; - std::map> ForwardImporters; + std::map> + ForwardImporters; std::map> ReverseImporters; public: @@ -201,7 +263,7 @@ llvm::ArrayRef> ImportCIs) : ImportCIs(ImportCIs) { for (const std::unique_ptr &ImportCI : ImportCIs) { - ForwardImporters[ImportCI.get()] = llvm::make_unique( + ForwardImporters[ImportCI.get()] = llvm::make_unique( ExpressionCI.getASTContext(), ExpressionCI.getFileManager(), ImportCI->getASTContext(), ImportCI->getFileManager(), /*MinimalImport=*/true); @@ -212,29 +274,88 @@ } } + void ForEachMatchingDC(const DeclContext *DC, + std::function + Callback) { + for (const std::unique_ptr &I : ImportCIs) { + TranslationUnitDecl *SearchTU = + I->getASTContext().getTranslationUnitDecl(); + ASTImporter &ForwardImporter = *ForwardImporters[I.get()]; + ASTImporter &ReverseImporter = *ReverseImporters[I.get()]; + const DeclContext *SearchDC = + LookupSameContext(SearchTU, DC, ReverseImporter); + if (SearchDC) { + Callback(ForwardImporter, ReverseImporter, SearchDC); + } + } + } + bool FindExternalVisibleDeclsByName(const DeclContext *DC, DeclarationName Name) override { llvm::SmallVector Decls; - if (isa(DC)) { - for (const std::unique_ptr &I : ImportCIs) { - DeclarationName FromName = ReverseImporters[I.get()]->Import(Name); - DeclContextLookupResult Result = - I->getASTContext().getTranslationUnitDecl()->lookup(FromName); - for (NamedDecl *FromD : Result) { - NamedDecl *D = - llvm::cast(ForwardImporters[I.get()]->Import(FromD)); - Decls.push_back(D); + typedef std::pair Candidate; + + std::vector CompleteDecls; + std::vector ForwardDecls; + + auto FilterFoundDecl = [&CompleteDecls, &ForwardDecls](const Candidate &C) { + if (IsForwardDeclaration(C.first)) { + if (std::none_of(ForwardDecls.begin(), ForwardDecls.end(), + [&C](Candidate &D) { + return C.first->getKind() == D.first->getKind(); + })) { + ForwardDecls.push_back(C); } + } else { + CompleteDecls.push_back(C); } - } - if (Decls.empty()) { + }; + + ForEachMatchingDC( + DC, [Name, &FilterFoundDecl](ASTImporter &ForwardImporter, + ASTImporter &ReverseImporter, + const DeclContext *SearchDC) { + DeclarationName FromName = ReverseImporter.Import(Name); + DeclContextLookupResult Result = SearchDC->lookup(FromName); + for (NamedDecl *FromD : Result) { + FilterFoundDecl(std::make_pair(FromD, &ForwardImporter)); + } + }); + + std::vector &DeclsToReport = + CompleteDecls.empty() ? ForwardDecls : CompleteDecls; + + if (DeclsToReport.empty()) { return false; - } else { - SetExternalVisibleDeclsForName(DC, Name, Decls); - return true; } + + Decls.resize(DeclsToReport.size()); + std::transform(DeclsToReport.begin(), DeclsToReport.end(), Decls.begin(), + [](Candidate &C) { + return llvm::cast(C.second->Import(C.first)); + }); + SetExternalVisibleDeclsForName(DC, Name, Decls); + return true; } + + void + FindExternalLexicalDecls(const DeclContext *DC, + llvm::function_ref IsKindWeWant, + SmallVectorImpl &Result) override { + ForEachMatchingDC(DC, [DC, IsKindWeWant](ASTImporter &ForwardImporter, + ASTImporter &ReverseImporter, + const DeclContext *SearchDC) { + for (Decl *SearchDecl : SearchDC->decls()) { + if (IsKindWeWant(SearchDecl->getKind())) { + Decl *ImportedDecl = ForwardImporter.Import(SearchDecl); + assert(ImportedDecl->getDeclContext() == DC); + } + } + }); + } }; void AddExternalSource(