Skip to content

Commit d2a229a

Browse files
committed
Provided FixIts for 'override func' that should be 'override var' and vice-versa
Fixes Issue #57499
1 parent 80b9386 commit d2a229a

File tree

4 files changed

+98
-0
lines changed

4 files changed

+98
-0
lines changed

include/swift/AST/DiagnosticsSema.def

+6
Original file line numberDiff line numberDiff line change
@@ -2924,8 +2924,14 @@ ERROR(override_of_non_open,none,
29242924

29252925
ERROR(method_does_not_override,none,
29262926
"method does not override any method from its %select{parent protocol|superclass}0", (bool))
2927+
NOTE(override_method_in_lieu_of_property,none,
2928+
"did you mean to override the property %0?", (Identifier))
2929+
29272930
ERROR(property_does_not_override,none,
29282931
"property does not override any property from its %select{parent protocol|superclass}0", (bool))
2932+
NOTE(override_property_in_lieu_of_method,none,
2933+
"did you mean to override the method %0?", (Identifier))
2934+
29292935
ERROR(subscript_does_not_override,none,
29302936
"subscript does not override any subscript from its %select{parent protocol|superclass}0", (bool))
29312937
ERROR(initializer_does_not_override,none,

lib/Sema/TypeCheckDeclPrimary.cpp

+42
Original file line numberDiff line numberDiff line change
@@ -2130,6 +2130,27 @@ class DeclChecker : public DeclVisitor<DeclChecker> {
21302130
} else {
21312131
VD->diagnose(diag::property_does_not_override, isClassContext)
21322132
.highlight(OA->getLocation());
2133+
//If the override is a property-decl, check if there exists
2134+
//a no-args func-decl in the base class, if yes, provide a fix-it.
2135+
auto declName = VD->getBaseName();
2136+
auto declType = VD->getResultTypeRepr();
2137+
auto inherited = DC->getSelfClassDecl()->getInherited();
2138+
//If there is an inherited context, perform member lookup.
2139+
if (!inherited.empty()) {
2140+
auto superClass = inherited.front().getType();
2141+
auto lookupResult = superClass->getAnyNominal()->lookupDirect(declName);
2142+
2143+
for (auto& candidate : lookupResult) {
2144+
//If the parameter list is empty, compare the return types
2145+
//of the candidates with the declaration type.
2146+
if (getParameterList(candidate)->size() == 0) {
2147+
auto candidateReturnType = candidate->getResultTypeRepr();
2148+
if (candidateReturnType->getKind() == declType->getKind())
2149+
VD->diagnose(diag::override_property_in_lieu_of_method, declName.getIdentifier())
2150+
.fixItReplace(VD->Decl::getSourceRangeIncludingAttrs(), "override func " + declName.getIdentifier().str().str() + "() -> " + VD->getInterfaceType()->getRValueType().getString() + " { <#code#> }");
2151+
}
2152+
}
2153+
}
21332154
}
21342155
OA->setInvalid();
21352156
}
@@ -3158,6 +3179,27 @@ class DeclChecker : public DeclVisitor<DeclChecker> {
31583179
} else {
31593180
FD->diagnose(diag::method_does_not_override, isClassContext)
31603181
.highlight(OA->getLocation());
3182+
//If the override is a no-args fun-decl, check if there exists
3183+
//a no-args var-decl in the base class, if yes, provide a fix-it.
3184+
if (FD->getParameters()->size() == 0) {
3185+
auto declName = FD->getBaseName();
3186+
auto declReturnType = FD->getResultInterfaceType()->getRValueType();
3187+
auto inherited = DC->getSelfClassDecl()->getInherited();
3188+
//If there is an inherited context, perform member lookup.
3189+
if (!inherited.empty()) {
3190+
auto superClass = inherited.front().getType();
3191+
auto lookupResult = superClass->getAnyNominal()->lookupDirect(declName);
3192+
//Compare the equality of return types for each candidate.
3193+
for (auto& candidate : lookupResult) {
3194+
auto candidateType = candidate->getInterfaceType()->getRValueType();
3195+
if (candidateType->isEqual(declReturnType))
3196+
FD->diagnose(diag::override_method_in_lieu_of_property, declName.getIdentifier())
3197+
.fixItRemove(FD->getBodySourceRange())
3198+
.fixItReplace(FD->getSourceRangeIncludingAttrs(),
3199+
"override var " + declName.getIdentifier().str().str() + ": " + declReturnType.getString() + " { <#code#> }");
3200+
}
3201+
}
3202+
}
31613203
}
31623204
OA->setInvalid();
31633205
}

test/decl/class/override.swift

+25
Original file line numberDiff line numberDiff line change
@@ -414,3 +414,28 @@ open class OpenDerivedFinal : OpenBase {
414414
open class OpenDerivedStatic : OpenBase {
415415
override public static func classMethod() {}
416416
}
417+
418+
// Context: https://github.com/apple/swift/issues/57499
419+
// FixIt for 'override func' that should be 'override var' and vice-versa
420+
func overrideInLieu() {
421+
422+
class BaseClass {
423+
var someValueX: Bool {
424+
get { return false }
425+
set { }
426+
}
427+
428+
func someFuncX() -> Int { return 0 }
429+
}
430+
431+
class Inherited: BaseClass {
432+
override var someFuncX: Int { // expected-error {{property does not override any property from its superclass}}
433+
// expected-note@-1 {{did you mean to override the method 'someFuncX'?}}
434+
get { return 0 }
435+
set { }
436+
}
437+
438+
override func someValueX() -> Bool { return false } // expected-error {{method does not override any method from its superclass}}
439+
// expected-note@-1 {{did you mean to override the property 'someValueX'?}}
440+
}
441+
}

test/decl/inherit/override.swift

+25
Original file line numberDiff line numberDiff line change
@@ -86,3 +86,28 @@ class ObjCSub : ObjCSuper {
8686

8787
@objc(method3:withInt:) func method3(_ x: Sub, with y: Int) { } // expected-error{{method3(_:with:)' with Objective-C selector 'method3:withInt:' conflicts with method 'method3(_:withInt:)' from superclass 'ObjCSuper' with the same Objective-C selector}}
8888
}
89+
90+
// Context: https://github.com/apple/swift/issues/57499
91+
// FixIt for 'override func' that should be 'override var' and vice-versa
92+
func overrideInLieu() {
93+
94+
class BaseClass {
95+
var someValueX: Bool {
96+
get { return false }
97+
set { }
98+
}
99+
100+
func someFuncX() -> Int { return 0 }
101+
}
102+
103+
class Inherited: BaseClass {
104+
override var someFuncX: Int { // expected-error {{property does not override any property from its superclass}}
105+
// expected-note@-1 {{did you mean to override the method 'someFuncX'?}}
106+
get { return 0 }
107+
set { }
108+
}
109+
110+
override func someValueX() -> Bool { return false } // expected-error {{method does not override any method from its superclass}}
111+
// expected-note@-1 {{did you mean to override the property 'someValueX'?}}
112+
}
113+
}

0 commit comments

Comments
 (0)