Skip to content

Commit 12128ca

Browse files
committed
[NFC] Add parsing helpers for @attr(<identifier>)
Extends the existing `parseSingleAttrOption()` helper to also be able to parse a single arbitrary `Identifier`. This simplifies the handling of `SwiftNativeObjCRuntimeBaseAttr`, `ObjCRuntimeNameAttr`, and `ProjectedValuePropertyAttr`.
1 parent b3c1339 commit 12128ca

File tree

3 files changed

+51
-72
lines changed

3 files changed

+51
-72
lines changed

include/swift/Parse/Parser.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -896,7 +896,7 @@ class Parser {
896896

897897
/// Parse the specified expected token and return its location on success. On failure, emit the specified
898898
/// error diagnostic, a note at the specified note location, and return the location of the previous token.
899-
bool parseMatchingToken(tok K, SourceLoc &TokLoc, Diag<> ErrorDiag,
899+
bool parseMatchingToken(tok K, SourceLoc &TokLoc, Diagnostic ErrorDiag,
900900
SourceLoc OtherLoc);
901901

902902
/// Returns the proper location for a missing right brace, parenthesis, etc.

lib/Parse/ParseDecl.cpp

Lines changed: 49 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -2061,7 +2061,7 @@ class LLVM_NODISCARD AttrOptionSwitch {
20612061
bool isDeclModifier;
20622062

20632063
// State:
2064-
StringRef exampleName; // empty: when() was never called
2064+
Diagnostic misparseDiagnostic = diag::invalid_diagnostic;
20652065
Optional<R> result; // None: no when() has matched
20662066

20672067
public:
@@ -2084,8 +2084,9 @@ class LLVM_NODISCARD AttrOptionSwitch {
20842084
/// If the option has the identifier \p name, give it value \p value.
20852085
AttrOptionSwitch<R, T> &when(StringLiteral name, T value) {
20862086
// Save this to use in a future diagnostic, if needed.
2087-
if (exampleName.empty() && !name.empty())
2088-
exampleName = name;
2087+
if (misparseDiagnostic.is(diag::invalid_diagnostic) && !name.empty())
2088+
misparseDiagnostic = Diagnostic(diag::attr_expected_option_such_as,
2089+
attrName, name);
20892090

20902091
// Does this string match?
20912092
if (parsedName && *parsedName == name) {
@@ -2096,10 +2097,32 @@ class LLVM_NODISCARD AttrOptionSwitch {
20962097
return *this;
20972098
}
20982099

2100+
template<typename Body>
2101+
AttrOptionSwitch<R, T> &whenAny(Diagnostic misparse, Body body) {
2102+
if (misparseDiagnostic.is(diag::invalid_diagnostic))
2103+
misparseDiagnostic = misparse;
2104+
2105+
if (parsedName && !parsedName->empty()) {
2106+
assert(!result && "overlapping AttrOptionSwitch::whenAny()?");
2107+
result = std::move(body(*parsedName));
2108+
}
2109+
2110+
return *this;
2111+
}
2112+
2113+
template<typename Ret = AttrOptionSwitch<R, T>>
2114+
std::enable_if_t<std::is_same<T, Identifier>::value, Ret> &
2115+
whenAny(Diagnostic misparse) {
2116+
return whenAny(misparse, [&](StringRef parsed) {
2117+
return P.Context.getIdentifier(parsed);
2118+
});
2119+
}
2120+
20992121
/// Diagnose if the option is missing or was not matched, returning either the
21002122
/// option's value or \c None if an error was diagnosed.
21012123
Optional<R> diagnoseWhenOmitted() {
2102-
assert(!exampleName.empty() && "No AttrOptionSwitch::when() calls");
2124+
assert(!misparseDiagnostic.is(diag::invalid_diagnostic)
2125+
&& "No AttrOptionSwitch::when() calls");
21032126

21042127
if (attrName.empty())
21052128
// An error has already been diagnosed; nothing to do.
@@ -2108,8 +2131,7 @@ class LLVM_NODISCARD AttrOptionSwitch {
21082131
if (!result) {
21092132
if (!parsedName)
21102133
// We parsed a non-identifier; diagnose it with `exampleName`.
2111-
P.diagnose(loc, diag::attr_expected_option_such_as, attrName,
2112-
exampleName);
2134+
P.diagnose(loc, misparseDiagnostic);
21132135
else if (*parsedName == "")
21142136
// Option list was omitted; apparently this attr doesn't allow that.
21152137
P.diagnose(loc, diag::attr_expected_lparen, attrName, isDeclModifier);
@@ -2601,29 +2623,15 @@ bool Parser::parseNewDeclAttribute(DeclAttributes &Attributes, SourceLoc AtLoc,
26012623
}
26022624

26032625
case DAK_SwiftNativeObjCRuntimeBase: {
2604-
if (!consumeIf(tok::l_paren)) {
2605-
diagnose(Loc, diag::attr_expected_lparen, AttrName,
2606-
DeclAttribute::isDeclModifier(DK));
2607-
return false;
2608-
}
2609-
2610-
if (Tok.isNot(tok::identifier)) {
2611-
diagnose(Loc, diag::swift_native_objc_runtime_base_must_be_identifier);
2626+
SourceRange range;
2627+
auto name = parseSingleAttrOption<Identifier>
2628+
(*this, Loc, range, AttrName, DK)
2629+
.whenAny(diag::swift_native_objc_runtime_base_must_be_identifier)
2630+
.diagnoseWhenOmitted();
2631+
if (!name)
26122632
return false;
2613-
}
2614-
2615-
Identifier name;
2616-
consumeIdentifier(name, /*diagnoseDollarPrefix=*/false);
2617-
2618-
auto range = SourceRange(Loc, Tok.getRange().getStart());
26192633

2620-
if (!consumeIf(tok::r_paren)) {
2621-
diagnose(Loc, diag::attr_expected_rparen, AttrName,
2622-
DeclAttribute::isDeclModifier(DK));
2623-
return false;
2624-
}
2625-
2626-
Attributes.add(new (Context) SwiftNativeObjCRuntimeBaseAttr(name,
2634+
Attributes.add(new (Context) SwiftNativeObjCRuntimeBaseAttr(*name,
26272635
AtLoc, range, /*implicit*/ false));
26282636
break;
26292637
}
@@ -2864,30 +2872,15 @@ bool Parser::parseNewDeclAttribute(DeclAttributes &Attributes, SourceLoc AtLoc,
28642872
break;
28652873
}
28662874
case DAK_ObjCRuntimeName: {
2867-
if (!consumeIf(tok::l_paren)) {
2868-
diagnose(Loc, diag::attr_expected_lparen, AttrName,
2869-
DeclAttribute::isDeclModifier(DK));
2870-
return false;
2871-
}
2872-
2873-
if (Tok.isNot(tok::identifier)) {
2874-
diagnose(Loc, diag::objc_runtime_name_must_be_identifier);
2875-
return false;
2876-
}
2877-
2878-
auto name = Tok.getText();
2879-
2880-
consumeToken(tok::identifier);
2881-
2882-
auto range = SourceRange(Loc, Tok.getRange().getStart());
2883-
2884-
if (!consumeIf(tok::r_paren)) {
2885-
diagnose(Loc, diag::attr_expected_rparen, AttrName,
2886-
DeclAttribute::isDeclModifier(DK));
2875+
SourceRange range;
2876+
auto name = parseSingleAttrOption<Identifier>
2877+
(*this, Loc, range, AttrName, DK)
2878+
.whenAny(diag::objc_runtime_name_must_be_identifier)
2879+
.diagnoseWhenOmitted();
2880+
if (!name)
28872881
return false;
2888-
}
28892882

2890-
Attributes.add(new (Context) ObjCRuntimeNameAttr(name, AtLoc, range,
2883+
Attributes.add(new (Context) ObjCRuntimeNameAttr(name->str(), AtLoc, range,
28912884
/*implicit*/ false));
28922885
break;
28932886
}
@@ -3032,30 +3025,16 @@ bool Parser::parseNewDeclAttribute(DeclAttributes &Attributes, SourceLoc AtLoc,
30323025
}
30333026

30343027
case DAK_ProjectedValueProperty: {
3035-
if (!consumeIf(tok::l_paren)) {
3036-
diagnose(Loc, diag::attr_expected_lparen, AttrName,
3037-
DeclAttribute::isDeclModifier(DK));
3038-
return false;
3039-
}
3040-
3041-
if (Tok.isNot(tok::identifier)) {
3042-
diagnose(Loc, diag::projection_value_property_not_identifier);
3043-
return false;
3044-
}
3045-
3046-
Identifier name;
3047-
consumeIdentifier(name, /*diagnoseDollarPrefix=*/false);
3048-
3049-
auto range = SourceRange(Loc, Tok.getRange().getStart());
3050-
3051-
if (!consumeIf(tok::r_paren)) {
3052-
diagnose(Loc, diag::attr_expected_rparen, AttrName,
3053-
DeclAttribute::isDeclModifier(DK));
3028+
SourceRange range;
3029+
auto name = parseSingleAttrOption<Identifier>
3030+
(*this, Loc, range, AttrName, DK)
3031+
.whenAny(diag::projection_value_property_not_identifier)
3032+
.diagnoseWhenOmitted();
3033+
if (!name)
30543034
return false;
3055-
}
30563035

30573036
Attributes.add(new (Context) ProjectedValuePropertyAttr(
3058-
name, AtLoc, range, /*implicit*/ false));
3037+
*name, AtLoc, range, /*implicit*/ false));
30593038
break;
30603039
}
30613040
case DAK_TypeSequence: {

lib/Parse/Parser.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -975,7 +975,7 @@ bool Parser::parseToken(tok K, SourceLoc &TokLoc, const Diagnostic &D) {
975975
return true;
976976
}
977977

978-
bool Parser::parseMatchingToken(tok K, SourceLoc &TokLoc, Diag<> ErrorDiag,
978+
bool Parser::parseMatchingToken(tok K, SourceLoc &TokLoc, Diagnostic ErrorDiag,
979979
SourceLoc OtherLoc) {
980980
Diag<> OtherNote;
981981
switch (K) {

0 commit comments

Comments
 (0)