Record Objective-C method lookup tables in Swift modules.

Include a mapping from Objective-C selectors to the @objc methods that
produce Objective-c methods with those selectors. Use this to lazily
populate the Objective-C method lookup tables in each class. This makes
@objc override checking work across Swift modules, which is part of
rdar://problem/18391046.

Note that we use a single, unified selector table, both because it is
simpler and because it makes global queries ("is there any method with
the given selector?") easier.

Swift SVN r23214
This commit is contained in:
Doug Gregor
2014-11-11 00:19:03 +00:00
parent 3910c25da1
commit b27e88b70b
16 changed files with 426 additions and 18 deletions

View File

@@ -530,6 +530,31 @@ public:
/// one.
void loadExtensions(NominalTypeDecl *nominal, unsigned previousGeneration);
/// \brief Load the methods within the given class that that produce
/// Objective-C class or instance methods with the given selector.
///
/// \param classDecl The class in which we are searching for @objc methods.
/// The search only considers this class and its extensions; not any
/// superclasses.
///
/// \param selector The selector to search for.
///
/// \param isInstanceMethod Whether we are looking for an instance method
/// (vs. a class method).
///
/// \param previousGeneration The previous generation with which this
/// callback was invoked. The list of methods will already contain all of
/// the results from generations up and and including \c previousGeneration.
///
/// \param methods The list of @objc methods in this class that have this
/// selector and are instance/class methods as requested. This list will be
/// extended with any methods found in subsequent generations.
void loadObjCMethods(ClassDecl *classDecl,
ObjCSelector selector,
bool isInstanceMethod,
unsigned previousGeneration,
llvm::TinyPtrVector<AbstractFunctionDecl *> &methods);
/// \brief Retrieve the Clang module loader for this ASTContext.
///
/// If there is no Clang module loader, returns a null pointer.

View File

@@ -2996,8 +2996,6 @@ public:
}
};
class ObjCMethodLookupTable;
/// ClassDecl - This is the declaration of a class, for example:
///
/// class Complex { var R : Double, I : Double }
@@ -3005,6 +3003,8 @@ class ObjCMethodLookupTable;
/// The type of the decl itself is a MetatypeType; use getDeclaredType()
/// to get the declared type ("Complex" in the above example).
class ClassDecl : public NominalTypeDecl {
class ObjCMethodLookupTable;
SourceLoc ClassLoc;
Type Superclass;
ObjCMethodLookupTable *ObjCMethodLookup = nullptr;

View File

@@ -441,12 +441,35 @@ public:
LLVM_ATTRIBUTE_DEPRECATED(void dump() const,
"only for use within the debugger");
/// Compare two Objective-C selectors, producing -1 if \c *this comes before
/// \c other, 1 if \c *this comes after \c other, and 0 if they are equal.
int compare(ObjCSelector other) const {
return Storage.compare(other.Storage);
}
friend bool operator==(ObjCSelector lhs, ObjCSelector rhs) {
return lhs.getOpaqueValue() == rhs.getOpaqueValue();
}
friend bool operator!=(ObjCSelector lhs, ObjCSelector rhs) {
return lhs.getOpaqueValue() != rhs.getOpaqueValue();
}
friend bool operator<(ObjCSelector lhs, ObjCSelector rhs) {
return lhs.compare(rhs) < 0;
}
friend bool operator<=(ObjCSelector lhs, ObjCSelector rhs) {
return lhs.compare(lhs) <= 0;
}
friend bool operator>(ObjCSelector lhs, ObjCSelector rhs) {
return lhs.compare(lhs) > 0;
}
friend bool operator>=(ObjCSelector lhs, ObjCSelector rhs) {
return lhs.compare(lhs) >= 0;
}
};
} // end namespace swift

View File

@@ -20,9 +20,12 @@
#include "swift/AST/Identifier.h"
#include "swift/Basic/LLVM.h"
#include "swift/Basic/SourceLoc.h"
#include "llvm/ADT/TinyPtrVector.h"
namespace swift {
class AbstractFunctionDecl;
class ClassDecl;
class Module;
class NominalTypeDecl;
@@ -76,6 +79,32 @@ public:
virtual void loadExtensions(NominalTypeDecl *nominal,
unsigned previousGeneration) { }
/// \brief Load the methods within the given class that that produce
/// Objective-C class or instance methods with the given selector.
///
/// \param classDecl The class in which we are searching for @objc methods.
/// The search only considers this class and its extensions; not any
/// superclasses.
///
/// \param selector The selector to search for.
///
/// \param isInstanceMethod Whether we are looking for an instance method
/// (vs. a class method).
///
/// \param previousGeneration The previous generation with which this
/// callback was invoked. The list of methods will already contain all of
/// the results from generations up and and including \c previousGeneration.
///
/// \param methods The list of @objc methods in this class that have this
/// selector and are instance/class methods as requested. This list will be
/// extended with any methods found in subsequent generations.
virtual void loadObjCMethods(
ClassDecl *classDecl,
ObjCSelector selector,
bool isInstanceMethod,
unsigned previousGeneration,
llvm::TinyPtrVector<AbstractFunctionDecl *> &methods) { }
/// \brief Verify all modules loaded by this loader.
virtual void verifyAllModules() { }
};

View File

@@ -252,6 +252,12 @@ private:
std::unique_ptr<SerializedDeclTable> ClassMembersByName;
std::unique_ptr<SerializedDeclTable> OperatorMethodDecls;
class ObjCMethodTableInfo;
using SerializedObjCMethodTable =
llvm::OnDiskIterableChainedHashTable<ObjCMethodTableInfo>;
std::unique_ptr<SerializedObjCMethodTable> ObjCMethods;
llvm::DenseMap<const ValueDecl *, Identifier> PrivateDiscriminatorsByValue;
TinyPtrVector<Decl *> ImportDecls;
@@ -323,6 +329,11 @@ private:
std::unique_ptr<SerializedDeclTable>
readDeclTable(ArrayRef<uint64_t> fields, StringRef blobData);
/// Read an on-disk Objective-C method table stored in
/// index_block::ObjCMethodTableLayout format.
std::unique_ptr<ModuleFile::SerializedObjCMethodTable>
readObjCMethodTable(ArrayRef<uint64_t> fields, StringRef blobData);
/// Reads the index block, which contains global tables.
///
/// Returns false if there was an error.
@@ -450,6 +461,25 @@ public:
/// Note that this may cause other decls to load as well.
void loadExtensions(NominalTypeDecl *nominal);
/// \brief Load the methods within the given class that that produce
/// Objective-C class or instance methods with the given selector.
///
/// \param classDecl The class in which we are searching for @objc methods.
/// The search only considers this class and its extensions; not any
/// superclasses.
///
/// \param selector The selector to search for.
///
/// \param isInstanceMethod Whether we are looking for an instance method
/// (vs. a class method).
///
/// \param methods The list of @objc methods in this class that have this
/// selector and are instance/class methods as requested.
void loadObjCMethods(ClassDecl *classDecl,
ObjCSelector selector,
bool isInstanceMethod,
llvm::TinyPtrVector<AbstractFunctionDecl *> &methods);
/// Reports all class members in the module to the given consumer.
///
/// This is intended for use with id-style lookup and code completion.

View File

@@ -51,7 +51,7 @@ const uint16_t VERSION_MAJOR = 0;
/// To ensure that two separate changes don't silently get merged into one
/// in source control, you should also update the comment to briefly
/// describe what change you made.
const uint16_t VERSION_MINOR = 158; // Last change: objc decl attribute
const uint16_t VERSION_MINOR = 159; // Last change: objc method3 table
using DeclID = Fixnum<31>;
using DeclIDField = BCFixed<31>;
@@ -328,7 +328,7 @@ enum BlockID {
/// The comment block, which contains documentation comments.
///
/// \sa comment_block
COMMENT_BLOCK_ID,
COMMENT_BLOCK_ID
};
/// The record types within the control block.
@@ -1210,7 +1210,12 @@ namespace index_block {
OPERATORS,
EXTENSIONS,
CLASS_MEMBERS,
OPERATOR_METHODS
OPERATOR_METHODS,
/// The Objective-C method index, which contains a mapping from
/// Objective-C selectors to the methods/initializers/properties/etc. that
/// produce Objective-C methods.
OBJC_METHODS,
};
using OffsetsLayout = BCGenericRecordLayout<
@@ -1223,6 +1228,12 @@ namespace index_block {
BCVBR<16>, // table offset within the blob (see below)
BCBlob // map from identifier strings to decl kinds / decl IDs
>;
using ObjCMethodTableLayout = BCRecordLayout<
OBJC_METHODS, // record ID
BCVBR<16>, // table offset within the blob (see below)
BCBlob // map from Objective-C selectors to methods with that selector
>;
}
/// \sa COMMENT_BLOCK_ID

View File

@@ -113,6 +113,13 @@ public:
virtual void loadExtensions(NominalTypeDecl *nominal,
unsigned previousGeneration) override;
virtual void loadObjCMethods(
ClassDecl *classDecl,
ObjCSelector selector,
bool isInstanceMethod,
unsigned previousGeneration,
llvm::TinyPtrVector<AbstractFunctionDecl *> &methods);
/// Returns true if the data looks like it contains a serialized AST.
static bool isSerializedAST(StringRef data);

View File

@@ -1049,6 +1049,18 @@ void ASTContext::loadExtensions(NominalTypeDecl *nominal,
}
}
void ASTContext::loadObjCMethods(
ClassDecl *classDecl,
ObjCSelector selector,
bool isInstanceMethod,
unsigned previousGeneration,
llvm::TinyPtrVector<AbstractFunctionDecl *> &methods) {
for (auto &loader : Impl.ModuleLoaders) {
loader->loadObjCMethods(classDecl, selector, isInstanceMethod,
previousGeneration, methods);
}
}
void ASTContext::verifyAllLoadedModules() const {
for (auto &loader : Impl.ModuleLoaders)
loader->verifyAllModules();

View File

@@ -15,6 +15,7 @@
//===----------------------------------------------------------------------===//
#include "swift/AST/Identifier.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/ConvertUTF.h"
using namespace swift;

View File

@@ -772,11 +772,23 @@ public:
}
};
namespace {
/// Stores the set of Objective-C methods with a given selector within the
/// Objective-C method lookup table.
struct StoredObjCMethods {
/// The generation count at which this list was last updated.
unsigned Generation = 0;
/// The set of methods with the given selector.
llvm::TinyPtrVector<AbstractFunctionDecl *> Methods;
};
}
/// Class member lookup table, which is a member lookup table with a second
/// table for lookup based on Objective-C selector.
class swift::ObjCMethodLookupTable
class ClassDecl::ObjCMethodLookupTable
: public llvm::DenseMap<std::pair<ObjCSelector, char>,
llvm::TinyPtrVector<AbstractFunctionDecl *>>
StoredObjCMethods>
{
public:
void destroy() {
@@ -1008,12 +1020,17 @@ ClassDecl::lookupDirect(ObjCSelector selector, bool isInstance) {
createObjCMethodLookup();
}
auto known = ObjCMethodLookup->find({selector, isInstance});
if (known != ObjCMethodLookup->end())
return { known->second.begin(), known->second.end() };
// If any modules have been loaded since we did the search last (or if we
// hadn't searched before), look in those modules, too.
auto &stored = (*ObjCMethodLookup)[{selector, isInstance}];
ASTContext &ctx = getASTContext();
if (ctx.getCurrentGeneration() > stored.Generation) {
ctx.loadObjCMethods(this, selector, isInstance, stored.Generation,
stored.Methods);
stored.Generation = ctx.getCurrentGeneration();
}
// FIXME: Callback to perform lazy lookup of selectors.
return { };
return { stored.Methods.begin(), stored.Methods.end() };
}
void ClassDecl::recordObjCMethod(AbstractFunctionDecl *method) {
@@ -1027,7 +1044,7 @@ void ClassDecl::recordObjCMethod(AbstractFunctionDecl *method) {
bool isInstanceMethod
= method->isInstanceMember() || isa<ConstructorDecl>(method);
auto selector = method->getObjCSelector();
auto &vec = (*ObjCMethodLookup)[{selector, isInstanceMethod}];
auto &vec = (*ObjCMethodLookup)[{selector, isInstanceMethod}].Methods;
// In a non-empty vector, we could have duplicates or conflicts.
if (!vec.empty()) {

View File

@@ -264,6 +264,65 @@ ModuleFile::readDeclTable(ArrayRef<uint64_t> fields, StringRef blobData) {
base + sizeof(uint32_t), base));
}
/// Used to deserialize entries in the on-disk Objective-C method table.
class ModuleFile::ObjCMethodTableInfo {
public:
using internal_key_type = std::string;
using external_key_type = ObjCSelector;
using data_type = SmallVector<std::tuple<TypeID, bool, DeclID>, 8>;
using hash_value_type = uint32_t;
using offset_type = unsigned;
internal_key_type GetInternalKey(external_key_type ID) {
llvm::SmallString<32> scratch;
return ID.getString(scratch).str();
}
hash_value_type ComputeHash(internal_key_type key) {
return llvm::HashString(key);
}
static bool EqualKey(internal_key_type lhs, internal_key_type rhs) {
return lhs == rhs;
}
static std::pair<unsigned, unsigned> ReadKeyDataLength(const uint8_t *&data) {
unsigned keyLength = endian::readNext<uint16_t, little, unaligned>(data);
unsigned dataLength = endian::readNext<uint16_t, little, unaligned>(data);
return { keyLength, dataLength };
}
static internal_key_type ReadKey(const uint8_t *data, unsigned length) {
return std::string(reinterpret_cast<const char *>(data), length);
}
static data_type ReadData(internal_key_type key, const uint8_t *data,
unsigned length) {
data_type result;
while (length > 0) {
TypeID typeID = endian::readNext<uint32_t, little, unaligned>(data);
bool isInstanceMethod = *data++ != 0;
DeclID methodID = endian::readNext<uint32_t, little, unaligned>(data);
result.push_back(std::make_tuple(typeID, isInstanceMethod, methodID));
length -= sizeof(TypeID) + 1 + sizeof(DeclID);
}
return result;
}
};
std::unique_ptr<ModuleFile::SerializedObjCMethodTable>
ModuleFile::readObjCMethodTable(ArrayRef<uint64_t> fields, StringRef blobData) {
uint32_t tableOffset;
index_block::ObjCMethodTableLayout::readRecord(fields, tableOffset);
auto base = reinterpret_cast<const uint8_t *>(blobData.data());
using OwnedTable = std::unique_ptr<SerializedObjCMethodTable>;
return OwnedTable(
SerializedObjCMethodTable::Create(base + tableOffset,
base + sizeof(uint32_t), base));
}
bool ModuleFile::readIndexBlock(llvm::BitstreamCursor &cursor) {
cursor.EnterSubBlock(INDEX_BLOCK_ID);
@@ -317,6 +376,9 @@ bool ModuleFile::readIndexBlock(llvm::BitstreamCursor &cursor) {
case index_block::OPERATOR_METHODS:
OperatorMethodDecls = readDeclTable(scratch, blobData);
break;
case index_block::OBJC_METHODS:
ObjCMethods = readObjCMethodTable(scratch, blobData);
break;
default:
// Unknown index kind, which this version of the compiler won't use.
break;
@@ -1012,6 +1074,40 @@ void ModuleFile::loadExtensions(NominalTypeDecl *nominal) {
}
}
void ModuleFile::loadObjCMethods(
ClassDecl *classDecl,
ObjCSelector selector,
bool isInstanceMethod,
llvm::TinyPtrVector<AbstractFunctionDecl *> &methods) {
// If we don't have an Objective-C method table, there's nothing to do.
if (!ObjCMethods)
return;
// Look for all methods in the module file with this selector.
auto known = ObjCMethods->find(selector);
if (known == ObjCMethods->end()) {
return;
}
auto results = *known;
for (const auto &result : results) {
// If the method is the wrong kind (instance vs. class), skip it.
if (isInstanceMethod != std::get<1>(result))
continue;
// If the method isn't defined in the requested class, skip it.
Type type = getType(std::get<0>(result));
if (type->getClassOrBoundGenericClass() != classDecl)
continue;
// Deserialize the method and add it to the list.
if (auto func = dyn_cast_or_null<AbstractFunctionDecl>(
getDecl(std::get<2>(result)))) {
methods.push_back(func);
}
}
}
void ModuleFile::lookupClassMember(Module::AccessPathTy accessPath,
DeclName name,
SmallVectorImpl<ValueDecl*> &results) {

View File

@@ -40,6 +40,8 @@
#include "llvm/Support/OnDiskHashTable.h"
#include "llvm/Support/raw_ostream.h"
#include <vector>
using namespace swift;
using namespace swift::serialization;
using namespace llvm::support;
@@ -334,6 +336,7 @@ void Serializer::writeBlockInfoBlock() {
BLOCK_RECORD(index_block, EXTENSIONS);
BLOCK_RECORD(index_block, CLASS_MEMBERS);
BLOCK_RECORD(index_block, OPERATOR_METHODS);
BLOCK_RECORD(index_block, OBJC_METHODS);
BLOCK(SIL_BLOCK);
BLOCK_RECORD(sil_block, SIL_FUNCTION);
@@ -2897,6 +2900,82 @@ static void writeDeclCommentTable(
DeclCommentList.emit(scratch, tableOffset, hashTableBlob);
}
namespace {
/// Used to serialize the on-disk Objective-C method hash table.
class ObjCMethodTableInfo {
public:
using key_type = ObjCSelector;
using key_type_ref = key_type;
using data_type = Serializer::ObjCMethodTableData;
using data_type_ref = const data_type &;
using hash_value_type = uint32_t;
using offset_type = unsigned;
hash_value_type ComputeHash(key_type_ref key) {
llvm::SmallString<32> scratch;
return llvm::HashString(key.getString(scratch));
}
std::pair<unsigned, unsigned> EmitKeyDataLength(raw_ostream &out,
key_type_ref key,
data_type_ref data) {
llvm::SmallString<32> scratch;
uint32_t keyLength = key.getString(scratch).size();
uint32_t dataLength = (sizeof(TypeID) + 1 + sizeof(DeclID)) * data.size();
endian::Writer<little> writer(out);
writer.write<uint16_t>(keyLength);
writer.write<uint16_t>(dataLength);
return { keyLength, dataLength };
}
void EmitKey(raw_ostream &out, key_type_ref key, unsigned len) {
out << key;
}
void EmitData(raw_ostream &out, key_type_ref key, data_type_ref data,
unsigned len) {
static_assert(sizeof(DeclID) <= 4, "DeclID too large");
endian::Writer<little> writer(out);
for (auto entry : data) {
writer.write<uint32_t>(std::get<0>(entry));
writer.write<uint8_t>(std::get<1>(entry));
writer.write<uint32_t>(std::get<2>(entry));
}
}
};
} // end anonymous namespace
static void writeObjCMethodTable(const index_block::ObjCMethodTableLayout &out,
Serializer::ObjCMethodTable &objcMethods) {
// Collect all of the Objective-C selectors in the method table.
std::vector<ObjCSelector> selectors;
for (const auto &entry : objcMethods) {
selectors.push_back(entry.first);
}
// Sort the Objective-C selectors so we emit them in a stable order.
llvm::array_pod_sort(selectors.begin(), selectors.end());
// Create the on-disk hash table.
llvm::OnDiskChainedHashTableGenerator<ObjCMethodTableInfo> generator;
llvm::SmallString<32> hashTableBlob;
uint32_t tableOffset;
{
llvm::raw_svector_ostream blobStream(hashTableBlob);
for (auto selector : selectors) {
generator.insert(selector, objcMethods[selector]);
}
// Make sure that no bucket is at offset 0
endian::Writer<little>(blobStream).write<uint32_t>(0);
tableOffset = generator.Emit(blobStream);
}
SmallVector<uint64_t, 8> scratch;
out.emit(scratch, tableOffset, hashTableBlob);
}
/// Add operator methods from the given declaration type.
///
/// Recursively walks the members and derived global decls of any nested
@@ -2905,6 +2984,7 @@ template<typename Range>
static void addOperatorsAndTopLevel(Serializer &S, Range members,
Serializer::DeclTable &operatorMethodDecls,
Serializer::DeclTable &topLevelDecls,
Serializer::ObjCMethodTable &objcMethods,
bool isDerivedTopLevel) {
for (const Decl *member : members) {
auto memberValue = dyn_cast<ValueDecl>(member);
@@ -2929,15 +3009,31 @@ static void addOperatorsAndTopLevel(Serializer &S, Range members,
// Recurse into nested types.
if (auto nominal = dyn_cast<NominalTypeDecl>(member)) {
addOperatorsAndTopLevel(S, nominal->getMembers(),
operatorMethodDecls, topLevelDecls, false);
operatorMethodDecls, topLevelDecls, objcMethods,
false);
addOperatorsAndTopLevel(S, nominal->getDerivedGlobalDecls(),
operatorMethodDecls, topLevelDecls, true);
operatorMethodDecls, topLevelDecls, objcMethods,
true);
}
// Record Objective-C methods.
if (auto func = dyn_cast<AbstractFunctionDecl>(member)) {
if (func->isObjC()) {
TypeID owningTypeID
= S.addTypeRef(func->getDeclContext()->getDeclaredInterfaceType());
objcMethods[func->getObjCSelector()].push_back(
std::make_tuple(owningTypeID,
func->isInstanceMember(),
S.addDeclRef(memberValue)));
}
}
}
}
void Serializer::writeAST(ModuleOrSourceFile DC) {
DeclTable topLevelDecls, extensionDecls, operatorDecls, operatorMethodDecls;
ObjCMethodTable objcMethods;
ArrayRef<const FileUnit *> files = SF ? SF : M->getFiles();
for (auto nextFile : files) {
// FIXME: Switch to a visitor interface?
@@ -2956,9 +3052,11 @@ void Serializer::writeAST(ModuleOrSourceFile DC) {
// Add operator methods from nominal types.
if (auto nominal = dyn_cast<NominalTypeDecl>(VD)) {
addOperatorsAndTopLevel(*this, nominal->getMembers(),
operatorMethodDecls, topLevelDecls, false);
operatorMethodDecls, topLevelDecls,
objcMethods, false);
addOperatorsAndTopLevel(*this, nominal->getDerivedGlobalDecls(),
operatorMethodDecls, topLevelDecls, true);
operatorMethodDecls, topLevelDecls,
objcMethods, true);
}
} else if (auto ED = dyn_cast<ExtensionDecl>(D)) {
Type extendedTy = ED->getExtendedType();
@@ -2968,7 +3066,8 @@ void Serializer::writeAST(ModuleOrSourceFile DC) {
// Add operator methods from extensions.
addOperatorsAndTopLevel(*this, ED->getMembers(),
operatorMethodDecls, topLevelDecls, false);
operatorMethodDecls, topLevelDecls, objcMethods,
false);
} else if (auto OD = dyn_cast<OperatorDecl>(D)) {
operatorDecls[OD->getName()]
@@ -2994,6 +3093,9 @@ void Serializer::writeAST(ModuleOrSourceFile DC) {
writeDeclTable(DeclList, index_block::EXTENSIONS, extensionDecls);
writeDeclTable(DeclList, index_block::CLASS_MEMBERS, ClassMembersByName);
writeDeclTable(DeclList, index_block::OPERATOR_METHODS, operatorMethodDecls);
index_block::ObjCMethodTableLayout ObjCMethodTable(Out);
writeObjCMethodTable(ObjCMethodTable, objcMethods);
}
}

View File

@@ -23,6 +23,7 @@
#include "swift/Basic/LLVM.h"
#include <array>
#include <queue>
#include <tuple>
namespace swift {
class SILModule;
@@ -104,6 +105,12 @@ public:
/// with.
const Decl *getGenericContext(const GenericParamList *paramList);
using ObjCMethodTableData = SmallVector<std::tuple<TypeID, bool, DeclID>, 4>;
// In-memory representation of what will eventually be an on-disk
// hash table of all defined Objective-C methods.
using ObjCMethodTable = llvm::DenseMap<ObjCSelector, ObjCMethodTableData>;
private:
/// A map from identifiers to methods and properties with the given name.
///

View File

@@ -340,6 +340,20 @@ void SerializedModuleLoader::loadExtensions(NominalTypeDecl *nominal,
}
}
void SerializedModuleLoader::loadObjCMethods(
ClassDecl *classDecl,
ObjCSelector selector,
bool isInstanceMethod,
unsigned previousGeneration,
llvm::TinyPtrVector<AbstractFunctionDecl *> &methods) {
for (auto &modulePair : LoadedModuleFiles) {
if (modulePair.second <= previousGeneration)
continue;
modulePair.first->loadObjCMethods(classDecl, selector, isInstanceMethod,
methods);
}
}
bool SerializedModuleLoader::isSerializedAST(StringRef data) {
using serialization::MODULE_SIGNATURE;
StringRef signatureStr(reinterpret_cast<const char *>(MODULE_SIGNATURE),

View File

@@ -0,0 +1,8 @@
public class A {
public init() { }
@objc(a1) public func f1() { }
@objc(initWithInt:) public func f2(int: Int) { }
@objc(setFoo:) public func f3(i: Int) { }
@objc(objectAtIndexedSubscript:) public func f4(i: Int) { }
}

View File

@@ -0,0 +1,26 @@
// RUN: rm -rf %t
// RUN: mkdir %t
// RUN: %swift -emit-module -disable-objc-attr-requires-foundation-module -o %t %S/Inputs/objc_method_decls.swift
// RUN: llvm-bcanalyzer %t/objc_method_decls.swiftmodule | FileCheck %s
// RUN: %swift -parse -disable-objc-attr-requires-foundation-module -I=%t %s -verify
import objc_method_decls
class B : A {
@objc func a1() { } // expected-error{{method 'a1()' overrides Objective-C method 'a1' from superclass 'A'}}
@objc init(int: Int) { // expected-error{{initializer 'init(int:)' overrides Objective-C method 'initWithInt:' from superclass 'A'}}
self.foo = int
super.init()
}
@objc var foo: Int // expected-error{{setter for 'foo' overrides Objective-C method 'setFoo:' from superclass 'A'}}
@objc subscript (i: Int) -> AnyObject {
get { return self } // expected-error{{subscript getter overrides Objective-C method 'objectAtIndexedSubscript:' from superclass 'A'}}
set { }
}
}
// Make sure the OBJC_METHODS table is present.
// CHECK: OBJC_METHODS