Skip to content

Commit facaad1

Browse files
authored
A diagnosis from the argument clinic (#20997)
[Parse] Warn if the same argument is specified more than once in @available
1 parent 026d02f commit facaad1

File tree

3 files changed

+36
-2
lines changed

3 files changed

+36
-2
lines changed

include/swift/AST/DiagnosticsParse.def

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1349,6 +1349,8 @@ ERROR(attr_availability_unavailable_deprecated,none,
13491349
"'%0' attribute cannot be both unconditionally 'unavailable' and "
13501350
"'deprecated'", (StringRef))
13511351

1352+
WARNING(attr_availability_invalid_duplicate,none,
1353+
"'%0' argument has already been specified", (StringRef))
13521354
WARNING(attr_availability_unknown_platform,none,
13531355
"unknown platform '%0' for attribute '%1'", (StringRef, StringRef))
13541356
ERROR(attr_availability_invalid_renamed,none,

lib/Parse/ParseDecl.cpp

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -358,6 +358,7 @@ ParserResult<AvailableAttr> Parser::parseExtendedAvailabilitySpecList(
358358
while (HasUpcomingEntry) {
359359
SyntaxParsingContext EntryContext(SyntaxContext,
360360
SyntaxKind::AvailabilityArgument);
361+
auto ArgumentLoc = Tok.getLoc();
361362
AnyAnnotations = true;
362363
StringRef ArgumentKindStr = Tok.getText();
363364
ParamIndex++;
@@ -382,8 +383,8 @@ ParserResult<AvailableAttr> Parser::parseExtendedAvailabilitySpecList(
382383
}
383384

384385
if (ArgumentKind == IsInvalid) {
385-
diagnose(Tok.getLoc(), diag::attr_availability_expected_option, AttrName)
386-
.highlight(SourceRange(Tok.getLoc()));
386+
diagnose(ArgumentLoc, diag::attr_availability_expected_option, AttrName)
387+
.highlight(SourceRange(ArgumentLoc));
387388
if (Tok.is(tok::code_complete) && CodeCompletion) {
388389
CodeCompletion->completeDeclAttrParam(DAK_Available, ParamIndex);
389390
consumeToken(tok::code_complete);
@@ -395,6 +396,13 @@ ParserResult<AvailableAttr> Parser::parseExtendedAvailabilitySpecList(
395396

396397
consumeToken();
397398

399+
auto diagnoseDuplicate = [&](bool WasEmpty) {
400+
if (!WasEmpty) {
401+
diagnose(ArgumentLoc, diag::attr_availability_invalid_duplicate,
402+
ArgumentKindStr);
403+
}
404+
};
405+
398406
switch (ArgumentKind) {
399407
case IsMessage:
400408
case IsRenamed: {
@@ -427,6 +435,7 @@ ParserResult<AvailableAttr> Parser::parseExtendedAvailabilitySpecList(
427435
}
428436

429437
if (ArgumentKind == IsMessage) {
438+
diagnoseDuplicate(Message.empty());
430439
Message = Value.getValue();
431440
} else {
432441
ParsedDeclName parsedName = parseDeclName(Value.getValue());
@@ -435,6 +444,7 @@ ParserResult<AvailableAttr> Parser::parseExtendedAvailabilitySpecList(
435444
AnyArgumentInvalid = true;
436445
break;
437446
}
447+
diagnoseDuplicate(Renamed.empty());
438448
Renamed = Value.getValue();
439449
}
440450

@@ -476,6 +486,7 @@ ParserResult<AvailableAttr> Parser::parseExtendedAvailabilitySpecList(
476486
? Introduced
477487
: (ArgumentKind == IsDeprecated) ? Deprecated : Obsoleted;
478488

489+
bool VerArgWasEmpty = VerArg.empty();
479490
if (parseVersionTuple(
480491
VerArg.Version, VerArg.Range,
481492
Diagnostic(diag::attr_availability_expected_version, AttrName))) {
@@ -484,6 +495,7 @@ ParserResult<AvailableAttr> Parser::parseExtendedAvailabilitySpecList(
484495
consumeToken();
485496
}
486497
VerArg.DelimiterLoc = DelimiterLoc;
498+
diagnoseDuplicate(VerArgWasEmpty);
487499

488500
SyntaxContext->createNodeInPlace(SyntaxKind::AvailabilityLabeledArgument);
489501

test/attr/attr_availability.swift

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1049,3 +1049,23 @@ struct SR8634_Struct: Equatable {
10491049
@available(*, deprecated, message: "I must not be raised in synthesized code", renamed: "x")
10501050
let a: Int
10511051
}
1052+
1053+
@available(*, deprecated, message: "This is a message", message: "This is another message")
1054+
// expected-warning@-1 {{'message' argument has already been specified}}
1055+
func rdar46348825_message() {}
1056+
1057+
@available(*, deprecated, renamed: "rdar46348825_message", renamed: "unavailable_func_with_message")
1058+
// expected-warning@-1 {{'renamed' argument has already been specified}}
1059+
func rdar46348825_renamed() {}
1060+
1061+
@available(swift, introduced: 4.0, introduced: 4.0)
1062+
// expected-warning@-1 {{'introduced' argument has already been specified}}
1063+
func rdar46348825_introduced() {}
1064+
1065+
@available(swift, deprecated: 4.0, deprecated: 4.0)
1066+
// expected-warning@-1 {{'deprecated' argument has already been specified}}
1067+
func rdar46348825_deprecated() {}
1068+
1069+
@available(swift, obsoleted: 4.0, obsoleted: 4.0)
1070+
// expected-warning@-1 {{'obsoleted' argument has already been specified}}
1071+
func rdar46348825_obsoleted() {}

0 commit comments

Comments
 (0)