1
1
use darling:: { util:: SpannedValue , Error , FromMeta } ;
2
2
use k8s_version:: Version ;
3
3
use proc_macro2:: Span ;
4
- use syn:: { spanned:: Spanned , Ident , Path } ;
4
+ use syn:: { spanned:: Spanned , Attribute , Ident , Path } ;
5
5
6
6
use crate :: {
7
7
attrs:: common:: ContainerAttributes ,
@@ -19,8 +19,8 @@ pub(crate) trait ValidateVersions<I>
19
19
where
20
20
I : Spanned ,
21
21
{
22
- /// Validates that each field action version is present in the declared
23
- /// container versions.
22
+ /// Validates that each field or variant action version is present in the
23
+ /// declared container versions.
24
24
fn validate_versions (
25
25
& self ,
26
26
container_attrs : & ContainerAttributes ,
42
42
43
43
let mut errors = Error :: accumulator ( ) ;
44
44
45
- if let Some ( added) = & self . common_attrs ( ) . added {
45
+ if let Some ( added) = & self . common_attributes ( ) . added {
46
46
if !container_attrs
47
47
. versions
48
48
. iter ( )
55
55
}
56
56
}
57
57
58
- for rename in & * self . common_attrs ( ) . renames {
58
+ for rename in & * self . common_attributes ( ) . renames {
59
59
if !container_attrs
60
60
. versions
61
61
. iter ( )
68
68
}
69
69
}
70
70
71
- if let Some ( deprecated) = & self . common_attrs ( ) . deprecated {
71
+ if let Some ( deprecated) = & self . common_attributes ( ) . deprecated {
72
72
if !container_attrs
73
73
. versions
74
74
. iter ( )
@@ -107,8 +107,8 @@ pub(crate) enum ItemType {
107
107
/// is part of the container in every version until renamed or deprecated.
108
108
/// - An item can be renamed many times. That's why renames are stored in a
109
109
/// [`Vec`].
110
- /// - An item can only be deprecated once. A field not marked as 'deprecated'
111
- /// will be included up until the latest version.
110
+ /// - An item can only be deprecated once. A field or variant not marked as
111
+ /// 'deprecated' will be included up until the latest version.
112
112
#[ derive( Debug , FromMeta ) ]
113
113
pub ( crate ) struct ItemAttributes {
114
114
/// This parses the `added` attribute on items (fields or variants). It can
@@ -126,15 +126,20 @@ pub(crate) struct ItemAttributes {
126
126
}
127
127
128
128
impl ItemAttributes {
129
- pub ( crate ) fn validate ( & self , item_ident : & Ident , item_type : & ItemType ) -> Result < ( ) , Error > {
129
+ pub ( crate ) fn validate (
130
+ & self ,
131
+ item_ident : & Ident ,
132
+ item_type : & ItemType ,
133
+ item_attrs : & Vec < Attribute > ,
134
+ ) -> Result < ( ) , Error > {
130
135
// NOTE (@Techassi): This associated function is NOT called by darling's
131
136
// and_then attribute, but instead by the wrapper, FieldAttributes and
132
137
// VariantAttributes.
133
138
134
139
let mut errors = Error :: accumulator ( ) ;
135
140
136
- // TODO (@Techassi): Make the field 'note' optional, because in the
137
- // future, the macro will generate parts of the deprecation note
141
+ // TODO (@Techassi): Make the field or variant 'note' optional, because
142
+ // in the future, the macro will generate parts of the deprecation note
138
143
// automatically. The user-provided note will then be appended to the
139
144
// auto-generated one.
140
145
@@ -150,10 +155,12 @@ impl ItemAttributes {
150
155
// Semantic validation
151
156
errors. handle ( self . validate_action_combinations ( item_ident, item_type) ) ;
152
157
errors. handle ( self . validate_action_order ( item_ident, item_type) ) ;
153
- errors. handle ( self . validate_field_name ( item_ident, item_type) ) ;
158
+ errors. handle ( self . validate_item_name ( item_ident, item_type) ) ;
159
+ errors. handle ( self . validate_item_attributes ( item_attrs) ) ;
154
160
155
- // TODO (@Techassi): Add hint if a field is added in the first version
156
- // that it might be clever to remove the 'added' attribute.
161
+ // TODO (@Techassi): Add hint if a field or variant is added in the
162
+ // first version that it might be clever to remove the 'added'
163
+ // attribute.
157
164
158
165
errors. finish ( ) ?;
159
166
@@ -164,13 +171,13 @@ impl ItemAttributes {
164
171
/// and validates that each item uses a valid combination of actions.
165
172
/// Invalid combinations are:
166
173
///
167
- /// - `added` and `deprecated` using the same version: A field cannot be
168
- /// marked as added in a particular version and then marked as deprecated
169
- /// immediately after. Fields must be included for at least one version
170
- /// before being marked deprecated.
174
+ /// - `added` and `deprecated` using the same version: A field or variant
175
+ /// cannot be marked as added in a particular version and then marked as
176
+ /// deprecated immediately after. Fields and variants must be included for
177
+ /// at least one version before being marked deprecated.
171
178
/// - `added` and `renamed` using the same version: The same reasoning from
172
- /// above applies here as well. Fields must be included for at least one
173
- /// version before being renamed.
179
+ /// above applies here as well. Fields and variants must be included for
180
+ /// at least one version before being renamed.
174
181
/// - `renamed` and `deprecated` using the same version: Again, the same
175
182
/// rules from above apply here as well.
176
183
fn validate_action_combinations (
@@ -195,7 +202,7 @@ impl ItemAttributes {
195
202
if renamed. iter ( ) . any ( |r| * r. since == * deprecated. since ) =>
196
203
{
197
204
Err ( Error :: custom (
198
- "field cannot be marked as `deprecated` and `renamed` in the same version",
205
+ format ! ( "{item_type} cannot be marked as `deprecated` and `renamed` in the same version") ,
199
206
)
200
207
. with_span ( item_ident) )
201
208
}
@@ -252,10 +259,10 @@ impl ItemAttributes {
252
259
///
253
260
/// The following naming rules apply:
254
261
///
255
- /// - Fields marked as deprecated need to include the 'deprecated_' prefix
256
- /// in their name. The prefix must not be included for fields which are
257
- /// not deprecated.
258
- fn validate_field_name ( & self , item_ident : & Ident , item_type : & ItemType ) -> Result < ( ) , Error > {
262
+ /// - Fields or variants marked as deprecated need to include the
263
+ /// deprecation prefix in their name. The prefix must not be included for
264
+ /// fields or variants which are not deprecated.
265
+ fn validate_item_name ( & self , item_ident : & Ident , item_type : & ItemType ) -> Result < ( ) , Error > {
259
266
let prefix = match item_type {
260
267
ItemType :: Field => DEPRECATED_FIELD_PREFIX ,
261
268
ItemType :: Variant => DEPRECATED_VARIANT_PREFIX ,
@@ -277,6 +284,25 @@ impl ItemAttributes {
277
284
278
285
Ok ( ( ) )
279
286
}
287
+
288
+ /// This associated function is called by the top-level validation function
289
+ /// and validates that disallowed item attributes are not used.
290
+ ///
291
+ /// The following naming rules apply:
292
+ ///
293
+ /// - `deprecated` must not be set on items. Instead, use the `deprecated()`
294
+ /// action of the `#[versioned()]` macro.
295
+ fn validate_item_attributes ( & self , item_attrs : & Vec < Attribute > ) -> Result < ( ) , Error > {
296
+ for attr in item_attrs {
297
+ for segment in & attr. path ( ) . segments {
298
+ if segment. ident == "deprecated" {
299
+ return Err ( Error :: custom ( "deprecation must be done using #[versioned(deprecated(since = \" VERSION\" ))]" )
300
+ . with_span ( & attr. span ( ) ) ) ;
301
+ }
302
+ }
303
+ }
304
+ Ok ( ( ) )
305
+ }
280
306
}
281
307
282
308
/// For the added() action
0 commit comments