Switch ValueDecl::getObjCSelector() and friends over to ObjCSelector.

Formatting names into strings repeatedly, and using those for semantic
analysis, is generally considered poor form. Additionally, use the
camelCase utilities to perform the string manipulation we need, and
cache results on the ObjCAttr so we don't repeatedly do string
manipulation.

Swift SVN r16334
This commit is contained in:
Doug Gregor
2014-04-14 22:02:51 +00:00
parent 204c7006c4
commit 53b84c121e
9 changed files with 157 additions and 155 deletions

View File

@@ -3049,12 +3049,12 @@ public:
bool usesObjCGetterAndSetter() const;
/// Given that this is an Objective-C property or subscript declaration,
/// produce its getter selector in the given buffer (as UTF-8).
StringRef getObjCGetterSelector(SmallVectorImpl<char> &buffer) const;
/// produce its getter selector.
ObjCSelector getObjCGetterSelector() const;
/// Given that this is an Objective-C property or subscript declaration,
/// produce its setter selector in the given buffer (as UTF-8).
StringRef getObjCSetterSelector(SmallVectorImpl<char> &buffer) const;
/// produce its setter selector.
ObjCSelector getObjCSetterSelector() const;
AbstractStorageDecl *getOverriddenDecl() const {
return OverriddenDecl.getPointer();
@@ -3373,7 +3373,7 @@ public:
}
/// Retrieve the Objective-C selector that names this method.
StringRef getObjCSelector(SmallVectorImpl<char> &buffer) const;
ObjCSelector getObjCSelector() const;
/// Determine the default argument kind and type for the given argument index
/// in this declaration, which must be a function or constructor.
@@ -3722,9 +3722,8 @@ public:
/// return type.
DynamicSelfType *getDynamicSelfInterface() const;
/// Given that this is an Objective-C method declaration, produce
/// its selector in the given buffer (as UTF-8).
StringRef getObjCSelector(SmallVectorImpl<char> &buffer) const;
/// Given that this is an Objective-C method declaration, get its selector.
ObjCSelector getObjCSelector() const;
void getLocalCaptures(SmallVectorImpl<CaptureInfo::
LocalCaptureTy> &Result) const {
@@ -3955,9 +3954,8 @@ public:
/// \brief Get the type of the constructed object.
Type getResultType() const;
/// Given that this is an Objective-C method declaration, produce
/// its selector in the given buffer (as UTF-8).
StringRef getObjCSelector(SmallVectorImpl<char> &buffer) const;
/// Given that this is an Objective-C method declaration, get its selector.
ObjCSelector getObjCSelector() const;
/// Get the type of the initializing constructor.
Type getInitializerType() const { return InitializerType; }
@@ -4075,7 +4073,7 @@ public:
/// Retrieve the Objective-C selector associated with the destructor.
///
/// This is always "dealloc".
StringRef getObjCSelector(SmallVectorImpl<char> &buffer) const;
ObjCSelector getObjCSelector() const;
static bool classof(const Decl *D) {
return D->getKind() == DeclKind::Destructor;

View File

@@ -474,8 +474,8 @@ ERROR(override_decl_extension,sema_tcd,none,
NOTE(overridden_here,sema_tcd,none,
"overridden declaration is here", ())
ERROR(override_objc_type_mismatch_method,sema_tcd,none,
"overriding method with selector '%0' has incompatible type %1",
(StringRef, Type))
"overriding method with selector %0 has incompatible type %1",
(ObjCSelector, Type))
ERROR(override_objc_type_mismatch_subscript,sema_tcd,none,
"overriding %select{|indexed |keyed }0subscript with incompatible type "
"%1",

View File

@@ -23,10 +23,16 @@
# error Must define IDENTIFIER_WITH_NAME(Name, IdStr) before including this x-macro file
#endif
IDENTIFIER(atIndexedSubscript)
IDENTIFIER(dealloc)
IDENTIFIER(deinit)
IDENTIFIER(forKeyedSubscript)
IDENTIFIER(init)
IDENTIFIER(objectAtIndexedSubscript)
IDENTIFIER(objectForKeyedSubscript)
IDENTIFIER(self)
IDENTIFIER(Self)
IDENTIFIER(setObject)
IDENTIFIER(subscript)
IDENTIFIER_WITH_NAME(MatchOperator, "~=")

View File

@@ -1670,75 +1670,72 @@ void AbstractStorageDecl::setObservingAccessors(FuncDecl *Get,
Set->makeAccessor(this, AccessorKind::IsSetter);
}
StringRef AbstractStorageDecl::
getObjCGetterSelector(SmallVectorImpl<char> &buffer) const {
ObjCSelector AbstractStorageDecl::getObjCGetterSelector() const {
// If the getter has an @objc attribute with a name, use that.
if (auto getter = getGetter()) {
if (auto objcAttr = getter->getAttrs().getAttribute<ObjCAttr>()) {
if (auto name = objcAttr->getName())
return name->getString(buffer);
return *name;
}
}
llvm::raw_svector_ostream out(buffer);
// Subscripts use a specific selector.
auto &ctx = getASTContext();
if (auto *SD = dyn_cast<SubscriptDecl>(this)) {
switch (SD->getObjCSubscriptKind()) {
case ObjCSubscriptKind::None:
llvm_unreachable("Not an Objective-C subscript");
case ObjCSubscriptKind::Indexed:
out << "objectAtIndexedSubscript:";
break;
return ObjCSelector(ctx, 1, ctx.Id_objectAtIndexedSubscript);
case ObjCSubscriptKind::Keyed:
out << "objectForKeyedSubscript:";
break;
return ObjCSelector(ctx, 1, ctx.Id_objectForKeyedSubscript);
}
return out.str();
}
// The getter selector is the property name itself.
return getName().str();
return ObjCSelector(ctx, 0, getName());
}
StringRef AbstractStorageDecl::getObjCSetterSelector(SmallVectorImpl<char> &buffer) const {
ObjCSelector AbstractStorageDecl::getObjCSetterSelector() const {
// If the setter has an @objc attribute with a name, use that.
if (auto setter = getSetter()) {
if (auto objcAttr = setter->getAttrs().getAttribute<ObjCAttr>()) {
auto setter = getSetter();
auto objcAttr = setter ? setter->getAttrs().getAttribute<ObjCAttr>()
: nullptr;
if (objcAttr) {
if (auto name = objcAttr->getName())
return name->getString(buffer);
return *name;
}
}
llvm::raw_svector_ostream out(buffer);
// Subscripts use a specific selector.
auto &ctx = getASTContext();
if (auto *SD = dyn_cast<SubscriptDecl>(this)) {
switch (SD->getObjCSubscriptKind()) {
case ObjCSubscriptKind::None:
llvm_unreachable("Not an Objective-C subscript");
case ObjCSubscriptKind::Indexed:
out << "setObject:atIndexedSubscript:";
break;
return ObjCSelector(ctx, 2,
{ ctx.Id_setObject, ctx.Id_atIndexedSubscript });
case ObjCSubscriptKind::Keyed:
out << "setObject:forKeyedSubscript:";
break;
return ObjCSelector(ctx, 2,
{ ctx.Id_setObject, ctx.Id_forKeyedSubscript });
}
return out.str();
}
// The setter selector for, e.g., 'fooBar' is 'setFooBar:', with the
// property name capitalized and preceded by 'set'.
StringRef name = getName().str();
assert(name.size() >= 1 && "empty var name?!");
llvm::SmallString<16> scratch1, scratch2;
scratch1 += "set";
scratch1 += camel_case::toSentencecase(getName().str(), scratch2);
out << "set" << clang::toUppercase(name[0])
<< name.slice(1, name.size()) << ':';
return out.str();
auto result = ObjCSelector(ctx, 1, ctx.getIdentifier(scratch1));
// Cache the result, so we don't perform string manipulation again.
if (objcAttr)
const_cast<ObjCAttr *>(objcAttr)->setName(result);
return result;
}
SourceLoc AbstractStorageDecl::getOverrideLoc() const {
@@ -2130,14 +2127,13 @@ SourceRange AbstractFunctionDecl::getBodySourceRange() const {
}
}
StringRef AbstractFunctionDecl::getObjCSelector(
SmallVectorImpl<char> &buffer) const {
ObjCSelector AbstractFunctionDecl::getObjCSelector() const {
if (auto func = dyn_cast<FuncDecl>(this))
return func->getObjCSelector(buffer);
return func->getObjCSelector();
if (auto ctor = dyn_cast<ConstructorDecl>(this))
return ctor->getObjCSelector(buffer);
return ctor->getObjCSelector();
if (auto dtor = dyn_cast<DestructorDecl>(this))
return dtor->getObjCSelector(buffer);
return dtor->getObjCSelector();
llvm_unreachable("Unhandled AbstractFunctionDecl subclass");
}
@@ -2333,27 +2329,21 @@ DynamicSelfType *FuncDecl::getDynamicSelfInterface() const {
}
/// Produce the selector for this "Objective-C method" in the given buffer.
StringRef FuncDecl::getObjCSelector(SmallVectorImpl<char> &buffer) const {
ObjCSelector FuncDecl::getObjCSelector() const {
// For a getter or setter, go through the variable or subscript decl.
if (isGetterOrSetter()) {
auto asd = cast<AbstractStorageDecl>(getAccessorStorageDecl());
return isGetter() ? asd->getObjCGetterSelector(buffer)
: asd->getObjCSetterSelector(buffer);
return isGetter() ? asd->getObjCGetterSelector()
: asd->getObjCSetterSelector();
}
// If there is an @objc attribute with a name, use that name.
if (auto objc = getAttrs().getAttribute<ObjCAttr>()) {
auto objc = getAttrs().getAttribute<ObjCAttr>();
if (objc) {
if (auto name = objc->getName())
return name->getString(buffer);
return *name;
}
assert(buffer.empty());
llvm::raw_svector_ostream out(buffer);
// Start with the method name.
out << getName().str();
// We should always have exactly two levels of argument pattern.
auto argPatterns = getArgParamPatterns();
assert(argPatterns.size() == 2);
@@ -2361,44 +2351,46 @@ StringRef FuncDecl::getObjCSelector(SmallVectorImpl<char> &buffer) const {
auto tuple = dyn_cast<TuplePattern>(pattern);
// If it's an empty tuple pattern, it's a nullary selector.
auto &ctx = getASTContext();
if (tuple && tuple->getNumFields() == 0)
return out.str();
return ObjCSelector(ctx, 0, getName());
// Otherwise, it's at least a unary selector.
// If the first tuple element has a name, uppercase and emit it.
if (tuple && getASTContext().LangOpts.SplitPrepositions) {
llvm::SmallString<16> scratch;
if (auto named = dyn_cast<NamedPattern>(
tuple->getFields()[0].getPattern()
->getSemanticsProvidingPattern())) {
out << camel_case::toSentencecase(named->getBoundName().str(), scratch);
}
}
out << ':';
// If it's a unary selector, we're done.
// If it's a unary selector with no name for the first argument, we're done.
if (!tuple) {
return out.str();
return ObjCSelector(ctx, 1, getName());
}
// For every element except the first, add a selector component.
// Attach the first parameter name to the base name.
auto firstPiece = getName();
bool didStringManipulation = false;
if (tuple && ctx.LangOpts.SplitPrepositions) {
llvm::SmallString<32> scratch1, scratch2;
scratch1 += firstPiece.str();
auto firstName = tuple->getFields()[0].getPattern()->getBoundName();
if (!firstName.empty()) {
scratch1 += camel_case::toSentencecase(firstName.str(), scratch2);
firstPiece = ctx.getIdentifier(scratch1);
}
}
// For every element beyond the first, add a selector component.
SmallVector<Identifier, 4> argumentNames;
argumentNames.push_back(firstPiece);
for (auto &elt : tuple->getFields().slice(1)) {
auto eltPattern = elt.getPattern()->getSemanticsProvidingPattern();
// Add a label to the selector component if there's a tag.
if (auto named = dyn_cast<NamedPattern>(eltPattern)) {
out << named->getBoundName().str();
argumentNames.push_back(eltPattern->getBoundName());
}
// Add the colon regardless. Yes, this can sometimes create a
// component that's just a colon, and that's actually a legal
// selector.
out << ':';
}
// Form the result.
auto result = ObjCSelector(ctx, argumentNames.size(), argumentNames);
return out.str();
// If we did any string manipulation, cache the result. We don't want to
// do that again.
if (didStringManipulation && objc)
const_cast<ObjCAttr *>(objc)->setName(result);
return result;
}
SourceRange FuncDecl::getSourceRange() const {
@@ -2460,66 +2452,70 @@ Type ConstructorDecl::getResultType() const {
return ArgTy;
}
/// Produce the selector for this "Objective-C method" in the given buffer.
StringRef
ConstructorDecl::getObjCSelector(SmallVectorImpl<char> &buffer) const {
ObjCSelector ConstructorDecl::getObjCSelector() const {
// If there is an @objc attribute with a name, use that name.
if (auto objc = getAttrs().getAttribute<ObjCAttr>()) {
auto objc = getAttrs().getAttribute<ObjCAttr>();
if (objc) {
if (auto name = objc->getName())
return name->getString(buffer);
return *name;
}
assert(buffer.empty());
llvm::raw_svector_ostream out(buffer);
// In the beginning, there was 'init'.
out << "init";
auto &ctx = getASTContext();
// If there are no parameters, this is just 'init()'.
auto tuple = cast<TuplePattern>(getArgParamPatterns()[1]);
if (tuple->getNumFields() == 0)
return out.str();
return ObjCSelector(ctx, 0, ctx.Id_init);
// The first field is special: we uppercase the name.
bool didStringManipulation = false;
SmallVector<Identifier, 4> selectorPieces;
const auto &firstElt = tuple->getFields()[0];
auto firstPattern = firstElt.getPattern()->getSemanticsProvidingPattern();
if (auto firstNamed = dyn_cast<NamedPattern>(firstPattern)) {
if (!firstNamed->getBoundName().empty()) {
auto nameStr = firstNamed->getBoundName().str();
out << (char)toupper(nameStr[0]);
out << nameStr.substr(1);
auto firstName = firstElt.getPattern()->getBoundName();
if (firstName.empty())
selectorPieces.push_back(ctx.Id_init);
else {
llvm::SmallString<16> scratch1, scratch2;
scratch1 += "init";
scratch1 += camel_case::toSentencecase(firstName.str(), scratch2);
selectorPieces.push_back(ctx.getIdentifier(scratch1));
didStringManipulation = true;
}
// If there is only a single parameter and its type is the empty tuple
// type, we're done: don't add the trailing colon.
// If we have just one field, check whether this is actually a
// nullary selector that we mapped to a single-element initializer to catch
// the name after "init".
if (tuple->getNumFields() == 1) {
auto emptyTupleTy = TupleType::getEmpty(getASTContext());
if (!firstPattern->getType()->isEqual(emptyTupleTy))
out << ':';
return out.str();
}
if (firstPattern->hasType()) {
if (firstPattern->getType()->isEqual(TupleType::getEmpty(ctx))) {
auto result = ObjCSelector(ctx, 0, selectorPieces[0]);
// Continue with the remaining selectors.
out << ':';
// Cache the name in the 'objc' attribute. We don't want to perform
// string manipulation again.
if (objc)
const_cast<ObjCAttr *>(objc)->setName(result);
return result;
}
} else {
// If we couldn't check the type, don't cache the result.
didStringManipulation = false;
}
}
// For every remaining element, add a selector component.
for (auto &elt : tuple->getFields().slice(1)) {
auto eltPattern = elt.getPattern()->getSemanticsProvidingPattern();
// Add a label to the selector component if there's a tag.
if (auto named = dyn_cast<NamedPattern>(eltPattern)) {
out << named->getBoundName().str();
selectorPieces.push_back(elt.getPattern()->getBoundName());
}
// Add the colon regardless. Yes, this can sometimes create a
// component that's just a colon, and that's actually a legal
// selector.
out << ':';
}
auto result = ObjCSelector(ctx, selectorPieces.size(), selectorPieces);
return out.str();
// Cache the name in the 'objc' attribute. We don't want to perform
// string manipulation again.
if (objc && didStringManipulation)
const_cast<ObjCAttr *>(objc)->setName(result);
return result;
}
Type ConstructorDecl::getInitializerInterfaceType() {
@@ -2629,8 +2625,9 @@ ConstructorDecl::getDelegatingOrChainedInitKind(DiagnosticEngine *diags,
return finder.Kind;
}
StringRef DestructorDecl::getObjCSelector(SmallVectorImpl<char> &buffer) const {
return "dealloc";
ObjCSelector DestructorDecl::getObjCSelector() const {
auto &ctx = getASTContext();
return ObjCSelector(ctx, 0, ctx.Id_dealloc);
}
SourceRange DestructorDecl::getSourceRange() const {

View File

@@ -312,18 +312,18 @@ namespace {
Selector() = default;
Selector(FuncDecl *method) {
Text = method->getObjCSelector(Buffer);
Text = method->getObjCSelector().getString(Buffer);
}
Selector(ConstructorDecl *ctor) {
Text = ctor->getObjCSelector(Buffer);
Text = ctor->getObjCSelector().getString(Buffer);
}
Selector(ValueDecl *methodOrCtorOrDtor) {
if (auto *method = dyn_cast<FuncDecl>(methodOrCtorOrDtor)) {
Text = method->getObjCSelector(Buffer);
Text = method->getObjCSelector().getString(Buffer);
} else if (auto *ctor = dyn_cast<ConstructorDecl>(methodOrCtorOrDtor)) {
Text = ctor->getObjCSelector(Buffer);
Text = ctor->getObjCSelector().getString(Buffer);
} else if (isa<DestructorDecl>(methodOrCtorOrDtor)) {
Text = "dealloc";
} else {
@@ -333,11 +333,11 @@ namespace {
}
Selector(AbstractStorageDecl *asd, ForGetter_t) {
Text = asd->getObjCGetterSelector(Buffer);
Text = asd->getObjCGetterSelector().getString(Buffer);
}
Selector(AbstractStorageDecl *asd, ForSetter_t) {
Text = asd->getObjCSetterSelector(Buffer);
Text = asd->getObjCSetterSelector().getString(Buffer);
}
Selector(SILDeclRef ref) {
@@ -354,11 +354,13 @@ namespace {
break;
case SILDeclRef::Kind::Func:
Text = cast<FuncDecl>(ref.getDecl())->getObjCSelector(Buffer);
Text = cast<FuncDecl>(ref.getDecl())->getObjCSelector()
.getString(Buffer);
break;
case SILDeclRef::Kind::Initializer:
Text = cast<ConstructorDecl>(ref.getDecl())->getObjCSelector(Buffer);
Text = cast<ConstructorDecl>(ref.getDecl())->getObjCSelector()
.getString(Buffer);
break;
case SILDeclRef::Kind::IVarInitializer:

View File

@@ -2023,9 +2023,9 @@ void IRGenSILFunction::visitDynamicMethodBranchInst(DynamicMethodBranchInst *i){
StringRef selector;
llvm::SmallString<64> selectorBuffer;
if (auto fnDecl = dyn_cast<FuncDecl>(i->getMember().getDecl()))
selector = fnDecl->getObjCSelector(selectorBuffer);
selector = fnDecl->getObjCSelector().getString(selectorBuffer);
else if (auto var = dyn_cast<AbstractStorageDecl>(i->getMember().getDecl()))
selector = var->getObjCGetterSelector(selectorBuffer);
selector = var->getObjCGetterSelector().getString(selectorBuffer);
else
llvm_unreachable("Unhandled dynamic method branch query");

View File

@@ -414,7 +414,7 @@ private:
assert(bodyPatterns.size() == 2 && "not an ObjC-compatible method");
llvm::SmallString<128> selectorBuf;
StringRef selectorString = AFD->getObjCSelector(selectorBuf);
StringRef selectorString = AFD->getObjCSelector().getString(selectorBuf);
if (isa<ParenPattern>(bodyPatterns.back())) {
// One argument.
@@ -493,10 +493,10 @@ private:
if (overridesObjC) {
llvm::SmallString<64> buffer;
os << ", getter=" << VD->getObjCGetterSelector(buffer);
os << ", getter=" << VD->getObjCGetterSelector().getString(buffer);
if (VD->isSettable(nullptr)) {
buffer.clear();
os << ", setter=" << VD->getObjCSetterSelector(buffer);
os << ", setter=" << VD->getObjCSetterSelector().getString(buffer);
}
}

View File

@@ -151,7 +151,8 @@ getDynamicResultSignature(ValueDecl *decl,
Type type;
if (auto func = dyn_cast<FuncDecl>(decl)) {
// Handle functions.
selector = func->getObjCSelector(buffer);
// FIXME: Use ObjCSelector here!
selector = func->getObjCSelector().getString(buffer);
type = decl->getType()->castTo<AnyFunctionType>()->getResult();
// Append a '+' for static methods, '-' for instance methods. This
@@ -165,11 +166,11 @@ getDynamicResultSignature(ValueDecl *decl,
selector = buffer.str();
} else if (auto asd = dyn_cast<AbstractStorageDecl>(decl)) {
// Handle properties and subscripts. Only the getter matters.
selector = asd->getObjCGetterSelector(buffer);
selector = asd->getObjCGetterSelector().getString(buffer);
type = asd->getType();
} else if (auto ctor = dyn_cast<ConstructorDecl>(decl)) {
// Handle constructors.
selector = ctor->getObjCSelector(buffer);
selector = ctor->getObjCSelector().getString(buffer);
type = decl->getType()->castTo<AnyFunctionType>()->getResult();
} else {
llvm_unreachable("Dynamic lookup found a non-[objc] result");

View File

@@ -3273,13 +3273,12 @@ public:
uncurriedDeclTy = uncurriedDeclTy->getUnlabeledType(TC.Context);
// If the method is an Objective-C method, compute its selector.
llvm::SmallString<32> methodSelectorBuffer;
StringRef methodSelector;
Optional<ObjCSelector> methodSelector;
ObjCSubscriptKind subscriptKind = ObjCSubscriptKind::None;
if (decl->isObjC()) {
if (method)
methodSelector = method->getObjCSelector(methodSelectorBuffer);
methodSelector = method->getObjCSelector();
else if (auto *subscript = dyn_cast<SubscriptDecl>(abstractStorage))
subscriptKind = subscript->getObjCSubscriptKind();
}
@@ -3318,8 +3317,7 @@ public:
if (decl->isObjC() && parentDecl->isObjC()) {
if (method) {
// If the selectors don't match, it's not an override.
llvm::SmallString<32> buffer;
if (methodSelector != parentMethod->getObjCSelector(buffer))
if (*methodSelector != parentMethod->getObjCSelector())
continue;
objCMatch = true;
@@ -3377,7 +3375,7 @@ public:
if (objCMatch) {
if (method) {
TC.diagnose(decl, diag::override_objc_type_mismatch_method,
methodSelector, uncurriedDeclTy);
*methodSelector, uncurriedDeclTy);
} else {
TC.diagnose(decl, diag::override_objc_type_mismatch_subscript,
static_cast<unsigned>(subscriptKind), uncurriedDeclTy);