Skip to content

[FixCode] Add a fixit to help users migrate to Swift 3 name convention. #4058

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Aug 6, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions include/swift/AST/DiagnosticsSema.def
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,9 @@ ERROR(could_not_find_value_member,none,
ERROR(could_not_find_type_member,none,
"type %0 has no member %1", (Type, DeclName))

ERROR(could_not_find_enum_case,none,
"enum type %0 has no case %1; did you mean %2", (Type, DeclName, DeclName))

NOTE(did_you_mean_raw_type,none,
"did you mean to specify a raw type on the enum declaration?", ())

Expand Down
35 changes: 34 additions & 1 deletion lib/Sema/CSDiag.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2401,6 +2401,32 @@ diagnoseEnumInstanceMemberLookup(EnumElementDecl *enumElementDecl,
return;
}

/// When a user refers a enum case with a wrong member name, we try to find a enum
/// element whose name differs from the wrong name only in convention; meaning their
/// lower case counterparts are identical.
/// - DeclName is valid when such a correct case is found; invalid otherwise.
static DeclName
findCorrectEnumCaseName(MetatypeType *MetaTy, LookupResult &Result,
DeclName memberName) {
if (!memberName.isSimpleName())
return DeclName();
if (!MetaTy->getInstanceType()->is<EnumType>())
return DeclName();
std::vector<DeclName> candidates;
for (auto &correction : Result) {
DeclName correctName = correction.Decl->getFullName();
if (!correctName.isSimpleName())
continue;
if (!isa<EnumElementDecl>(correction.Decl))
continue;
if (correctName.getBaseName().str().
compare_lower(memberName.getBaseName().str()) == 0)
candidates.push_back(correctName);
}
if (candidates.size() == 1)
return candidates.front();
return DeclName();
}

/// Given a result of name lookup that had no viable results, diagnose the
/// unviable ones.
Expand All @@ -2426,10 +2452,17 @@ diagnoseUnviableLookupResults(MemberLookupResult &result, Type baseObjTy,
diagnose(loc, diag::type_not_subscriptable, baseObjTy)
.highlight(baseRange);
} else if (auto MTT = baseObjTy->getAs<MetatypeType>()) {
tryTypoCorrection();
if (DeclName rightName = findCorrectEnumCaseName(MTT, correctionResults,
memberName)) {
diagnose(loc, diag::could_not_find_enum_case, MTT->getInstanceType(),
memberName, rightName).fixItReplace(nameLoc.getBaseNameLoc(),
rightName.getBaseName().str());
return;
}
diagnose(loc, diag::could_not_find_type_member,
MTT->getInstanceType(), memberName)
.highlight(baseRange).highlight(nameLoc.getSourceRange());
tryTypoCorrection();
} else {
diagnose(loc, diag::could_not_find_value_member,
baseObjTy, memberName)
Expand Down
6 changes: 3 additions & 3 deletions test/Constraints/diagnostics.swift
Original file line number Diff line number Diff line change
Expand Up @@ -412,7 +412,7 @@ CurriedClass.m2(12) // expected-error {{use of instance member 'm2' on type 'Cu

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

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

func testTypeSugar(_ a : Int) {
typealias Stride = Int
Expand Down
8 changes: 7 additions & 1 deletion test/NameBinding/name_lookup.swift
Original file line number Diff line number Diff line change
Expand Up @@ -522,7 +522,8 @@ class r16954496 {
enum MyEnum {
case one
case two

case oneTwoThree

static let kMyConstant = "myConstant"
}

Expand All @@ -535,3 +536,8 @@ default:
break
}

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