Skip to content

Commit d015505

Browse files
authored
Merge pull request #61234 from tshortli/correct-platform-case-fixit
Parse: Offer a fix-it when platform is specified with the wrong case in availability attributes and queries
2 parents 1c9b003 + f1ecb4c commit d015505

12 files changed

+82
-8
lines changed

include/swift/AST/DiagnosticsParse.def

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1513,7 +1513,10 @@ ERROR(attr_availability_multiple_kinds ,none,
15131513
WARNING(attr_availability_invalid_duplicate,none,
15141514
"'%0' argument has already been specified", (StringRef))
15151515
WARNING(attr_availability_unknown_platform,none,
1516-
"unknown platform '%0' for attribute '%1'", (StringRef, StringRef))
1516+
"unknown platform '%0' for attribute '%1'", (StringRef, StringRef))
1517+
WARNING(attr_availability_suggest_platform,none,
1518+
"unknown platform '%0' for attribute '%1'; did you mean '%2'?",
1519+
(StringRef, StringRef, StringRef))
15171520
ERROR(attr_availability_expected_platform,none,
15181521
"expected platform in '%0' attribute", (StringRef))
15191522
ERROR(attr_availability_invalid_renamed,none,
@@ -1897,6 +1900,10 @@ ERROR(avail_query_expected_rparen,PointsToFirstBadToken,
18971900

18981901
WARNING(avail_query_unrecognized_platform_name,
18991902
PointsToFirstBadToken, "unrecognized platform name %0", (Identifier))
1903+
WARNING(avail_query_suggest_platform_name,
1904+
PointsToFirstBadToken, "unrecognized platform name %0;"
1905+
" did you mean '%1'?",
1906+
(Identifier, StringRef))
19001907

19011908
ERROR(avail_query_disallowed_operator, PointsToFirstBadToken,
19021909
"'%0' cannot be used in an availability condition", (StringRef))

include/swift/AST/PlatformKind.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,10 @@ StringRef platformString(PlatformKind platform);
4141
/// or None if such a platform kind does not exist.
4242
Optional<PlatformKind> platformFromString(StringRef Name);
4343

44+
/// Returns a valid platform string if the candidate string would be a valid
45+
/// platform string if its case were adjusted (e.g. "macos" -> "macOS").
46+
Optional<StringRef> caseCorrectedPlatformString(StringRef candidate);
47+
4448
/// Returns a human-readable version of the platform name as a string, suitable
4549
/// for emission in diagnostics (e.g., "macOS").
4650
StringRef prettyPlatformString(PlatformKind platform);

lib/AST/PlatformKind.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,15 @@ Optional<PlatformKind> swift::platformFromString(StringRef Name) {
5858
.Default(Optional<PlatformKind>());
5959
}
6060

61+
Optional<StringRef> swift::caseCorrectedPlatformString(StringRef candidate) {
62+
#define AVAILABILITY_PLATFORM(X, PrettyName) \
63+
if (candidate.compare_insensitive(#X) == 0) { \
64+
return StringRef(#X); \
65+
}
66+
#include "swift/AST/PlatformKinds.def"
67+
return None;
68+
}
69+
6170
static bool isApplicationExtensionPlatform(PlatformKind Platform) {
6271
switch (Platform) {
6372
case PlatformKind::macOSApplicationExtension:

lib/Parse/ParseDecl.cpp

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -295,6 +295,7 @@ ParserResult<AvailableAttr> Parser::parseExtendedAvailabilitySpecList(
295295
};
296296

297297
StringRef Platform = Tok.getText();
298+
SourceLoc PlatformLoc = Tok.getLoc();
298299

299300
StringRef Message, Renamed;
300301
VersionArg Introduced, Deprecated, Obsoleted;
@@ -564,8 +565,14 @@ ParserResult<AvailableAttr> Parser::parseExtendedAvailabilitySpecList(
564565
if (AnyArgumentInvalid)
565566
return nullptr;
566567
if (!PlatformKind.hasValue()) {
567-
diagnose(AttrLoc, diag::attr_availability_unknown_platform,
568-
Platform, AttrName);
568+
if (auto CorrectedPlatform = caseCorrectedPlatformString(Platform)) {
569+
diagnose(PlatformLoc, diag::attr_availability_suggest_platform, Platform,
570+
AttrName, *CorrectedPlatform)
571+
.fixItReplace(SourceRange(PlatformLoc), *CorrectedPlatform);
572+
} else {
573+
diagnose(AttrLoc, diag::attr_availability_unknown_platform, Platform,
574+
AttrName);
575+
}
569576
return nullptr;
570577
}
571578

@@ -1820,8 +1827,14 @@ ParserStatus Parser::parsePlatformVersionInList(StringRef AttrName,
18201827
consumeToken();
18211828

18221829
if (!MaybePlatform.hasValue()) {
1823-
diagnose(PlatformLoc, diag::attr_availability_unknown_platform,
1824-
platformText, AttrName);
1830+
if (auto correctedPlatform = caseCorrectedPlatformString(platformText)) {
1831+
diagnose(PlatformLoc, diag::attr_availability_suggest_platform,
1832+
platformText, AttrName, *correctedPlatform)
1833+
.fixItReplace(SourceRange(PlatformLoc), *correctedPlatform);
1834+
} else {
1835+
diagnose(PlatformLoc, diag::attr_availability_unknown_platform,
1836+
platformText, AttrName);
1837+
}
18251838
} else if (*MaybePlatform == PlatformKind::none) {
18261839
// Wildcards ('*') aren't supported in this kind of list.
18271840
diagnose(PlatformLoc, diag::attr_availability_wildcard_ignored,

lib/Parse/ParseExpr.cpp

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3952,8 +3952,15 @@ Parser::parsePlatformVersionConstraintSpec() {
39523952
platformFromString(PlatformIdentifier.str());
39533953

39543954
if (!Platform.hasValue() || Platform.getValue() == PlatformKind::none) {
3955-
diagnose(Tok, diag::avail_query_unrecognized_platform_name,
3956-
PlatformIdentifier);
3955+
if (auto CorrectedPlatform =
3956+
caseCorrectedPlatformString(PlatformIdentifier.str())) {
3957+
diagnose(PlatformLoc, diag::avail_query_suggest_platform_name,
3958+
PlatformIdentifier, *CorrectedPlatform)
3959+
.fixItReplace(PlatformLoc, *CorrectedPlatform);
3960+
} else {
3961+
diagnose(PlatformLoc, diag::avail_query_unrecognized_platform_name,
3962+
PlatformIdentifier);
3963+
}
39573964
Platform = PlatformKind::none;
39583965
}
39593966

test/Parse/availability_query.swift

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,9 @@ if #available(iDishwasherOS 10.51) { // expected-warning {{unrecognized platform
4646
if #available(iDishwasherOS 10.51, *) { // expected-warning {{unrecognized platform name 'iDishwasherOS'}}
4747
}
4848

49+
if #available(macos 10.51, *) { // expected-warning {{unrecognized platform name 'macos'; did you mean 'macOS'?}} {{15-20=macOS}}
50+
}
51+
4952
if #available(OSX 10.51, OSX 10.52, *) { // expected-error {{version for 'macOS' already specified}}
5053
}
5154

test/Parse/availability_query_unavailability.swift

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,9 @@ if #unavailable(iDishwasherOS 10.51) { // expected-warning {{unrecognized platfo
4343
if #unavailable(iDishwasherOS 10.51) { // expected-warning {{unrecognized platform name 'iDishwasherOS'}}
4444
}
4545

46+
if #unavailable(macos 10.51) { // expected-warning {{unrecognized platform name 'macos'; did you mean 'macOS'?}} {{17-22=macOS}}
47+
}
48+
4649
if #unavailable(OSX 10.51, OSX 10.52) { // expected-error {{version for 'macOS' already specified}}
4750
}
4851

test/Sema/availability_define_parsing.swift

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
// RUN: -define-availability "_justAName" \
55
// RUN: -define-availability "_brokenPlatforms:spaceOS 10.11" \
66
// RUN: -define-availability "_refuseWildcard:iOS 13.0, *, macOS 11.0" \
7+
// RUN: -define-availability "_incorrectCase:ios 13.0, macos 11.0" \
78
// RUN: -define-availability "_duplicateVersion 1.0:iOS 13.0" \
89
// RUN: -define-availability "_duplicateVersion 1.0:iOS 13.0" \
910
// RUN: 2>&1 | %FileCheck %s
@@ -21,11 +22,17 @@ public func brokenPlatforms() {}
2122
// CHECK: -define-availability argument:1:11: error: expected ':' after '_justAName' in availability macro definition
2223
// CHECK-NEXT: _justAName
2324

24-
// CHECK: -define-availability argument:1:31: warning: unrecognized platform name 'spaceOS'
25+
// CHECK: -define-availability argument:1:18: warning: unrecognized platform name 'spaceOS'
2526
// CHECK-NEXT: _brokenPlatforms:spaceOS 10.11
2627

2728
// CHECK: -define-availability argument:1:27: error: future platforms identified by '*' cannot be used in an availability macro
2829
// CHECK-NEXT: _refuseWildcard
2930

31+
// CHECK: -define-availability argument:1:16: warning: unrecognized platform name 'ios'; did you mean 'iOS'?
32+
// CHECK-NEXT: _incorrectCase
33+
34+
// CHECK: -define-availability argument:1:26: warning: unrecognized platform name 'macos'; did you mean 'macOS'?
35+
// CHECK-NEXT: _incorrectCase
36+
3037
// CHECK: duplicate definition of availability macro '_duplicateVersion' for version '1.0'
3138
// CHECK-NEXT: _duplicateVersion

test/Sema/diag_originally_definedin.swift

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,11 @@ public func macroVersioned() {}
2626
// expected-error@-1 {{expected version number in '@_originallyDefinedIn' attribute}}
2727
public func macroUnknown() {}
2828

29+
@available(macOS 10.9, *)
30+
@_originallyDefinedIn(module: "original", macos 10.13) // expected-warning {{unknown platform 'macos' for attribute '@_originallyDefinedIn'; did you mean 'macOS'?}} {{43-48=macOS}}
31+
// expected-error@-1 {{expected at least one platform version in '@_originallyDefinedIn' attribute}}
32+
public func incorrectPlatformCase() {}
33+
2934
@available(macOS 10.9, *)
3035
@_originallyDefinedIn(module: "original", swift 5.1) // expected-warning {{unknown platform 'swift' for attribute '@_originallyDefinedIn'}}
3136
// expected-error@-1 {{expected at least one platform version in '@_originallyDefinedIn' attribute}}

test/attr/attr_availability.swift

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,9 @@ func noKind() {}
2020
@available(badPlatform, unavailable) // expected-warning {{unknown platform 'badPlatform' for attribute 'available'}}
2121
func unavailable_bad_platform() {}
2222

23+
@available(macos, unavailable) // expected-warning {{unknown platform 'macos' for attribute 'available'; did you mean 'macOS'?}} {{12-17=macOS}}
24+
func incorrect_platform_case() {}
25+
2326
// Handle unknown platform.
2427
@available(HAL9000, unavailable) // expected-warning {{unknown platform 'HAL9000'}}
2528
func availabilityUnknownPlatform() {}
@@ -225,6 +228,12 @@ func shortFormWithUnrecognizedPlatform() {
225228
func shortFormWithTwoUnrecognizedPlatforms() {
226229
}
227230

231+
@available(ios 8.0, macos 10.12, *)
232+
// expected-warning@-1 {{unrecognized platform name 'ios'; did you mean 'iOS'?}}
233+
// expected-warning@-2 {{unrecognized platform name 'macos'; did you mean 'macOS'?}}
234+
func shortFormWithTwoPlatformsIncorrectCase() {
235+
}
236+
228237
// Make sure that even after the parser hits an unrecognized
229238
// platform it validates the availability.
230239
@available(iOS 8.0, iDishwasherOS 22.0, iOS 9.0, *)

test/attr/attr_backDeploy.swift

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -253,6 +253,10 @@ public func transparentFunc() {}
253253

254254
// MARK: - Attribute parsing
255255

256+
@available(macOS 11.0, iOS 14.0, *)
257+
@_backDeploy(before: macos 12.0, iOS 15.0) // expected-warning {{unknown platform 'macos' for attribute '@_backDeploy'; did you mean 'macOS'?}} {{22-27=macOS}}
258+
public func incorrectPlatformCaseFunc() {}
259+
256260
@available(macOS 11.0, *)
257261
@_backDeploy(before: macOS 12.0, unknownOS 1.0) // expected-warning {{unknown platform 'unknownOS' for attribute '@_backDeploy'}}
258262
public func unknownOSFunc() {}

test/attr/spi_available.swift

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,6 @@ public class SPIClass3 {}
1111

1212
@_spi_available(macOS 10.4, *)
1313
public class SPIClass4 {} // expected-warning {{symbols that are @_spi_available on all platforms should use @_spi instead}}
14+
15+
@_spi_available(macos 10.15, *) // expected-warning {{unrecognized platform name 'macos'; did you mean 'macOS'?}} {{17-22=macOS}}
16+
public class SPIClass5 {}

0 commit comments

Comments
 (0)