Skip to content

Commit b721488

Browse files
authored
Merge pull request swiftlang#37992 from jackgmarch/SR-4559
[SR-4559] Warn when unapplied reference to a function 'self' is referenced in property initialiser
2 parents e2c583e + 7e0a7f3 commit b721488

File tree

3 files changed

+118
-0
lines changed

3 files changed

+118
-0
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3756,8 +3756,13 @@ NOTE(add_self_to_type,none,
37563756
WARNING(warn_unqualified_access,none,
37573757
"use of %0 treated as a reference to %1 in %2 %3",
37583758
(Identifier, DescriptiveDeclKind, DescriptiveDeclKind, DeclName))
3759+
WARNING(self_refers_to_method,none,
3760+
"'self' refers to the method '%0.self', which may be unexpected",
3761+
(StringRef))
37593762
NOTE(fix_unqualified_access_member,none,
37603763
"use 'self.' to silence this warning", ())
3764+
NOTE(fix_unqualified_access_member_named_self,none,
3765+
"use '%0.self' to silence this warning", (StringRef))
37613766
NOTE(fix_unqualified_access_top_level,none,
37623767
"use '%0' to reference the %1",
37633768
(StringRef, DescriptiveDeclKind, Identifier))

lib/Sema/MiscDiagnostics.cpp

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4664,6 +4664,60 @@ static void diagnoseComparisonWithNaN(const Expr *E, const DeclContext *DC) {
46644664
const_cast<Expr *>(E)->walk(Walker);
46654665
}
46664666

4667+
static void diagUnqualifiedAccessToMethodNamedSelf(const Expr *E,
4668+
const DeclContext *DC) {
4669+
if (!E || isa<ErrorExpr>(E) || !E->getType())
4670+
return;
4671+
4672+
class DiagnoseWalker : public ASTWalker {
4673+
ASTContext &Ctx;
4674+
const DeclContext *DC;
4675+
4676+
public:
4677+
DiagnoseWalker(const DeclContext *DC) : Ctx(DC->getASTContext()), DC(DC) {}
4678+
4679+
bool shouldWalkIntoSeparatelyCheckedClosure(ClosureExpr *expr) override {
4680+
return false;
4681+
}
4682+
4683+
bool shouldWalkIntoTapExpression() override { return false; }
4684+
4685+
std::pair<bool, Expr *> walkToExprPre(Expr *E) override {
4686+
if (!E || isa<ErrorExpr>(E) || !E->getType())
4687+
return {false, E};
4688+
4689+
if (auto *declRefExpr = dyn_cast<DeclRefExpr>(E)) {
4690+
if (declRefExpr->getDecl()->getBaseName() == Ctx.Id_self &&
4691+
declRefExpr->getType()->is<AnyFunctionType>()) {
4692+
if (auto typeContext = DC->getInnermostTypeContext()) {
4693+
// self() is not easily confusable
4694+
if (!isa<CallExpr>(Parent.getAsExpr())) {
4695+
4696+
auto baseType = typeContext->getDeclaredInterfaceType();
4697+
auto baseTypeString = baseType.getString();
4698+
4699+
Ctx.Diags.diagnose(E->getLoc(), diag::self_refers_to_method,
4700+
baseTypeString);
4701+
4702+
Ctx.Diags
4703+
.diagnose(E->getLoc(),
4704+
diag::fix_unqualified_access_member_named_self,
4705+
baseTypeString)
4706+
.fixItInsert(E->getLoc(), diag::insert_type_qualification,
4707+
baseType);
4708+
}
4709+
}
4710+
}
4711+
}
4712+
4713+
return {true, E};
4714+
}
4715+
};
4716+
4717+
DiagnoseWalker Walker(DC);
4718+
const_cast<Expr *>(E)->walk(Walker);
4719+
}
4720+
46674721
namespace {
46684722

46694723
class CompletionHandlerUsageChecker final : public ASTWalker {
@@ -4749,6 +4803,7 @@ void swift::performSyntacticExprDiagnostics(const Expr *E,
47494803
if (ctx.LangOpts.EnableObjCInterop)
47504804
diagDeprecatedObjCSelectors(DC, E);
47514805
diagnoseConstantArgumentRequirement(E, DC);
4806+
diagUnqualifiedAccessToMethodNamedSelf(E, DC);
47524807
}
47534808

47544809
void swift::performStmtDiagnostics(const Stmt *S, DeclContext *DC) {

test/Parse/self_rebinding.swift

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,3 +58,61 @@ class MyCls {
5858
something() // this should still refer `MyCls.something`.
5959
}
6060
}
61+
62+
// MARK: fix method called 'self' can be confused with regular 'self' https://bugs.swift.org/browse/SR-4559
63+
64+
func funcThatReturnsSomething(_ any: Any) -> Any {
65+
any
66+
}
67+
68+
struct TypeWithSelfMethod {
69+
70+
let property = self // expected-warning {{'self' refers to the method 'TypeWithSelfMethod.self', which may be unexpected}} expected-note{{use 'TypeWithSelfMethod.self' to silence this warning}} {{20-20=TypeWithSelfMethod.}}
71+
72+
// Existing warning expected, not confusable
73+
let property2 = self() // expected-error {{cannot use instance member 'self' within property initializer; property initializers run before 'self' is available}}
74+
75+
let propertyFromClosure: () = {
76+
print(self) // expected-warning {{'self' refers to the method 'TypeWithSelfMethod.self', which may be unexpected}} expected-note{{use 'TypeWithSelfMethod.self' to silence this warning}} {{15-15=TypeWithSelfMethod.}}
77+
}()
78+
79+
let propertyFromFunc = funcThatReturnsSomething(self) // expected-warning {{'self' refers to the method 'TypeWithSelfMethod.self', which may be unexpected}} expected-note{{use 'TypeWithSelfMethod.self' to silence this warning}} {{53-53=TypeWithSelfMethod.}}
80+
81+
let propertyFromFunc2 = funcThatReturnsSomething(TypeWithSelfMethod.self) // OK
82+
83+
func `self`() {
84+
85+
}
86+
}
87+
88+
/// Test fix_unqualified_access_member_named_self doesn't appear for computed var called `self`
89+
/// it can't currently be referenced as a static member -- unlike a method with the same name
90+
struct TypeWithSelfComputedVar {
91+
92+
let property = self // expected-error {{cannot use instance member 'self' within property initializer; property initializers run before 'self' is available}}
93+
94+
let propertyFromClosure: () = {
95+
print(self) // expected-error {{cannot use instance member 'self' within property initializer; property initializers run before 'self' is available}}
96+
}()
97+
98+
let propertyFromFunc = funcThatReturnsSomething(self) // expected-error {{cannot use instance member 'self' within property initializer; property initializers run before 'self' is available}}
99+
100+
var `self`: () {
101+
()
102+
}
103+
}
104+
105+
/// Test fix_unqualified_access_member_named_self doesn't appear appear for property called `self`
106+
/// it can't currently be referenced as a static member -- unlike a method with the same name
107+
struct TypeWithSelfProperty {
108+
109+
let property = self // expected-error {{cannot use instance member 'self' within property initializer; property initializers run before 'self' is available}}
110+
111+
let propertyFromClosure: () = {
112+
print(self) // expected-error {{cannot use instance member 'self' within property initializer; property initializers run before 'self' is available}}
113+
}()
114+
115+
let propertyFromFunc = funcThatReturnsSomething(self) // expected-error {{cannot use instance member 'self' within property initializer; property initializers run before 'self' is available}}
116+
117+
let `self`: () = ()
118+
}

0 commit comments

Comments
 (0)