@@ -2908,7 +2908,7 @@ ParserStatus Parser::parseNewDeclAttribute(DeclAttributes &Attributes,
2908
2908
break ;
2909
2909
}
2910
2910
2911
- consumeAttributeLParen ();
2911
+ auto LParenLoc = consumeAttributeLParen ();
2912
2912
2913
2913
if (Tok.is (tok::code_complete)) {
2914
2914
if (CodeCompletionCallbacks) {
@@ -2920,27 +2920,43 @@ ParserStatus Parser::parseNewDeclAttribute(DeclAttributes &Attributes,
2920
2920
}
2921
2921
2922
2922
// Parse the subject.
2923
- if (Tok.isContextualKeyword (" set" )) {
2924
- consumeToken ();
2925
- } else {
2926
- diagnose (Loc, diag::attr_access_expected_set, AttrName);
2927
-
2923
+ if (!Tok.isContextualKeyword (" set" )) {
2924
+ auto diag = diagnose (Loc, diag::attr_access_expected_set, AttrName);
2925
+
2928
2926
// Minimal recovery: if there's a single token and then an r_paren,
2929
2927
// consume them both. If there's just an r_paren, consume that.
2930
- if (!consumeIf (tok::r_paren)) {
2931
- if (Tok.isNot (tok::l_paren) && peekToken ().is (tok::r_paren)) {
2932
- consumeToken ();
2933
- consumeToken (tok::r_paren);
2934
- }
2928
+ if (Tok.is (tok::r_paren)) {
2929
+ // Suggest `set` between empty parens e.g. `private()` -> `private(set)`
2930
+ auto SetLoc = consumeToken (tok::r_paren);
2931
+ diag.fixItInsert (SetLoc, " set" );
2932
+ } else if (!Tok.is (tok::l_paren) && peekToken ().is (tok::r_paren)) {
2933
+ // Suggest `set` in place of an invalid token between parens
2934
+ // e.g. `private(<invalid>)` -> `private(set)`
2935
+ auto SetLoc = consumeToken ();
2936
+ diag.fixItReplace (SetLoc, " set" );
2937
+ consumeToken (tok::r_paren);
2938
+ } else if (isNextStartOfSwiftDecl ()) {
2939
+ // Suggest `set)` in place of an invalid token after l_paren followed by
2940
+ // a valid declaration start.
2941
+ // e.g. `private( var x: Int` -> `private(set) var x: Int`
2942
+ diag.fixItReplace (Tok.getLoc (), " set)" );
2943
+ } else {
2944
+ // Suggest `set)` after l_paren if not followed by a valid declaration
2945
+ // e.g. `private( val x: Int` -> `private(set) val x: Int`
2946
+ diag.fixItInsertAfter (LParenLoc, " set)" );
2935
2947
}
2948
+
2936
2949
return makeParserSuccess ();
2937
2950
}
2951
+
2952
+ auto SubjectLoc = consumeToken ();
2938
2953
2939
2954
AttrRange = SourceRange (Loc, Tok.getLoc ());
2940
2955
2941
2956
if (!consumeIf (tok::r_paren)) {
2942
2957
diagnose (Loc, diag::attr_expected_rparen, AttrName,
2943
- DeclAttribute::isDeclModifier (DK));
2958
+ DeclAttribute::isDeclModifier (DK))
2959
+ .fixItInsertAfter (SubjectLoc, " )" );
2944
2960
return makeParserSuccess ();
2945
2961
}
2946
2962
0 commit comments