From d02c4822046e37cf33bdb5246527a2b37d5413ba Mon Sep 17 00:00:00 2001 From: Jordan Rose Date: Thu, 25 Feb 2016 17:36:23 -0800 Subject: [PATCH] [ClangImporter] Record C declarations found in @interfaces. (including both classes and categories, and also @protocol declarations) This is a hack in that we use two different mechanisms for importing bridging header decls now: the manual output of ParseTopLevelDecl, and the callbacks of a clang::ASTConsumer. We should probably unify these, but that's a bigger change that isn't as obviously safe. Also note that we probably aren't getting this right for things included with -include, which we already don't have a good model for. This adds test cases for both the module and bridging header cases, although the former worked correctly already. rdar://problem/24806068 --- lib/ClangImporter/ClangImporter.cpp | 63 +++++++++++++++---- .../Mixed.framework/Headers/Mixed.h | 12 ++++ .../MixedSource/Inputs/mixed-target/header.h | 12 ++++ .../mixed-target-using-header.swift | 6 ++ .../mixed-target-using-module.swift | 5 ++ 5 files changed, 86 insertions(+), 12 deletions(-) diff --git a/lib/ClangImporter/ClangImporter.cpp b/lib/ClangImporter/ClangImporter.cpp index c9a0843a8b6b6..11e4291aaf051 100644 --- a/lib/ClangImporter/ClangImporter.cpp +++ b/lib/ClangImporter/ClangImporter.cpp @@ -121,6 +121,30 @@ namespace { } }; + class HeaderParsingASTConsumer : public clang::ASTConsumer { + SmallVector DeclGroups; + public: + void + HandleTopLevelDeclInObjCContainer(clang::DeclGroupRef decls) override { + DeclGroups.push_back(decls); + } + + ArrayRef getAdditionalParsedDecls() { + return DeclGroups; + } + + void reset() { + DeclGroups.clear(); + } + }; + + class ParsingAction : public clang::ASTFrontendAction { + std::unique_ptr + CreateASTConsumer(clang::CompilerInstance &CI, StringRef InFile) override { + return llvm::make_unique(); + } + }; + class StdStringMemBuffer : public llvm::MemoryBuffer { const std::string storage; const std::string name; @@ -579,7 +603,7 @@ ClangImporter::create(ASTContext &ctx, instance.setInvocation(&*invocation); // Create the associated action. - importer->Impl.Action.reset(new clang::SyntaxOnlyAction); + importer->Impl.Action.reset(new ParsingAction); auto *action = importer->Impl.Action.get(); // Execute the action. We effectively inline most of @@ -640,6 +664,9 @@ ClangImporter::create(ASTContext &ctx, for (auto path : searchPathOpts.ImportSearchPaths) importer->addSearchPath(path, /*isFramework*/false); + // FIXME: These decls are not being parsed correctly since (a) some of the + // callbacks are still being added, and (b) the logic to parse them has + // changed. clang::Parser::DeclGroupPtrTy parsed; while (!importer->Impl.Parser->ParseTopLevelDecl(parsed)) { for (auto *D : parsed.get()) { @@ -812,28 +839,40 @@ bool ClangImporter::Implementation::importHeader( /*LoadedID=*/0, /*LoadedOffset=*/0, includeLoc); + auto &consumer = + static_cast(Instance->getASTConsumer()); + consumer.reset(); pp.EnterSourceFile(bufferID, /*directoryLookup=*/nullptr, /*loc=*/{}); // Force the import to occur. pp.LookAhead(0); - SmallVector parsedNamedDecls; - clang::Parser::DeclGroupPtrTy parsed; - while (!Parser->ParseTopLevelDecl(parsed)) { - if (!parsed) continue; - - for (auto *D : parsed.get()) { - if (trackParsedSymbols) + SmallVector allParsedDecls; + auto handleParsed = [&](clang::DeclGroupRef parsed) { + if (trackParsedSymbols) { + for (auto *D : parsed) { addBridgeHeaderTopLevelDecls(D); - if (auto named = dyn_cast(D)) - parsedNamedDecls.push_back(named); + } } + + allParsedDecls.push_back(parsed); + }; + + clang::Parser::DeclGroupPtrTy parsed; + while (!Parser->ParseTopLevelDecl(parsed)) { + if (parsed) + handleParsed(parsed.get()); + for (auto additionalParsedGroup : consumer.getAdditionalParsedDecls()) + handleParsed(additionalParsedGroup); + consumer.reset(); } // We can't do this as we're parsing because we may want to resolve naming // conflicts between the things we've parsed. - for (auto *named : parsedNamedDecls) - addEntryToLookupTable(getClangSema(), BridgingHeaderLookupTable, named); + for (auto group : allParsedDecls) + for (auto *D : group) + if (auto named = dyn_cast(D)) + addEntryToLookupTable(getClangSema(), BridgingHeaderLookupTable, named); pp.EndSourceFile(); bumpGeneration(); diff --git a/test/ClangModules/MixedSource/Inputs/mixed-target/Mixed.framework/Headers/Mixed.h b/test/ClangModules/MixedSource/Inputs/mixed-target/Mixed.framework/Headers/Mixed.h index cb91a60a81d4b..8a86c05aeab4c 100644 --- a/test/ClangModules/MixedSource/Inputs/mixed-target/Mixed.framework/Headers/Mixed.h +++ b/test/ClangModules/MixedSource/Inputs/mixed-target/Mixed.framework/Headers/Mixed.h @@ -35,3 +35,15 @@ void doSomethingPartialSub(PartialSubClass *arg); - (NSObject *)unsafeOverridePartialSubParam:(NSObject *)arg; - (PartialSubClass *)unsafeOverridePartialSubReturn:(PartialSubClass *)arg; @end + +@interface WrapperInterface +typedef int NameInInterface; +@end + +@protocol WrapperProto +typedef int NameInProtocol; +@end + +@interface WrapperInterface (Category) +typedef int NameInCategory; +@end diff --git a/test/ClangModules/MixedSource/Inputs/mixed-target/header.h b/test/ClangModules/MixedSource/Inputs/mixed-target/header.h index e8664db286412..749255be07210 100644 --- a/test/ClangModules/MixedSource/Inputs/mixed-target/header.h +++ b/test/ClangModules/MixedSource/Inputs/mixed-target/header.h @@ -57,3 +57,15 @@ typedef NS_ENUM(short, AALevel) { @end @interface ConflictingName2 @end + +@interface WrapperInterface +typedef int NameInInterface; +@end + +@protocol WrapperProto +typedef int NameInProtocol; +@end + +@interface WrapperInterface (Category) +typedef int NameInCategory; +@end diff --git a/test/ClangModules/MixedSource/mixed-target-using-header.swift b/test/ClangModules/MixedSource/mixed-target-using-header.swift index de0980d346460..022ddcbdaf561 100644 --- a/test/ClangModules/MixedSource/mixed-target-using-header.swift +++ b/test/ClangModules/MixedSource/mixed-target-using-header.swift @@ -69,3 +69,9 @@ func testProtocolNamingConflict() { d = c // expected-error {{cannot assign value of type 'ConflictingName2?' to type 'ConflictingName2Protocol?'}} _ = d } + +func testDeclsNestedInObjCContainers() { + let _: NameInInterface = 0 + let _: NameInProtocol = 0 + let _: NameInCategory = 0 +} diff --git a/test/ClangModules/MixedSource/mixed-target-using-module.swift b/test/ClangModules/MixedSource/mixed-target-using-module.swift index 8c8b261a8d3c3..ae45897394537 100644 --- a/test/ClangModules/MixedSource/mixed-target-using-module.swift +++ b/test/ClangModules/MixedSource/mixed-target-using-module.swift @@ -75,3 +75,8 @@ func testProtocolWrapper(conformer: ForwardClassUser) { } testProtocolWrapper(ProtoConformer()) +func testDeclsNestedInObjCContainers() { + let _: NameInInterface = 0 + let _: NameInProtocol = 0 + let _: NameInCategory = 0 +}