Skip to content

Commit 7afe4cc

Browse files
authored
[FixCode] Add a fixit to help users migrate to Swift 3 name convention. (#4058)
* [FixCode] Add a fixit to help users migrate to Swift 3 name convention of enum cases. rdar://26887735 When users' referring to a enum case with a wrong name and we can find a correct enum case whose name differs from the wrong name only in capitalization, we replace the wrong name with the correct one. * Addressing Argyrios' code review comments. NFC * [test] Update existing test. * Grammatical polish suggested by @CodaFi.
1 parent b02102c commit 7afe4cc

File tree

4 files changed

+47
-5
lines changed

4 files changed

+47
-5
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,9 @@ ERROR(could_not_find_value_member,none,
7272
ERROR(could_not_find_type_member,none,
7373
"type %0 has no member %1", (Type, DeclName))
7474

75+
ERROR(could_not_find_enum_case,none,
76+
"enum type %0 has no case %1; did you mean %2", (Type, DeclName, DeclName))
77+
7578
NOTE(did_you_mean_raw_type,none,
7679
"did you mean to specify a raw type on the enum declaration?", ())
7780

lib/Sema/CSDiag.cpp

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2448,6 +2448,32 @@ diagnoseTypeMemberOnInstanceLookup(Type baseObjTy,
24482448
return;
24492449
}
24502450

2451+
/// When a user refers a enum case with a wrong member name, we try to find a enum
2452+
/// element whose name differs from the wrong name only in convention; meaning their
2453+
/// lower case counterparts are identical.
2454+
/// - DeclName is valid when such a correct case is found; invalid otherwise.
2455+
static DeclName
2456+
findCorrectEnumCaseName(MetatypeType *MetaTy, LookupResult &Result,
2457+
DeclName memberName) {
2458+
if (!memberName.isSimpleName())
2459+
return DeclName();
2460+
if (!MetaTy->getInstanceType()->is<EnumType>())
2461+
return DeclName();
2462+
std::vector<DeclName> candidates;
2463+
for (auto &correction : Result) {
2464+
DeclName correctName = correction.Decl->getFullName();
2465+
if (!correctName.isSimpleName())
2466+
continue;
2467+
if (!isa<EnumElementDecl>(correction.Decl))
2468+
continue;
2469+
if (correctName.getBaseName().str().
2470+
compare_lower(memberName.getBaseName().str()) == 0)
2471+
candidates.push_back(correctName);
2472+
}
2473+
if (candidates.size() == 1)
2474+
return candidates.front();
2475+
return DeclName();
2476+
}
24512477

24522478
/// Given a result of name lookup that had no viable results, diagnose the
24532479
/// unviable ones.
@@ -2473,10 +2499,17 @@ diagnoseUnviableLookupResults(MemberLookupResult &result, Type baseObjTy,
24732499
diagnose(loc, diag::type_not_subscriptable, baseObjTy)
24742500
.highlight(baseRange);
24752501
} else if (auto MTT = baseObjTy->getAs<MetatypeType>()) {
2502+
tryTypoCorrection();
2503+
if (DeclName rightName = findCorrectEnumCaseName(MTT, correctionResults,
2504+
memberName)) {
2505+
diagnose(loc, diag::could_not_find_enum_case, MTT->getInstanceType(),
2506+
memberName, rightName).fixItReplace(nameLoc.getBaseNameLoc(),
2507+
rightName.getBaseName().str());
2508+
return;
2509+
}
24762510
diagnose(loc, diag::could_not_find_type_member,
24772511
MTT->getInstanceType(), memberName)
24782512
.highlight(baseRange).highlight(nameLoc.getSourceRange());
2479-
tryTypoCorrection();
24802513
} else {
24812514
diagnose(loc, diag::could_not_find_value_member,
24822515
baseObjTy, memberName)

test/Constraints/diagnostics.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -412,7 +412,7 @@ CurriedClass.m2(12) // expected-error {{use of instance member 'm2' on type 'Cu
412412

413413
// <rdar://problem/20491794> Error message does not tell me what the problem is
414414
enum Color {
415-
case Red // expected-note 2 {{did you mean 'Red'?}}
415+
case Red
416416
case Unknown(description: String)
417417

418418
static func rainbow() -> Color {}
@@ -446,8 +446,8 @@ let _: Color = .frob(1, i) // expected-error {{passing value of type 'Int' to a
446446
let _: Color = .frob(1, b: i) // expected-error {{passing value of type 'Int' to an inout parameter requires explicit '&'}}
447447
let _: Color = .frob(1, &d) // expected-error {{cannot convert value of type 'Double' to expected argument type 'Int'}}
448448
let _: Color = .frob(1, b: &d) // expected-error {{cannot convert value of type 'Double' to expected argument type 'Int'}}
449-
var someColor : Color = .red // expected-error {{type 'Color' has no member 'red'}}
450-
someColor = .red // expected-error {{type 'Color' has no member 'red'}}
449+
var someColor : Color = .red // expected-error {{enum type 'Color' has no case 'red'; did you mean 'Red'}}
450+
someColor = .red // expected-error {{enum type 'Color' has no case 'red'; did you mean 'Red'}}
451451

452452
func testTypeSugar(_ a : Int) {
453453
typealias Stride = Int

test/NameBinding/name_lookup.swift

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -522,7 +522,8 @@ class r16954496 {
522522
enum MyEnum {
523523
case one
524524
case two
525-
525+
case oneTwoThree
526+
526527
static let kMyConstant = "myConstant"
527528
}
528529

@@ -535,3 +536,8 @@ default:
535536
break
536537
}
537538

539+
func foo() {
540+
_ = MyEnum.One // expected-error {{enum type 'MyEnum' has no case 'One'; did you mean 'one'}}{{14-17=one}}
541+
_ = MyEnum.Two // expected-error {{enum type 'MyEnum' has no case 'Two'; did you mean 'two'}}{{14-17=two}}
542+
_ = MyEnum.OneTwoThree // expected-error {{enum type 'MyEnum' has no case 'OneTwoThree'; did you mean 'oneTwoThree'}}{{14-25=oneTwoThree}}
543+
}

0 commit comments

Comments
 (0)