Skip to content

Commit 08d46d2

Browse files
Merge pull request #80473 from AnthonyLatsis/diag_type_attr
DiagnosticEngine: Support `TypeAttribute` diagnostic arguments
2 parents 835e305 + 99f63ed commit 08d46d2

31 files changed

+628
-446
lines changed

docs/Diagnostics.md

Lines changed: 11 additions & 2 deletions
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 ###

include/swift/AST/Attr.h

Lines changed: 4 additions & 0 deletions
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
}
Lines changed: 213 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,213 @@
1+
//===--- DiagnosticArgument.h -----------------------------------*- C++ -*-===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2025 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
#ifndef SWIFT_AST_DIAGNOSTIC_ARGUMENT_H
14+
#define SWIFT_AST_DIAGNOSTIC_ARGUMENT_H
15+
16+
#include "swift/AST/ActorIsolation.h"
17+
#include "swift/AST/AvailabilityDomain.h"
18+
#include "swift/AST/DiagnosticConsumer.h"
19+
#include "swift/AST/Identifier.h"
20+
#include "swift/AST/LayoutConstraint.h"
21+
#include "swift/AST/TypeLoc.h"
22+
#include "swift/Basic/Version.h"
23+
#include "llvm/Support/VersionTuple.h"
24+
25+
namespace clang {
26+
class NamedDecl;
27+
class Type;
28+
} // namespace clang
29+
30+
namespace swift {
31+
32+
class Decl;
33+
class DeclAttribute;
34+
class TypeAttribute;
35+
class TypeRepr;
36+
37+
enum class DescriptivePatternKind : uint8_t;
38+
enum class DescriptiveDeclKind : uint8_t;
39+
enum class ReferenceOwnership : uint8_t;
40+
enum class SelfAccessKind : uint8_t;
41+
enum class StaticSpellingKind : uint8_t;
42+
enum class StmtKind;
43+
44+
/// A family of wrapper types for compiler data types that forces its
45+
/// underlying data to be formatted with full qualification.
46+
///
47+
/// So far, this is only useful for \c Type, hence the SFINAE'ing.
48+
template <typename T, typename = void>
49+
struct FullyQualified {};
50+
51+
template <typename T>
52+
struct FullyQualified<
53+
T, typename std::enable_if<std::is_convertible<T, Type>::value>::type> {
54+
Type t;
55+
56+
public:
57+
FullyQualified(T t) : t(t) {};
58+
59+
Type getType() const { return t; }
60+
};
61+
62+
struct WitnessType {
63+
Type t;
64+
65+
WitnessType(Type t) : t(t) {}
66+
67+
Type getType() { return t; }
68+
};
69+
70+
/// Describes the kind of diagnostic argument we're storing.
71+
enum class DiagnosticArgumentKind {
72+
String,
73+
Integer,
74+
Unsigned,
75+
Identifier,
76+
ObjCSelector,
77+
Decl,
78+
Type,
79+
TypeRepr,
80+
FullyQualifiedType,
81+
WitnessType,
82+
DescriptivePatternKind,
83+
SelfAccessKind,
84+
ReferenceOwnership,
85+
StaticSpellingKind,
86+
DescriptiveDeclKind,
87+
DescriptiveStmtKind,
88+
DeclAttribute,
89+
TypeAttribute,
90+
AvailabilityDomain,
91+
AvailabilityRange,
92+
VersionTuple,
93+
LayoutConstraint,
94+
ActorIsolation,
95+
IsolationSource,
96+
Diagnostic,
97+
ClangDecl,
98+
ClangType,
99+
};
100+
101+
/// Variant type that holds a single diagnostic argument of a known
102+
/// type.
103+
///
104+
/// All diagnostic arguments are converted to an instance of this class.
105+
class DiagnosticArgument {
106+
DiagnosticArgumentKind Kind;
107+
union {
108+
int IntegerVal;
109+
unsigned UnsignedVal;
110+
StringRef StringVal;
111+
DeclNameRef IdentifierVal;
112+
ObjCSelector ObjCSelectorVal;
113+
const Decl *TheDecl;
114+
Type TypeVal;
115+
TypeRepr *TyR;
116+
FullyQualified<Type> FullyQualifiedTypeVal;
117+
WitnessType WitnessTypeVal;
118+
DescriptivePatternKind DescriptivePatternKindVal;
119+
SelfAccessKind SelfAccessKindVal;
120+
ReferenceOwnership ReferenceOwnershipVal;
121+
StaticSpellingKind StaticSpellingKindVal;
122+
DescriptiveDeclKind DescriptiveDeclKindVal;
123+
StmtKind DescriptiveStmtKindVal;
124+
const DeclAttribute *DeclAttributeVal;
125+
const TypeAttribute *TypeAttributeVal;
126+
AvailabilityDomain AvailabilityDomainVal;
127+
AvailabilityRange AvailabilityRangeVal;
128+
llvm::VersionTuple VersionVal;
129+
LayoutConstraint LayoutConstraintVal;
130+
ActorIsolation ActorIsolationVal;
131+
IsolationSource IsolationSourceVal;
132+
DiagnosticInfo *DiagnosticVal;
133+
const clang::NamedDecl *ClangDecl;
134+
const clang::Type *ClangType;
135+
};
136+
137+
public:
138+
DiagnosticArgument(StringRef S);
139+
DiagnosticArgument(int I);
140+
DiagnosticArgument(unsigned I);
141+
DiagnosticArgument(DeclNameRef R);
142+
DiagnosticArgument(DeclName D);
143+
DiagnosticArgument(DeclBaseName D);
144+
DiagnosticArgument(Identifier I);
145+
DiagnosticArgument(ObjCSelector S);
146+
DiagnosticArgument(const Decl *VD);
147+
DiagnosticArgument(Type T);
148+
DiagnosticArgument(TypeRepr *T);
149+
DiagnosticArgument(FullyQualified<Type> FQT);
150+
DiagnosticArgument(WitnessType WT);
151+
DiagnosticArgument(const TypeLoc &TL);
152+
DiagnosticArgument(DescriptivePatternKind DPK);
153+
DiagnosticArgument(ReferenceOwnership RO);
154+
DiagnosticArgument(SelfAccessKind SAK);
155+
DiagnosticArgument(StaticSpellingKind SSK);
156+
DiagnosticArgument(DescriptiveDeclKind DDK);
157+
DiagnosticArgument(StmtKind SK);
158+
DiagnosticArgument(const DeclAttribute *attr);
159+
DiagnosticArgument(const TypeAttribute *attr);
160+
DiagnosticArgument(const AvailabilityDomain domain);
161+
DiagnosticArgument(const AvailabilityRange &range);
162+
DiagnosticArgument(llvm::VersionTuple version);
163+
DiagnosticArgument(LayoutConstraint L);
164+
DiagnosticArgument(ActorIsolation AI);
165+
DiagnosticArgument(IsolationSource IS);
166+
DiagnosticArgument(DiagnosticInfo *D);
167+
DiagnosticArgument(const clang::NamedDecl *ND);
168+
DiagnosticArgument(const clang::Type *Ty);
169+
170+
/// Initializes a diagnostic argument using the underlying type of the
171+
/// given enum.
172+
template <
173+
typename EnumType,
174+
typename std::enable_if<std::is_enum<EnumType>::value>::type * = nullptr>
175+
DiagnosticArgument(EnumType value)
176+
: DiagnosticArgument(
177+
static_cast<typename std::underlying_type<EnumType>::type>(value)) {
178+
}
179+
180+
DiagnosticArgumentKind getKind() const;
181+
182+
StringRef getAsString() const;
183+
int getAsInteger() const;
184+
unsigned getAsUnsigned() const;
185+
DeclNameRef getAsIdentifier() const;
186+
ObjCSelector getAsObjCSelector() const;
187+
const Decl *getAsDecl() const;
188+
Type getAsType() const;
189+
TypeRepr *getAsTypeRepr() const;
190+
FullyQualified<Type> getAsFullyQualifiedType() const;
191+
WitnessType getAsWitnessType() const;
192+
DescriptivePatternKind getAsDescriptivePatternKind() const;
193+
ReferenceOwnership getAsReferenceOwnership() const;
194+
SelfAccessKind getAsSelfAccessKind() const;
195+
StaticSpellingKind getAsStaticSpellingKind() const;
196+
DescriptiveDeclKind getAsDescriptiveDeclKind() const;
197+
StmtKind getAsDescriptiveStmtKind() const;
198+
const DeclAttribute *getAsDeclAttribute() const;
199+
const TypeAttribute *getAsTypeAttribute() const;
200+
const AvailabilityDomain getAsAvailabilityDomain() const;
201+
const AvailabilityRange getAsAvailabilityRange() const;
202+
llvm::VersionTuple getAsVersionTuple() const;
203+
LayoutConstraint getAsLayoutConstraint() const;
204+
ActorIsolation getAsActorIsolation() const;
205+
IsolationSource getAsIsolationSource() const;
206+
DiagnosticInfo *getAsDiagnostic() const;
207+
const clang::NamedDecl *getAsClangDecl() const;
208+
const clang::Type *getAsClangType() const;
209+
};
210+
211+
} // namespace swift
212+
213+
#endif /* SWIFT_AST_DIAGNOSTIC_ARGUMENT_H */

0 commit comments

Comments
 (0)