Skip to content

Commit 99f63ed

Browse files
committed
DiagnosticEngine: Support TypeAttribute diagnostic arguments
1 parent dafad5b commit 99f63ed

26 files changed

+160
-67
lines changed

Diff for: docs/Diagnostics.md

+11-2
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,8 @@ Clang also has a kind of diagnostic called a "remark", which represents informat
4141
- Normal: "cannot call 'super.init' outside of an initializer"
4242
- Better: "'super.init' cannot be called outside of an initializer"
4343

44-
- When referring to attributes by name, use *either* "the 'foo' attribute" or "'@foo'", rather than "the '@foo' attribute".
44+
- When referring to attributes by name, use *either* `attribute 'foo'` or
45+
`'@foo'`, rather than `attribute '@foo'`.
4546

4647
- Match the tone and phrasing of other diagnostics. Some common phrases:
4748

@@ -130,7 +131,10 @@ If you run into any issues or have questions while following the steps above, fe
130131

131132
- `%%` - Emits a literal percent sign.
132133

133-
There are several format specifiers that are specific to `Decl` parameters:
134+
The following subsections describe format specifiers that are specific to
135+
diagnostic arguments of a given type.
136+
137+
#### `Decl`
134138

135139
- `%kind0` - Prefixes the declaration's name with its descriptive decl kind (e.g. `instance method 'foo(x:)'`).
136140

@@ -140,6 +144,11 @@ There are several format specifiers that are specific to `Decl` parameters:
140144

141145
- `%kindbase0` - Combines `kind` and `base` (e.g. `instance method 'foo'`).
142146

147+
#### `TypeAttribute`
148+
149+
- `%kind0` - Replaced with `attribute 'foo'`, whereas `%0` is replaced with
150+
`'@foo'`.
151+
143152
Note: If your diagnostic could apply to accessors, be careful how you format the declaration's name; accessors have an empty name, so you need to display their accessor kind and the name of their storage decl instead. Inserting the name with a `Decl *` parameter will handle these complications automatically; if you want to use `DeclName` or `Identifier` instead, you'll probably need a separate version of the diagnostic for accessors.
144153

145154
### Diagnostic Verifier ###

Diff for: include/swift/AST/Attr.h

+4
Original file line numberDiff line numberDiff line change
@@ -3781,6 +3781,10 @@ class alignas(1 << AttrAlignInBits) TypeAttribute
37813781
TypeAttrKind getKind() const {
37823782
return TypeAttrKind(Bits.TypeAttribute.Kind);
37833783
}
3784+
3785+
/// - Note: Do not call this directly when emitting a diagnostic. Instead,
3786+
/// define the diagnostic to accept a `const TypeAttribute *` and use the
3787+
/// appropriate format specifier.
37843788
const char *getAttrName() const {
37853789
return getAttrName(getKind());
37863790
}

Diff for: include/swift/AST/DiagnosticArgument.h

+5
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ namespace swift {
3131

3232
class Decl;
3333
class DeclAttribute;
34+
class TypeAttribute;
3435
class TypeRepr;
3536

3637
enum class DescriptivePatternKind : uint8_t;
@@ -85,6 +86,7 @@ enum class DiagnosticArgumentKind {
8586
DescriptiveDeclKind,
8687
DescriptiveStmtKind,
8788
DeclAttribute,
89+
TypeAttribute,
8890
AvailabilityDomain,
8991
AvailabilityRange,
9092
VersionTuple,
@@ -120,6 +122,7 @@ class DiagnosticArgument {
120122
DescriptiveDeclKind DescriptiveDeclKindVal;
121123
StmtKind DescriptiveStmtKindVal;
122124
const DeclAttribute *DeclAttributeVal;
125+
const TypeAttribute *TypeAttributeVal;
123126
AvailabilityDomain AvailabilityDomainVal;
124127
AvailabilityRange AvailabilityRangeVal;
125128
llvm::VersionTuple VersionVal;
@@ -153,6 +156,7 @@ class DiagnosticArgument {
153156
DiagnosticArgument(DescriptiveDeclKind DDK);
154157
DiagnosticArgument(StmtKind SK);
155158
DiagnosticArgument(const DeclAttribute *attr);
159+
DiagnosticArgument(const TypeAttribute *attr);
156160
DiagnosticArgument(const AvailabilityDomain domain);
157161
DiagnosticArgument(const AvailabilityRange &range);
158162
DiagnosticArgument(llvm::VersionTuple version);
@@ -192,6 +196,7 @@ class DiagnosticArgument {
192196
DescriptiveDeclKind getAsDescriptiveDeclKind() const;
193197
StmtKind getAsDescriptiveStmtKind() const;
194198
const DeclAttribute *getAsDeclAttribute() const;
199+
const TypeAttribute *getAsTypeAttribute() const;
195200
const AvailabilityDomain getAsAvailabilityDomain() const;
196201
const AvailabilityRange getAsAvailabilityRange() const;
197202
llvm::VersionTuple getAsVersionTuple() const;

Diff for: include/swift/AST/DiagnosticsCommon.def

+3-1
Original file line numberDiff line numberDiff line change
@@ -251,8 +251,10 @@ REMARK(remark_scanner_invalidate_missing_cas, none,
251251
// MARK: custom attribute diagnostics
252252
//------------------------------------------------------------------------------
253253

254-
ERROR(unknown_attribute,none,
254+
ERROR(unknown_attr_name,none,
255255
"unknown attribute '%0'", (StringRef))
256+
ERROR(unknown_type_attr,none,
257+
"unknown %kind0", (const TypeAttribute *))
256258

257259
//------------------------------------------------------------------------------
258260
// MARK: macro diagnostics

Diff for: include/swift/AST/DiagnosticsParse.def

+4-1
Original file line numberDiff line numberDiff line change
@@ -1484,9 +1484,12 @@ ERROR(multiple_access_level_modifiers,none,
14841484
"multiple incompatible access-level modifiers specified", ())
14851485
NOTE(previous_access_level_modifier,none,
14861486
"previous modifier specified here", ())
1487-
ERROR(mutually_exclusive_attrs,none,
1487+
ERROR(mutually_exclusive_decl_attrs,none,
14881488
"%0 contradicts previous %select{attribute|modifier}2 %1",
14891489
(DeclAttribute, DeclAttribute, bool))
1490+
ERROR(mutually_exclusive_type_attrs,none,
1491+
"%0 contradicts previous %1",
1492+
(const TypeAttribute *, const TypeAttribute *))
14901493
ERROR(mutually_exclusive_attr_names,none,
14911494
"'%0' contradicts previous %select{attribute|modifier}2 '%1'",
14921495
(StringRef, StringRef, bool))

Diff for: include/swift/AST/DiagnosticsSema.def

+11-10
Original file line numberDiff line numberDiff line change
@@ -2686,10 +2686,6 @@ NOTE(invalid_extension_rewrite,none,
26862686
ERROR(cannot_extend_nominal,none,
26872687
"cannot extend %kind0", (const NominalTypeDecl *))
26882688

2689-
ERROR(retroactive_not_in_extension_inheritance_clause,none,
2690-
"'retroactive' attribute only applies in inheritance clauses in "
2691-
"extensions", ())
2692-
26932689
ERROR(retroactive_attr_does_not_apply,none,
26942690
"'retroactive' attribute does not apply; %0 is declared in "
26952691
"%select{the same package|this module}1",
@@ -5862,9 +5858,14 @@ ERROR(sendable_raw_storage,none,
58625858
"struct %0 with @_rawLayout does not conform to the 'Sendable' protocol", (DeclName))
58635859

58645860
ERROR(typeattr_not_inheritance_clause,none,
5865-
"'%0' attribute only applies in inheritance clauses", (StringRef))
5861+
"%0 only applies in inheritance clauses",
5862+
(const TypeAttribute *))
5863+
ERROR(typeattr_not_extension_inheritance_clause,none,
5864+
"%0 only applies in inheritance clauses in extensions",
5865+
(const TypeAttribute *))
58665866
ERROR(typeattr_not_existential,none,
5867-
"'%0' attribute cannot apply to non-protocol type %1", (StringRef, Type))
5867+
"%0 cannot apply to non-protocol type %1",
5868+
(const TypeAttribute *, Type))
58685869

58695870
WARNING(unchecked_conformance_not_special,none,
58705871
"@unchecked conformance to %0 has no meaning", (Type))
@@ -6262,8 +6263,8 @@ NOTE(overridden_required_initializer_here,none,
62626263
"overridden required initializer is here", ())
62636264

62646265
// Functions
6265-
ERROR(attribute_requires_function_type,none,
6266-
"@%0 attribute only applies to function types", (StringRef))
6266+
ERROR(type_attr_requires_function_type,none,
6267+
"%0 only applies to function types", (const TypeAttribute *))
62676268
ERROR(generic_function_type,none,
62686269
"function values cannot be generic", ())
62696270
ERROR(unsupported_convention,none,
@@ -7603,8 +7604,8 @@ ERROR(marker_protocol_conditional_conformance,none,
76037604
//------------------------------------------------------------------------------
76047605

76057606
ERROR(differentiable_programming_attr_used_without_required_module, none,
7606-
"'@%0' attribute used without importing module %1",
7607-
(StringRef, Identifier))
7607+
"%0 used without importing module %1",
7608+
(const TypeAttribute *, Identifier))
76087609

76097610
//------------------------------------------------------------------------------
76107611
// MARK: OSLog

Diff for: lib/AST/DiagnosticArgument.cpp

+8
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,9 @@ DiagnosticArgument::DiagnosticArgument(StmtKind SK)
9191
DiagnosticArgument::DiagnosticArgument(const DeclAttribute *attr)
9292
: Kind(DiagnosticArgumentKind::DeclAttribute), DeclAttributeVal(attr) {}
9393

94+
DiagnosticArgument::DiagnosticArgument(const TypeAttribute *attr)
95+
: Kind(DiagnosticArgumentKind::TypeAttribute), TypeAttributeVal(attr) {}
96+
9497
DiagnosticArgument::DiagnosticArgument(const AvailabilityDomain domain)
9598
: Kind(DiagnosticArgumentKind::AvailabilityDomain),
9699
AvailabilityDomainVal(domain) {}
@@ -207,6 +210,11 @@ const DeclAttribute *DiagnosticArgument::getAsDeclAttribute() const {
207210
return DeclAttributeVal;
208211
}
209212

213+
const TypeAttribute *DiagnosticArgument::getAsTypeAttribute() const {
214+
ASSERT(Kind == DiagnosticArgumentKind::TypeAttribute);
215+
return TypeAttributeVal;
216+
}
217+
210218
const AvailabilityDomain DiagnosticArgument::getAsAvailabilityDomain() const {
211219
ASSERT(Kind == DiagnosticArgumentKind::AvailabilityDomain);
212220
return AvailabilityDomainVal;

Diff for: lib/AST/DiagnosticEngine.cpp

+20
Original file line numberDiff line numberDiff line change
@@ -1079,6 +1079,26 @@ static void formatDiagnosticArgument(StringRef Modifier,
10791079
}
10801080
break;
10811081
}
1082+
case DiagnosticArgumentKind::TypeAttribute: {
1083+
bool useAtStyle = true;
1084+
if (Modifier == "kind") {
1085+
useAtStyle = false;
1086+
} else {
1087+
ASSERT(Modifier.empty() &&
1088+
"Improper modifier for TypeAttribute argument");
1089+
}
1090+
1091+
if (!useAtStyle) {
1092+
Out << "attribute ";
1093+
}
1094+
Out << FormatOpts.OpeningQuotationMark;
1095+
if (useAtStyle) {
1096+
Out << '@';
1097+
}
1098+
Out << Arg.getAsTypeAttribute()->getAttrName();
1099+
Out << FormatOpts.ClosingQuotationMark;
1100+
break;
1101+
}
10821102
case DiagnosticArgumentKind::AvailabilityDomain:
10831103
assert(Modifier.empty() &&
10841104
"Improper modifier for AvailabilityDomain argument");

Diff for: lib/Parse/ParseDecl.cpp

+3-3
Original file line numberDiff line numberDiff line change
@@ -4343,7 +4343,7 @@ ParserStatus Parser::parseDeclAttribute(DeclAttributes &Attributes,
43434343
if (TypeAttribute::getAttrKindFromString(Tok.getText()).has_value())
43444344
diagnose(Tok, diag::type_attribute_applied_to_decl);
43454345
else if (Tok.isContextualKeyword("unknown")) {
4346-
diagnose(Tok, diag::unknown_attribute, "unknown");
4346+
diagnose(Tok, diag::unknown_attr_name, "unknown");
43474347
} else {
43484348
// Change the context to create a custom attribute syntax.
43494349
auto customAttr = parseCustomAttribute(AtLoc);
@@ -4713,7 +4713,7 @@ ParserStatus Parser::parseTypeAttribute(TypeOrCustomAttr &result,
47134713
} else {
47144714
// We could use diag::only_allowed_in_sil here, but it's better
47154715
// not to mention SIL in general diagnostics.
4716-
diagnose(AtLoc, diag::unknown_attribute, Text);
4716+
diagnose(AtLoc, diag::unknown_attr_name, Text);
47174717
}
47184718
}
47194719
return makeParserSuccess();
@@ -5457,7 +5457,7 @@ static void diagnoseOperatorFixityAttributes(Parser &P,
54575457
for (auto it = fixityAttrs.begin(); it != fixityAttrs.end(); ++it) {
54585458
if (it != fixityAttrs.begin()) {
54595459
auto *attr = *it;
5460-
P.diagnose(attr->getLocation(), diag::mutually_exclusive_attrs, attr,
5460+
P.diagnose(attr->getLocation(), diag::mutually_exclusive_decl_attrs, attr,
54615461
fixityAttrs.front(), attr->isDeclModifier())
54625462
.fixItRemove(attr->getRange());
54635463
attr->setInvalid();

Diff for: lib/Parse/ParseStmt.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -2720,7 +2720,7 @@ ParserResult<CaseStmt> Parser::parseStmtCase(bool IsActive) {
27202720
assert(peekToken().is(tok::identifier) && "isAtStartOfSwitchCase() lied");
27212721

27222722
consumeToken(tok::at_sign);
2723-
diagnose(Tok, diag::unknown_attribute, Tok.getText());
2723+
diagnose(Tok, diag::unknown_attr_name, Tok.getText());
27242724
consumeToken(tok::identifier);
27252725

27262726
if (Tok.is(tok::l_paren))

Diff for: lib/SIL/Parser/ParseSIL.cpp

+3-3
Original file line numberDiff line numberDiff line change
@@ -4843,7 +4843,7 @@ bool SILParser::parseSpecificSILInstruction(SILBuilder &B,
48434843
} else if (attr == "builtin") {
48444844
setFromBuiltin(true);
48454845
} else {
4846-
P.diagnose(identLoc, diag::unknown_attribute, attr);
4846+
P.diagnose(identLoc, diag::unknown_attr_name, attr);
48474847
}
48484848

48494849
if (!P.consumeIf(tok::r_square))
@@ -7045,14 +7045,14 @@ bool SILParser::parseCallInstruction(SILLocation InstLoc,
70457045
llvm::SmallString<64> name;
70467046
llvm::raw_svector_ostream os(name);
70477047
os << isolationCrossing->getCalleeIsolation();
7048-
P.diagnose(InstLoc.getSourceLoc(), diag::unknown_attribute, name);
7048+
P.diagnose(InstLoc.getSourceLoc(), diag::unknown_attr_name, name);
70497049
}
70507050
if (isolationCrossing->getCallerIsolation() !=
70517051
ActorIsolation::Unspecified) {
70527052
llvm::SmallString<64> name;
70537053
llvm::raw_svector_ostream os(name);
70547054
os << isolationCrossing->getCalleeIsolation();
7055-
P.diagnose(InstLoc.getSourceLoc(), diag::unknown_attribute, name);
7055+
P.diagnose(InstLoc.getSourceLoc(), diag::unknown_attr_name, name);
70567056
}
70577057
return true;
70587058
}

Diff for: lib/SIL/Parser/SILParser.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -411,7 +411,7 @@ class SILParser {
411411
if (allowed)
412412
setEnum(existing, value, name, loc);
413413
else
414-
P.diagnose(loc, diag::unknown_attribute, name);
414+
P.diagnose(loc, diag::unknown_attr_name, name);
415415
}
416416
};
417417

Diff for: lib/Sema/TypeCheckAttr.cpp

+2-1
Original file line numberDiff line numberDiff line change
@@ -4409,7 +4409,8 @@ void AttributeChecker::visitCustomAttr(CustomAttr *attr) {
44094409
llvm::raw_string_ostream out(typeName);
44104410
typeRepr->print(out);
44114411

4412-
Ctx.Diags.diagnose(attr->getLocation(), diag::unknown_attribute, typeName);
4412+
Ctx.Diags.diagnose(attr->getLocation(), diag::unknown_attr_name,
4413+
typeName);
44134414
}
44144415

44154416
attr->setInvalid();

0 commit comments

Comments
 (0)