mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
[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:
@@ -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
|
||||
|
||||
@@ -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
0
test/Inputs/empty.h
Normal file
22
test/PrintAsObjC/accessibility.swift
Normal file
22
test/PrintAsObjC/accessibility.swift
Normal 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 {}
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -29,8 +29,8 @@
|
||||
|
||||
import Foundation
|
||||
|
||||
class Dummy: NSNumber {
|
||||
func getProto() -> CustomProto? {
|
||||
public class Dummy: NSNumber {
|
||||
public func getProto() -> CustomProto? {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user