Skip to content

[NFC] Move selector family logic to ObjCSelector #22605

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Feb 16, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions include/swift/AST/Identifier.h
Original file line number Diff line number Diff line change
Expand Up @@ -592,6 +592,12 @@ class DeclName {
"only for use within the debugger");
};

enum class ObjCSelectorFamily : unsigned {
None,
#define OBJC_SELECTOR_FAMILY(LABEL, PREFIX) LABEL,
#include "swift/AST/ObjCSelectorFamily.def"
};

/// Represents an Objective-C selector.
class ObjCSelector {
/// The storage for an Objective-C selector.
Expand Down Expand Up @@ -656,6 +662,8 @@ class ObjCSelector {
/// \param scratch Scratch space to use.
StringRef getString(llvm::SmallVectorImpl<char> &scratch) const;

ObjCSelectorFamily getSelectorFamily() const;

void *getOpaqueValue() const { return Storage.getOpaqueValue(); }
static ObjCSelector getFromOpaqueValue(void *p) {
return ObjCSelector(DeclName::getFromOpaqueValue(p));
Expand Down
29 changes: 29 additions & 0 deletions include/swift/AST/ObjCSelectorFamily.def
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
//===--- ObjCSelectorFamily.def - Objective-C Selector Families - C++ ---*-===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
//
// This file defines macros used for macro-metaprogramming with Objective-C
// selector families, categories of Objective-C methods with special ARC
// semantics.
//
//===----------------------------------------------------------------------===//

#ifndef OBJC_SELECTOR_FAMILY
#define OBJC_SELECTOR_FAMILY(LABEL, PREFIX)
#endif

OBJC_SELECTOR_FAMILY(Alloc, "alloc")
OBJC_SELECTOR_FAMILY(Copy, "copy")
OBJC_SELECTOR_FAMILY(Init, "init")
OBJC_SELECTOR_FAMILY(MutableCopy, "mutableCopy")
OBJC_SELECTOR_FAMILY(New, "new")

#undef OBJC_SELECTOR_FAMILY
25 changes: 25 additions & 0 deletions lib/AST/Identifier.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
#include "llvm/ADT/StringExtras.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/ConvertUTF.h"
#include "clang/Basic/CharInfo.h"
using namespace swift;

void *DeclBaseName::SubscriptIdentifierData =
Expand Down Expand Up @@ -199,6 +200,30 @@ ObjCSelector::ObjCSelector(ASTContext &ctx, unsigned numArgs,
Storage = DeclName(ctx, Identifier(), pieces);
}

ObjCSelectorFamily ObjCSelector::getSelectorFamily() const {
StringRef text = getSelectorPieces().front().get();
while (!text.empty() && text[0] == '_') text = text.substr(1);

// Does the given selector start with the given string as a prefix, in the
// sense of the selector naming conventions?
// This implementation matches the one used by
// clang::Selector::getMethodFamily, to make sure we behave the same as
// Clang ARC. We're not just calling that method here because it means
// allocating a clang::IdentifierInfo, which requires a Clang ASTContext.
auto hasPrefix = [](StringRef text, StringRef prefix) {
if (!text.startswith(prefix)) return false;
if (text.size() == prefix.size()) return true;
assert(text.size() > prefix.size());
return !clang::isLowercase(text[prefix.size()]);
};

if (false) /*for #define purposes*/;
#define OBJC_SELECTOR_FAMILY(LABEL, PREFIX) \
else if (hasPrefix(text, PREFIX)) return ObjCSelectorFamily::LABEL;
#include "swift/AST/ObjCSelectorFamily.def"
else return ObjCSelectorFamily::None;
}

StringRef ObjCSelector::getString(llvm::SmallVectorImpl<char> &scratch) const {
// Fast path for zero-argument selectors.
if (getNumArgs() == 0) {
Expand Down
108 changes: 35 additions & 73 deletions lib/SIL/SILFunctionType.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@
#include "clang/AST/Attr.h"
#include "clang/AST/DeclObjC.h"
#include "clang/Analysis/DomainSpecific/CocoaConventions.h"
#include "clang/Basic/CharInfo.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/Debug.h"
Expand Down Expand Up @@ -221,7 +220,7 @@ enum class ConventionsKind : uint8_t {
ObjCMethod = 2,
CFunctionType = 3,
CFunction = 4,
SelectorFamily = 5,
ObjCSelectorFamily = 5,
Deallocator = 6,
Capture = 7,
};
Expand Down Expand Up @@ -1710,64 +1709,27 @@ static const clang::Decl *findClangMethod(ValueDecl *method) {
// Selector Family SILFunctionTypes
//===----------------------------------------------------------------------===//

/// Apply a macro FAMILY(Name, Prefix) to all ObjC selector families.
#define FOREACH_FAMILY(FAMILY) \
FAMILY(Alloc, "alloc") \
FAMILY(Copy, "copy") \
FAMILY(Init, "init") \
FAMILY(MutableCopy, "mutableCopy") \
FAMILY(New, "new")

namespace {
enum class SelectorFamily : unsigned {
None,
#define GET_LABEL(LABEL, PREFIX) LABEL,
FOREACH_FAMILY(GET_LABEL)
#undef GET_LABEL
};
} // end anonymous namespace

/// Derive the ObjC selector family from an identifier.
///
/// Note that this will never derive the Init family, which is too dangerous
/// to leave to chance. Swift functions starting with "init" are always
/// emitted as if they are part of the "none" family.
static SelectorFamily getSelectorFamily(Identifier name) {
StringRef text = name.get();
while (!text.empty() && text[0] == '_') text = text.substr(1);

// Does the given selector start with the given string as a prefix, in the
// sense of the selector naming conventions?
// This implementation matches the one used by
// clang::Selector::getMethodFamily, to make sure we behave the same as Clang
// ARC. We're not just calling that method here because it means allocating a
// clang::IdentifierInfo, which requires a Clang ASTContext.
auto hasPrefix = [](StringRef text, StringRef prefix) {
if (!text.startswith(prefix)) return false;
if (text.size() == prefix.size()) return true;
assert(text.size() > prefix.size());
return !clang::isLowercase(text[prefix.size()]);
};

auto result = SelectorFamily::None;
if (false) /*for #define purposes*/;
#define CHECK_PREFIX(LABEL, PREFIX) \
else if (hasPrefix(text, PREFIX)) result = SelectorFamily::LABEL;
FOREACH_FAMILY(CHECK_PREFIX)
#undef CHECK_PREFIX

if (result == SelectorFamily::Init)
return SelectorFamily::None;
static ObjCSelectorFamily getObjCSelectorFamily(ObjCSelector name) {
auto result = name.getSelectorFamily();

if (result == ObjCSelectorFamily::Init)
return ObjCSelectorFamily::None;

return result;
}

/// Get the ObjC selector family a foreign SILDeclRef belongs to.
static SelectorFamily getSelectorFamily(SILDeclRef c) {
static ObjCSelectorFamily getObjCSelectorFamily(SILDeclRef c) {
assert(c.isForeign);
switch (c.kind) {
case SILDeclRef::Kind::Func: {
if (!c.hasDecl())
return SelectorFamily::None;
return ObjCSelectorFamily::None;

auto *FD = cast<FuncDecl>(c.getDecl());
if (auto accessor = dyn_cast<AccessorDecl>(FD)) {
Expand All @@ -1783,11 +1745,11 @@ static SelectorFamily getSelectorFamily(SILDeclRef c) {
}
}

return getSelectorFamily(FD->getObjCSelector().getSelectorPieces().front());
return getObjCSelectorFamily(FD->getObjCSelector());
}
case SILDeclRef::Kind::Initializer:
case SILDeclRef::Kind::IVarInitializer:
return SelectorFamily::Init;
return ObjCSelectorFamily::Init;

/// Currently IRGen wraps alloc/init methods into Swift constructors
/// with Swift conventions.
Expand All @@ -1796,7 +1758,7 @@ static SelectorFamily getSelectorFamily(SILDeclRef c) {
case SILDeclRef::Kind::Destroyer:
case SILDeclRef::Kind::Deallocator:
case SILDeclRef::Kind::IVarDestroyer:
return SelectorFamily::None;
return ObjCSelectorFamily::None;

case SILDeclRef::Kind::EnumElement:
case SILDeclRef::Kind::GlobalAccessor:
Expand All @@ -1810,12 +1772,12 @@ static SelectorFamily getSelectorFamily(SILDeclRef c) {

namespace {

class SelectorFamilyConventions : public Conventions {
SelectorFamily Family;
class ObjCSelectorFamilyConventions : public Conventions {
ObjCSelectorFamily Family;

public:
SelectorFamilyConventions(SelectorFamily family)
: Conventions(ConventionsKind::SelectorFamily), Family(family) {}
ObjCSelectorFamilyConventions(ObjCSelectorFamily family)
: Conventions(ConventionsKind::ObjCSelectorFamily), Family(family) {}

ParameterConvention getIndirectParameter(unsigned index,
const AbstractionPattern &type,
Expand All @@ -1836,14 +1798,14 @@ class SelectorFamilyConventions : public Conventions {

ResultConvention getResult(const TypeLowering &tl) const override {
switch (Family) {
case SelectorFamily::Alloc:
case SelectorFamily::Copy:
case SelectorFamily::Init:
case SelectorFamily::MutableCopy:
case SelectorFamily::New:
case ObjCSelectorFamily::Alloc:
case ObjCSelectorFamily::Copy:
case ObjCSelectorFamily::Init:
case ObjCSelectorFamily::MutableCopy:
case ObjCSelectorFamily::New:
return ResultConvention::Owned;

case SelectorFamily::None:
case ObjCSelectorFamily::None:
// Defaults below.
break;
}
Expand All @@ -1860,7 +1822,7 @@ class SelectorFamilyConventions : public Conventions {

ParameterConvention
getDirectSelfParameter(const AbstractionPattern &type) const override {
if (Family == SelectorFamily::Init)
if (Family == ObjCSelectorFamily::Init)
return ParameterConvention::Direct_Owned;
return ObjCSelfConvention;
}
Expand All @@ -1872,21 +1834,21 @@ class SelectorFamilyConventions : public Conventions {
}

static bool classof(const Conventions *C) {
return C->getKind() == ConventionsKind::SelectorFamily;
return C->getKind() == ConventionsKind::ObjCSelectorFamily;
}
};

} // end anonymous namespace

static CanSILFunctionType
getSILFunctionTypeForSelectorFamily(SILModule &M, SelectorFamily family,
CanAnyFunctionType origType,
CanAnyFunctionType substInterfaceType,
AnyFunctionType::ExtInfo extInfo,
const ForeignInfo &foreignInfo,
Optional<SILDeclRef> constant) {
getSILFunctionTypeForObjCSelectorFamily(SILModule &M, ObjCSelectorFamily family,
CanAnyFunctionType origType,
CanAnyFunctionType substInterfaceType,
AnyFunctionType::ExtInfo extInfo,
const ForeignInfo &foreignInfo,
Optional<SILDeclRef> constant) {
return getSILFunctionType(M, AbstractionPattern(origType), substInterfaceType,
extInfo, SelectorFamilyConventions(family),
extInfo, ObjCSelectorFamilyConventions(family),
foreignInfo, constant, constant,
/*requirement subs*/None,
/*witnessMethodConformance=*/None);
Expand Down Expand Up @@ -1967,10 +1929,10 @@ getUncachedSILFunctionTypeForConstant(SILModule &M,

// If the decl belongs to an ObjC method family, use that family's
// ownership conventions.
return getSILFunctionTypeForSelectorFamily(M, getSelectorFamily(constant),
origLoweredInterfaceType,
origLoweredInterfaceType,
extInfo, foreignInfo, constant);
return getSILFunctionTypeForObjCSelectorFamily(
M, getObjCSelectorFamily(constant),
origLoweredInterfaceType, origLoweredInterfaceType,
extInfo, foreignInfo, constant);
}

CanSILFunctionType TypeConverter::
Expand Down