Index: include/clang/AST/ExternalASTMerger.h =================================================================== --- include/clang/AST/ExternalASTMerger.h +++ include/clang/AST/ExternalASTMerger.h @@ -21,22 +21,38 @@ class ExternalASTMerger : public ExternalASTSource { public: - struct ImporterPair { - std::unique_ptr Forward; - std::unique_ptr Reverse; + struct DCOrigin { + DeclContext *DC; + ASTContext *AST; }; + typedef std::map OriginMap; + typedef std::vector> ImporterVector; private: - std::vector Importers; + ImporterVector Importers; + OriginMap Origins; public: - struct ImporterEndpoint { + struct ImporterTarget { ASTContext &AST; FileManager &FM; }; - ExternalASTMerger(const ImporterEndpoint &Target, - llvm::ArrayRef Sources); + struct ImporterSource { + ASTContext &AST; + FileManager &FM; + const OriginMap &OM; + }; +private: + ImporterTarget Target; + +public: + ExternalASTMerger(const ImporterTarget &Target, + llvm::ArrayRef Sources); + + void AddSources(llvm::ArrayRef Sources); + void RemoveSources(llvm::ArrayRef Sources); + bool FindExternalVisibleDeclsByName(const DeclContext *DC, DeclarationName Name) override; @@ -44,6 +60,22 @@ FindExternalLexicalDecls(const DeclContext *DC, llvm::function_ref IsKindWeWant, SmallVectorImpl &Result) override; + + void CompleteType(TagDecl *Tag) override; + void CompleteType(ObjCInterfaceDecl *Interface) override; + bool CanComplete(DeclContext *DC); + + void MaybeRecordOrigin(const DeclContext *ToDC, DCOrigin Origin); + void ForceRecordOrigin(const DeclContext *ToDC, DCOrigin Origin); + const OriginMap &GetOrigins() { return Origins; } + + bool HasImporterForOrigin(ASTContext &OriginContext); + ASTImporter &ImporterForOrigin(ASTContext &OriginContext); +private: + void RecordOriginImpl(const DeclContext *ToDC, DCOrigin Origin, + ASTImporter &importer); + template + void ForEachMatchingDC(const DeclContext *DC, CallbackType Callback); }; } // end namespace clang Index: lib/AST/ExternalASTMerger.cpp =================================================================== --- lib/AST/ExternalASTMerger.cpp +++ lib/AST/ExternalASTMerger.cpp @@ -14,9 +14,17 @@ #include "clang/AST/ASTContext.h" #include "clang/AST/Decl.h" +#include "clang/AST/DeclCXX.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/ExternalASTMerger.h" +#define ENABLE_DEBUG 0 +#if ENABLE_DEBUG +#define DEBUG_PRINTF(...) fprintf(stderr, __VA_ARGS__); +#else +#define DEBUG_PRINTF(...) {} +#endif + using namespace clang; namespace { @@ -32,29 +40,16 @@ typedef std::pair, 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(To)) { - ToTag->setHasExternalLexicalStorage(); - ToTag->setMustBuildLookupTable(); - } else if (auto ToNamespace = dyn_cast(To)) { - ToNamespace->setHasExternalVisibleStorage(); - } else if (auto ToContainer = dyn_cast(To)) { - ToContainer->setHasExternalLexicalStorage(); - ToContainer->setMustBuildLookupTable(); - } - return ASTImporter::Imported(From, To); - } -}; +const DeclContext *CanonicalizeDC(const DeclContext *DC) { + if (isa(DC)) + return DC->getRedeclContext(); + return DC; +} Source LookupSameContext(Source SourceTU, const DeclContext *DC, ASTImporter &ReverseImporter) { + DC = CanonicalizeDC(DC); if (DC->isTranslationUnit()) { return SourceTU; } @@ -70,95 +65,290 @@ 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 + if (SearchResultSize == 0 || SearchResultSize > 1) { + // There are two cases here. First, we might not find the name. + // We might also find multiple copies, in which case we have no + // guarantee that the one we wanted is the one we pick. (E.g., + // if we have two specializations of the same template it is + // very hard to determine which is the one you want.) + // + // Since we have the Origins map, the most reliable solution here + // is to rely on that and give up on being able to find better + // versions elsewhere. return nullptr; } else { NamedDecl *SearchResultDecl = SearchResult[0]; - return dyn_cast(SearchResultDecl); + if (isa(SearchResultDecl) && + SearchResultDecl->getKind() == DC->getDeclKind()) + return cast(SearchResultDecl)->getPrimaryContext(); + else + return nullptr; // This type of lookup is unsupported } } -bool IsForwardDeclaration(Decl *D) { - if (auto TD = dyn_cast(D)) { - return !TD->isThisDeclarationADefinition(); - } else if (auto FD = dyn_cast(D)) { - return !FD->isThisDeclarationADefinition(); - } else if (auto OID = dyn_cast(D)) { - return OID->isThisDeclarationADefinition(); - } else { +class LazyASTImporter : public ASTImporter { +private: + ExternalASTMerger &Parent; + ASTImporter Reverse; + const ExternalASTMerger::OriginMap &FromOrigins; +public: + LazyASTImporter(ExternalASTMerger &_Parent, ASTContext &ToContext, + FileManager &ToFileManager, ASTContext &FromContext, + FileManager &FromFileManager, + const ExternalASTMerger::OriginMap &_FromOrigins) + : ASTImporter(ToContext, ToFileManager, FromContext, FromFileManager, + /*MinimalImport=*/true), + Parent(_Parent), Reverse(FromContext, FromFileManager, ToContext, + ToFileManager, /*MinimalImport=*/true), FromOrigins(_FromOrigins) {} + Decl *Imported(Decl *From, Decl *To) override { + if (auto *ToDC = dyn_cast(To)) { + DEBUG_PRINTF("(ExternalASTMerger*)%p imported (DeclContext*)%p, (ASTContext*)%p from (DeclContext*)%p, (ASTContext*)%p\n", (void*)&Parent, (void*)ToDC, (void*)&getToContext(), (void*)llvm::cast(From), (void*)&getFromContext()); + Source FromDC( + cast(From)->getPrimaryContext()); + if (FromOrigins.count(FromDC) && + Parent.HasImporterForOrigin(*FromOrigins.at(FromDC).AST)) { + DEBUG_PRINTF("(ExternalASTMerger*)%p forced origin (DeclContext*)%p, (ASTContext*)%p\n", (void*)&Parent, (void*)FromOrigins.at(FromDC).DC, (void*)FromOrigins.at(FromDC).AST); + Parent.ForceRecordOrigin(ToDC, FromOrigins.at(FromDC)); + } else { + DEBUG_PRINTF("(ExternalASTMerger*)%p maybe recording origin (DeclContext*)%p, (ASTContext*)%p\n", (void*)&Parent, (void*)FromDC, (void*)&getFromContext()); + Parent.MaybeRecordOrigin(ToDC, {FromDC, &getFromContext()}); + } + } + if (auto ToTag = dyn_cast(To)) { + ToTag->setHasExternalLexicalStorage(); + ToTag->setMustBuildLookupTable(); + assert(Parent.CanComplete(ToTag)); + } else if (auto ToNamespace = dyn_cast(To)) { + ToNamespace->setHasExternalVisibleStorage(); + assert(Parent.CanComplete(ToNamespace)); + } else if (auto ToContainer = dyn_cast(To)) { + ToContainer->setHasExternalLexicalStorage(); + ToContainer->setMustBuildLookupTable(); + assert(Parent.CanComplete(ToContainer)); + } + return ASTImporter::Imported(From, To); + } + ASTImporter &GetReverse() { return Reverse; } +}; + +bool HasDeclOfSameType(llvm::ArrayRef Decls, const Candidate &C) { + if (isa(C.first.get())) return false; + return llvm::any_of(Decls, [&](const Candidate &D) { return C.first.get()->getKind() == D.first.get()->getKind(); + }); +} + +} // end namespace + +ASTImporter &ExternalASTMerger::ImporterForOrigin(ASTContext &OriginContext) { + for (const std::unique_ptr &I : Importers) { + if (&I->getFromContext() == &OriginContext) + return *I; } + llvm_unreachable("We should have an importer for this origin!"); } +namespace { +LazyASTImporter &LazyImporterForOrigin(ExternalASTMerger &merger, + ASTContext &OriginContext) { + return static_cast( + merger.ImporterForOrigin(OriginContext)); +} +} + +bool ExternalASTMerger::HasImporterForOrigin(ASTContext &OriginContext) { + for (const std::unique_ptr &I : Importers) { + if (&I->getFromContext() == &OriginContext) + return true; + } + return false; +} + template -void ForEachMatchingDC( - const DeclContext *DC, - llvm::ArrayRef Importers, - CallbackType Callback) { - for (const ExternalASTMerger::ImporterPair &IP : Importers) { - Source SourceTU = - IP.Forward->getFromContext().getTranslationUnitDecl(); - if (auto SourceDC = LookupSameContext(SourceTU, DC, *IP.Reverse)) - Callback(IP, SourceDC); +void ExternalASTMerger::ForEachMatchingDC(const DeclContext *DC, + CallbackType Callback) { + if (Origins.count(DC)) { + ExternalASTMerger::DCOrigin Origin = Origins[DC]; + LazyASTImporter &Importer = LazyImporterForOrigin(*this, *Origin.AST); + Callback(Importer, Importer.GetReverse(), Origin.DC); + } else { + bool DidCallback = false; + for (const std::unique_ptr &Importer : Importers) { + Source SourceTU = + Importer->getFromContext().getTranslationUnitDecl(); + ASTImporter &Reverse = + static_cast(Importer.get())->GetReverse(); + if (auto SourceDC = LookupSameContext(SourceTU, DC, Reverse)) { + DidCallback = true; + if (Callback(*Importer, Reverse, SourceDC)) + break; + } + } + if (!DidCallback) + DEBUG_PRINTF("(ExternalASTMerger*)%p asserting for (DeclContext*)%p, (ASTContext*)%p\n", (void*)this, (void*)DC, (void*)&Target.AST); + assert(DidCallback && "Couldn't find a source context matching our DC"); } } -bool HasDeclOfSameType(llvm::ArrayRef Decls, const Candidate &C) { - return llvm::any_of(Decls, [&](const Candidate &D) { - return C.first.get()->getKind() == D.first.get()->getKind(); +void ExternalASTMerger::CompleteType(TagDecl *Tag) { + assert(Tag->hasExternalLexicalStorage()); + ForEachMatchingDC(Tag, [&](ASTImporter &Forward, ASTImporter &Reverse, + Source SourceDC) -> bool { + auto *SourceTag = const_cast(cast(SourceDC.get())); + if (SourceTag->hasExternalLexicalStorage()) + SourceTag->getASTContext().getExternalSource()->CompleteType(SourceTag); + if (!SourceTag->getDefinition()) + return false; + Forward.Imported(SourceTag, Tag); + Forward.ImportDefinition(SourceTag); + Tag->setCompleteDefinition(SourceTag->isCompleteDefinition()); + return true; }); } -} // end namespace -ExternalASTMerger::ExternalASTMerger(const ImporterEndpoint &Target, - llvm::ArrayRef Sources) { - for (const ImporterEndpoint &S : Sources) { - Importers.push_back( - {llvm::make_unique(Target.AST, Target.FM, S.AST, S.FM), - llvm::make_unique(S.AST, S.FM, Target.AST, Target.FM, - /*MinimalImport=*/true)}); +void ExternalASTMerger::CompleteType(ObjCInterfaceDecl *Interface) { + assert(Interface->hasExternalLexicalStorage()); + ForEachMatchingDC( + Interface, [&](ASTImporter &Forward, ASTImporter &Reverse, + Source SourceDC) -> bool { + auto *SourceInterface = const_cast( + cast(SourceDC.get())); + if (SourceInterface->hasExternalLexicalStorage()) + SourceInterface->getASTContext().getExternalSource()->CompleteType( + SourceInterface); + if (!SourceInterface->getDefinition()) + return false; + Forward.Imported(SourceInterface, Interface); + Forward.ImportDefinition(SourceInterface); + return true; + }); +} + +bool ExternalASTMerger::CanComplete(DeclContext *Interface) { + assert(Interface->hasExternalLexicalStorage() || + Interface->hasExternalVisibleStorage()); + bool FoundMatchingDC = false; + ForEachMatchingDC(Interface, + [&](ASTImporter &Forward, ASTImporter &Reverse, + Source SourceDC) -> bool { + FoundMatchingDC = true; + return true; + }); + return FoundMatchingDC; +} + +namespace { +bool IsSameDC(const DeclContext *D1, const DeclContext *D2) { + if (isa(D1) && isa(D2)) + return true; // There are many cases where Objective-C is ambiguous. + if (auto T1 = dyn_cast(D1)) + if (auto T2 = dyn_cast(D2)) + if (T1->getFirstDecl() == T2->getFirstDecl()) + return true; + return D1 == D2 || D1 == CanonicalizeDC(D2); +} +} + +void ExternalASTMerger::MaybeRecordOrigin(const DeclContext *ToDC, DCOrigin Origin) { + LazyASTImporter &Importer = LazyImporterForOrigin(*this, *Origin.AST); + ASTImporter &Reverse = Importer.GetReverse(); + Source FoundFromDC = + LookupSameContext(Origin.AST->getTranslationUnitDecl(), ToDC, Reverse); + if (!FoundFromDC || !IsSameDC(FoundFromDC.get(), Origin.DC)) { + DEBUG_PRINTF("(ExternalASTMerger*)%p decided to record origin (DeclContext*)%p, (ASTContext*)%p\n", (void*)this, (void*)Origin.DC, (void*)&Origin.AST); + RecordOriginImpl(ToDC, Origin, Importer); + } else { + DEBUG_PRINTF("(ExternalASTMerger*)%p decided NOT to record origin (DeclContext*)%p, (ASTContext*)%p\n", (void*)this, (void*)Origin.DC, (void*)&Origin.AST); } } +void ExternalASTMerger::ForceRecordOrigin(const DeclContext *ToDC, + DCOrigin Origin) { + RecordOriginImpl(ToDC, Origin, ImporterForOrigin(*Origin.AST)); +} + +void ExternalASTMerger::RecordOriginImpl(const DeclContext *ToDC, DCOrigin Origin, + ASTImporter &Importer) { + Origins[ToDC] = Origin; + Importer.ASTImporter::Imported(cast(Origin.DC), const_cast(cast(ToDC))); +} + +ExternalASTMerger::ExternalASTMerger(const ImporterTarget &Target, + llvm::ArrayRef Sources) : Target(Target) { + AddSources(Sources); +} + +void ExternalASTMerger::AddSources(llvm::ArrayRef Sources) { + for (const ImporterSource &S : Sources) { + assert(&S.AST != &Target.AST); +/* assert( + std::none_of(Importers.begin(), Importers.end(), + [&S](std::unique_ptr &Importer) -> bool { + return &Importer->getFromContext() == &S.AST; + }));*/ + Importers.push_back(llvm::make_unique( + *this, Target.AST, Target.FM, S.AST, S.FM, S.OM)); + } +} + +void ExternalASTMerger::RemoveSources(llvm::ArrayRef Sources) { +#if ENABLE_DEBUG + for (const ImporterSource &S : Sources) + DEBUG_PRINTF("(ExternalASTMerger*)%p removing source (ASTContext*)%p\n", (void*)this, (void*)&S.AST); +#endif + Importers.erase( + std::remove_if(Importers.begin(), Importers.end(), + [&Sources](std::unique_ptr &Importer) -> bool { + for (const ImporterSource &S : Sources) { + if (&Importer->getFromContext() == &S.AST) + return true; + } + return false; + }), + Importers.end()); + for (OriginMap::iterator OI = Origins.begin(), OE = Origins.end(); OI != OE; ) { + std::pair Origin = *OI; + bool Erase = false; + for (const ImporterSource &S : Sources) { + if (&S.AST == Origin.second.AST) { + Erase = true; + break; + } + } + if (Erase) { + OI = Origins.erase(OI); + } + else + ++OI; + } +} + bool ExternalASTMerger::FindExternalVisibleDeclsByName(const DeclContext *DC, DeclarationName Name) { llvm::SmallVector Decls; - llvm::SmallVector CompleteDecls; - llvm::SmallVector ForwardDecls; + llvm::SmallVector Candidates; - 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); - } + auto FilterFoundDecl = [&Candidates](const Candidate &C) { + if (!HasDeclOfSameType(Candidates, C)) + Candidates.push_back(C); }; - ForEachMatchingDC( - DC, Importers, - [&](const ImporterPair &IP, Source 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())); - } - }); + ForEachMatchingDC(DC, [&](ASTImporter &Forward, ASTImporter &Reverse, + Source SourceDC) -> bool { + DeclarationName FromName = Reverse.Import(Name); + DeclContextLookupResult Result = SourceDC.get()->lookup(FromName); + for (NamedDecl *FromD : Result) { + FilterFoundDecl(std::make_pair(FromD, &Forward)); + } + return false; + }); - llvm::ArrayRef DeclsToReport = - CompleteDecls.empty() ? ForwardDecls : CompleteDecls; - - if (DeclsToReport.empty()) { + if (Candidates.empty()) { return false; } - Decls.reserve(DeclsToReport.size()); - for (const Candidate &C : DeclsToReport) { + Decls.reserve(Candidates.size()); + for (const Candidate &C : Candidates) { NamedDecl *d = cast(C.second->Import(C.first.get())); assert(d); Decls.push_back(d); @@ -170,17 +360,15 @@ void ExternalASTMerger::FindExternalLexicalDecls( const DeclContext *DC, llvm::function_ref IsKindWeWant, SmallVectorImpl &Result) { - ForEachMatchingDC( - DC, Importers, - [&](const ImporterPair &IP, Source SourceDC) { - for (const Decl *SourceDecl : SourceDC.get()->decls()) { - if (IsKindWeWant(SourceDecl->getKind())) { - Decl *ImportedDecl = - IP.Forward->Import(const_cast(SourceDecl)); - assert(ImportedDecl->getDeclContext() == DC); - (void)ImportedDecl; - } - } - }); + ForEachMatchingDC(DC, [&](ASTImporter &Forward, ASTImporter &Reverse, + Source SourceDC) -> bool { + for (const Decl *SourceDecl : SourceDC.get()->decls()) { + if (IsKindWeWant(SourceDecl->getKind())) { + Decl *ImportedDecl = Forward.Import(const_cast(SourceDecl)); + assert(!ImportedDecl || IsSameDC(ImportedDecl->getDeclContext(), DC)); + (void)ImportedDecl; + } + } + return false; + }); } - Index: lib/Sema/SemaType.cpp =================================================================== --- lib/Sema/SemaType.cpp +++ lib/Sema/SemaType.cpp @@ -7304,11 +7304,15 @@ // Give the external AST source a chance to complete the type. if (auto *Source = Context.getExternalSource()) { - if (Tag) - Source->CompleteType(Tag->getDecl()); - else - Source->CompleteType(IFace->getDecl()); - + if (Tag) { + TagDecl *TagD = Tag->getDecl(); + if (TagD->hasExternalLexicalStorage()) + Source->CompleteType(TagD); + } else { + ObjCInterfaceDecl *IFaceD = IFace->getDecl(); + if (IFaceD->hasExternalLexicalStorage()) + Source->CompleteType(IFace->getDecl()); + } // If the external source completed the type, go through the motions // again to ensure we're allowed to use the completed type. if (!T->isIncompleteType()) Index: test/Import/extern-c-function/Inputs/F.cpp =================================================================== --- test/Import/extern-c-function/Inputs/F.cpp +++ test/Import/extern-c-function/Inputs/F.cpp @@ -1 +1,3 @@ -void f(int arg) { } +extern "C" { + void f(int arg); +} Index: test/Import/extern-c-function/test.cpp =================================================================== --- test/Import/extern-c-function/test.cpp +++ test/Import/extern-c-function/test.cpp @@ -1,7 +1,4 @@ -// RUN: clang-import-test -import %S/Inputs/F1.c -import %S/Inputs/F2.c -expression %s +// RUN: clang-import-test -import %S/Inputs/F.cpp -expression %s void expr() { f(2); - f("world"); - S s; - f(s); -} +} \ No newline at end of file Index: test/Import/forward-declared-objc-class/Inputs/S1.m =================================================================== --- test/Import/forward-declared-objc-class/Inputs/S1.m +++ test/Import/forward-declared-objc-class/Inputs/S1.m @@ -1 +1 @@ -struct S; +@class MyClass; \ No newline at end of file Index: test/Import/forward-declared-objc-class/Inputs/S2.m =================================================================== --- test/Import/forward-declared-objc-class/Inputs/S2.m +++ test/Import/forward-declared-objc-class/Inputs/S2.m @@ -1,3 +1,6 @@ -struct S { - int a; +@interface MyClass { + int j; }; ++(MyClass*)fromInteger:(int)_j; +-(int)getInteger; +@end \ No newline at end of file Index: test/Import/forward-declared-objc-class/Inputs/S3.m =================================================================== --- test/Import/forward-declared-objc-class/Inputs/S3.m +++ test/Import/forward-declared-objc-class/Inputs/S3.m @@ -1 +1 @@ -struct S; +@class MyClass; \ No newline at end of file Index: test/Import/forward-declared-objc-class/test.m =================================================================== --- test/Import/forward-declared-objc-class/test.m +++ test/Import/forward-declared-objc-class/test.m @@ -1,5 +1,6 @@ -// RUN: clang-import-test -import %S/Inputs/S1.c --import %S/Inputs/S2.c -expression %s +// RUN: clang-import-test -x objective-c++ -import %S/Inputs/S1.m --import %S/Inputs/S2.m --import %S/Inputs/S3.m -expression %s void expr() { - struct S MyS; - MyS.a = 3; + MyClass *c = [MyClass fromInteger:3]; + const int i = [c getInteger]; + const int j = c->j; } Index: test/Import/forward-declared-struct/test.c =================================================================== --- test/Import/forward-declared-struct/test.c +++ test/Import/forward-declared-struct/test.c @@ -1,4 +1,4 @@ -// RUN: clang-import-test -import %S/Inputs/S1.c --import %S/Inputs/S2.c -expression %s +// RUN: clang-import-test -import %S/Inputs/S1.c --import %S/Inputs/S2.c --import %S/Inputs/S3.c -expression %s void expr() { struct S MyS; MyS.a = 3; Index: test/Import/local-struct-use-origins/test.cpp =================================================================== --- test/Import/local-struct-use-origins/test.cpp +++ test/Import/local-struct-use-origins/test.cpp @@ -1,7 +1,6 @@ -// RUN: clang-import-test -dump-ir -import %S/Inputs/Callee.cpp -expression %s | FileCheck %s -// XFAIL: * +// RUN: clang-import-test -dump-ir -use-origins -import %S/Inputs/Callee.cpp -expression %s | FileCheck %s // CHECK: %struct.S = type { i -// CHECK: %struct.S.0 = type { i1 } +// CHECK: %struct.S.0 = type { i void foo() { return Bar().bar(3, true); Index: test/Import/local-struct/test.cpp =================================================================== --- test/Import/local-struct/test.cpp +++ test/Import/local-struct/test.cpp @@ -1,7 +1,6 @@ // RUN: clang-import-test -dump-ir -import %S/Inputs/Callee.cpp -expression %s | FileCheck %s -// XFAIL: * // CHECK: %struct.S = type { i -// CHECK: %struct.S.0 = type { i1 } +// CHECK: %struct.S.0 = type { i void foo() { return Bar().bar(3, true); Index: test/Import/objc-definitions-in-expression/test.m =================================================================== --- test/Import/objc-definitions-in-expression/test.m +++ test/Import/objc-definitions-in-expression/test.m @@ -1,5 +1,21 @@ // RUN: clang-import-test -x objective-c++ -import %S/Inputs/S.m -expression %s +@class D; + +@interface B { + int x; + int y; +} +@end + +@interface D : B { + int z; +} +-(int)n; +@end + void expr() { C *c; int i = [c m]; + D *d; + int j = [d n] + d->x; } Index: test/Import/struct-and-var/Inputs/S1.cpp =================================================================== --- test/Import/struct-and-var/Inputs/S1.cpp +++ test/Import/struct-and-var/Inputs/S1.cpp @@ -1,6 +1 @@ -class T; - -class S { - T *t; - int a; -}; +int F; Index: test/Import/struct-and-var/Inputs/S2.cpp =================================================================== --- test/Import/struct-and-var/Inputs/S2.cpp +++ test/Import/struct-and-var/Inputs/S2.cpp @@ -1,7 +1,3 @@ -class U { - int b; +struct F { + int a; }; - -class T { - U u; -}; Index: test/Import/struct-and-var/test.cpp =================================================================== --- test/Import/struct-and-var/test.cpp +++ test/Import/struct-and-var/test.cpp @@ -1,7 +1,5 @@ // RUN: clang-import-test --import %S/Inputs/S1.cpp --import %S/Inputs/S2.cpp -expression %s void expr() { - S MyS; - T MyT; - MyS.a = 3; - MyT.u.b = 2; + struct F f; + int x = f.a; } Index: test/Import/template/Inputs/T.cpp =================================================================== --- test/Import/template/Inputs/T.cpp +++ test/Import/template/Inputs/T.cpp @@ -1,14 +1,5 @@ template struct A { -}; - -template <> struct A { struct B { - int f; + T f; }; }; - -template <> struct A { - struct B { - int g; - }; -}; Index: test/Import/template/test.cpp =================================================================== --- test/Import/template/test.cpp +++ test/Import/template/test.cpp @@ -1,7 +1,4 @@ // RUN: clang-import-test -import %S/Inputs/T.cpp -expression %s -// XFAIL: * void expr() { - A::B b1; - A::B b2; - b1.f + b2.g; + A::B b; } 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 @@ -48,8 +48,12 @@ static llvm::cl::opt Direct("direct", llvm::cl::Optional, - llvm::cl::desc("Use the parsed declarations without indirection")); + llvm::cl::desc("Use the parsed declarations without indirection")); +static llvm::cl::opt + UseOrigins("use-origins", llvm::cl::Optional, + llvm::cl::desc("Use DeclContext origin information for more accurate lookups")); + static llvm::cl::list ClangArgs("Xcc", llvm::cl::ZeroOrMore, llvm::cl::desc("Argument to pass to the CompilerInvocation"), @@ -60,13 +64,11 @@ llvm::cl::desc("The language to parse (default: c++)"), llvm::cl::init("c++")); -static llvm::cl::opt -DumpAST("dump-ast", llvm::cl::init(false), - llvm::cl::desc("Dump combined AST")); +static llvm::cl::opt DumpAST("dump-ast", llvm::cl::init(false), + llvm::cl::desc("Dump combined AST")); -static llvm::cl::opt -DumpIR("dump-ir", llvm::cl::init(false), - llvm::cl::desc("Dump IR from final parse")); +static llvm::cl::opt DumpIR("dump-ir", llvm::cl::init(false), + llvm::cl::desc("Dump IR from final parse")); namespace init_convenience { class TestDiagnosticConsumer : public DiagnosticConsumer { @@ -154,8 +156,7 @@ } }; -std::unique_ptr -BuildCompilerInstance() { +std::unique_ptr BuildCompilerInstance() { auto Ins = llvm::make_unique(); auto DC = llvm::make_unique(); const bool ShouldOwnClient = true; @@ -227,29 +228,48 @@ } // end namespace namespace { - -void AddExternalSource( - CompilerInstance &CI, - llvm::ArrayRef> Imports) { - ExternalASTMerger::ImporterEndpoint Target({CI.getASTContext(), CI.getFileManager()}); - llvm::SmallVector Sources; - for (const std::unique_ptr &CI : Imports) { - Sources.push_back({CI->getASTContext(), CI->getFileManager()}); + +struct CIAndOrigins { + using OriginMap = clang::ExternalASTMerger::OriginMap; + std::unique_ptr CI; + + ASTContext &getASTContext() { return CI->getASTContext(); } + FileManager &getFileManager() { return CI->getFileManager(); } + const OriginMap &getOriginMap() { + static const OriginMap EmptyOriginMap; + if (ExternalASTSource *Source = CI->getASTContext().getExternalSource()) + return static_cast(Source)->GetOrigins(); + else + return EmptyOriginMap; } + DiagnosticConsumer &getDiagnosticClient() { + return CI->getDiagnosticClient(); + } + CompilerInstance &getCompilerInstance() { return *CI; } +}; + +void AddExternalSource(CIAndOrigins &CI, + llvm::MutableArrayRef Imports) { + ExternalASTMerger::ImporterTarget Target( + {CI.getASTContext(), CI.getFileManager()}); + llvm::SmallVector Sources; + for (CIAndOrigins &Import : Imports) { + Sources.push_back( + {Import.getASTContext(), Import.getFileManager(), Import.getOriginMap()}); + } auto ES = llvm::make_unique(Target, Sources); CI.getASTContext().setExternalSource(ES.release()); CI.getASTContext().getTranslationUnitDecl()->setHasExternalVisibleStorage(); } -std::unique_ptr BuildIndirect(std::unique_ptr &CI) { - std::unique_ptr IndirectCI = - init_convenience::BuildCompilerInstance(); +CIAndOrigins BuildIndirect(CIAndOrigins &CI) { + CIAndOrigins IndirectCI{init_convenience::BuildCompilerInstance()}; auto ST = llvm::make_unique(); auto BC = llvm::make_unique(); - std::unique_ptr AST = - init_convenience::BuildASTContext(*IndirectCI, *ST, *BC); - IndirectCI->setASTContext(AST.release()); - AddExternalSource(*IndirectCI, CI); + std::unique_ptr AST = init_convenience::BuildASTContext( + IndirectCI.getCompilerInstance(), *ST, *BC); + IndirectCI.getCompilerInstance().setASTContext(AST.release()); + AddExternalSource(IndirectCI, CI); return IndirectCI; } @@ -266,41 +286,41 @@ return llvm::Error::success(); } -llvm::Expected> -Parse(const std::string &Path, - llvm::ArrayRef> Imports, - bool ShouldDumpAST, bool ShouldDumpIR) { - std::unique_ptr CI = - init_convenience::BuildCompilerInstance(); +llvm::Expected Parse(const std::string &Path, + llvm::MutableArrayRef Imports, + bool ShouldDumpAST, bool ShouldDumpIR) { + CIAndOrigins CI{init_convenience::BuildCompilerInstance()}; auto ST = llvm::make_unique(); auto BC = llvm::make_unique(); std::unique_ptr AST = - init_convenience::BuildASTContext(*CI, *ST, *BC); - CI->setASTContext(AST.release()); + init_convenience::BuildASTContext(CI.getCompilerInstance(), *ST, *BC); + CI.getCompilerInstance().setASTContext(AST.release()); if (Imports.size()) - AddExternalSource(*CI, Imports); + AddExternalSource(CI, Imports); std::vector> ASTConsumers; auto LLVMCtx = llvm::make_unique(); - ASTConsumers.push_back(init_convenience::BuildCodeGen(*CI, *LLVMCtx)); - auto &CG = *static_cast(ASTConsumers.back().get()); + ASTConsumers.push_back( + init_convenience::BuildCodeGen(CI.getCompilerInstance(), *LLVMCtx)); + auto &CG = *static_cast(ASTConsumers.back().get()); if (ShouldDumpAST) ASTConsumers.push_back(CreateASTDumper("", true, false, false)); - CI->getDiagnosticClient().BeginSourceFile(CI->getLangOpts(), - &CI->getPreprocessor()); + CI.getDiagnosticClient().BeginSourceFile( + CI.getCompilerInstance().getLangOpts(), + &CI.getCompilerInstance().getPreprocessor()); MultiplexConsumer Consumers(std::move(ASTConsumers)); - Consumers.Initialize(CI->getASTContext()); + Consumers.Initialize(CI.getASTContext()); - if (llvm::Error PE = ParseSource(Path, *CI, Consumers)) { + if (llvm::Error PE = ParseSource(Path, CI.getCompilerInstance(), Consumers)) { return std::move(PE); } - CI->getDiagnosticClient().EndSourceFile(); + CI.getDiagnosticClient().EndSourceFile(); if (ShouldDumpIR) CG.GetModule()->print(llvm::outs(), nullptr); - if (CI->getDiagnosticClient().getNumErrors()) { + if (CI.getDiagnosticClient().getNumErrors()) { return llvm::make_error( "Errors occured while parsing the expression.", std::error_code()); } else { @@ -308,16 +328,26 @@ } } +void Forget(CIAndOrigins &CI, llvm::MutableArrayRef Imports) { + llvm::SmallVector Sources; + for (CIAndOrigins &Import : Imports) { + Sources.push_back( + {Import.getASTContext(), Import.getFileManager(), Import.getOriginMap()}); + } + ExternalASTSource *Source = CI.CI->getASTContext().getExternalSource(); + auto *Merger = static_cast(Source); + Merger->RemoveSources(Sources); +} + } // end namespace int main(int argc, const char **argv) { const bool DisableCrashReporting = true; llvm::sys::PrintStackTraceOnErrorSignal(argv[0], DisableCrashReporting); llvm::cl::ParseCommandLineOptions(argc, argv); - std::vector> ImportCIs; + std::vector ImportCIs; for (auto I : Imports) { - llvm::Expected> ImportCI = - Parse(I, {}, false, false); + llvm::Expected ImportCI = Parse(I, {}, false, false); if (auto E = ImportCI.takeError()) { llvm::errs() << llvm::toString(std::move(E)); exit(-1); @@ -325,20 +355,26 @@ ImportCIs.push_back(std::move(*ImportCI)); } } - std::vector> IndirectCIs; - if (!Direct) { + std::vector IndirectCIs; + if (!Direct || UseOrigins) { for (auto &ImportCI : ImportCIs) { - std::unique_ptr IndirectCI = BuildIndirect(ImportCI); + CIAndOrigins IndirectCI = BuildIndirect(ImportCI); IndirectCIs.push_back(std::move(IndirectCI)); } } - llvm::Expected> ExpressionCI = - Parse(Expression, Direct ? ImportCIs : IndirectCIs, DumpAST, DumpIR); + if (UseOrigins) { + for (auto &ImportCI : ImportCIs) { + IndirectCIs.push_back(std::move(ImportCI)); + } + } + llvm::Expected ExpressionCI = + Parse(Expression, (Direct && !UseOrigins) ? ImportCIs : IndirectCIs, + DumpAST, DumpIR); if (auto E = ExpressionCI.takeError()) { llvm::errs() << llvm::toString(std::move(E)); exit(-1); } else { + Forget(*ExpressionCI, (Direct && !UseOrigins) ? ImportCIs : IndirectCIs); return 0; } } -