Skip to content

Commit 6f14344

Browse files
bitjammertkremenek
authored andcommitted
Improve imported enums' lowercased case diagnostics (26245512) (#2716)
* Diagnose enum cases renamed to lowercase When importing foreign enum cases, we create a new case with a lowercase name, and set the renamed unavailability bits on the imported name, so they are still visible to the compiler but unavailable, so we can throw a diagnostic. Renamed enum cases can be found by digging through a VarDecl in the AST, and there were no availability checks there. This area probably needs deeper refactoring, but add an UnavailableInCurrentSwift check for now. https://bugs.swift.org/browse/SR-1496 rdar://problem/26245512 * [Sema] Check for any unavailability with rename when suggesting rename of enum cases, not just ones that aren't available in the current version of Swift. https://bugs.swift.org/browse/SR-1496 rdar://problem/26245512 * Reuse some unavailable diagnosis code in the type checker This could still stand some more refactoring but reuses the renaming diagnostic.
1 parent dab0e74 commit 6f14344

File tree

2 files changed

+32
-14
lines changed

2 files changed

+32
-14
lines changed

lib/Sema/TypeCheckPattern.cpp

Lines changed: 25 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,10 @@ using namespace swift;
3232
/// This requires the getter's body to have a certain syntactic form. It should
3333
/// be kept in sync with importEnumCaseAlias in the ClangImporter library.
3434
static EnumElementDecl *
35-
extractEnumElement(const VarDecl *constant) {
35+
extractEnumElement(TypeChecker &TC, DeclContext *DC, SourceLoc UseLoc,
36+
const VarDecl *constant) {
37+
TC.diagnoseExplicitUnavailability(constant, UseLoc, DC, nullptr);
38+
3639
const FuncDecl *getter = constant->getGetter();
3740
if (!getter)
3841
return nullptr;
@@ -62,7 +65,8 @@ extractEnumElement(const VarDecl *constant) {
6265
/// If there are no enum elements but there are properties, attempts to map
6366
/// an arbitrary property to an enum element using extractEnumElement.
6467
static EnumElementDecl *
65-
filterForEnumElement(LookupResult foundElements) {
68+
filterForEnumElement(TypeChecker &TC, DeclContext *DC, SourceLoc UseLoc,
69+
LookupResult foundElements) {
6670
EnumElementDecl *foundElement = nullptr;
6771
VarDecl *foundConstant = nullptr;
6872

@@ -86,32 +90,32 @@ filterForEnumElement(LookupResult foundElements) {
8690
}
8791

8892
if (!foundElement && foundConstant && foundConstant->hasClangNode())
89-
foundElement = extractEnumElement(foundConstant);
93+
foundElement = extractEnumElement(TC, DC, UseLoc, foundConstant);
9094

9195
return foundElement;
9296
}
9397

9498
/// Find an unqualified enum element.
9599
static EnumElementDecl *
96100
lookupUnqualifiedEnumMemberElement(TypeChecker &TC, DeclContext *DC,
97-
Identifier name) {
101+
Identifier name, SourceLoc UseLoc) {
98102
auto lookupOptions = defaultUnqualifiedLookupOptions;
99103
lookupOptions |= NameLookupFlags::KnownPrivate;
100104
auto lookup = TC.lookupUnqualified(DC, name, SourceLoc(), lookupOptions);
101-
return filterForEnumElement(lookup);
105+
return filterForEnumElement(TC, DC, UseLoc, lookup);
102106
}
103107

104108
/// Find an enum element in an enum type.
105109
static EnumElementDecl *
106110
lookupEnumMemberElement(TypeChecker &TC, DeclContext *DC, Type ty,
107-
Identifier name) {
111+
Identifier name, SourceLoc UseLoc) {
108112
assert(ty->getAnyNominal());
109113
// Look up the case inside the enum.
110114
// FIXME: We should be able to tell if this is a private lookup.
111115
NameLookupOptions lookupOptions
112116
= defaultMemberLookupOptions - NameLookupFlags::DynamicLookup;
113117
LookupResult foundElements = TC.lookupMember(DC, ty, name, lookupOptions);
114-
return filterForEnumElement(foundElements);
118+
return filterForEnumElement(TC, DC, UseLoc, foundElements);
115119
}
116120

117121
namespace {
@@ -436,7 +440,8 @@ class ResolvePattern : public ASTVisitor<ResolvePattern,
436440

437441
// FIXME: Argument labels?
438442
EnumElementDecl *referencedElement
439-
= lookupEnumMemberElement(TC, DC, ty, ude->getName().getBaseName());
443+
= lookupEnumMemberElement(TC, DC, ty, ude->getName().getBaseName(),
444+
ude->getLoc());
440445

441446
// Build a TypeRepr from the head of the full path.
442447
// FIXME: Compound names.
@@ -474,7 +479,8 @@ class ResolvePattern : public ASTVisitor<ResolvePattern,
474479
// Try looking up an enum element in context.
475480
if (EnumElementDecl *referencedElement
476481
= lookupUnqualifiedEnumMemberElement(TC, DC,
477-
ude->getName().getBaseName())) {
482+
ude->getName().getBaseName(),
483+
ude->getLoc())) {
478484
auto *enumDecl = referencedElement->getParentEnum();
479485
auto enumTy = enumDecl->getDeclaredTypeInContext();
480486
TypeLoc loc = TypeLoc::withoutLoc(enumTy);
@@ -558,7 +564,8 @@ class ResolvePattern : public ASTVisitor<ResolvePattern,
558564
if (auto compId = dyn_cast<ComponentIdentTypeRepr>(repr)) {
559565
// Try looking up an enum element in context.
560566
EnumElementDecl *referencedElement
561-
= lookupUnqualifiedEnumMemberElement(TC, DC, compId->getIdentifier());
567+
= lookupUnqualifiedEnumMemberElement(TC, DC, compId->getIdentifier(),
568+
repr->getLoc());
562569

563570
if (!referencedElement)
564571
return nullptr;
@@ -596,7 +603,8 @@ class ResolvePattern : public ASTVisitor<ResolvePattern,
596603
auto tailComponent = compoundR->Components.back();
597604

598605
EnumElementDecl *referencedElement
599-
= lookupEnumMemberElement(TC, DC, enumTy, tailComponent->getIdentifier());
606+
= lookupEnumMemberElement(TC, DC, enumTy, tailComponent->getIdentifier(),
607+
tailComponent->getLoc());
600608
if (!referencedElement)
601609
return nullptr;
602610

@@ -1382,8 +1390,10 @@ bool TypeChecker::coercePatternToType(Pattern *&P, DeclContext *dc, Type type,
13821390

13831391
Type enumTy;
13841392
if (!elt) {
1385-
if (type->getAnyNominal())
1386-
elt = lookupEnumMemberElement(*this, dc, type, EEP->getName());
1393+
if (type->getAnyNominal()) {
1394+
elt = lookupEnumMemberElement(*this, dc, type, EEP->getName(),
1395+
EEP->getLoc());
1396+
}
13871397
if (!elt) {
13881398
if (!type->is<ErrorType>()) {
13891399
// Lowercasing of Swift.Optional's cases is handled in the
@@ -1513,7 +1523,8 @@ bool TypeChecker::coercePatternToType(Pattern *&P, DeclContext *dc, Type type,
15131523
// If the element decl was not resolved (because it was spelled without a
15141524
// type as `.Foo`), resolve it now that we have a type.
15151525
if (!OP->getElementDecl()) {
1516-
auto *element = lookupEnumMemberElement(*this, dc, type, Context.Id_some);
1526+
auto *element = lookupEnumMemberElement(*this, dc, type, Context.Id_some,
1527+
OP->getLoc());
15171528
if (!element) {
15181529
diagnose(OP->getLoc(), diag::enum_element_pattern_member_not_found,
15191530
"Some", type);

test/ClangModules/swift2_warnings.swift

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,3 +95,10 @@ class X : NSDocument {
9595
}
9696

9797
func makeCopy<T: NSWobbling>(thing: T) {} // expected-error {{'NSWobbling' has been renamed to 'Wobbling'}} {{18-28=Wobbling}}
98+
99+
func useLowercasedEnumCase(x: RuncingMode) {
100+
switch x {
101+
case .Mince: return // expected-error {{'Mince' has been renamed to 'mince'}} {{11-16=mince}}
102+
case .Quince: return // expected-error {{'Quince' has been renamed to 'quince'}} {{11-17=quince}}
103+
}
104+
}

0 commit comments

Comments
 (0)