Skip to content

Commit 8323152

Browse files
committed
[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 bb1bc65 commit 8323152

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
@@ -2401,6 +2401,32 @@ diagnoseEnumInstanceMemberLookup(EnumElementDecl *enumElementDecl,
24012401
return;
24022402
}
24032403

2404+
/// When a user refers a enum case with a wrong member name, we try to find a enum
2405+
/// element whose name differs from the wrong name only in convention; meaning their
2406+
/// lower case counterparts are identical.
2407+
/// - DeclName is valid when such a correct case is found; invalid otherwise.
2408+
static DeclName
2409+
findCorrectEnumCaseName(MetatypeType *MetaTy, LookupResult &Result,
2410+
DeclName memberName) {
2411+
if (!memberName.isSimpleName())
2412+
return DeclName();
2413+
if (!MetaTy->getInstanceType()->is<EnumType>())
2414+
return DeclName();
2415+
std::vector<DeclName> candidates;
2416+
for (auto &correction : Result) {
2417+
DeclName correctName = correction.Decl->getFullName();
2418+
if (!correctName.isSimpleName())
2419+
continue;
2420+
if (!isa<EnumElementDecl>(correction.Decl))
2421+
continue;
2422+
if (correctName.getBaseName().str().
2423+
compare_lower(memberName.getBaseName().str()) == 0)
2424+
candidates.push_back(correctName);
2425+
}
2426+
if (candidates.size() == 1)
2427+
return candidates.front();
2428+
return DeclName();
2429+
}
24042430

24052431
/// Given a result of name lookup that had no viable results, diagnose the
24062432
/// unviable ones.
@@ -2426,10 +2452,17 @@ diagnoseUnviableLookupResults(MemberLookupResult &result, Type baseObjTy,
24262452
diagnose(loc, diag::type_not_subscriptable, baseObjTy)
24272453
.highlight(baseRange);
24282454
} else if (auto MTT = baseObjTy->getAs<MetatypeType>()) {
2455+
tryTypoCorrection();
2456+
if (DeclName rightName = findCorrectEnumCaseName(MTT, correctionResults,
2457+
memberName)) {
2458+
diagnose(loc, diag::could_not_find_enum_case, MTT->getInstanceType(),
2459+
memberName, rightName).fixItReplace(nameLoc.getBaseNameLoc(),
2460+
rightName.getBaseName().str());
2461+
return;
2462+
}
24292463
diagnose(loc, diag::could_not_find_type_member,
24302464
MTT->getInstanceType(), memberName)
24312465
.highlight(baseRange).highlight(nameLoc.getSourceRange());
2432-
tryTypoCorrection();
24332466
} else {
24342467
diagnose(loc, diag::could_not_find_value_member,
24352468
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)