Skip to content

Commit f4d4893

Browse files
authored
Merge pull request #4063 from nkcsgexi/enum-fixit-swift3
[FixCode] Add a fixit to help users migrate to Swift 3 name convention.
2 parents c102e91 + a314f8c commit f4d4893

File tree

4 files changed

+58
-5
lines changed

4 files changed

+58
-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: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2401,6 +2401,33 @@ 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+
!MetaTy->getInstanceType()->is<BoundGenericEnumType>())
2415+
return DeclName();
2416+
llvm::SmallVector<DeclName, 4> candidates;
2417+
for (auto &correction : Result) {
2418+
DeclName correctName = correction.Decl->getFullName();
2419+
if (!correctName.isSimpleName())
2420+
continue;
2421+
if (!isa<EnumElementDecl>(correction.Decl))
2422+
continue;
2423+
if (correctName.getBaseName().str().
2424+
equals_lower(memberName.getBaseName().str()))
2425+
candidates.push_back(correctName);
2426+
}
2427+
if (candidates.size() == 1)
2428+
return candidates.front();
2429+
return DeclName();
2430+
}
24042431

24052432
/// Given a result of name lookup that had no viable results, diagnose the
24062433
/// unviable ones.
@@ -2426,10 +2453,17 @@ diagnoseUnviableLookupResults(MemberLookupResult &result, Type baseObjTy,
24262453
diagnose(loc, diag::type_not_subscriptable, baseObjTy)
24272454
.highlight(baseRange);
24282455
} else if (auto MTT = baseObjTy->getAs<MetatypeType>()) {
2456+
tryTypoCorrection();
2457+
if (DeclName rightName = findCorrectEnumCaseName(MTT, correctionResults,
2458+
memberName)) {
2459+
diagnose(loc, diag::could_not_find_enum_case, MTT->getInstanceType(),
2460+
memberName, rightName).fixItReplace(nameLoc.getBaseNameLoc(),
2461+
rightName.getBaseName().str());
2462+
return;
2463+
}
24292464
diagnose(loc, diag::could_not_find_type_member,
24302465
MTT->getInstanceType(), memberName)
24312466
.highlight(baseRange).highlight(nameLoc.getSourceRange());
2432-
tryTypoCorrection();
24332467
} else {
24342468
diagnose(loc, diag::could_not_find_value_member,
24352469
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: 17 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,18 @@ 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+
}
544+
545+
enum MyGenericEnum<T> {
546+
case one(T)
547+
case oneTwo(T)
548+
}
549+
550+
func foo1() {
551+
_ = MyGenericEnum<Int>.One // expected-error {{enum type 'MyGenericEnum<Int>' has no case 'One'; did you mean 'one'}}{{26-29=one}}
552+
_ = MyGenericEnum<Int>.OneTwo // expected-error {{enum type 'MyGenericEnum<Int>' has no case 'OneTwo'; did you mean 'oneTwo'}}{{26-32=oneTwo}}
553+
}

0 commit comments

Comments
 (0)