Skip to content

Commit

Permalink
Merge pull request #23028 from brentdax/all-in-the-family-5.1
Browse files Browse the repository at this point in the history
[5.1] [NFC] Move selector family logic to ObjCSelector
  • Loading branch information
beccadax committed Mar 2, 2019
2 parents b89b723 + b223ccb commit 2283543
Show file tree
Hide file tree
Showing 4 changed files with 97 additions and 73 deletions.
8 changes: 8 additions & 0 deletions include/swift/AST/Identifier.h
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
@@ -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
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
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

0 comments on commit 2283543

Please sign in to comment.