Skip to content

Commit f45196d

Browse files
d-ronnqvistCodaFi
authored andcommitted
[SR-4231] Add diagnostic (& fix-it) for mixed syntax availability attribute (swiftlang#9122)
* [Parse] Add diagnostic for mixed syntax availability attribute When parsing a list of availablity specifications in the shorthand syntax, check to see that the next specification is also in shorthand syntax. If the next specification looks like an explicit “deprecated” (or similad) attribute, then emit a specific diagnostic about it to help the developer understand the problem. https://bugs.swift.org/browse/SR-4231 * [Parse] Add fix-it for single mixed availability syntax For the scenario that’s described in SR-4231, when there is one shorthard syntax followed by ‘deprecated’ (or similar), then we can guess that the intention was to treat the shorthand as ‘introduced’ so that the two of them work together. This guess is only made if there is one platform version constrain, that is followed by ‘deprecated’, ‘renamed’, etc. but not ‘introduced’. https://bugs.swift.org/browse/SR-4231 * Automatic formatting using git-clang-format * Fix typos in test code and language in comment Also, consistently names test functions as “deprecated” and "introduced" * [Parse] Add note to explain the mixed availability syntax fix-it insertion This change also moves the fix-it from the error to the note.
1 parent 21d040b commit f45196d

File tree

3 files changed

+83
-1
lines changed

3 files changed

+83
-1
lines changed

include/swift/AST/DiagnosticsParse.def

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1472,6 +1472,13 @@ ERROR(avail_query_unrecognized_platform_name,
14721472
ERROR(avail_query_disallowed_operator, PointsToFirstBadToken,
14731473
"'%0' cannot be used in an availability condition", (StringRef))
14741474

1475+
ERROR(avail_query_argument_and_shorthand_mix_not_allowed, PointsToFirstBadToken,
1476+
"'%0' can't be combined with shorthand specification '%1'",
1477+
(StringRef, StringRef))
1478+
1479+
NOTE(avail_query_meant_introduced,PointsToFirstBadToken,
1480+
"did you mean to use '%0, introduced: %1'?", (StringRef, StringRef))
1481+
14751482
ERROR(avail_query_version_comparison_not_needed,
14761483
none,"version comparison not needed", ())
14771484

lib/Parse/ParseStmt.cpp

Lines changed: 48 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1103,7 +1103,54 @@ Parser::parseAvailabilitySpecList(SmallVectorImpl<AvailabilitySpec *> &Specs) {
11031103
consumeToken();
11041104
Status.setIsParseError();
11051105
} else if (consumeIf(tok::comma)) {
1106-
// keep going.
1106+
// There is more to parse in this list.
1107+
1108+
// Before continuing to parse the next specification, we check that it's
1109+
// also in the shorthand syntax and provide a more specific diagnostic if
1110+
// that's not the case.
1111+
if (Tok.isIdentifierOrUnderscore() &&
1112+
!peekToken().isAny(tok::integer_literal, tok::floating_literal)) {
1113+
auto Text = Tok.getText();
1114+
if (Text == "deprecated" || Text == "renamed" || Text == "introduced" ||
1115+
Text == "message" || Text == "obsoleted" || Text == "unavailable") {
1116+
auto *Previous = Specs.back();
1117+
auto &SourceManager = Context.SourceMgr;
1118+
auto PreviousSpecText =
1119+
SourceManager.extractText(L->getCharSourceRangeFromSourceRange(
1120+
SourceManager, Previous->getSourceRange()));
1121+
1122+
diagnose(Tok,
1123+
diag::avail_query_argument_and_shorthand_mix_not_allowed,
1124+
Text, PreviousSpecText);
1125+
1126+
// If this was preceded by a single platform version constraint, we
1127+
// can guess that the intention was to treat it as 'introduced' and
1128+
// suggest a fix-it to combine them.
1129+
if (Specs.size() == 1 &&
1130+
PlatformVersionConstraintAvailabilitySpec::classof(Previous) &&
1131+
Text != "introduced") {
1132+
auto *PlatformSpec =
1133+
cast<PlatformVersionConstraintAvailabilitySpec>(Previous);
1134+
1135+
auto PlatformName = platformString(PlatformSpec->getPlatform());
1136+
auto PlatformNameEndLoc =
1137+
PlatformSpec->getPlatformLoc().getAdvancedLoc(
1138+
PlatformName.size());
1139+
1140+
StringRef VersionName = PlatformSpec->getVersion().getAsString();
1141+
1142+
diagnose(PlatformSpec->getPlatformLoc(),
1143+
diag::avail_query_meant_introduced, PlatformName,
1144+
VersionName)
1145+
.fixItInsert(PlatformNameEndLoc, ", introduced:");
1146+
}
1147+
1148+
Status.setIsParseError();
1149+
break;
1150+
}
1151+
}
1152+
1153+
// Otherwise, keep going.
11071154
} else {
11081155
break;
11091156
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
// RUN: %target-typecheck-verify-swift
2+
3+
// SR-4231: Misleading/wrong error message for malformed @available
4+
5+
@available(OSX 10.6, *) // no error
6+
func availableSince10_6() {}
7+
8+
@available(OSX, introduced: 10.0, deprecated: 10.12) // no error
9+
func introducedFollowedByDeprecated() {}
10+
11+
@available(OSX 10.0, deprecated: 10.12)
12+
// expected-error@-1 {{'deprecated' can't be combined with shorthand specification 'OSX 10.0'}}
13+
// expected-note@-2 {{did you mean to use 'OSX, introduced: 10.0'?}} {{15-15=, introduced:}}
14+
// expected-error@-3 {{expected declaration}}
15+
func shorthandFollowedByDeprecated() {}
16+
17+
@available(OSX 10.0, introduced: 10.12)
18+
// expected-error@-1 {{'introduced' can't be combined with shorthand specification 'OSX 10.0'}}
19+
// expected-error@-2 {{expected declaration}}
20+
func shorthandFollowedByIntroduced() {}
21+
22+
@available(iOS 6.0, OSX 10.8, *) // no error
23+
func availableOnMultiplePlatforms() {}
24+
25+
@available(iOS 6.0, OSX 10.0, deprecated: 10.12)
26+
// expected-error@-1 {{'deprecated' can't be combined with shorthand specification 'OSX 10.0'}}
27+
// expected-error@-2 {{expected declaration}}
28+
func twoShorthandsFollowedByDeprecated() {}

0 commit comments

Comments
 (0)