diff --git a/vlib/v/ast/str.v b/vlib/v/ast/str.v index 2ff288bfb7..f2f9bb6200 100644 --- a/vlib/v/ast/str.v +++ b/vlib/v/ast/str.v @@ -51,6 +51,12 @@ pub fn (node &FnDecl) fkey() string { return node.name } +// sfkey returns a unique name of the struct field. +// it is used in v.markused. +pub fn (node &StructField) sfkey() string { + return '${int(node.container_typ)}.${node.name}}' +} + pub fn (node &Fn) fkey() string { if node.is_method { return '${int(node.receiver_type)}.${node.name}' diff --git a/vlib/v/markused/markused.v b/vlib/v/markused/markused.v index a2e38dfb84..9b8ced2fd4 100644 --- a/vlib/v/markused/markused.v +++ b/vlib/v/markused/markused.v @@ -8,7 +8,7 @@ import v.pref // mark_used walks the AST, starting at main() and marks all used fns transitively pub fn mark_used(mut table ast.Table, mut pref_ pref.Preferences, ast_files []&ast.File) { - mut all_fns, all_consts, all_globals := all_fn_const_and_global(ast_files) + mut all_fns, all_consts, all_globals, all_fields := all_global_decl(ast_files) util.timing_start('MARKUSED') defer { util.timing_measure('MARKUSED') @@ -464,11 +464,13 @@ pub fn mark_used(mut table ast.Table, mut pref_ pref.Preferences, ast_files []&a all_fns: all_fns all_consts: all_consts all_globals: all_globals + all_fields: all_fields pref: pref_ ) walker.mark_markused_consts() // tagged with `@[markused]` walker.mark_markused_globals() // tagged with `@[markused]` walker.mark_markused_fns() // tagged with `@[markused]`, `@[export]` and veb actions + walker.mark_struct_field_default_expr() for k, _ in table.used_features.comptime_calls { walker.fn_by_name(k) @@ -553,7 +555,7 @@ pub fn mark_used(mut table ast.Table, mut pref_ pref.Preferences, ast_files []&a } } -fn all_fn_const_and_global(ast_files []&ast.File) (map[string]ast.FnDecl, map[string]ast.ConstField, map[string]ast.GlobalField) { +fn all_global_decl(ast_files []&ast.File) (map[string]ast.FnDecl, map[string]ast.ConstField, map[string]ast.GlobalField, map[string]ast.StructField) { util.timing_start(@METHOD) defer { util.timing_measure(@METHOD) @@ -561,6 +563,7 @@ fn all_fn_const_and_global(ast_files []&ast.File) (map[string]ast.FnDecl, map[st mut all_fns := map[string]ast.FnDecl{} mut all_consts := map[string]ast.ConstField{} mut all_globals := map[string]ast.GlobalField{} + mut all_fields := map[string]ast.StructField{} for i in 0 .. ast_files.len { for node in ast_files[i].stmts { match node { @@ -582,11 +585,17 @@ fn all_fn_const_and_global(ast_files []&ast.File) (map[string]ast.FnDecl, map[st all_globals[gkey] = gfield } } + ast.StructDecl { + for sfield in node.fields { + sfkey := sfield.sfkey() + all_fields[sfkey] = sfield + } + } else {} } } } - return all_fns, all_consts, all_globals + return all_fns, all_consts, all_globals, all_fields } fn mark_all_methods_used(mut table ast.Table, mut all_fn_root_names []string, typ ast.Type) { diff --git a/vlib/v/markused/walker.v b/vlib/v/markused/walker.v index f67b738888..e1c127f1cf 100644 --- a/vlib/v/markused/walker.v +++ b/vlib/v/markused/walker.v @@ -15,6 +15,7 @@ pub mut: used_consts map[string]bool // used_consts['os.args'] == true used_globals map[string]bool used_structs map[string]bool + used_fields map[string]bool n_asserts int pref &pref.Preferences = unsafe { nil } mut: @@ -22,6 +23,7 @@ mut: all_fns map[string]ast.FnDecl all_consts map[string]ast.ConstField all_globals map[string]ast.GlobalField + all_fields map[string]ast.StructField } pub fn Walker.new(params Walker) &Walker { @@ -90,6 +92,16 @@ pub fn (mut w Walker) mark_global_as_used(ckey string) { } } +pub fn (mut w Walker) mark_struct_field_default_expr_as_used(sfkey string) { + if w.used_fields[sfkey] { + return + } + w.used_fields[sfkey] = true + sfield := w.all_fields[sfkey] or { return } + + w.expr(sfield.default_expr) +} + pub fn (mut w Walker) mark_markused_fns() { for _, mut func in w.all_fns { // @[export] @@ -149,6 +161,14 @@ pub fn (mut w Walker) mark_markused_globals() { } } +pub fn (mut w Walker) mark_struct_field_default_expr() { + for sfkey, mut structfield in w.all_fields { + if structfield.has_default_expr { + w.mark_struct_field_default_expr_as_used(sfkey) + } + } +} + pub fn (mut w Walker) stmt(node_ ast.Stmt) { mut node := unsafe { node_ } match mut node { diff --git a/vlib/v/tests/skip_unused/struct_field_default_expr.run.out b/vlib/v/tests/skip_unused/struct_field_default_expr.run.out new file mode 100644 index 0000000000..e69de29bb2 diff --git a/vlib/v/tests/skip_unused/struct_field_default_expr.skip_unused.run.out b/vlib/v/tests/skip_unused/struct_field_default_expr.skip_unused.run.out new file mode 100644 index 0000000000..e69de29bb2 diff --git a/vlib/v/tests/skip_unused/struct_field_default_expr.vv b/vlib/v/tests/skip_unused/struct_field_default_expr.vv new file mode 100644 index 0000000000..623e22976e --- /dev/null +++ b/vlib/v/tests/skip_unused/struct_field_default_expr.vv @@ -0,0 +1,15 @@ +module main + +import flag + +const c_default_port = u16(12345) + +struct Options { + headless bool + port u16 = c_default_port @[short: p] +} + +fn main() { + args := arguments() + _, _ := flag.to_struct[Options](args, style: .v, skip: 1)! +}