Skip to content

Commit

Permalink
Provided FixIts for 'override func' that should be 'override var' and…
Browse files Browse the repository at this point in the history
… vice-versa

Fixes Issue apple#57499
  • Loading branch information
Rajveer100 committed Apr 8, 2023
1 parent c776676 commit f4b3c44
Show file tree
Hide file tree
Showing 4 changed files with 98 additions and 0 deletions.
6 changes: 6 additions & 0 deletions include/swift/AST/DiagnosticsSema.def
Expand Up @@ -2924,8 +2924,14 @@ ERROR(override_of_non_open,none,

ERROR(method_does_not_override,none,
"method does not override any method from its %select{parent protocol|superclass}0", (bool))
NOTE(override_method_in_lieu_of_property,none,
"did you mean to override the property %0?", (Identifier))

ERROR(property_does_not_override,none,
"property does not override any property from its %select{parent protocol|superclass}0", (bool))
NOTE(override_property_in_lieu_of_method,none,
"did you mean to override the method %0?", (Identifier))

ERROR(subscript_does_not_override,none,
"subscript does not override any subscript from its %select{parent protocol|superclass}0", (bool))
ERROR(initializer_does_not_override,none,
Expand Down
42 changes: 42 additions & 0 deletions lib/Sema/TypeCheckDeclPrimary.cpp
Expand Up @@ -2130,6 +2130,27 @@ class DeclChecker : public DeclVisitor<DeclChecker> {
} else {
VD->diagnose(diag::property_does_not_override, isClassContext)
.highlight(OA->getLocation());
//If the override is a property-decl, check if there exists
//a no-args func-decl in the base class, if yes, provide a fix-it.
auto declName = VD->getBaseName();
auto declType = VD->getResultTypeRepr();
auto inherited = DC->getSelfClassDecl()->getInherited();
//If there is an inherited context, perform member lookup.
if (!inherited.empty()) {
auto superClass = inherited.front().getType();
auto lookupResult = superClass->getAnyNominal()->lookupDirect(declName);

for (auto& candidate : lookupResult) {
//If the parameter list is empty, compare the return types
//of the candidates with the declaration type.
if (getParameterList(candidate)->size() == 0) {
auto candidateReturnType = candidate->getResultTypeRepr();
if (candidateReturnType->getKind() == declType->getKind())
VD->diagnose(diag::override_property_in_lieu_of_method, declName.getIdentifier())
.fixItReplace(VD->Decl::getSourceRangeIncludingAttrs(), "override func " + declName.getIdentifier().str().str() + "() -> " + VD->getInterfaceType()->getRValueType().getString() + " { <#code#> }");
}
}
}
}
OA->setInvalid();
}
Expand Down Expand Up @@ -3158,6 +3179,27 @@ class DeclChecker : public DeclVisitor<DeclChecker> {
} else {
FD->diagnose(diag::method_does_not_override, isClassContext)
.highlight(OA->getLocation());
//If the override is a no-args fun-decl, check if there exists
//a no-args var-decl in the base class, if yes, provide a fix-it.
if (FD->getParameters()->size() == 0) {
auto declName = FD->getBaseName();
auto declReturnType = FD->getResultInterfaceType()->getRValueType();
auto inherited = DC->getSelfClassDecl()->getInherited();
//If there is an inherited context, perform member lookup.
if (!inherited.empty()) {
auto superClass = inherited.front().getType();
auto lookupResult = superClass->getAnyNominal()->lookupDirect(declName);
//Compare the equality of return types for each candidate.
for (auto& candidate : lookupResult) {
auto candidateType = candidate->getInterfaceType()->getRValueType();
if (candidateType->isEqual(declReturnType))
FD->diagnose(diag::override_method_in_lieu_of_property, declName.getIdentifier())
.fixItRemove(FD->getBodySourceRange())
.fixItReplace(FD->getSourceRangeIncludingAttrs(),
"override var " + declName.getIdentifier().str().str() + ": " + declReturnType.getString() + " { <#code#> }");
}
}
}
}
OA->setInvalid();
}
Expand Down
25 changes: 25 additions & 0 deletions test/decl/class/override.swift
Expand Up @@ -414,3 +414,28 @@ open class OpenDerivedFinal : OpenBase {
open class OpenDerivedStatic : OpenBase {
override public static func classMethod() {}
}

// Context: https://github.com/apple/swift/issues/57499
// FixIt for 'override func' that should be 'override var' and vice-versa
func overrideInLieu() {

class BaseClass {
var someValueX: Bool {
get { return false }
set { }
}

func someFuncX() -> Int { return 0 }
}

class Inherited: BaseClass {
override var someFuncX: Int { // expected-error {{property does not override any property from its superclass}}
// expected-note@-1 {{did you mean to override the method 'someFuncX'?}}
get { return 0 }
set { }
}

override func someValueX() -> Bool { return false } // expected-error {{method does not override any method from its superclass}}
// expected-note@-1 {{did you mean to override the property 'someValueX'?}}
}
}
25 changes: 25 additions & 0 deletions test/decl/inherit/override.swift
Expand Up @@ -86,3 +86,28 @@ class ObjCSub : ObjCSuper {

@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}}
}

// Context: https://github.com/apple/swift/issues/57499
// FixIt for 'override func' that should be 'override var' and vice-versa
func overrideInLieu() {

class BaseClass {
var someValueX: Bool {
get { return false }
set { }
}

func someFuncX() -> Int { return 0 }
}

class Inherited: BaseClass {
override var someFuncX: Int { // expected-error {{property does not override any property from its superclass}}
// expected-note@-1 {{did you mean to override the method 'someFuncX'?}}
get { return 0 }
set { }
}

override func someValueX() -> Bool { return false } // expected-error {{method does not override any method from its superclass}}
// expected-note@-1 {{did you mean to override the property 'someValueX'?}}
}
}

0 comments on commit f4b3c44

Please sign in to comment.