[PrintAsObjC] Only include internal decls if we have a bridging header.

The upshot of this is that internal decls in an app target will be in the
generated header but internal decls in a framework target will not. This
is important since the generated header is part of a framework's public
interface. Users always have the option to add members via category to an
internal framework type they need to use from Objective-C, or to write the
@interface themselves if the entire type is missing. Only internal protocols
are left out by this.

The presence of the bridging header isn't a /perfect/ way to decide this,
but it's close enough. In an app target without a bridging header, it's
unlikely that there will be ObjC sources depending on the generated header.

Swift SVN r19763
This commit is contained in:
Jordan Rose
2014-07-09 23:58:57 +00:00
parent bb6c62d2ca
commit c90cd11aff
14 changed files with 64 additions and 31 deletions

View File

@@ -14,6 +14,7 @@
#define SWIFT_PRINTASOBJC_H
#include "swift/Basic/LLVM.h"
#include "swift/AST/Attr.h"
namespace swift {
class Module;
@@ -22,7 +23,8 @@ namespace swift {
/// header.
///
/// Returns true on error.
bool printAsObjC(raw_ostream &out, Module *M, StringRef bridgingHeader);
bool printAsObjC(raw_ostream &out, Module *M, StringRef bridgingHeader,
Accessibility minRequiredAccess);
}
#endif

View File

@@ -30,10 +30,6 @@
using namespace swift;
static bool isNonPrivateObjC(const ValueDecl *VD) {
return VD->isObjC() && VD->getAccessibility() != Accessibility::Private;
}
namespace {
class ObjCPrinter : private DeclVisitor<ObjCPrinter>,
private TypeVisitor<ObjCPrinter> {
@@ -51,19 +47,25 @@ class ObjCPrinter : private DeclVisitor<ObjCPrinter>,
SmallVector<const FunctionType *, 4> openFunctionTypes;
Accessibility minRequiredAccess;
bool protocolMembersOptional = false;
friend ASTVisitor<ObjCPrinter>;
friend TypeVisitor<ObjCPrinter>;
public:
explicit ObjCPrinter(ASTContext &context, raw_ostream &out)
: ctx(context), os(out) {}
explicit ObjCPrinter(ASTContext &context, raw_ostream &out,
Accessibility access)
: ctx(context), os(out), minRequiredAccess(access) {}
void print(const Decl *D) {
visit(const_cast<Decl *>(D));
}
bool shouldInclude(const ValueDecl *VD) {
return VD->isObjC() && VD->getAccessibility() >= minRequiredAccess;
}
private:
using ASTVisitor::visit;
@@ -75,8 +77,8 @@ private:
SmallVector<ProtocolDecl *, 4> protosToPrint;
std::copy_if(protos.begin(), protos.end(),
std::back_inserter(protosToPrint),
[](const ProtocolDecl *PD) -> bool {
if (!isNonPrivateObjC(PD))
[this](const ProtocolDecl *PD) -> bool {
if (!shouldInclude(PD))
return false;
auto knownProtocol = PD->getKnownProtocolKind();
if (!knownProtocol)
@@ -105,7 +107,7 @@ private:
void printMembers(DeclRange members) {
for (auto member : members) {
auto VD = dyn_cast<ValueDecl>(member);
if (!VD || !isNonPrivateObjC(VD))
if (!VD || !shouldInclude(VD))
continue;
if (auto FD = dyn_cast<FuncDecl>(VD))
if (FD->isAccessor())
@@ -751,8 +753,8 @@ class ModuleWriter {
StringRef bridgingHeader;
ObjCPrinter printer;
public:
ModuleWriter(Module &mod, StringRef header)
: M(mod), bridgingHeader(header), printer(M.Ctx, os) {}
ModuleWriter(Module &mod, StringRef header, Accessibility access)
: M(mod), bridgingHeader(header), printer(M.Ctx, os, access) {}
/// Returns true if we added the decl's module to the import set, false if
/// the decl is a local decl.
@@ -812,7 +814,7 @@ public:
void forwardDeclareMemberTypes(DeclRange members) {
for (auto member : members) {
auto VD = dyn_cast<ValueDecl>(member);
if (!VD || !isNonPrivateObjC(VD))
if (!VD || !printer.shouldInclude(VD))
continue;
ReferencedTypeFinder::walk(VD->getType(),
[this](ReferencedTypeFinder &finder,
@@ -849,7 +851,7 @@ public:
allRequirementsSatisfied &= require(superclass);
}
for (auto proto : CD->getProtocols())
if (isNonPrivateObjC(proto))
if (printer.shouldInclude(proto))
allRequirementsSatisfied &= require(proto);
if (!allRequirementsSatisfied)
@@ -894,7 +896,7 @@ public:
const ClassDecl *CD = ED->getExtendedType()->getClassOrBoundGenericClass();
allRequirementsSatisfied &= require(CD);
for (auto proto : ED->getProtocols())
if (isNonPrivateObjC(proto))
if (printer.shouldInclude(proto))
allRequirementsSatisfied &= require(proto);
if (!allRequirementsSatisfied)
@@ -1018,13 +1020,13 @@ public:
M.getTopLevelDecls(decls);
auto newEnd = std::remove_if(decls.begin(), decls.end(),
[] (const Decl *D) -> bool {
[this](const Decl *D) -> bool {
if (auto VD = dyn_cast<ValueDecl>(D))
return !isNonPrivateObjC(VD);
return !printer.shouldInclude(VD);
if (auto ED = dyn_cast<ExtensionDecl>(D)) {
auto baseClass = ED->getExtendedType()->getClassOrBoundGenericClass();
return !baseClass || !isNonPrivateObjC(baseClass);
return !baseClass || !printer.shouldInclude(baseClass);
}
return true;
});
@@ -1135,6 +1137,7 @@ public:
}
bool swift::printAsObjC(llvm::raw_ostream &os, Module *M,
StringRef bridgingHeader) {
return ModuleWriter(*M, bridgingHeader).writeToStream(os);
StringRef bridgingHeader,
Accessibility minRequiredAccess) {
return ModuleWriter(*M, bridgingHeader, minRequiredAccess).writeToStream(os);
}

0
test/Inputs/empty.h Normal file
View File

View File

@@ -0,0 +1,22 @@
// RUN: rm -rf %t && mkdir %t
// RUN: %swift %s -parse -emit-objc-header-path %t/accessibility.h
// RUN: FileCheck -check-prefix=CHECK -check-prefix=CHECK-PUBLIC %s < %t/accessibility.h
// RUN: %check-in-clang %t/accessibility.h
// RUN: %swift %clang-importer-sdk -module-cache-path %t/clang-module-cache %s -parse -import-objc-header %S/../Inputs/empty.h -emit-objc-header-path %t/accessibility-internal.h
// RUN: FileCheck -check-prefix=CHECK -check-prefix=CHECK-INTERNAL %s < %t/accessibility-internal.h
// RUN: %check-in-clang %t/accessibility-internal.h
// CHECK-LABEL: @interface A_Public{{$}}
// CHECK-INTERNAL-NEXT: init
// CHECK-NEXT: @end
@objc public class A_Public {}
// CHECK-PUBLIC-NOT: B_Internal
// CHECK-INTERNAL-LABEL: @interface B_Internal{{$}}
// CHECK-INTERNAL-NEXT: init
// CHECK-INTERNAL-NEXT: @end
@objc internal class B_Internal {}
// CHECK-NOT: C_Private
@objc private class C_Private {}

View File

@@ -3,7 +3,7 @@
// RUN: rm -rf %t
// RUN: mkdir %t
// RUN: %swift %clang-importer-sdk -module-cache-path %t/clang-module-cache -emit-module -o %t %s
// RUN: %swift %clang-importer-sdk -module-cache-path %t/clang-module-cache -parse-as-library %t/blocks.swiftmodule -parse -emit-objc-header-path %t/blocks.h
// RUN: %swift %clang-importer-sdk -module-cache-path %t/clang-module-cache -parse-as-library %t/blocks.swiftmodule -parse -emit-objc-header-path %t/blocks.h -import-objc-header %S/../Inputs/empty.h
// RUN: FileCheck %s < %t/blocks.h
// RUN: %check-in-clang %t/blocks.h

View File

@@ -3,7 +3,7 @@
// RUN: rm -rf %t
// RUN: mkdir %t
// RUN: %swift %clang-importer-sdk -module-cache-path %t/clang-module-cache -enable-source-import -emit-module -o %t %s
// RUN: %swift %clang-importer-sdk -module-cache-path %t/clang-module-cache -parse-as-library %t/classes.swiftmodule -parse -emit-objc-header-path %t/classes.h
// RUN: %swift %clang-importer-sdk -module-cache-path %t/clang-module-cache -parse-as-library %t/classes.swiftmodule -parse -emit-objc-header-path %t/classes.h -import-objc-header %S/../Inputs/empty.h
// RUN: FileCheck %s < %t/classes.h
// RUN: FileCheck --check-prefix=NEGATIVE %s < %t/classes.h
// RUN: %check-in-clang %t/classes.h

View File

@@ -3,7 +3,7 @@
// RUN: rm -rf %t
// RUN: mkdir %t
// RUN: %swift %clang-importer-sdk -module-cache-path %t/clang-module-cache -enable-source-import -emit-module -emit-module-path %t/comments.swiftmodule -emit-module-doc -emit-module-doc-path %t/comments.swiftdoc -module-name comments %S/../Inputs/comment_to_something_conversion.swift
// RUN: %swift %clang-importer-sdk -module-cache-path %t/clang-module-cache -parse-as-library %t/comments.swiftmodule -parse -emit-objc-header-path %t/comments.h
// RUN: %swift %clang-importer-sdk -module-cache-path %t/clang-module-cache -parse-as-library %t/comments.swiftmodule -parse -emit-objc-header-path %t/comments.h -import-objc-header %S/../Inputs/empty.h
// RUN: sed -n -e '/A000/,$ p' %t/comments.h > %t/comments.h-cleaned
// RUN: diff %t/comments.h-cleaned %S/Inputs/comments-expected-output.h
// RUN: %check-in-clang %t/comments.h

View File

@@ -3,7 +3,7 @@
// RUN: rm -rf %t
// RUN: mkdir %t
// RUN: %swift %clang-importer-sdk -module-cache-path %t/clang-module-cache -emit-module -o %t %s
// RUN: %swift %clang-importer-sdk -module-cache-path %t/clang-module-cache -parse-as-library %t/extensions.swiftmodule -parse -emit-objc-header-path %t/extensions.h
// RUN: %swift %clang-importer-sdk -module-cache-path %t/clang-module-cache -parse-as-library %t/extensions.swiftmodule -parse -emit-objc-header-path %t/extensions.h -import-objc-header %S/../Inputs/empty.h
// RUN: FileCheck %s < %t/extensions.h
// RUN: FileCheck --check-prefix=NEGATIVE %s < %t/extensions.h
// RUN: %check-in-clang %t/extensions.h

View File

@@ -3,7 +3,7 @@
// RUN: rm -rf %t
// RUN: mkdir %t
// RUN: %swift %clang-importer-sdk -module-cache-path %t/clang-module-cache -emit-module -o %t %s -module-name local
// RUN: %swift %clang-importer-sdk -module-cache-path %t/clang-module-cache -parse-as-library %t/local.swiftmodule -parse -emit-objc-header-path %t/local.h
// RUN: %swift %clang-importer-sdk -module-cache-path %t/clang-module-cache -parse-as-library %t/local.swiftmodule -parse -emit-objc-header-path %t/local.h -import-objc-header %S/../Inputs/empty.h
// RUN: FileCheck %s < %t/local.h
// RUN: %check-in-clang %t/local.h

View File

@@ -29,8 +29,8 @@
import Foundation
class Dummy: NSNumber {
func getProto() -> CustomProto? {
public class Dummy: NSNumber {
public func getProto() -> CustomProto? {
return nil
}
}

View File

@@ -19,8 +19,8 @@
import Foundation
class Dummy: NSNumber {
func getIntAlias() -> CIntAlias {
public class Dummy: NSNumber {
public func getIntAlias() -> CIntAlias {
let result: CInt = 0
return result
}

View File

@@ -3,7 +3,7 @@
// RUN: rm -rf %t
// RUN: mkdir %t
// RUN: %swift %clang-importer-sdk -module-cache-path %t/clang-module-cache -emit-module -o %t %s
// RUN: %swift %clang-importer-sdk -module-cache-path %t/clang-module-cache -parse-as-library %t/protocols.swiftmodule -parse -emit-objc-header-path %t/protocols.h
// RUN: %swift %clang-importer-sdk -module-cache-path %t/clang-module-cache -parse-as-library %t/protocols.swiftmodule -parse -emit-objc-header-path %t/protocols.h -import-objc-header %S/../Inputs/empty.h
// RUN: FileCheck %s < %t/protocols.h
// RUN: FileCheck --check-prefix=NEGATIVE %s < %t/protocols.h
// RUN: %check-in-clang %t/protocols.h

View File

@@ -97,7 +97,9 @@ static bool printAsObjC(const std::string &path, Module *M,
return true;
}
return printAsObjC(out, M, bridgingHeader);
auto requiredAccess = bridgingHeader.empty() ? Accessibility::Public
: Accessibility::Internal;
return printAsObjC(out, M, bridgingHeader, requiredAccess);
}
/// Performs the compile requested by the user.

View File

@@ -12,6 +12,10 @@ Latest
The general principle is that an entity cannot be defined in terms of another
entity with less accessibility.
Along with this, the generated header for a framework will only include
public declarations. Generated headers for applications will include public
and internal declarations.
* CGFloat is now a distinct floating-point type that wraps either a
Float (on 32-bit architectures) or a Double (on 64-bit
architectures). It provides all of the same comparison and