Skip to content

Commit 5dc102b

Browse files
committed
Don’t emit success remarks for bad @objc names
1 parent a6a9dfe commit 5dc102b

File tree

4 files changed

+48
-35
lines changed

4 files changed

+48
-35
lines changed

include/swift/AST/Attr.h

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -854,6 +854,7 @@ class ObjCAttr final : public DeclAttribute,
854854
/// Determine whether the name associated with this attribute was
855855
/// implicit.
856856
bool isNameImplicit() const { return Bits.ObjCAttr.ImplicitName; }
857+
void setNameImplicit(bool newValue) { Bits.ObjCAttr.ImplicitName = newValue; }
857858

858859
/// Set the name of this entity.
859860
void setName(ObjCSelector name, bool implicit) {
@@ -882,11 +883,6 @@ class ObjCAttr final : public DeclAttribute,
882883
Bits.ObjCAttr.Swift3Inferred = inferred;
883884
}
884885

885-
/// Clear the name of this entity.
886-
void clearName() {
887-
NameData = nullptr;
888-
}
889-
890886
/// Retrieve the source locations for the names in a non-implicit
891887
/// nullary or selector attribute.
892888
ArrayRef<SourceLoc> getNameLocs() const;

lib/Sema/TypeCheckAttr.cpp

Lines changed: 23 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -997,6 +997,17 @@ void AttributeChecker::visitObjCAttr(ObjCAttr *attr) {
997997
return;
998998
}
999999

1000+
auto correctNameUsingNewAttr = [&](ObjCAttr *newAttr) {
1001+
if (attr->isInvalid()) newAttr->setInvalid();
1002+
newAttr->setImplicit(attr->isImplicit());
1003+
newAttr->setNameImplicit(attr->isNameImplicit());
1004+
newAttr->setAddedByAccessNote(attr->getAddedByAccessNote());
1005+
1006+
D->getAttrs().add(newAttr);
1007+
D->getAttrs().removeAttribute(attr);
1008+
attr->setInvalid();
1009+
};
1010+
10001011
// If there is a name, check whether the kind of name is
10011012
// appropriate.
10021013
if (auto objcName = attr->getName()) {
@@ -1021,9 +1032,12 @@ void AttributeChecker::visitObjCAttr(ObjCAttr *attr) {
10211032
D->getDescriptiveKind())
10221033
.fixItRemoveChars(afterFirstNameLoc, attr->getRParenLoc())
10231034
.limitBehavior(behavior));
1024-
const_cast<ObjCAttr *>(attr)->setName(
1025-
ObjCSelector(Ctx, 0, objcName->getSelectorPieces()[0]),
1026-
/*implicit=*/false);
1035+
1036+
correctNameUsingNewAttr(
1037+
ObjCAttr::createNullary(Ctx, attr->AtLoc, attr->getLocation(),
1038+
attr->getLParenLoc(), firstNameLoc,
1039+
objcName->getSelectorPieces()[0],
1040+
attr->getRParenLoc()));
10271041
}
10281042
} else if (isa<SubscriptDecl>(D) || isa<DestructorDecl>(D)) {
10291043
SourceLoc diagLoc = attr->getLParenLoc();
@@ -1035,7 +1049,9 @@ void AttributeChecker::visitObjCAttr(ObjCAttr *attr) {
10351049
? diag::objc_name_subscript
10361050
: diag::objc_name_deinit)
10371051
.limitBehavior(behavior));
1038-
const_cast<ObjCAttr *>(attr)->clearName();
1052+
1053+
correctNameUsingNewAttr(
1054+
ObjCAttr::createUnnamed(Ctx, attr->AtLoc, attr->getLocation()));
10391055
} else {
10401056
auto func = cast<AbstractFunctionDecl>(D);
10411057

@@ -1075,9 +1091,9 @@ void AttributeChecker::visitObjCAttr(ObjCAttr *attr) {
10751091
numParameters != 1,
10761092
func->hasThrows())
10771093
.limitBehavior(behavior));
1078-
D->getAttrs().add(
1079-
ObjCAttr::createUnnamed(Ctx, attr->AtLoc, attr->Range.Start));
1080-
D->getAttrs().removeAttribute(attr);
1094+
1095+
correctNameUsingNewAttr(
1096+
ObjCAttr::createUnnamed(Ctx, attr->AtLoc, attr->Range.Start));
10811097
}
10821098
}
10831099
} else if (isa<EnumElementDecl>(D)) {

lib/Sema/TypeCheckDeclObjC.cpp

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1696,13 +1696,14 @@ static ObjCSelector inferObjCName(ValueDecl *decl) {
16961696

16971697
/// Set the @objc name.
16981698
auto setObjCName = [&](ObjCSelector selector) {
1699-
// If there already is an @objc attribute, update its name.
1699+
// If there already is an @objc attribute, invalidate and remove it. (This
1700+
// helps with access notes.)
17001701
if (attr) {
1701-
const_cast<ObjCAttr *>(attr)->setName(selector, /*implicit=*/true);
1702-
return;
1702+
attr->setInvalid();
1703+
decl->getAttrs().removeAttribute(attr);
17031704
}
17041705

1705-
// Otherwise, create an @objc attribute with the implicit name.
1706+
// Create an @objc attribute with the implicit name.
17061707
attr = ObjCAttr::create(ctx, selector, /*implicitName=*/true);
17071708
decl->getAttrs().add(attr);
17081709
};
@@ -2178,7 +2179,7 @@ bool swift::fixDeclarationObjCName(InFlightDiagnostic &diag, const ValueDecl *de
21782179
// about implicit ones because they don't have useful source location
21792180
// information.
21802181
auto attr = decl->getAttrs().getAttribute<ObjCAttr>();
2181-
if (attr && attr->isImplicit())
2182+
if (attr && (attr->isImplicit() || attr->getLocation().isInvalid()))
21822183
attr = nullptr;
21832184

21842185
// If there is an @objc attribute with an explicit, incorrect witness

test/attr/attr_objc.swift

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -2003,51 +2003,51 @@ extension PlainClass {
20032003
func badlyNamed(_: Int, y: Int) {}
20042004
}
20052005

2006-
@objc(Class:) // access-note-move{{BadClass1}} expected-error{{'@objc' class must have a simple name}}{{12-13=}}
2006+
@objc(Class:) // bad-access-note-move{{BadClass1}} expected-error{{'@objc' class must have a simple name}}{{12-13=}}
20072007
class BadClass1 { }
20082008

2009-
@objc(Protocol:) // access-note-move{{BadProto1}} expected-error{{'@objc' protocol must have a simple name}}{{15-16=}}
2009+
@objc(Protocol:) // bad-access-note-move{{BadProto1}} expected-error{{'@objc' protocol must have a simple name}}{{15-16=}}
20102010
protocol BadProto1 { }
20112011

2012-
@objc(Enum:) // access-note-move{{BadEnum1}} expected-error{{'@objc' enum must have a simple name}}{{11-12=}}
2012+
@objc(Enum:) // bad-access-note-move{{BadEnum1}} expected-error{{'@objc' enum must have a simple name}}{{11-12=}}
20132013
enum BadEnum1: Int { case X }
20142014

20152015
@objc // access-note-move{{BadEnum2}}
20162016
enum BadEnum2: Int {
2017-
@objc(X:) // access-note-move{{BadEnum2.X}} expected-error{{'@objc' enum case must have a simple name}}{{10-11=}}
2017+
@objc(X:) // bad-access-note-move{{BadEnum2.X}} expected-error{{'@objc' enum case must have a simple name}}{{10-11=}}
20182018
case X
20192019
}
20202020

20212021
class BadClass2 {
20222022
@objc(realDealloc) // expected-error{{'@objc' deinitializer cannot have a name}}
20232023
deinit { }
20242024

2025-
@objc(badprop:foo:wibble:) // access-note-move{{BadClass2.badprop}} expected-error{{'@objc' property must have a simple name}}{{16-28=}}
2025+
@objc(badprop:foo:wibble:) // bad-access-note-move{{BadClass2.badprop}} expected-error{{'@objc' property must have a simple name}}{{16-28=}}
20262026
var badprop: Int = 5
20272027

2028-
@objc(foo) // access-note-move{{BadClass2.subscript(_:)}} expected-error{{'@objc' subscript cannot have a name; did you mean to put the name on the getter or setter?}}
2028+
@objc(foo) // bad-access-note-move{{BadClass2.subscript(_:)}} expected-error{{'@objc' subscript cannot have a name; did you mean to put the name on the getter or setter?}}
20292029
subscript (i: Int) -> Int {
20302030
get {
20312031
return i
20322032
}
20332033
}
20342034

2035-
@objc(foo) // access-note-move{{BadClass2.noArgNamesOneParam(x:)}} expected-error{{'@objc' method name provides names for 0 arguments, but method has one parameter}}
2035+
@objc(foo) // bad-access-note-move{{BadClass2.noArgNamesOneParam(x:)}} expected-error{{'@objc' method name provides names for 0 arguments, but method has one parameter}}
20362036
func noArgNamesOneParam(x: Int) { }
20372037

2038-
@objc(foo) // access-note-move{{BadClass2.noArgNamesOneParam2(_:)}} expected-error{{'@objc' method name provides names for 0 arguments, but method has one parameter}}
2038+
@objc(foo) // bad-access-note-move{{BadClass2.noArgNamesOneParam2(_:)}} expected-error{{'@objc' method name provides names for 0 arguments, but method has one parameter}}
20392039
func noArgNamesOneParam2(_: Int) { }
20402040

2041-
@objc(foo) // access-note-move{{BadClass2.noArgNamesTwoParams(_:y:)}} expected-error{{'@objc' method name provides names for 0 arguments, but method has 2 parameters}}
2041+
@objc(foo) // bad-access-note-move{{BadClass2.noArgNamesTwoParams(_:y:)}} expected-error{{'@objc' method name provides names for 0 arguments, but method has 2 parameters}}
20422042
func noArgNamesTwoParams(_: Int, y: Int) { }
20432043

2044-
@objc(foo:) // access-note-move{{BadClass2.oneArgNameTwoParams(_:y:)}} expected-error{{'@objc' method name provides one argument name, but method has 2 parameters}}
2044+
@objc(foo:) // bad-access-note-move{{BadClass2.oneArgNameTwoParams(_:y:)}} expected-error{{'@objc' method name provides one argument name, but method has 2 parameters}}
20452045
func oneArgNameTwoParams(_: Int, y: Int) { }
20462046

2047-
@objc(foo:) // access-note-move{{BadClass2.oneArgNameNoParams()}} expected-error{{'@objc' method name provides one argument name, but method has 0 parameters}}
2047+
@objc(foo:) // bad-access-note-move{{BadClass2.oneArgNameNoParams()}} expected-error{{'@objc' method name provides one argument name, but method has 0 parameters}}
20482048
func oneArgNameNoParams() { }
20492049

2050-
@objc(foo:) // access-note-move{{BadClass2.init()}} expected-error{{'@objc' initializer name provides one argument name, but initializer has 0 parameters}}
2050+
@objc(foo:) // bad-access-note-move{{BadClass2.init()}} expected-error{{'@objc' initializer name provides one argument name, but initializer has 0 parameters}}
20512051
init() { }
20522052

20532053
var _prop = 5
@@ -2098,14 +2098,14 @@ class Super {
20982098
}
20992099

21002100
class Sub1 : Super {
2101-
@objc(foo) // access-note-move{{Sub1.foo}} expected-error{{Objective-C property has a different name from the property it overrides ('foo' vs. 'renamedFoo')}}{{9-12=renamedFoo}}
2101+
@objc(foo) // bad-access-note-move{{Sub1.foo}} expected-error{{Objective-C property has a different name from the property it overrides ('foo' vs. 'renamedFoo')}}{{9-12=renamedFoo}}
21022102
override var foo: Int { get { return 5 } }
21032103

21042104
override func process(i: Int?) -> Int { } // expected-error{{method cannot be an @objc override because the type of the parameter cannot be represented in Objective-C}}
21052105
}
21062106

21072107
class Sub2 : Super {
2108-
@objc // access-note-move{{Sub2.foo}}
2108+
@objc // bad-access-note-move{{Sub2.foo}} -- @objc is already implied by overriding an @objc attribute, so access notes shouldn't emit a remark
21092109
override var foo: Int { get { return 5 } }
21102110
}
21112111

@@ -2119,7 +2119,7 @@ class Sub4 : Super {
21192119
}
21202120

21212121
class Sub5 : Super {
2122-
@objc(wrongFoo) // access-note-move{{Sub5.foo}} expected-error{{Objective-C property has a different name from the property it overrides ('wrongFoo' vs. 'renamedFoo')}} {{9-17=renamedFoo}}
2122+
@objc(wrongFoo) // bad-access-note-move{{Sub5.foo}} expected-error{{Objective-C property has a different name from the property it overrides ('wrongFoo' vs. 'renamedFoo')}} {{9-17=renamedFoo}}
21232123
override var foo: Int { get { return 5 } }
21242124
}
21252125

@@ -2402,10 +2402,10 @@ class ThrowsObjCName {
24022402
@objc(method5AndReturnError:x:closure:) // access-note-move{{ThrowsObjCName.method5(x:closure:)}}
24032403
func method5(x: Int, closure: @escaping (Int) -> Int) throws { }
24042404

2405-
@objc(method6) // access-note-move{{ThrowsObjCName.method6()}} expected-error{{'@objc' method name provides names for 0 arguments, but method has one parameter (the error parameter)}}
2405+
@objc(method6) // bad-access-note-move{{ThrowsObjCName.method6()}} expected-error{{'@objc' method name provides names for 0 arguments, but method has one parameter (the error parameter)}}
24062406
func method6() throws { }
24072407

2408-
@objc(method7) // access-note-move{{ThrowsObjCName.method7(x:)}} expected-error{{'@objc' method name provides names for 0 arguments, but method has 2 parameters (including the error parameter)}}
2408+
@objc(method7) // bad-access-note-move{{ThrowsObjCName.method7(x:)}} expected-error{{'@objc' method name provides names for 0 arguments, but method has 2 parameters (including the error parameter)}}
24092409
func method7(x: Int) throws { }
24102410

24112411
// CHECK-DUMP: func_decl{{.*}}"method8(_:fn1:fn2:)"{{.*}}foreign_error=ZeroResult,unowned,param=2,paramtype=Optional<AutoreleasingUnsafeMutablePointer<Optional<NSError>>>,resulttype=ObjCBool
@@ -2432,7 +2432,7 @@ protocol ProtocolThrowsObjCName {
24322432
}
24332433

24342434
class ConformsToProtocolThrowsObjCName1 : ProtocolThrowsObjCName {
2435-
@objc // access-note-move{{ConformsToProtocolThrowsObjCName1.doThing(_:)}}
2435+
@objc // bad-access-note-move{{ConformsToProtocolThrowsObjCName1.doThing(_:)}} -- @objc inherited, so no remarks
24362436
func doThing(_ x: String) throws -> String { return x } // okay
24372437
}
24382438

0 commit comments

Comments
 (0)