Skip to content

Commit feca4e6

Browse files
committed
Let access notes apply to accessors
`Name: ‘getter:Context.property()’` now applies an access note to a getter of Context.property, and `Name: ‘setter:Context.property(_:)’` applies one to its setter. Additionally, access notes without `getter:` or `setter:` now cannot apply to accessors.
1 parent 9ca2fbd commit feca4e6

File tree

4 files changed

+37
-8
lines changed

4 files changed

+37
-8
lines changed

include/swift/AST/AccessNotes.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#define ACCESSNOTES_H
2020

2121
#include "swift/AST/Identifier.h"
22+
#include "swift/AST/StorageImpl.h"
2223
#include "swift/Basic/NullablePtr.h"
2324
#include "llvm/Support/Error.h"
2425
#include "llvm/Support/MemoryBuffer.h"
@@ -33,6 +34,7 @@ class AccessNoteDeclName {
3334
public:
3435
std::vector<Identifier> parentNames;
3536
DeclName name;
37+
Optional<AccessorKind> accessorKind;
3638

3739
AccessNoteDeclName(ASTContext &ctx, StringRef str);
3840
AccessNoteDeclName();

lib/AST/AccessNotes.cpp

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,8 @@ parseObjCSelector(swift::ASTContext &ctx, llvm::StringRef string) {
6262

6363
namespace swift {
6464

65-
AccessNoteDeclName::AccessNoteDeclName() : parentNames(), name() { }
65+
AccessNoteDeclName::AccessNoteDeclName()
66+
: parentNames(), name(), accessorKind(None) { }
6667

6768
AccessNoteDeclName::AccessNoteDeclName(ASTContext &ctx, StringRef str) {
6869
auto parsedName = parseDeclName(str);
@@ -73,6 +74,13 @@ AccessNoteDeclName::AccessNoteDeclName(ASTContext &ctx, StringRef str) {
7374
parentNames.push_back(ctx.getIdentifier(first));
7475
}
7576

77+
if (parsedName.IsGetter)
78+
accessorKind = AccessorKind::Get;
79+
else if (parsedName.IsSetter)
80+
accessorKind = AccessorKind::Set;
81+
else
82+
accessorKind = None;
83+
7684
name = parsedName.formDeclName(ctx);
7785

7886
// FIXME: parseDeclName() doesn't handle the special `subscript` name.
@@ -84,10 +92,20 @@ AccessNoteDeclName::AccessNoteDeclName(ASTContext &ctx, StringRef str) {
8492
}
8593

8694
bool AccessNoteDeclName::matches(ValueDecl *VD) const {
95+
// These are normally just `VD` and `name`, but not for accessors.
8796
auto lookupVD = VD;
88-
if (auto accessor = dyn_cast<AccessorDecl>(VD))
89-
VD = accessor->getStorage();
9097

98+
// First, we check if the accessor-ness of `VD` matches the accessor-ness of
99+
// the name, and update `lookupVD` if necessary.
100+
if (auto accessor = dyn_cast<AccessorDecl>(VD)) {
101+
if (!accessorKind || *accessorKind != accessor->getAccessorKind())
102+
return false;
103+
lookupVD = accessor->getStorage();
104+
}
105+
else if (accessorKind.hasValue())
106+
return false;
107+
108+
// Check that `name` matches `lookupVD`.
91109
if (!lookupVD->getName().matchesRef(name))
92110
return false;
93111

@@ -125,6 +143,9 @@ bool AccessNoteDeclName::empty() const {
125143
}
126144

127145
void AccessNoteDeclName::print(llvm::raw_ostream &os) const {
146+
if (accessorKind)
147+
os << getAccessorLabel(*accessorKind) << "ter:";
148+
128149
for (auto parentName : parentNames)
129150
os << parentName << '.';
130151
name.print(os, /*skipEmptyArgumentNames=*/false);
@@ -259,7 +280,7 @@ StringRef MappingTraits<AccessNote>::validate(IO &io, AccessNote &note) {
259280
if (!note.ObjC)
260281
note.ObjC = true;
261282
else if (!*note.ObjC)
262-
return "cannot have an 'ObjCName' if 'ObjC' is false";
283+
return "cannot have an 'ObjCName' if 'ObjC' is false";
263284
}
264285

265286
return "";

test/SILGen/Inputs/objc_access_notes.accessnotes

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,10 @@ Notes:
3232
ObjC: true
3333
- Name: 'Hoozit.propComputed'
3434
ObjC: true
35-
# FIXME: Add a way to specify getter and setter names in an access note
35+
- Name: 'getter:Hoozit.propComputed()'
36+
ObjCName: 'initPropComputedGetter'
37+
- Name: 'setter:Hoozit.propComputed(_:)'
38+
ObjCName: 'initPropComputedSetter:'
3639
- Name: 'Hoozit.roProperty'
3740
ObjC: true
3841
- Name: 'Hoozit.rwProperty'

test/SILGen/objc_access_notes.swift

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -352,9 +352,12 @@ class Hoozit : Gizmo {
352352
// expected-warning@+2 {{access note for fancy test suite adds attribute 'objc' to this property}}
353353
// expected-note@+1 {{add attribute explicitly to silence this warning}} {{3-3=@objc }}
354354
var propComputed: Gizmo {
355-
// FIXME: Add a way to specify these names in an access note.
356-
@objc(initPropComputedGetter) get { return self }
357-
@objc(initPropComputedSetter:) set {}
355+
// expected-warning@+2 {{access note for fancy test suite adds attribute 'objc' to this getter}}
356+
// expected-note@+1 {{add attribute explicitly to silence this warning}} {{5-5=@objc(initPropComputedGetter) }}
357+
get { return self }
358+
// expected-warning@+2 {{access note for fancy test suite adds attribute 'objc' to this setter}}
359+
// expected-note@+1 {{add attribute explicitly to silence this warning}} {{5-5=@objc(initPropComputedSetter:) }}
360+
set {}
358361
}
359362
// -- getter
360363
// CHECK-LABEL: sil hidden [thunk] [ossa] @$s11objc_thunks6HoozitC12propComputedSo5GizmoCvgTo : $@convention(objc_method) (Hoozit) -> @autoreleased Gizmo {

0 commit comments

Comments
 (0)