From 9a0435db057d090aa084aff1c2a6317da5d64a6f Mon Sep 17 00:00:00 2001 From: Turiiya <34311583+ttytm@users.noreply.github.com> Date: Thu, 14 Mar 2024 19:38:53 +0100 Subject: [PATCH] checker: add support for deprecation messages for structs and struct fields (#21017) --- vlib/v/checker/struct.v | 43 ++++++++++++++++--- vlib/v/checker/tests/.gitignore | 3 -- vlib/v/checker/tests/field_deprecations.vv | 2 +- .../module.v} | 14 +++++- .../tests/struct_init_deprecations.out | 35 +++++++++++++++ .../checker/tests/struct_init_deprecations.vv | 23 ++++++++++ 6 files changed, 108 insertions(+), 12 deletions(-) rename vlib/v/checker/tests/{module_with_structs_with_deprecated_fields/fields.v => module_with_deprecated_structs/module.v} (63%) create mode 100644 vlib/v/checker/tests/struct_init_deprecations.out create mode 100644 vlib/v/checker/tests/struct_init_deprecations.vv diff --git a/vlib/v/checker/struct.v b/vlib/v/checker/struct.v index 21a5a64d4..f860bd0cb 100644 --- a/vlib/v/checker/struct.v +++ b/vlib/v/checker/struct.v @@ -483,10 +483,20 @@ fn (mut c Checker) struct_init(mut node ast.StructInit, is_field_zero_struct_ini && type_sym.mod != 'builtin')) && !is_field_zero_struct_init { c.error('type `${type_sym.name}` is private', node.pos) } - if type_sym.info is ast.Struct && type_sym.mod != c.mod - && type_sym.info.attrs.contains('noinit') { - c.error('struct `${type_sym.name}` is declared with a `@[noinit]` attribute, so ' + - 'it cannot be initialized with `${type_sym.name}{}`', node.pos) + if type_sym.info is ast.Struct && type_sym.mod != c.mod { + for attr in type_sym.info.attrs { + match attr.name { + 'noinit' { + c.error( + 'struct `${type_sym.name}` is declared with a `@[noinit]` attribute, so ' + + 'it cannot be initialized with `${type_sym.name}{}`', node.pos) + } + 'deprecated' { + c.deprecate('struct', type_sym.name, type_sym.info.attrs, node.pos) + } + else {} + } + } } if type_sym.name.len == 1 && c.table.cur_fn != unsafe { nil } && c.table.cur_fn.generic_names.len == 0 { @@ -506,9 +516,20 @@ fn (mut c Checker) struct_init(mut node ast.StructInit, is_field_zero_struct_ini } sym := c.table.sym(c.unwrap_generic(node.typ)) if sym.info is ast.Struct { - if sym.mod != c.mod && sym.info.attrs.contains('noinit') { - c.error('struct `${sym.name}` is declared with a `@[noinit]` attribute, so ' + - 'it cannot be initialized with `${sym.name}{}`', node.pos) + if sym.mod != c.mod { + for attr in sym.info.attrs { + match attr.name { + 'noinit' { + c.error( + 'struct `${sym.name}` is declared with a `@[noinit]` attribute, so ' + + 'it cannot be initialized with `${sym.name}{}`', node.pos) + } + 'deprecated' { + c.deprecate('struct', sym.name, sym.info.attrs, node.pos) + } + else {} + } + } } if node.no_keys && node.init_fields.len != sym.info.fields.len { fname := if sym.info.fields.len != 1 { 'fields' } else { 'field' } @@ -742,6 +763,14 @@ or use an explicit `unsafe{ a[..] }`, if you do not want a copy of the slice.', for i, mut field in fields { if field.name in inited_fields { + if c.mod != type_sym.mod && field.is_deprecated { + for init_field in node.init_fields { + if field.name == init_field.name { + c.deprecate('field', field.name, field.attrs, init_field.pos) + break + } + } + } continue } sym := c.table.sym(field.typ) diff --git a/vlib/v/checker/tests/.gitignore b/vlib/v/checker/tests/.gitignore index 914870a77..f80465160 100644 --- a/vlib/v/checker/tests/.gitignore +++ b/vlib/v/checker/tests/.gitignore @@ -1,5 +1,2 @@ -*.v -*.c require_or_block_sumtype_map.err !*_test.v -!modules/**/*.v diff --git a/vlib/v/checker/tests/field_deprecations.vv b/vlib/v/checker/tests/field_deprecations.vv index 7b5ae1c16..d8299a7eb 100644 --- a/vlib/v/checker/tests/field_deprecations.vv +++ b/vlib/v/checker/tests/field_deprecations.vv @@ -1,4 +1,4 @@ -import v.checker.tests.module_with_structs_with_deprecated_fields as m +import v.checker.tests.module_with_deprecated_structs as m struct Abc { mut: diff --git a/vlib/v/checker/tests/module_with_structs_with_deprecated_fields/fields.v b/vlib/v/checker/tests/module_with_deprecated_structs/module.v similarity index 63% rename from vlib/v/checker/tests/module_with_structs_with_deprecated_fields/fields.v rename to vlib/v/checker/tests/module_with_deprecated_structs/module.v index 1b3fe732d..117aed038 100644 --- a/vlib/v/checker/tests/module_with_structs_with_deprecated_fields/fields.v +++ b/vlib/v/checker/tests/module_with_deprecated_structs/module.v @@ -1,4 +1,4 @@ -module module_with_structs_with_deprecated_fields +module module_with_deprecated_structs pub struct Xyz { pub mut: @@ -8,14 +8,26 @@ pub mut: d int @[deprecated: 'd use Xyz.a instead'; deprecated_after: '2999-03-01'] } +@[deprecated: 'use New instead'] +@[deprecated_after: '2021-03-01'] +pub struct Old {} + +@[deprecated: 'use Future instead'] +@[deprecated_after: '2999-03-01'] +pub struct Present {} + fn some_internal_function() { mut x := Xyz{} // initialisation; no error + mut o := Old{} + mut p := Present{} // reads: dump(x.a) // no error dump(x.b) // no error internally dump(x.c) // no error internally dump(x.d) // no error internally + dump(o) // no error internally + dump(p) // no error internally // writes: x.a = 1 // no error diff --git a/vlib/v/checker/tests/struct_init_deprecations.out b/vlib/v/checker/tests/struct_init_deprecations.out new file mode 100644 index 000000000..a94951690 --- /dev/null +++ b/vlib/v/checker/tests/struct_init_deprecations.out @@ -0,0 +1,35 @@ +vlib/v/checker/tests/struct_init_deprecations.vv:5:9: notice: struct `v.checker.tests.module_with_deprecated_structs.Present` will be deprecated after 2999-03-01, and will become an error after 2999-08-28; use Future instead + 3 | fn init_deprecated_structs() { + 4 | o := m.Old{} + 5 | p := m.Present{} + | ~~~~~~~~~ + 6 | dump(o) + 7 | dump(p) +vlib/v/checker/tests/struct_init_deprecations.vv:15:3: notice: field `d` will be deprecated after 2999-03-01, and will become an error after 2999-08-28; d use Xyz.a instead + 13 | b: 1 + 14 | c: 2 + 15 | d: 3 + | ~~~~ + 16 | } + 17 | dump(x) +vlib/v/checker/tests/struct_init_deprecations.vv:13:3: warning: field `b` has been deprecated + 11 | x := m.Xyz{ + 12 | a: 0 + 13 | b: 1 + | ~~~~ + 14 | c: 2 + 15 | d: 3 +vlib/v/checker/tests/struct_init_deprecations.vv:4:9: error: struct `v.checker.tests.module_with_deprecated_structs.Old` has been deprecated since 2021-03-01; use New instead + 2 | + 3 | fn init_deprecated_structs() { + 4 | o := m.Old{} + | ~~~~~ + 5 | p := m.Present{} + 6 | dump(o) +vlib/v/checker/tests/struct_init_deprecations.vv:14:3: error: field `c` has been deprecated since 2021-03-01; c use Xyz.a instead + 12 | a: 0 + 13 | b: 1 + 14 | c: 2 + | ~~~~ + 15 | d: 3 + 16 | } diff --git a/vlib/v/checker/tests/struct_init_deprecations.vv b/vlib/v/checker/tests/struct_init_deprecations.vv new file mode 100644 index 000000000..d0aa9efd7 --- /dev/null +++ b/vlib/v/checker/tests/struct_init_deprecations.vv @@ -0,0 +1,23 @@ +import v.checker.tests.module_with_deprecated_structs as m + +fn init_deprecated_structs() { + o := m.Old{} + p := m.Present{} + dump(o) + dump(p) +} + +fn init_deprecated_fields() { + x := m.Xyz{ + a: 0 + b: 1 + c: 2 + d: 3 + } + dump(x) +} + +fn main() { + init_deprecated_structs() + init_deprecated_fields() +} -- 2.39.5