all: improve -skip-unused, track consts, walk all AST nodes, support tests
parent
26121d5ae7
commit
d77bb2f606
|
@ -26,7 +26,7 @@ pub fn (d float_literal) str() string {
|
||||||
return f64(d).str()
|
return f64(d).str()
|
||||||
}
|
}
|
||||||
|
|
||||||
// strsci returns the `f64` as a `string` in scientific notation with `digit_num` deciamals displayed, max 17 digits.
|
// strsci returns the `f64` as a `string` in scientific notation with `digit_num` decimals displayed, max 17 digits.
|
||||||
// Example: assert f64(1.234).strsci(3) == '1.234e+00'
|
// Example: assert f64(1.234).strsci(3) == '1.234e+00'
|
||||||
[inline]
|
[inline]
|
||||||
pub fn (x f64) strsci(digit_num int) string {
|
pub fn (x f64) strsci(digit_num int) string {
|
||||||
|
|
|
@ -8,46 +8,47 @@ import v.checker.mark_used_walker
|
||||||
// mark_used walks the AST, starting at main() and marks all used fns transitively
|
// mark_used walks the AST, starting at main() and marks all used fns transitively
|
||||||
fn (mut c Checker) mark_used(ast_files []ast.File) {
|
fn (mut c Checker) mark_used(ast_files []ast.File) {
|
||||||
util.timing_start(@METHOD)
|
util.timing_start(@METHOD)
|
||||||
mut walker := mark_used_walker.Walker{
|
util.timing_start('all_fn_and_const')
|
||||||
files: ast_files
|
mut all_fns := map[string]ast.FnDecl{}
|
||||||
}
|
mut all_consts := map[string]ast.ConstField{}
|
||||||
|
|
||||||
mut allfns := map[string]ast.FnDecl{}
|
|
||||||
for i in 0 .. ast_files.len {
|
for i in 0 .. ast_files.len {
|
||||||
file := unsafe { &ast_files[i] }
|
file := unsafe { &ast_files[i] }
|
||||||
for node in file.stmts {
|
for node in file.stmts {
|
||||||
if node is ast.FnDecl {
|
match node {
|
||||||
fkey := if node.is_method {
|
ast.FnDecl {
|
||||||
'${int(node.receiver.typ)}.$node.name'
|
fkey := if node.is_method {
|
||||||
} else {
|
'${int(node.receiver.typ)}.$node.name'
|
||||||
node.name
|
} else {
|
||||||
|
node.name
|
||||||
|
}
|
||||||
|
all_fns[fkey] = node
|
||||||
}
|
}
|
||||||
allfns[fkey] = node
|
ast.ConstDecl {
|
||||||
|
for cfield in node.fields {
|
||||||
|
ckey := cfield.name
|
||||||
|
all_consts[ckey] = cfield
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
all_fn_root_names := [
|
util.timing_measure('all_fn_and_const')
|
||||||
|
|
||||||
|
mut all_fn_root_names := [
|
||||||
'main.main',
|
'main.main',
|
||||||
'__new_array',
|
'__new_array',
|
||||||
'__new_array_with_default',
|
'__new_array_with_default',
|
||||||
'new_array_from_c_array',
|
'new_array_from_c_array',
|
||||||
'panic',
|
|
||||||
'memdup',
|
'memdup',
|
||||||
'vstrlen',
|
'vstrlen',
|
||||||
'tos2',
|
|
||||||
'tos',
|
'tos',
|
||||||
|
'tos2',
|
||||||
|
'tos3',
|
||||||
'isnil',
|
'isnil',
|
||||||
'utf8_char_len',
|
/* utf8_str_visible_length is used by c/str.v */
|
||||||
'utf8_str_visible_length',
|
'utf8_str_visible_length',
|
||||||
'builtin_init',
|
'builtin_init',
|
||||||
'print_backtrace_skipping_top_frames',
|
|
||||||
'print_backtrace_skipping_top_frames_mac',
|
|
||||||
'print_backtrace_skipping_top_frames_linux',
|
|
||||||
'print_backtrace_skipping_top_frames_freebsd',
|
|
||||||
'print_backtrace_skipping_top_frames_windows',
|
|
||||||
'print_backtrace_skipping_top_frames_mingw',
|
|
||||||
'print_backtrace_skipping_top_frames_msvc',
|
|
||||||
'print_backtrace_skipping_top_frames_tcc',
|
|
||||||
/* byteptr and charptr */
|
/* byteptr and charptr */
|
||||||
'3.vstring',
|
'3.vstring',
|
||||||
'3.vstring_with_len',
|
'3.vstring_with_len',
|
||||||
|
@ -55,8 +56,6 @@ fn (mut c Checker) mark_used(ast_files []ast.File) {
|
||||||
'4.vstring_with_len',
|
'4.vstring_with_len',
|
||||||
/* string. methods */
|
/* string. methods */
|
||||||
'18.add',
|
'18.add',
|
||||||
'18.all_after',
|
|
||||||
'18.all_before',
|
|
||||||
'18.trim_space',
|
'18.trim_space',
|
||||||
'18.replace',
|
'18.replace',
|
||||||
'18.clone',
|
'18.clone',
|
||||||
|
@ -81,9 +80,13 @@ fn (mut c Checker) mark_used(ast_files []ast.File) {
|
||||||
'19.add',
|
'19.add',
|
||||||
/* other array methods */
|
/* other array methods */
|
||||||
'21.get',
|
'21.get',
|
||||||
|
'21.set',
|
||||||
'21.get_unsafe',
|
'21.get_unsafe',
|
||||||
|
'21.set_unsafe',
|
||||||
|
'21.slice',
|
||||||
|
'21.slice2',
|
||||||
'59.get',
|
'59.get',
|
||||||
'65557.free',
|
'59.set',
|
||||||
'65557.push',
|
'65557.push',
|
||||||
'65557.set',
|
'65557.set',
|
||||||
'65557.set_unsafe',
|
'65557.set_unsafe',
|
||||||
|
@ -91,28 +94,75 @@ fn (mut c Checker) mark_used(ast_files []ast.File) {
|
||||||
'os.getwd',
|
'os.getwd',
|
||||||
'os.init_os_args',
|
'os.init_os_args',
|
||||||
]
|
]
|
||||||
// println( allfns.keys() )
|
|
||||||
for fn_name in all_fn_root_names {
|
// implicit string builders are generated in auto_eq_methods.v
|
||||||
walker.fn_decl(mut allfns[fn_name])
|
mut sb_mut_type := ''
|
||||||
|
if sbfn := c.table.find_fn('strings.new_builder') {
|
||||||
|
sb_mut_type = sbfn.return_type.set_nr_muls(1).str() + '.'
|
||||||
}
|
}
|
||||||
|
|
||||||
$if trace_skip_unused ? {
|
for k, _ in all_fns {
|
||||||
|
if k.ends_with('.init') {
|
||||||
|
all_fn_root_names << k
|
||||||
|
}
|
||||||
|
if k.ends_with('.free') {
|
||||||
|
all_fn_root_names << k
|
||||||
|
}
|
||||||
|
if c.pref.is_test && (k.starts_with('test_') || k.contains('.test_')) {
|
||||||
|
all_fn_root_names << k
|
||||||
|
}
|
||||||
|
if sb_mut_type != '' && k.starts_with(sb_mut_type) {
|
||||||
|
all_fn_root_names << k
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if c.pref.is_debug {
|
||||||
|
all_fn_root_names << 'panic_debug'
|
||||||
|
}
|
||||||
|
if c.pref.is_test {
|
||||||
|
all_fn_root_names << 'main.cb_assertion_ok'
|
||||||
|
all_fn_root_names << 'main.cb_assertion_failed'
|
||||||
|
if benched_tests_sym := c.table.find_type('main.BenchedTests') {
|
||||||
|
bts_type := benched_tests_sym.methods[0].params[0].typ
|
||||||
|
all_fn_root_names << '${bts_type}.testing_step_start'
|
||||||
|
all_fn_root_names << '${bts_type}.testing_step_end'
|
||||||
|
all_fn_root_names << '${bts_type}.end_testing'
|
||||||
|
all_fn_root_names << 'main.start_testing'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mut walker := mark_used_walker.Walker{
|
||||||
|
files: ast_files
|
||||||
|
all_fns: all_fns
|
||||||
|
all_consts: all_consts
|
||||||
|
}
|
||||||
|
// println( all_fns.keys() )
|
||||||
|
walker.mark_root_fns(all_fn_root_names)
|
||||||
|
|
||||||
|
if walker.n_asserts > 0 {
|
||||||
|
walker.fn_decl(mut all_fns['__print_assert_failure'])
|
||||||
|
}
|
||||||
|
if walker.n_maps > 0 {
|
||||||
|
for k, mut mfn in all_fns {
|
||||||
|
if k == 'new_map_2' || k.starts_with('map_') || k.ends_with('set_1')
|
||||||
|
|| k.ends_with('exists_1')|| k.ends_with('get_1') {
|
||||||
|
walker.fn_decl(mut mfn)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$if trace_skip_unused_fn_names ? {
|
||||||
for key, _ in walker.used_fns {
|
for key, _ in walker.used_fns {
|
||||||
println('> used fn key: $key')
|
println('> used fn key: $key')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
c.table.used_fns = walker.used_fns
|
c.table.used_fns = walker.used_fns
|
||||||
//
|
c.table.used_consts = walker.used_consts
|
||||||
c.table.used_fns['term.can_show_color_on_stdin'] = true
|
|
||||||
c.table.used_fns['term.can_show_color_on_stdout'] = true
|
|
||||||
c.table.used_fns['term.can_show_color_on_stderr'] = true
|
|
||||||
//
|
|
||||||
c.table.used_fns['main.can_use_relative_paths'] = true
|
|
||||||
//
|
|
||||||
// eprintln('>>> c.table.used_fns: $c.table.used_fns')
|
|
||||||
util.timing_measure(@METHOD)
|
|
||||||
|
|
||||||
// println(walker.used_fns)
|
$if trace_skip_unused ? {
|
||||||
// c.walk(ast_files)
|
eprintln('>> c.table.used_fns: $c.table.used_fns.keys()')
|
||||||
|
eprintln('>> c.table.used_consts: $c.table.used_consts.keys()')
|
||||||
|
eprintln('>> walker.n_maps: $walker.n_maps')
|
||||||
|
}
|
||||||
|
util.timing_measure(@METHOD)
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,25 +8,61 @@ import v.ast
|
||||||
|
|
||||||
pub struct Walker {
|
pub struct Walker {
|
||||||
pub mut:
|
pub mut:
|
||||||
used_fns map[string]bool // used_fns['println'] == true
|
used_fns map[string]bool // used_fns['println'] == true
|
||||||
|
used_consts map[string]bool // used_consts['os.args'] == true
|
||||||
|
n_maps int
|
||||||
|
n_asserts int
|
||||||
mut:
|
mut:
|
||||||
files []ast.File
|
files []ast.File
|
||||||
|
all_fns map[string]ast.FnDecl
|
||||||
|
all_consts map[string]ast.ConstField
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
pub fn (mut w Walker) mark_fn_as_used(fkey string) {
|
||||||
fn (mut w Walker) walk_files(ast_files []ast.File) {
|
$if trace_skip_unused_marked ? {
|
||||||
t := time.ticks()
|
eprintln(' fn > |$fkey|')
|
||||||
*/
|
}
|
||||||
|
w.used_fns[fkey] = true
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn (mut w Walker) mark_const_as_used(ckey string) {
|
||||||
|
$if trace_skip_unused_marked ? {
|
||||||
|
eprintln(' const > |$ckey|')
|
||||||
|
}
|
||||||
|
w.used_consts[ckey] = true
|
||||||
|
cfield := w.all_consts[ckey] or { return }
|
||||||
|
w.expr(cfield.expr)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn (mut w Walker) mark_root_fns(all_fn_root_names []string) {
|
||||||
|
for fn_name in all_fn_root_names {
|
||||||
|
if fn_name !in w.used_fns {
|
||||||
|
$if trace_skip_unused_roots ? {
|
||||||
|
println('>>>> $fn_name uses: ')
|
||||||
|
}
|
||||||
|
w.fn_decl(mut w.all_fns[fn_name])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn (mut w Walker) stmt(node ast.Stmt) {
|
pub fn (mut w Walker) stmt(node ast.Stmt) {
|
||||||
match mut node {
|
match mut node {
|
||||||
|
ast.AssertStmt {
|
||||||
|
w.expr(node.expr)
|
||||||
|
w.n_asserts++
|
||||||
|
}
|
||||||
ast.AssignStmt {
|
ast.AssignStmt {
|
||||||
for l in node.left {
|
w.exprs(node.left)
|
||||||
w.expr(l)
|
w.exprs(node.right)
|
||||||
}
|
}
|
||||||
for r in node.right {
|
ast.Block {
|
||||||
w.expr(r)
|
w.stmts(node.stmts)
|
||||||
}
|
}
|
||||||
|
ast.CompFor {
|
||||||
|
w.stmts(node.stmts)
|
||||||
|
}
|
||||||
|
ast.ConstDecl {
|
||||||
|
w.const_fields(node.fields)
|
||||||
}
|
}
|
||||||
ast.ExprStmt {
|
ast.ExprStmt {
|
||||||
w.expr(node.expr)
|
w.expr(node.expr)
|
||||||
|
@ -34,92 +70,295 @@ pub fn (mut w Walker) stmt(node ast.Stmt) {
|
||||||
ast.FnDecl {
|
ast.FnDecl {
|
||||||
w.fn_decl(mut node)
|
w.fn_decl(mut node)
|
||||||
}
|
}
|
||||||
|
ast.ForCStmt {
|
||||||
|
w.expr(node.cond)
|
||||||
|
w.stmt(node.inc)
|
||||||
|
w.stmts(node.stmts)
|
||||||
|
}
|
||||||
|
ast.ForInStmt {
|
||||||
|
w.expr(node.cond)
|
||||||
|
w.expr(node.high)
|
||||||
|
w.stmts(node.stmts)
|
||||||
|
}
|
||||||
ast.ForStmt {
|
ast.ForStmt {
|
||||||
w.expr(node.cond)
|
w.expr(node.cond)
|
||||||
for stmt in node.stmts {
|
w.stmts(node.stmts)
|
||||||
w.stmt(stmt)
|
}
|
||||||
|
ast.GoStmt {
|
||||||
|
w.expr(node.call_expr)
|
||||||
|
}
|
||||||
|
ast.Return {
|
||||||
|
w.exprs(node.exprs)
|
||||||
|
}
|
||||||
|
ast.SqlStmt {
|
||||||
|
w.expr(node.db_expr)
|
||||||
|
w.expr(node.where_expr)
|
||||||
|
w.exprs(node.update_exprs)
|
||||||
|
}
|
||||||
|
ast.StructDecl {
|
||||||
|
w.struct_fields(node.fields)
|
||||||
|
}
|
||||||
|
ast.DeferStmt {
|
||||||
|
w.stmts(node.stmts)
|
||||||
|
}
|
||||||
|
ast.GlobalDecl {
|
||||||
|
for gf in node.fields {
|
||||||
|
if gf.has_expr {
|
||||||
|
w.expr(gf.expr)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {}
|
ast.BranchStmt {}
|
||||||
|
ast.EnumDecl {}
|
||||||
|
ast.GotoLabel {}
|
||||||
|
ast.GotoStmt {}
|
||||||
|
ast.HashStmt {}
|
||||||
|
ast.Import {}
|
||||||
|
ast.InterfaceDecl {}
|
||||||
|
ast.Module {}
|
||||||
|
ast.TypeDecl {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn (mut w Walker) defer_stmts(stmts []ast.DeferStmt) {
|
||||||
|
for stmt in stmts {
|
||||||
|
w.stmts(stmt.stmts)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn (mut w Walker) stmts(stmts []ast.Stmt) {
|
||||||
|
for stmt in stmts {
|
||||||
|
w.stmt(stmt)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn (mut w Walker) exprs(exprs []ast.Expr) {
|
||||||
|
for expr in exprs {
|
||||||
|
w.expr(expr)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (mut w Walker) expr(node ast.Expr) {
|
fn (mut w Walker) expr(node ast.Expr) {
|
||||||
match mut node {
|
match mut node {
|
||||||
|
ast.AnonFn {
|
||||||
|
w.fn_decl(mut node.decl)
|
||||||
|
}
|
||||||
|
ast.Assoc {
|
||||||
|
w.exprs(node.exprs)
|
||||||
|
}
|
||||||
|
ast.ArrayInit {
|
||||||
|
w.expr(node.len_expr)
|
||||||
|
w.expr(node.cap_expr)
|
||||||
|
w.expr(node.default_expr)
|
||||||
|
w.exprs(node.exprs)
|
||||||
|
}
|
||||||
|
ast.ArrayDecompose {
|
||||||
|
w.expr(node.expr)
|
||||||
|
}
|
||||||
ast.CallExpr {
|
ast.CallExpr {
|
||||||
w.call_expr(mut node)
|
w.call_expr(mut node)
|
||||||
}
|
}
|
||||||
|
ast.CastExpr {
|
||||||
|
w.expr(node.expr)
|
||||||
|
w.expr(node.arg)
|
||||||
|
}
|
||||||
|
ast.ChanInit {
|
||||||
|
w.expr(node.cap_expr)
|
||||||
|
}
|
||||||
|
ast.ConcatExpr {
|
||||||
|
w.exprs(node.vals)
|
||||||
|
}
|
||||||
|
ast.ComptimeSelector {
|
||||||
|
w.expr(node.left)
|
||||||
|
w.expr(node.field_expr)
|
||||||
|
}
|
||||||
|
ast.ComptimeCall {
|
||||||
|
w.expr(node.left)
|
||||||
|
if node.is_vweb {
|
||||||
|
w.stmts(node.vweb_tmpl.stmts)
|
||||||
|
}
|
||||||
|
}
|
||||||
ast.GoExpr {
|
ast.GoExpr {
|
||||||
w.expr(node.go_stmt.call_expr)
|
w.expr(node.go_stmt.call_expr)
|
||||||
}
|
}
|
||||||
ast.IndexExpr {
|
ast.IndexExpr {
|
||||||
w.expr(node.left)
|
w.expr(node.left)
|
||||||
w.expr(node.index)
|
w.expr(node.index)
|
||||||
|
w.or_block(node.or_expr)
|
||||||
|
}
|
||||||
|
ast.InfixExpr {
|
||||||
|
w.expr(node.left)
|
||||||
|
w.expr(node.right)
|
||||||
|
w.or_block(node.or_block)
|
||||||
|
}
|
||||||
|
ast.IfGuardExpr {
|
||||||
|
w.expr(node.expr)
|
||||||
}
|
}
|
||||||
ast.IfExpr {
|
ast.IfExpr {
|
||||||
|
w.expr(node.left)
|
||||||
for b in node.branches {
|
for b in node.branches {
|
||||||
w.expr(b.cond)
|
w.expr(b.cond)
|
||||||
for stmt in b.stmts {
|
w.stmts(b.stmts)
|
||||||
w.stmt(stmt)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
ast.Ident {
|
||||||
|
if node.kind == .constant {
|
||||||
|
w.mark_const_as_used(node.name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ast.Likely {
|
||||||
|
w.expr(node.expr)
|
||||||
|
}
|
||||||
|
ast.MapInit {
|
||||||
|
w.exprs(node.keys)
|
||||||
|
w.exprs(node.vals)
|
||||||
|
w.n_maps++
|
||||||
|
}
|
||||||
ast.MatchExpr {
|
ast.MatchExpr {
|
||||||
w.expr(node.cond)
|
w.expr(node.cond)
|
||||||
for b in node.branches {
|
for b in node.branches {
|
||||||
for expr in b.exprs {
|
w.exprs(b.exprs)
|
||||||
w.expr(expr)
|
w.stmts(b.stmts)
|
||||||
}
|
|
||||||
for stmt in b.stmts {
|
|
||||||
w.stmt(stmt)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {}
|
ast.None {
|
||||||
|
w.mark_fn_as_used('opt_none')
|
||||||
|
}
|
||||||
|
ast.ParExpr {
|
||||||
|
w.expr(node.expr)
|
||||||
|
}
|
||||||
|
ast.PrefixExpr {
|
||||||
|
w.expr(node.right)
|
||||||
|
}
|
||||||
|
ast.PostfixExpr {
|
||||||
|
w.expr(node.expr)
|
||||||
|
}
|
||||||
|
ast.RangeExpr {
|
||||||
|
if node.has_low {
|
||||||
|
w.expr(node.low)
|
||||||
|
}
|
||||||
|
if node.has_high {
|
||||||
|
w.expr(node.high)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ast.SizeOf {
|
||||||
|
w.expr(node.expr)
|
||||||
|
}
|
||||||
|
ast.StringInterLiteral {
|
||||||
|
w.exprs(node.exprs)
|
||||||
|
}
|
||||||
|
ast.SelectorExpr {
|
||||||
|
w.expr(node.expr)
|
||||||
|
}
|
||||||
|
ast.SqlExpr {
|
||||||
|
w.expr(node.db_expr)
|
||||||
|
w.expr(node.offset_expr)
|
||||||
|
w.expr(node.order_expr)
|
||||||
|
w.expr(node.limit_expr)
|
||||||
|
w.expr(node.where_expr)
|
||||||
|
}
|
||||||
|
ast.StructInit {
|
||||||
|
// eprintln('>>>> ast.StructInit: $node')
|
||||||
|
w.expr(node.update_expr)
|
||||||
|
for sif in node.fields {
|
||||||
|
w.expr(sif.expr)
|
||||||
|
}
|
||||||
|
for sie in node.embeds {
|
||||||
|
w.expr(sie.expr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ast.TypeOf {
|
||||||
|
w.expr(node.expr)
|
||||||
|
}
|
||||||
|
///
|
||||||
|
ast.AsCast {
|
||||||
|
w.expr(node.expr)
|
||||||
|
}
|
||||||
|
ast.AtExpr {}
|
||||||
|
ast.BoolLiteral {}
|
||||||
|
ast.FloatLiteral {}
|
||||||
|
ast.CharLiteral {}
|
||||||
|
ast.IntegerLiteral {}
|
||||||
|
ast.StringLiteral {}
|
||||||
|
ast.CTempVar {
|
||||||
|
w.expr(node.orig)
|
||||||
|
}
|
||||||
|
ast.Comment {}
|
||||||
|
ast.EnumVal {}
|
||||||
|
ast.LockExpr {
|
||||||
|
w.stmts(node.stmts)
|
||||||
|
}
|
||||||
|
ast.OffsetOf {}
|
||||||
|
ast.OrExpr {
|
||||||
|
w.or_block(node)
|
||||||
|
}
|
||||||
|
ast.SelectExpr {
|
||||||
|
for branch in node.branches {
|
||||||
|
w.stmt(branch.stmt)
|
||||||
|
w.stmts(branch.stmts)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ast.Type {}
|
||||||
|
ast.UnsafeExpr {
|
||||||
|
w.expr(node.expr)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn (mut w Walker) fn_decl(mut node ast.FnDecl) {
|
pub fn (mut w Walker) fn_decl(mut node ast.FnDecl) {
|
||||||
|
if node.language == .c {
|
||||||
|
return
|
||||||
|
}
|
||||||
fkey := if node.is_method { '${int(node.receiver.typ)}.$node.name' } else { node.name }
|
fkey := if node.is_method { '${int(node.receiver.typ)}.$node.name' } else { node.name }
|
||||||
if w.used_fns[fkey] {
|
if w.used_fns[fkey] {
|
||||||
// This function is already known to be called, meaning it has been processed already.
|
// This function is already known to be called, meaning it has been processed already.
|
||||||
// Save CPU time and do nothing.
|
// Save CPU time and do nothing.
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if node.language == .c {
|
w.mark_fn_as_used(fkey)
|
||||||
return
|
w.stmts(node.stmts)
|
||||||
}
|
w.defer_stmts(node.defer_stmts)
|
||||||
w.used_fns[fkey] = true
|
|
||||||
for stmt in node.stmts {
|
|
||||||
w.stmt(stmt)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn (mut w Walker) call_expr(mut node ast.CallExpr) {
|
pub fn (mut w Walker) call_expr(mut node ast.CallExpr) {
|
||||||
|
if node.language == .c {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
w.expr(node.left)
|
||||||
|
for arg in node.args {
|
||||||
|
w.expr(arg.expr)
|
||||||
|
}
|
||||||
|
w.or_block(node.or_block)
|
||||||
|
//
|
||||||
fn_name := if node.is_method { node.receiver_type.str() + '.' + node.name } else { node.name }
|
fn_name := if node.is_method { node.receiver_type.str() + '.' + node.name } else { node.name }
|
||||||
// fn_name := node.name
|
|
||||||
// println('call_expr $fn_name')
|
|
||||||
// if node.is_method {
|
|
||||||
// println('M $node.name $node.receiver_type')
|
|
||||||
//}
|
|
||||||
if w.used_fns[fn_name] {
|
if w.used_fns[fn_name] {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
// w.used_fns[fn_name] = true
|
stmt := w.all_fns[fn_name] or { return }
|
||||||
// Find the FnDecl for this CallExpr, mark the function as used, and process
|
if stmt.name == node.name {
|
||||||
// all its statements.
|
if !node.is_method || (node.receiver_type == stmt.receiver.typ) {
|
||||||
loop: for file in w.files {
|
w.mark_fn_as_used(fn_name)
|
||||||
for stmt in file.stmts {
|
w.stmts(stmt.stmts)
|
||||||
if stmt is ast.FnDecl {
|
|
||||||
if stmt.name == node.name
|
|
||||||
&& (!node.is_method || (node.receiver_type == stmt.receiver.typ)) {
|
|
||||||
w.used_fns[fn_name] = true
|
|
||||||
for fn_stmt in stmt.stmts {
|
|
||||||
w.stmt(fn_stmt)
|
|
||||||
}
|
|
||||||
break loop
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn (mut w Walker) struct_fields(sfields []ast.StructField) {
|
||||||
|
for sf in sfields {
|
||||||
|
if sf.has_default_expr {
|
||||||
|
w.expr(sf.default_expr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn (mut w Walker) const_fields(cfields []ast.ConstField) {
|
||||||
|
for cf in cfields {
|
||||||
|
w.expr(cf.expr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn (mut w Walker) or_block(node ast.OrExpr) {
|
||||||
|
if node.kind == .block {
|
||||||
|
w.stmts(node.stmts)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -4725,6 +4725,15 @@ fn (mut g Gen) const_decl(node ast.ConstDecl) {
|
||||||
g.inside_const = false
|
g.inside_const = false
|
||||||
}
|
}
|
||||||
for field in node.fields {
|
for field in node.fields {
|
||||||
|
if g.pref.skip_unused {
|
||||||
|
if field.name !in g.table.used_consts {
|
||||||
|
$if trace_skip_unused_consts ? {
|
||||||
|
eprintln('>> skipping unused const name: $field.name')
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
name := c_name(field.name)
|
name := c_name(field.name)
|
||||||
// TODO hack. Cut the generated value and paste it into definitions.
|
// TODO hack. Cut the generated value and paste it into definitions.
|
||||||
pos := g.out.len
|
pos := g.out.len
|
||||||
|
|
|
@ -30,7 +30,7 @@ fn (mut g Gen) gen_fn_decl(node ast.FnDecl, skip bool) {
|
||||||
if g.pref.skip_unused {
|
if g.pref.skip_unused {
|
||||||
fkey := if node.is_method { '${int(node.receiver.typ)}.$node.name' } else { node.name }
|
fkey := if node.is_method { '${int(node.receiver.typ)}.$node.name' } else { node.name }
|
||||||
is_used_by_main := g.table.used_fns[fkey]
|
is_used_by_main := g.table.used_fns[fkey]
|
||||||
$if trace_skip_unused ? {
|
$if trace_skip_unused_fns ? {
|
||||||
println('> is_used_by_main: $is_used_by_main | node.name: $node.name | fkey: $fkey | node.is_method: $node.is_method')
|
println('> is_used_by_main: $is_used_by_main | node.name: $node.name | fkey: $fkey | node.is_method: $node.is_method')
|
||||||
}
|
}
|
||||||
if !is_used_by_main {
|
if !is_used_by_main {
|
||||||
|
|
|
@ -20,6 +20,7 @@ pub mut:
|
||||||
cmod_prefix string // needed for table.type_to_str(Type) while vfmt; contains `os.`
|
cmod_prefix string // needed for table.type_to_str(Type) while vfmt; contains `os.`
|
||||||
is_fmt bool
|
is_fmt bool
|
||||||
used_fns map[string]bool // filled in by the checker, when pref.skip_unused = true;
|
used_fns map[string]bool // filled in by the checker, when pref.skip_unused = true;
|
||||||
|
used_consts map[string]bool // filled in by the checker, when pref.skip_unused = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Fn {
|
pub struct Fn {
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
fn test_abc() {
|
||||||
|
assert 'abc' == 'abc'
|
||||||
|
}
|
|
@ -0,0 +1,5 @@
|
||||||
|
vlib/v/tests/skip_unused/assert_works_test.vv:2: fn test_abc
|
||||||
|
> assert 'abc' == 'xyz'
|
||||||
|
Left value: abc
|
||||||
|
Right value: xyz
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
vlib/v/tests/skip_unused/assert_works_test.vv:2: fn test_abc
|
||||||
|
> assert 'abc' == 'xyz'
|
||||||
|
Left value: abc
|
||||||
|
Right value: xyz
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
fn test_abc() {
|
||||||
|
assert 'abc' == 'xyz'
|
||||||
|
}
|
Loading…
Reference in New Issue