Skip to content

Commit 127bc79

Browse files
committed
[Sema] FixIt for override func that should be override var and vice-versa
Resolves #57499 This adds `override_property_not_method` and `override_method_not_property` notes by performing a member lookup for the respective diagnostics.
1 parent 5674b6e commit 127bc79

File tree

3 files changed

+80
-0
lines changed

3 files changed

+80
-0
lines changed

Diff for: include/swift/AST/DiagnosticsSema.def

+4
Original file line numberDiff line numberDiff line change
@@ -3475,8 +3475,12 @@ ERROR(override_of_non_open,none,
34753475

34763476
ERROR(method_does_not_override,none,
34773477
"method does not override any method from its %select{parent protocol|superclass}0", (bool))
3478+
NOTE(override_property_not_method,none,
3479+
"did you mean to override the property %0", (Identifier))
34783480
ERROR(property_does_not_override,none,
34793481
"property does not override any property from its %select{parent protocol|superclass}0", (bool))
3482+
NOTE(override_method_not_property,none,
3483+
"did you mean to override the method %0", (Identifier))
34803484
ERROR(subscript_does_not_override,none,
34813485
"subscript does not override any subscript from its %select{parent protocol|superclass}0", (bool))
34823486
ERROR(initializer_does_not_override,none,

Diff for: lib/Sema/TypeCheckDeclPrimary.cpp

+59
Original file line numberDiff line numberDiff line change
@@ -2674,6 +2674,7 @@ class DeclChecker : public DeclVisitor<DeclChecker> {
26742674
} else {
26752675
VD->diagnose(diag::property_does_not_override, isClassContext)
26762676
.highlight(OA->getLocation());
2677+
diagnoseOverridenProperty(VD, DC, OA);
26772678
}
26782679
OA->setInvalid();
26792680
}
@@ -2742,6 +2743,32 @@ class DeclChecker : public DeclVisitor<DeclChecker> {
27422743
}
27432744
}
27442745

2746+
static void diagnoseOverridenProperty(VarDecl *VD, DeclContext *DC,
2747+
OverrideAttr *OA) {
2748+
auto declName = VD->getBaseName();
2749+
auto declType = VD->getInterfaceType()->getRValueType();
2750+
2751+
auto inherited = DC->getSelfClassDecl()->getInherited();
2752+
if (!inherited.empty()) {
2753+
auto superClassType = inherited.getResolvedType(0);
2754+
auto lookupResult =
2755+
TypeChecker::lookupMember(DC, superClassType, DeclNameRef(declName));
2756+
for (auto &candidate : lookupResult) {
2757+
auto *valueDecl = candidate.getValueDecl();
2758+
if (auto funcDecl = dyn_cast<FuncDecl>(valueDecl)) {
2759+
if (funcDecl->getBaseName() == declName &&
2760+
funcDecl->getParameters()->size() == 0) {
2761+
std::string funcDeclTypeStr = " -> " + declType.getString();
2762+
VD->diagnose(diag::override_method_not_property,
2763+
funcDecl->getBaseName().getIdentifier())
2764+
.highlight(OA->getLocation())
2765+
.fixItReplace(getFixItLocForVarToLet(VD), "func");
2766+
}
2767+
}
2768+
}
2769+
}
2770+
}
2771+
27452772
bool checkBoundInOutVarDecl(PatternBindingDecl *pbd, unsigned patternIndex,
27462773
const Pattern *p, VarDecl *vd) {
27472774
// If our var decl doesn't have an initial value, error. We always want an
@@ -3714,6 +3741,7 @@ class DeclChecker : public DeclVisitor<DeclChecker> {
37143741
} else {
37153742
FD->diagnose(diag::method_does_not_override, isClassContext)
37163743
.highlight(OA->getLocation());
3744+
diagnoseOverridenMethod(FD, DC, OA);
37173745
}
37183746
OA->setInvalid();
37193747
}
@@ -3804,6 +3832,37 @@ class DeclChecker : public DeclVisitor<DeclChecker> {
38043832
TypeChecker::checkObjCImplementation(FD);
38053833
}
38063834

3835+
static void diagnoseOverridenMethod(FuncDecl *FD, DeclContext *DC,
3836+
OverrideAttr *OA) {
3837+
if (FD->getParameters()->size() == 0) {
3838+
auto declName = FD->getBaseName();
3839+
auto declRetType = FD->getResultInterfaceType()->getRValueType();
3840+
3841+
auto inherited = DC->getSelfClassDecl()->getInherited();
3842+
if (!inherited.empty()) {
3843+
auto superClassType = inherited.getResolvedType(0);
3844+
auto lookupResult = TypeChecker::lookupMember(DC, superClassType,
3845+
DeclNameRef(declName));
3846+
for (auto &candidate : lookupResult) {
3847+
auto *valueDecl = candidate.getValueDecl();
3848+
if (auto vardecl = dyn_cast<VarDecl>(valueDecl)) {
3849+
if (vardecl->getBaseName() == declName) {
3850+
std::string varDeclTypeStr = ": " + declRetType.getString();
3851+
FD->diagnose(diag::override_property_not_method,
3852+
vardecl->getBaseName().getIdentifier())
3853+
.highlight(OA->getLocation())
3854+
.fixItReplace(FD->getFuncLoc(), "var")
3855+
.fixItReplaceChars(
3856+
FD->getParameters()->getLParenLoc(),
3857+
FD->getBody()->getLBraceLoc().getAdvancedLoc(-1),
3858+
varDeclTypeStr);
3859+
}
3860+
}
3861+
}
3862+
}
3863+
}
3864+
}
3865+
38073866
void visitModuleDecl(ModuleDecl *) { }
38083867

38093868
void visitEnumCaseDecl(EnumCaseDecl *ECD) {

Diff for: test/decl/inherit/override.swift

+17
Original file line numberDiff line numberDiff line change
@@ -86,3 +86,20 @@ 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+
class C {
91+
var v1: Bool {
92+
return false
93+
}
94+
95+
func f1() -> Int { }
96+
}
97+
98+
class D: C {
99+
override func v1() -> Bool { } // expected-error{{method does not override any method from its superclass}}
100+
// expected-note@-1{{did you mean to override the property 'v1'}} {{12-16=var}} {{19-29=: Bool}}
101+
102+
override var f1: Int { // expected-error{{property does not override any property from its superclass}}
103+
return 0 // expected-note@-1{{did you mean to override the method 'f1'}} {{12-15=func}}
104+
}
105+
}

0 commit comments

Comments
 (0)