Skip to content

Commit

Permalink
v: fix all -skip-unused issues so that it can be enabled by default (
Browse files Browse the repository at this point in the history
  • Loading branch information
felipensp authored Nov 30, 2024
1 parent 6f4c59e commit a850718
Show file tree
Hide file tree
Showing 26 changed files with 151 additions and 49 deletions.
6 changes: 3 additions & 3 deletions cmd/tools/vcover/cover_test.v
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ fn test_simple() {
assert !os.exists(t2), t2
assert !os.exists(t3), t3

r1 := os.execute('${os.quoted_path(vexe)} -coverage ${os.quoted_path(t1)} cmd/tools/vcover/testdata/simple/t1_test.v')
r1 := os.execute('${os.quoted_path(vexe)} -no-skip-unused -coverage ${os.quoted_path(t1)} cmd/tools/vcover/testdata/simple/t1_test.v')
assert r1.exit_code == 0, r1.str()
assert r1.output.trim_space() == '10', r1.str()
assert os.exists(t1), t1
Expand All @@ -72,7 +72,7 @@ fn test_simple() {
assert nzeros1.any(it.contains('simple.v:8')), nzeros1.str()
assert nzeros1.any(it.contains('simple.v:25')), nzeros1.str()

r2 := os.execute('${os.quoted_path(vexe)} -coverage ${os.quoted_path(t2)} cmd/tools/vcover/testdata/simple/t2_test.v')
r2 := os.execute('${os.quoted_path(vexe)} -no-skip-unused -coverage ${os.quoted_path(t2)} cmd/tools/vcover/testdata/simple/t2_test.v')
assert r2.exit_code == 0, r2.str()
assert r2.output.trim_space() == '24', r2.str()
assert os.exists(t2), t2
Expand All @@ -97,7 +97,7 @@ fn test_simple() {
assert nzeros2.any(it.contains('simple.v:25')), nzeros2.str()

// Run both tests. The coverage should be combined and == 100%
r3 := os.execute('${os.quoted_path(vexe)} -coverage ${os.quoted_path(t3)} test cmd/tools/vcover/testdata/simple/')
r3 := os.execute('${os.quoted_path(vexe)} -no-skip-unused -coverage ${os.quoted_path(t3)} test cmd/tools/vcover/testdata/simple/')
assert r3.exit_code == 0, r3.str()
assert r3.output.trim_space().contains('Summary for all V _test.v files: '), r3.str()
assert os.exists(t3), t3
Expand Down
3 changes: 3 additions & 0 deletions vlib/v/ast/table.v
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,12 @@ pub mut:
auto_str bool // auto str fns
auto_str_ptr bool // auto str fns for ptr type
arr_prepend bool // arr.prepend()
arr_insert bool // arr.insert()
arr_first bool // arr.first()
arr_last bool // arr.last()
arr_pop bool // arr.pop()
arr_delete bool // arr.delete()
arr_reverse bool // arr.reverse()
arr_init bool // [1, 2, 3]
arr_map bool // []map[key]value
map_update bool // {...foo}
Expand All @@ -41,6 +43,7 @@ pub mut:
// json bool // json is imported
debugger bool // debugger is used
comptime_calls map[string]bool // resolved name to call on comptime
comptime_for bool // uses $for
}

@[unsafe]
Expand Down
2 changes: 1 addition & 1 deletion vlib/v/checker/assign.v
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ fn (mut c Checker) assign_stmt(mut node ast.AssignStmt) {
mut right_first_type := ast.void_type
for i, mut right in node.right {
if right in [ast.CallExpr, ast.IfExpr, ast.LockExpr, ast.MatchExpr, ast.DumpExpr,
ast.SelectorExpr, ast.ParExpr] {
ast.SelectorExpr, ast.ParExpr, ast.ComptimeCall] {
if right in [ast.IfExpr, ast.MatchExpr] && node.left.len == node.right.len && !is_decl
&& node.left[i] in [ast.Ident, ast.SelectorExpr] && !node.left[i].is_blank_ident() {
mut expr := node.left[i]
Expand Down
10 changes: 10 additions & 0 deletions vlib/v/checker/checker.v
Original file line number Diff line number Diff line change
Expand Up @@ -1728,6 +1728,9 @@ fn (mut c Checker) selector_expr(mut node ast.SelectorExpr) ast.Type {
return field.typ
}
if mut method := c.table.sym(c.unwrap_generic(typ)).find_method_with_generic_parent(field_name) {
if c.pref.skip_unused && typ.has_flag(.generic) {
c.table.used_features.comptime_calls['${int(method.params[0].typ)}.${field_name}'] = true
}
if c.expected_type != 0 && c.expected_type != ast.none_type {
fn_type := ast.new_type(c.table.find_or_register_fn_type(method, false, true))
// if the expected type includes the receiver, don't hide it behind a closure
Expand Down Expand Up @@ -3193,6 +3196,10 @@ pub fn (mut c Checker) expr(mut node ast.Expr) ast.Type {
ast.StructInit {
if node.unresolved {
mut expr_ := c.table.resolve_init(node, c.unwrap_generic(node.typ))
if c.pref.skip_unused && c.table.used_features.used_maps == 0
&& expr_ is ast.MapInit {
c.table.used_features.used_maps++
}
return c.expr(mut expr_)
}
mut inited_fields := []string{}
Expand Down Expand Up @@ -3902,6 +3909,9 @@ fn (mut c Checker) ident(mut node ast.Ident) ast.Type {
c.error('`mut` is not allowed with `=` (use `:=` to declare a variable)',
node.pos)
}
if c.pref.skip_unused && !c.is_builtin_mod && node.language == .v && node.name.contains('.') {
c.table.used_features.used_modules[node.name.all_before('.')] = true
}
if mut obj := node.scope.find(node.name) {
match mut obj {
ast.GlobalField {
Expand Down
29 changes: 24 additions & 5 deletions vlib/v/checker/comptime.v
Original file line number Diff line number Diff line change
Expand Up @@ -133,10 +133,23 @@ fn (mut c Checker) comptime_call(mut node ast.ComptimeCall) ast.Type {
// check each arg expression
node.args[i].typ = c.expr(mut arg.expr)
}
if c.pref.skip_unused && node.method_name == 'method' {
sym := c.table.sym(c.unwrap_generic(node.left_type))
for m in sym.get_methods() {
c.table.used_features.comptime_calls['${int(c.unwrap_generic(m.receiver_type))}.${m.name}'] = true
if c.pref.skip_unused {
c.table.used_features.comptime_calls['${int(c.unwrap_generic(c.comptime.comptime_for_method.receiver_type))}.${c.comptime.comptime_for_method.name}'] = true
if c.inside_anon_fn {
// $method passed to anon fn, mark all methods as used
sym := c.table.sym(c.unwrap_generic(node.left_type))
for m in sym.get_methods() {
c.table.used_features.comptime_calls['${int(c.unwrap_generic(m.receiver_type))}.${m.name}'] = true
if node.args.len > 0 && m.params.len > 0 {
last_param := m.params.last().typ
if (last_param.is_int() || last_param.is_bool())
&& c.table.final_sym(node.args.last().typ).kind == .array {
c.table.used_features.comptime_calls['${ast.string_type_idx}.${c.table.type_to_str(m.params.last().typ)}'] = true
}
}
}
} else {
m := c.comptime.comptime_for_method
if node.args.len > 0 && m.params.len > 0 {
last_param := m.params.last().typ
if (last_param.is_int() || last_param.is_bool())
Expand Down Expand Up @@ -204,11 +217,15 @@ fn (mut c Checker) comptime_call(mut node ast.ComptimeCall) ast.Type {
} else {
c.error('todo: not a string literal', node.method_pos)
}
left_sym := c.table.sym(c.unwrap_generic(node.left_type))
left_type := c.unwrap_generic(node.left_type)
left_sym := c.table.sym(left_type)
f := left_sym.find_method(method_name) or {
c.error('could not find method `${method_name}`', node.method_pos)
return ast.void_type
}
if c.pref.skip_unused {
c.table.used_features.comptime_calls['${int(left_type)}.${method_name}'] = true
}
node.result_type = f.return_type
return f.return_type
}
Expand Down Expand Up @@ -331,6 +348,7 @@ fn (mut c Checker) comptime_for(mut node ast.ComptimeFor) {
c.comptime.type_map['${node.val_var}.typ'] = node.typ
c.stmts(mut node.stmts)
c.pop_comptime_info()
c.table.used_features.comptime_for = true
} else {
c.error('iterating over .values is supported only for enums, and ${sym.name} is not an enum',
node.typ_pos)
Expand All @@ -348,6 +366,7 @@ fn (mut c Checker) comptime_for(mut node ast.ComptimeFor) {
c.stmts(mut node.stmts)
c.pop_comptime_info()
}
c.table.used_features.comptime_for = true
} else if node.kind == .params {
if !(sym.kind == .function || sym.name == 'FunctionData') {
c.error('iterating over `.params` is supported only for functions, and `${sym.name}` is not a function',
Expand Down
23 changes: 17 additions & 6 deletions vlib/v/checker/fn.v
Original file line number Diff line number Diff line change
Expand Up @@ -868,6 +868,7 @@ fn (mut c Checker) fn_call(mut node ast.CallExpr, mut continue_check &bool) ast.
if c.table.cur_fn != unsafe { nil } {
node.left_type, fn_name = c.table.convert_generic_static_type_name(fn_name,
c.table.cur_fn.generic_names, c.table.cur_concrete_types)
c.table.used_features.comptime_calls[fn_name] = true
}
}
if fn_name == 'main' {
Expand Down Expand Up @@ -1420,12 +1421,12 @@ fn (mut c Checker) fn_call(mut node ast.CallExpr, mut continue_check &bool) ast.
&& node.args[0].expr !is ast.StringLiteral {
if !c.table.sym(c.unwrap_generic(node.args[0].typ)).has_method('str') {
c.table.used_features.auto_str = true
if node.args[0].typ.is_ptr() {
c.table.used_features.auto_str_ptr = true
}
} else {
c.table.used_features.print_types[node.args[0].typ.idx()] = true
}
if node.args[0].typ.is_ptr() {
c.table.used_features.auto_str_ptr = true
}
}
return func.return_type
}
Expand Down Expand Up @@ -2178,9 +2179,13 @@ fn (mut c Checker) method_call(mut node ast.CallExpr, mut continue_check &bool)
continue_check = false
return ast.void_type
}
if c.pref.skip_unused && mut left_expr is ast.Ident {
if left_expr.obj is ast.Var && left_expr.obj.ct_type_var == .smartcast {
c.table.used_features.comptime_calls['${int(left_type)}.${node.name}'] = true
if c.pref.skip_unused {
if !left_type.has_flag(.generic) && mut left_expr is ast.Ident {
if left_expr.obj is ast.Var && left_expr.obj.ct_type_var == .smartcast {
c.table.used_features.comptime_calls['${int(left_type)}.${node.name}'] = true
}
} else if left_type.has_flag(.generic) {
c.table.used_features.comptime_calls['${int(c.unwrap_generic(left_type))}.${node.name}'] = true
}
}
c.expected_type = left_type
Expand Down Expand Up @@ -2313,6 +2318,9 @@ fn (mut c Checker) method_call(mut node ast.CallExpr, mut continue_check &bool)
if embed_types.len != 0 {
is_method_from_embed = true
node.from_embed_types = embed_types
if c.pref.skip_unused && node.left_type.has_flag(.generic) {
c.table.used_features.comptime_calls['${int(method.receiver_type)}.${method.name}'] = true
}
}
}
if final_left_sym.kind == .aggregate {
Expand Down Expand Up @@ -3353,6 +3361,7 @@ fn (mut c Checker) array_builtin_method_call(mut node ast.CallExpr, left_type as
return ast.void_type
}
}
c.table.used_features.arr_insert = true
} else {
c.table.used_features.arr_prepend = true
if node.args.len != 1 {
Expand Down Expand Up @@ -3628,6 +3637,8 @@ fn (mut c Checker) array_builtin_method_call(mut node ast.CallExpr, left_type as
}
}
node.return_type = ast.void_type
} else if method_name == 'reverse' {
c.table.used_features.arr_reverse = true
}
return node.return_type
}
Expand Down
4 changes: 3 additions & 1 deletion vlib/v/gen/c/cgen.v
Original file line number Diff line number Diff line change
Expand Up @@ -6769,7 +6769,9 @@ fn (mut g Gen) write_init_function() {
for mod_name in reversed_table_modules {
g.writeln2('\t// Cleanups for module ${mod_name} :', g.cleanups[mod_name].str())
}
g.writeln('\tarray_free(&as_cast_type_indexes);')
if g.as_cast_type_names.len > 0 {
g.writeln('\tarray_free(&as_cast_type_indexes);')
}
}
for x in cleaning_up_array.reverse() {
g.writeln(x)
Expand Down
8 changes: 6 additions & 2 deletions vlib/v/gen/c/comptime.v
Original file line number Diff line number Diff line change
Expand Up @@ -195,8 +195,12 @@ fn (mut g Gen) comptime_call(mut node ast.ComptimeCall) {
}
}

mut has_unwrap := false
if !g.inside_call && node.or_block.kind != .block && m.return_type.has_option_or_result() {
g.write('(*(${g.base_type(m.return_type)}*)')
if !(g.assign_ct_type != 0 && g.assign_ct_type.has_option_or_result()) {
g.write('(*(${g.base_type(m.return_type)}*)')
has_unwrap = true
}
}
// TODO: check argument types
g.write('${util.no_dots(sym.name)}_${g.comptime.comptime_for_method.name}(')
Expand Down Expand Up @@ -258,7 +262,7 @@ fn (mut g Gen) comptime_call(mut node ast.ComptimeCall) {
}
}
g.write(')')
if !g.inside_call && node.or_block.kind != .block && m.return_type.has_option_or_result() {
if has_unwrap {
g.write('.data)')
}
if node.or_block.kind != .absent && m.return_type.has_option_or_result() {
Expand Down
1 change: 1 addition & 0 deletions vlib/v/gen/c/testdata/addr.vv
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ mut:
a int
}

@[markused]
fn test_addr() {
mut a := 4
b := unsafe { __addr(a) }
Expand Down
5 changes: 4 additions & 1 deletion vlib/v/gen/c/testdata/alias_char_ptr_to_ptr.vv
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
// vtest vflags: -no-skip-unused
type ALcharptr = &char

fn return_text_one() ALcharptr {
return ALcharptr(''.str)
}

fn return_text_two() &char {
return ''.str
}
Expand All @@ -14,4 +17,4 @@ fn get_one() string {
fn get_two() string {
s := return_text_two()
return unsafe { cstring_to_vstring(s) }
}
}
2 changes: 1 addition & 1 deletion vlib/v/gen/c/testdata/comptime_if_attribute_in_test2.vv
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// vtest vflags: -d customflag
// vtest vflags: -d customflag -no-skip-unused
@[if customflag ?]
fn test_abcdef() {
println('this should be in the c code')
Expand Down
2 changes: 1 addition & 1 deletion vlib/v/gen/c/testdata/comptime_option_call.out
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,5 @@ Option(none)
Option(none)
1
1
Option('')
Option(none)
Option(none)
1 change: 1 addition & 0 deletions vlib/v/gen/c/testdata/embed.vv
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// vtest vflags: -no-skip-unused
fn main() {
mut my_source := $embed_file('embed.vv')
assert my_source.len > 0
Expand Down
4 changes: 2 additions & 2 deletions vlib/v/gen/c/testdata/embed_with_prod.c.must_have
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
#define _VPROD (1)

// V embedded data:
static const unsigned char _v_embed_blob_0[138] = {
0x66,0x6e,0x20,0x6d,0x61,0x69,0x6e,0x28,0x29,0x20,0x7b,0x0a,0x09,0x6d,0x75,0x74,
static const unsigned char _v_embed_blob_0[171] = {
0x2f,0x2f,0x20,0x76,0x74,0x65,0x73,0x74,0x20,0x76,0x66,0x6c,0x61,0x67,0x73,0x3a,

const v__embed_file__EmbedFileIndexEntry _v_embed_file_index[] = {
{0, { .str=(byteptr)("embed.vv"), .len=8, .is_lit=1 }, { .str=(byteptr)("none"), .len=4, .is_lit=1 }, (byteptr)_v_embed_blob_0},
Expand Down
1 change: 1 addition & 0 deletions vlib/v/gen/c/testdata/embed_with_prod.out
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// vtest vflags: -no-skip-unused
fn main() {
mut my_source := $embed_file('embed.vv')
assert my_source.len > 0
Expand Down
2 changes: 1 addition & 1 deletion vlib/v/gen/c/testdata/embed_with_prod.vv
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// vtest vflags: -prod
// vtest vflags: -prod -no-skip-unused
fn main() {
mut my_source := $embed_file('embed.vv')
assert my_source.len > 0
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// vtest vflags: -no-skip-unused
fn main() {
mut my_source := $embed_file('embed.vv')
assert my_source.len > 0
Expand All @@ -6,6 +7,7 @@ fn main() {
print(s)
}
--------------------------------------
// vtest vflags: -no-skip-unused
fn main() {
mut my_source := $embed_file('embed.vv')
assert my_source.len > 0
Expand All @@ -14,6 +16,7 @@ fn main() {
print(s)
}
--------------------------------------
// vtest vflags: -no-skip-unused
fn main() {
mut my_source := $embed_file('embed.vv')
assert my_source.len > 0
Expand Down
4 changes: 2 additions & 2 deletions vlib/v/gen/c/testdata/embed_with_prod_zlib.c.must_have
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
#define _VPROD (1)

// V embedded data:
static const unsigned char _v_embed_blob_0[121] = {
0x78,0x01,0x05,0x40,0x4b,0x0a,0x83,0x30,0x10,0x5d,0x67,0x4e,0xf1,0x16,0x05,0x93,
static const unsigned char _v_embed_blob_0[142] = {
0x78,0x01,0x05,0x00,0x41,0x0a,0x84,0x20,0xf0,0xac,0xaf,0x98,0xc3,0xc2,0xea,0x21,

const v__embed_file__EmbedFileIndexEntry _v_embed_file_index[] = {
{0, { .str=(byteptr)("embed.vv"), .len=8, .is_lit=1 }, { .str=(byteptr)("zlib"), .len=4, .is_lit=1 }, (byteptr)_v_embed_blob_0},
Expand Down
1 change: 1 addition & 0 deletions vlib/v/gen/c/testdata/embed_with_prod_zlib.out
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// vtest vflags: -no-skip-unused
fn main() {
mut my_source := $embed_file('embed.vv')
assert my_source.len > 0
Expand Down
2 changes: 1 addition & 1 deletion vlib/v/gen/c/testdata/embed_with_prod_zlib.vv
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// vtest vflags: -prod
// vtest vflags: -prod -no-skip-unused
fn main() {
mut my_source := $embed_file('embed.vv', .zlib)
assert my_source.len > 0
Expand Down
2 changes: 1 addition & 1 deletion vlib/v/gen/c/testdata/global_initializer_nix.vv
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// vtest vflags: -enable-globals
// vtest vflags: -enable-globals -no-skip-unused

struct Foo {
foo int
Expand Down
2 changes: 2 additions & 0 deletions vlib/v/gen/c/testdata/unused_import_aliased_as_underscore.vv
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
// vtest vflags: -no-skip-unused

import flag as _
Loading

0 comments on commit a850718

Please sign in to comment.