mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
[TBDGen] Add support for Objective-C Categories.
Emit Objective-C Categories for extensions that have the @objc attribute directly (or indirectly via one of its methods, subscripts, etc) attached. Also associate and emit all methods for that category into the API JSON file. This fixes rdar://94734748.
This commit is contained in:
@@ -42,12 +42,22 @@ ObjCInterfaceRecord *API::addObjCClass(StringRef name, APILinkage linkage,
|
|||||||
return interface;
|
return interface;
|
||||||
}
|
}
|
||||||
|
|
||||||
void API::addObjCMethod(ObjCInterfaceRecord *cls, StringRef name, APILoc loc,
|
ObjCCategoryRecord *API::addObjCCategory(StringRef name, APILinkage linkage,
|
||||||
|
APILoc loc, APIAccess access,
|
||||||
|
APIAvailability availability,
|
||||||
|
StringRef interface) {
|
||||||
|
auto *category = new (allocator)
|
||||||
|
ObjCCategoryRecord(name, linkage, loc, access, availability, interface);
|
||||||
|
categories.push_back(category);
|
||||||
|
return category;
|
||||||
|
}
|
||||||
|
|
||||||
|
void API::addObjCMethod(ObjCContainerRecord *record, StringRef name, APILoc loc,
|
||||||
APIAccess access, bool isInstanceMethod,
|
APIAccess access, bool isInstanceMethod,
|
||||||
bool isOptional, APIAvailability availability) {
|
bool isOptional, APIAvailability availability) {
|
||||||
auto method = new (allocator) ObjCMethodRecord(
|
auto method = new (allocator) ObjCMethodRecord(
|
||||||
name, loc, access, isInstanceMethod, isOptional, availability);
|
name, loc, access, isInstanceMethod, isOptional, availability);
|
||||||
cls->methods.push_back(method);
|
record->methods.push_back(method);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void serialize(llvm::json::OStream &OS, APIAccess access) {
|
static void serialize(llvm::json::OStream &OS, APIAccess access) {
|
||||||
@@ -151,6 +161,30 @@ static void serialize(llvm::json::OStream &OS,
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void serialize(llvm::json::OStream &OS,
|
||||||
|
const ObjCCategoryRecord &record) {
|
||||||
|
OS.object([&]() {
|
||||||
|
OS.attribute("name", record.name);
|
||||||
|
serialize(OS, record.access);
|
||||||
|
serialize(OS, record.loc);
|
||||||
|
serialize(OS, record.linkage);
|
||||||
|
serialize(OS, record.availability);
|
||||||
|
OS.attribute("interface", record.interface);
|
||||||
|
OS.attributeArray("instanceMethods", [&]() {
|
||||||
|
for (auto &method : record.methods) {
|
||||||
|
if (method->isInstanceMethod)
|
||||||
|
serialize(OS, *method);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
OS.attributeArray("classMethods", [&]() {
|
||||||
|
for (auto &method : record.methods) {
|
||||||
|
if (!method->isInstanceMethod)
|
||||||
|
serialize(OS, *method);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
void API::writeAPIJSONFile(llvm::raw_ostream &os, bool PrettyPrint) {
|
void API::writeAPIJSONFile(llvm::raw_ostream &os, bool PrettyPrint) {
|
||||||
unsigned indentSize = PrettyPrint ? 2 : 0;
|
unsigned indentSize = PrettyPrint ? 2 : 0;
|
||||||
llvm::json::OStream JSON(os, indentSize);
|
llvm::json::OStream JSON(os, indentSize);
|
||||||
@@ -167,6 +201,11 @@ void API::writeAPIJSONFile(llvm::raw_ostream &os, bool PrettyPrint) {
|
|||||||
for (const auto *i : interfaces)
|
for (const auto *i : interfaces)
|
||||||
serialize(JSON, *i);
|
serialize(JSON, *i);
|
||||||
});
|
});
|
||||||
|
JSON.attributeArray("categories", [&]() {
|
||||||
|
llvm::sort(categories, sortAPIRecords);
|
||||||
|
for (const auto *c : categories)
|
||||||
|
serialize(JSON, *c);
|
||||||
|
});
|
||||||
JSON.attribute("version", "1.0");
|
JSON.attribute("version", "1.0");
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -152,6 +152,16 @@ struct ObjCInterfaceRecord : ObjCContainerRecord {
|
|||||||
superClassName(superClassName.data(), superClassName.size()) {}
|
superClassName(superClassName.data(), superClassName.size()) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct ObjCCategoryRecord : ObjCContainerRecord {
|
||||||
|
std::string interface;
|
||||||
|
|
||||||
|
ObjCCategoryRecord(StringRef name, APILinkage linkage, APILoc loc,
|
||||||
|
APIAccess access, APIAvailability availability,
|
||||||
|
StringRef interface)
|
||||||
|
: ObjCContainerRecord(name, linkage, loc, access, availability),
|
||||||
|
interface(interface.data(), interface.size()) {}
|
||||||
|
};
|
||||||
|
|
||||||
class API {
|
class API {
|
||||||
public:
|
public:
|
||||||
API(const llvm::Triple &triple) : target(triple) {}
|
API(const llvm::Triple &triple) : target(triple) {}
|
||||||
@@ -167,11 +177,16 @@ public:
|
|||||||
APIAvailability availability,
|
APIAvailability availability,
|
||||||
StringRef superClassName);
|
StringRef superClassName);
|
||||||
|
|
||||||
void addObjCMethod(ObjCInterfaceRecord *cls, StringRef name, APILoc loc,
|
ObjCCategoryRecord *addObjCCategory(StringRef name, APILinkage linkage,
|
||||||
|
APILoc loc, APIAccess access,
|
||||||
|
APIAvailability availability,
|
||||||
|
StringRef interface);
|
||||||
|
|
||||||
|
void addObjCMethod(ObjCContainerRecord *record, StringRef name, APILoc loc,
|
||||||
APIAccess access, bool isInstanceMethod, bool isOptional,
|
APIAccess access, bool isInstanceMethod, bool isOptional,
|
||||||
APIAvailability availability);
|
APIAvailability availability);
|
||||||
|
|
||||||
void writeAPIJSONFile(llvm::raw_ostream &os, bool PrettyPrint = false);
|
void writeAPIJSONFile(raw_ostream &os, bool PrettyPrint = false);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const llvm::Triple target;
|
const llvm::Triple target;
|
||||||
@@ -179,6 +194,7 @@ private:
|
|||||||
llvm::BumpPtrAllocator allocator;
|
llvm::BumpPtrAllocator allocator;
|
||||||
std::vector<GlobalRecord*> globals;
|
std::vector<GlobalRecord*> globals;
|
||||||
std::vector<ObjCInterfaceRecord*> interfaces;
|
std::vector<ObjCInterfaceRecord*> interfaces;
|
||||||
|
std::vector<ObjCCategoryRecord *> categories;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // end namespace apigen
|
} // end namespace apigen
|
||||||
|
|||||||
@@ -747,6 +747,15 @@ void TBDGenVisitor::visitAbstractFunctionDecl(AbstractFunctionDecl *AFD) {
|
|||||||
if (AFD->hasAsync()) {
|
if (AFD->hasAsync()) {
|
||||||
addAsyncFunctionPointerSymbol(SILDeclRef(AFD));
|
addAsyncFunctionPointerSymbol(SILDeclRef(AFD));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Skip non objc compatible methods or non-public methods.
|
||||||
|
if (isa<DestructorDecl>(AFD) || !AFD->isObjC() ||
|
||||||
|
AFD->getFormalAccess() != AccessLevel::Public)
|
||||||
|
return;
|
||||||
|
if (auto *CD = dyn_cast<ClassDecl>(AFD->getDeclContext()))
|
||||||
|
recorder.addObjCMethod(CD, SILDeclRef(AFD));
|
||||||
|
else if (auto *ED = dyn_cast<ExtensionDecl>(AFD->getDeclContext()))
|
||||||
|
recorder.addObjCMethod(ED, SILDeclRef(AFD));
|
||||||
}
|
}
|
||||||
|
|
||||||
void TBDGenVisitor::visitFuncDecl(FuncDecl *FD) {
|
void TBDGenVisitor::visitFuncDecl(FuncDecl *FD) {
|
||||||
@@ -956,30 +965,9 @@ void TBDGenVisitor::visitClassDecl(ClassDecl *CD) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TBD.addMethodDescriptor(method);
|
TBD.addMethodDescriptor(method);
|
||||||
|
|
||||||
if (auto methodOrCtorOrDtor = method.getDecl()) {
|
|
||||||
// Skip non objc compatible methods or non-public methods.
|
|
||||||
if (!methodOrCtorOrDtor->isObjC() ||
|
|
||||||
methodOrCtorOrDtor->getFormalAccess() != AccessLevel::Public)
|
|
||||||
return;
|
|
||||||
|
|
||||||
// only handle FuncDecl here. Initializers are handled in
|
|
||||||
// visitConstructorDecl.
|
|
||||||
if (isa<FuncDecl>(methodOrCtorOrDtor))
|
|
||||||
recorder.addObjCMethod(CD, method);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void addMethodOverride(SILDeclRef baseRef, SILDeclRef derivedRef) {
|
void addMethodOverride(SILDeclRef baseRef, SILDeclRef derivedRef) {}
|
||||||
if (auto methodOrCtorOrDtor = derivedRef.getDecl()) {
|
|
||||||
if (!methodOrCtorOrDtor->isObjC() ||
|
|
||||||
methodOrCtorOrDtor->getFormalAccess() != AccessLevel::Public)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (isa<FuncDecl>(methodOrCtorOrDtor))
|
|
||||||
recorder.addObjCMethod(CD, derivedRef);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void addPlaceholder(MissingMemberDecl *) {}
|
void addPlaceholder(MissingMemberDecl *) {}
|
||||||
|
|
||||||
@@ -1001,10 +989,6 @@ void TBDGenVisitor::visitConstructorDecl(ConstructorDecl *CD) {
|
|||||||
addAsyncFunctionPointerSymbol(
|
addAsyncFunctionPointerSymbol(
|
||||||
SILDeclRef(CD, SILDeclRef::Kind::Initializer));
|
SILDeclRef(CD, SILDeclRef::Kind::Initializer));
|
||||||
}
|
}
|
||||||
if (auto parentClass = CD->getParent()->getSelfClassDecl()) {
|
|
||||||
if (parentClass->isObjC() || CD->isObjC())
|
|
||||||
recorder.addObjCMethod(parentClass, SILDeclRef(CD));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
visitAbstractFunctionDecl(CD);
|
visitAbstractFunctionDecl(CD);
|
||||||
@@ -1397,8 +1381,11 @@ public:
|
|||||||
addOrGetObjCInterface(decl);
|
addOrGetObjCInterface(decl);
|
||||||
}
|
}
|
||||||
|
|
||||||
void addObjCMethod(const ClassDecl *cls,
|
void addObjCCategory(const ExtensionDecl *decl) override {
|
||||||
SILDeclRef method) override {
|
addOrGetObjCCategory(decl);
|
||||||
|
}
|
||||||
|
|
||||||
|
void addObjCMethod(const GenericContext *ctx, SILDeclRef method) override {
|
||||||
SmallString<128> buffer;
|
SmallString<128> buffer;
|
||||||
StringRef name = getSelectorName(method, buffer);
|
StringRef name = getSelectorName(method, buffer);
|
||||||
apigen::APIAvailability availability;
|
apigen::APIAvailability availability;
|
||||||
@@ -1413,12 +1400,23 @@ public:
|
|||||||
access = apigen::APIAccess::Private;
|
access = apigen::APIAccess::Private;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto *clsRecord = addOrGetObjCInterface(cls);
|
apigen::ObjCContainerRecord *record = nullptr;
|
||||||
api.addObjCMethod(clsRecord, name, moduleLoc, access, isInstanceMethod,
|
if (auto *cls = dyn_cast<ClassDecl>(ctx))
|
||||||
|
record = addOrGetObjCInterface(cls);
|
||||||
|
else if (auto *ext = dyn_cast<ExtensionDecl>(ctx))
|
||||||
|
record = addOrGetObjCCategory(ext);
|
||||||
|
|
||||||
|
if (record)
|
||||||
|
api.addObjCMethod(record, name, moduleLoc, access, isInstanceMethod,
|
||||||
false, availability);
|
false, availability);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
/// Follow the naming schema that IRGen uses for Categories (see
|
||||||
|
/// ClassDataBuilder).
|
||||||
|
using CategoryNameKey = std::pair<const ClassDecl *, const ModuleDecl *>;
|
||||||
|
llvm::DenseMap<CategoryNameKey, unsigned> CategoryCounts;
|
||||||
|
|
||||||
apigen::APIAvailability getAvailability(const Decl *decl) {
|
apigen::APIAvailability getAvailability(const Decl *decl) {
|
||||||
bool unavailable = false;
|
bool unavailable = false;
|
||||||
std::string introduced, obsoleted;
|
std::string introduced, obsoleted;
|
||||||
@@ -1475,11 +1473,46 @@ private:
|
|||||||
return cls;
|
return cls;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void buildCategoryName(const ExtensionDecl *ext, const ClassDecl *cls,
|
||||||
|
SmallVectorImpl<char> &s) {
|
||||||
|
llvm::raw_svector_ostream os(s);
|
||||||
|
ModuleDecl *module = ext->getParentModule();
|
||||||
|
os << module->getName();
|
||||||
|
unsigned categoryCount = CategoryCounts[{cls, module}]++;
|
||||||
|
if (categoryCount > 0)
|
||||||
|
os << categoryCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
apigen::ObjCCategoryRecord *addOrGetObjCCategory(const ExtensionDecl *decl) {
|
||||||
|
auto entry = categoryMap.find(decl);
|
||||||
|
if (entry != categoryMap.end())
|
||||||
|
return entry->second;
|
||||||
|
|
||||||
|
SmallString<128> interfaceBuffer;
|
||||||
|
SmallString<128> nameBuffer;
|
||||||
|
ClassDecl *cls = decl->getSelfClassDecl();
|
||||||
|
auto interface = cls->getObjCRuntimeName(interfaceBuffer);
|
||||||
|
buildCategoryName(decl, cls, nameBuffer);
|
||||||
|
apigen::APIAvailability availability = getAvailability(decl);
|
||||||
|
apigen::APIAccess access =
|
||||||
|
decl->isSPI() ? apigen::APIAccess::Private : apigen::APIAccess::Public;
|
||||||
|
apigen::APILinkage linkage =
|
||||||
|
decl->getMaxAccessLevel() == AccessLevel::Public
|
||||||
|
? apigen::APILinkage::Exported
|
||||||
|
: apigen::APILinkage::Internal;
|
||||||
|
auto category = api.addObjCCategory(nameBuffer, linkage, moduleLoc, access,
|
||||||
|
availability, interface);
|
||||||
|
categoryMap.try_emplace(decl, category);
|
||||||
|
return category;
|
||||||
|
}
|
||||||
|
|
||||||
apigen::API &api;
|
apigen::API &api;
|
||||||
ModuleDecl *module;
|
ModuleDecl *module;
|
||||||
apigen::APILoc moduleLoc;
|
apigen::APILoc moduleLoc;
|
||||||
|
|
||||||
llvm::DenseMap<const ClassDecl*, apigen::ObjCInterfaceRecord*> classMap;
|
llvm::DenseMap<const ClassDecl*, apigen::ObjCInterfaceRecord*> classMap;
|
||||||
|
llvm::DenseMap<const ExtensionDecl *, apigen::ObjCCategoryRecord *>
|
||||||
|
categoryMap;
|
||||||
};
|
};
|
||||||
|
|
||||||
apigen::API APIGenRequest::evaluate(Evaluator &evaluator,
|
apigen::API APIGenRequest::evaluate(Evaluator &evaluator,
|
||||||
|
|||||||
@@ -68,7 +68,8 @@ public:
|
|||||||
virtual void addSymbol(StringRef name, llvm::MachO::SymbolKind kind,
|
virtual void addSymbol(StringRef name, llvm::MachO::SymbolKind kind,
|
||||||
SymbolSource source) {}
|
SymbolSource source) {}
|
||||||
virtual void addObjCInterface(const ClassDecl *decl) {}
|
virtual void addObjCInterface(const ClassDecl *decl) {}
|
||||||
virtual void addObjCMethod(const ClassDecl *cls, SILDeclRef method) {}
|
virtual void addObjCCategory(const ExtensionDecl *decl) {}
|
||||||
|
virtual void addObjCMethod(const GenericContext *ctx, SILDeclRef method) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
class SimpleAPIRecorder final : public APIRecorder {
|
class SimpleAPIRecorder final : public APIRecorder {
|
||||||
|
|||||||
@@ -364,12 +364,12 @@ public func myFunction2() {}
|
|||||||
// CHECK-NEXT: "super": "NSObject",
|
// CHECK-NEXT: "super": "NSObject",
|
||||||
// CHECK-NEXT: "instanceMethods": [
|
// CHECK-NEXT: "instanceMethods": [
|
||||||
// CHECK-NEXT: {
|
// CHECK-NEXT: {
|
||||||
// CHECK-NEXT: "name": "init",
|
// CHECK-NEXT: "name": "method1",
|
||||||
// CHECK-NEXT: "access": "public",
|
// CHECK-NEXT: "access": "public",
|
||||||
// CHECK-NEXT: "file": "/@input/MyModule.swiftinterface"
|
// CHECK-NEXT: "file": "/@input/MyModule.swiftinterface"
|
||||||
// CHECK-NEXT: },
|
// CHECK-NEXT: },
|
||||||
// CHECK-NEXT: {
|
// CHECK-NEXT: {
|
||||||
// CHECK-NEXT: "name": "method1",
|
// CHECK-NEXT: "name": "init",
|
||||||
// CHECK-NEXT: "access": "public",
|
// CHECK-NEXT: "access": "public",
|
||||||
// CHECK-NEXT: "file": "/@input/MyModule.swiftinterface"
|
// CHECK-NEXT: "file": "/@input/MyModule.swiftinterface"
|
||||||
// CHECK-NEXT: }
|
// CHECK-NEXT: }
|
||||||
@@ -416,12 +416,12 @@ public func myFunction2() {}
|
|||||||
// CHECK-NEXT: "super": "_TtC8MyModule4Test",
|
// CHECK-NEXT: "super": "_TtC8MyModule4Test",
|
||||||
// CHECK-NEXT: "instanceMethods": [
|
// CHECK-NEXT: "instanceMethods": [
|
||||||
// CHECK-NEXT: {
|
// CHECK-NEXT: {
|
||||||
// CHECK-NEXT: "name": "init",
|
// CHECK-NEXT: "name": "method1",
|
||||||
// CHECK-NEXT: "access": "public",
|
// CHECK-NEXT: "access": "public",
|
||||||
// CHECK-NEXT: "file": "/@input/MyModule.swiftinterface"
|
// CHECK-NEXT: "file": "/@input/MyModule.swiftinterface"
|
||||||
// CHECK-NEXT: },
|
// CHECK-NEXT: },
|
||||||
// CHECK-NEXT: {
|
// CHECK-NEXT: {
|
||||||
// CHECK-NEXT: "name": "method1",
|
// CHECK-NEXT: "name": "init",
|
||||||
// CHECK-NEXT: "access": "public",
|
// CHECK-NEXT: "access": "public",
|
||||||
// CHECK-NEXT: "file": "/@input/MyModule.swiftinterface"
|
// CHECK-NEXT: "file": "/@input/MyModule.swiftinterface"
|
||||||
// CHECK-NEXT: }
|
// CHECK-NEXT: }
|
||||||
@@ -429,4 +429,5 @@ public func myFunction2() {}
|
|||||||
// CHECK-NEXT: "classMethods": []
|
// CHECK-NEXT: "classMethods": []
|
||||||
// CHECK-NEXT: }
|
// CHECK-NEXT: }
|
||||||
// CHECK-NEXT: ],
|
// CHECK-NEXT: ],
|
||||||
|
// CHECK-NEXT: "categories": [],
|
||||||
// CHECK-NEXT: "version": "1.0"
|
// CHECK-NEXT: "version": "1.0"
|
||||||
|
|||||||
108
test/APIJSON/extension.swift
Normal file
108
test/APIJSON/extension.swift
Normal file
@@ -0,0 +1,108 @@
|
|||||||
|
// REQUIRES: objc_interop, OS=macosx
|
||||||
|
// RUN: %empty-directory(%t)
|
||||||
|
// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk-nosource -I %t) %s -typecheck -emit-module-interface-path %t/MyModule.swiftinterface -enable-library-evolution -module-name MyModule -swift-version 5
|
||||||
|
// RUN: %target-swift-api-extract -o - -pretty-print %t/MyModule.swiftinterface -module-name MyModule -module-cache-path %t | %FileCheck %s
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
// This should create an ObjC Category and a method with custom name.
|
||||||
|
extension NSDictionary {
|
||||||
|
@objc
|
||||||
|
public subscript(key: Any) -> Any? {
|
||||||
|
@objc(__custom_name:)
|
||||||
|
get { return nil }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// This shouldn't create an interface.
|
||||||
|
public class A {}
|
||||||
|
|
||||||
|
// This shouldn't create a category.
|
||||||
|
extension A {
|
||||||
|
public func run() {}
|
||||||
|
}
|
||||||
|
|
||||||
|
// This creates an interface.
|
||||||
|
public class B: NSObject {}
|
||||||
|
|
||||||
|
// This creates a category.
|
||||||
|
@objc
|
||||||
|
extension B {
|
||||||
|
public func run() {}
|
||||||
|
}
|
||||||
|
|
||||||
|
// This shouldn't create a category.
|
||||||
|
extension B {
|
||||||
|
public func noop() {}
|
||||||
|
}
|
||||||
|
|
||||||
|
// This creates a category with index 1.
|
||||||
|
@objc
|
||||||
|
extension B {
|
||||||
|
public func fun() {}
|
||||||
|
}
|
||||||
|
|
||||||
|
// CHECK: "interfaces": [
|
||||||
|
// CHECK-NEXT: {
|
||||||
|
// CHECK-NEXT: "name": "_TtC8MyModule1B",
|
||||||
|
// CHECK-NEXT: "access": "public",
|
||||||
|
// CHECK-NEXT: "file": "/@input/MyModule.swiftinterface",
|
||||||
|
// CHECK-NEXT: "linkage": "exported",
|
||||||
|
// CHECK-NEXT: "super": "NSObject",
|
||||||
|
// CHECK-NEXT: "instanceMethods": [
|
||||||
|
// CHECK-NEXT: {
|
||||||
|
// CHECK-NEXT: "name": "init",
|
||||||
|
// CHECK-NEXT: "access": "public",
|
||||||
|
// CHECK-NEXT: "file": "/@input/MyModule.swiftinterface"
|
||||||
|
// CHECK-NEXT: }
|
||||||
|
// CHECK-NEXT: ],
|
||||||
|
// CHECK-NEXT: "classMethods": []
|
||||||
|
// CHECK-NEXT: }
|
||||||
|
// CHECK-NEXT: ],
|
||||||
|
// CHECK-NEXT: "categories": [
|
||||||
|
// CHECK-NEXT: {
|
||||||
|
// CHECK-NEXT: "name": "MyModule",
|
||||||
|
// CHECK-NEXT: "access": "public",
|
||||||
|
// CHECK-NEXT: "file": "/@input/MyModule.swiftinterface",
|
||||||
|
// CHECK-NEXT: "linkage": "exported",
|
||||||
|
// CHECK-NEXT: "interface": "NSDictionary",
|
||||||
|
// CHECK-NEXT: "instanceMethods": [
|
||||||
|
// CHECK-NEXT: {
|
||||||
|
// CHECK-NEXT: "name": "__custom_name:",
|
||||||
|
// CHECK-NEXT: "access": "public",
|
||||||
|
// CHECK-NEXT: "file": "/@input/MyModule.swiftinterface"
|
||||||
|
// CHECK-NEXT: }
|
||||||
|
// CHECK-NEXT: ],
|
||||||
|
// CHECK-NEXT: "classMethods": []
|
||||||
|
// CHECK-NEXT: },
|
||||||
|
// CHECK-NEXT: {
|
||||||
|
// CHECK-NEXT: "name": "MyModule",
|
||||||
|
// CHECK-NEXT: "access": "public",
|
||||||
|
// CHECK-NEXT: "file": "/@input/MyModule.swiftinterface",
|
||||||
|
// CHECK-NEXT: "linkage": "exported",
|
||||||
|
// CHECK-NEXT: "interface": "_TtC8MyModule1B",
|
||||||
|
// CHECK-NEXT: "instanceMethods": [
|
||||||
|
// CHECK-NEXT: {
|
||||||
|
// CHECK-NEXT: "name": "run",
|
||||||
|
// CHECK-NEXT: "access": "public",
|
||||||
|
// CHECK-NEXT: "file": "/@input/MyModule.swiftinterface"
|
||||||
|
// CHECK-NEXT: }
|
||||||
|
// CHECK-NEXT: ],
|
||||||
|
// CHECK-NEXT: "classMethods": []
|
||||||
|
// CHECK-NEXT: },
|
||||||
|
// CHECK-NEXT: {
|
||||||
|
// CHECK-NEXT: "name": "MyModule1",
|
||||||
|
// CHECK-NEXT: "access": "public",
|
||||||
|
// CHECK-NEXT: "file": "/@input/MyModule.swiftinterface",
|
||||||
|
// CHECK-NEXT: "linkage": "exported",
|
||||||
|
// CHECK-NEXT: "interface": "_TtC8MyModule1B",
|
||||||
|
// CHECK-NEXT: "instanceMethods": [
|
||||||
|
// CHECK-NEXT: {
|
||||||
|
// CHECK-NEXT: "name": "fun",
|
||||||
|
// CHECK-NEXT: "access": "public",
|
||||||
|
// CHECK-NEXT: "file": "/@input/MyModule.swiftinterface"
|
||||||
|
// CHECK-NEXT: }
|
||||||
|
// CHECK-NEXT: ],
|
||||||
|
// CHECK-NEXT: "classMethods": []
|
||||||
|
// CHECK-NEXT: }
|
||||||
|
// CHECK-NEXT: ],
|
||||||
@@ -92,6 +92,7 @@ public class MyClass2 : NSObject {
|
|||||||
// CHECK-NEXT: "classMethods": []
|
// CHECK-NEXT: "classMethods": []
|
||||||
// CHECK-NEXT: }
|
// CHECK-NEXT: }
|
||||||
// CHECK-NEXT: ],
|
// CHECK-NEXT: ],
|
||||||
|
// CHECK-NEXT: "categories": [],
|
||||||
// CHECK-NEXT: "version": "1.0"
|
// CHECK-NEXT: "version": "1.0"
|
||||||
// CHECK-NEXT: }
|
// CHECK-NEXT: }
|
||||||
|
|
||||||
@@ -264,12 +265,12 @@ public class MyClass2 : NSObject {
|
|||||||
// CHECK-SPI-NEXT: "super": "NSObject",
|
// CHECK-SPI-NEXT: "super": "NSObject",
|
||||||
// CHECK-SPI-NEXT: "instanceMethods": [
|
// CHECK-SPI-NEXT: "instanceMethods": [
|
||||||
// CHECK-SPI-NEXT: {
|
// CHECK-SPI-NEXT: {
|
||||||
// CHECK-SPI-NEXT: "name": "init",
|
// CHECK-SPI-NEXT: "name": "spiMethod",
|
||||||
// CHECK-SPI-NEXT: "access": "private",
|
// CHECK-SPI-NEXT: "access": "private",
|
||||||
// CHECK-SPI-NEXT: "file": "/@input/MyModule.swiftmodule"
|
// CHECK-SPI-NEXT: "file": "/@input/MyModule.swiftmodule"
|
||||||
// CHECK-SPI-NEXT: },
|
// CHECK-SPI-NEXT: },
|
||||||
// CHECK-SPI-NEXT: {
|
// CHECK-SPI-NEXT: {
|
||||||
// CHECK-SPI-NEXT: "name": "spiMethod",
|
// CHECK-SPI-NEXT: "name": "init",
|
||||||
// CHECK-SPI-NEXT: "access": "private",
|
// CHECK-SPI-NEXT: "access": "private",
|
||||||
// CHECK-SPI-NEXT: "file": "/@input/MyModule.swiftmodule"
|
// CHECK-SPI-NEXT: "file": "/@input/MyModule.swiftmodule"
|
||||||
// CHECK-SPI-NEXT: }
|
// CHECK-SPI-NEXT: }
|
||||||
@@ -284,18 +285,19 @@ public class MyClass2 : NSObject {
|
|||||||
// CHECK-SPI-NEXT: "super": "NSObject",
|
// CHECK-SPI-NEXT: "super": "NSObject",
|
||||||
// CHECK-SPI-NEXT: "instanceMethods": [
|
// CHECK-SPI-NEXT: "instanceMethods": [
|
||||||
// CHECK-SPI-NEXT: {
|
// CHECK-SPI-NEXT: {
|
||||||
// CHECK-SPI-NEXT: "name": "init",
|
// CHECK-SPI-NEXT: "name": "spiMethod",
|
||||||
// CHECK-SPI-NEXT: "access": "public",
|
// CHECK-SPI-NEXT: "access": "private",
|
||||||
// CHECK-SPI-NEXT: "file": "/@input/MyModule.swiftmodule"
|
// CHECK-SPI-NEXT: "file": "/@input/MyModule.swiftmodule"
|
||||||
// CHECK-SPI-NEXT: },
|
// CHECK-SPI-NEXT: },
|
||||||
// CHECK-SPI-NEXT: {
|
// CHECK-SPI-NEXT: {
|
||||||
// CHECK-SPI-NEXT: "name": "spiMethod",
|
// CHECK-SPI-NEXT: "name": "init",
|
||||||
// CHECK-SPI-NEXT: "access": "private",
|
// CHECK-SPI-NEXT: "access": "public",
|
||||||
// CHECK-SPI-NEXT: "file": "/@input/MyModule.swiftmodule"
|
// CHECK-SPI-NEXT: "file": "/@input/MyModule.swiftmodule"
|
||||||
// CHECK-SPI-NEXT: }
|
// CHECK-SPI-NEXT: }
|
||||||
// CHECK-SPI-NEXT: ],
|
// CHECK-SPI-NEXT: ],
|
||||||
// CHECK-SPI-NEXT: "classMethods": []
|
// CHECK-SPI-NEXT: "classMethods": []
|
||||||
// CHECK-SPI-NEXT: }
|
// CHECK-SPI-NEXT: }
|
||||||
// CHECK-SPI-NEXT: ],
|
// CHECK-SPI-NEXT: ],
|
||||||
|
// CHECK-SPI-NEXT: "categories": [],
|
||||||
// CHECK-SPI-NEXT: "version": "1.0"
|
// CHECK-SPI-NEXT: "version": "1.0"
|
||||||
// CHECK-SPI-NEXT: }
|
// CHECK-SPI-NEXT: }
|
||||||
|
|||||||
@@ -48,5 +48,6 @@ public struct TestStruct {
|
|||||||
// CHECK-NEXT: }
|
// CHECK-NEXT: }
|
||||||
// CHECK-NEXT: ],
|
// CHECK-NEXT: ],
|
||||||
// CHECK-NEXT: "interfaces": [],
|
// CHECK-NEXT: "interfaces": [],
|
||||||
|
// CHECK-NEXT: "categories": [],
|
||||||
// CHECK-NEXT: "version": "1.0"
|
// CHECK-NEXT: "version": "1.0"
|
||||||
// CHECK-NEXT: }
|
// CHECK-NEXT: }
|
||||||
|
|||||||
Reference in New Issue
Block a user