all: support `[markused]` tags for fns/consts/globals

pull/12853/head
Delyan Angelov 2021-12-15 14:34:49 +02:00
parent 1a6899e85e
commit df7f2aa8a3
No known key found for this signature in database
GPG Key ID: 66886C0F12D595ED
8 changed files with 100 additions and 40 deletions

View File

@ -444,9 +444,9 @@ fn (t Tree) stmt(node ast.Stmt) &Node {
fn (t Tree) import_module(node ast.Import) &Node {
mut obj := new_object()
obj.add_terse('ast_type', t.string_node('Import'))
obj.add('mod', t.string_node(node.mod))
obj.add('alias', t.string_node(node.alias))
obj.add('syms', t.array_node_import_symbol(node.syms))
obj.add_terse('mod', t.string_node(node.mod))
obj.add_terse('alias', t.string_node(node.alias))
obj.add_terse('syms', t.array_node_import_symbol(node.syms))
obj.add('comments', t.array_node_comment(node.comments))
obj.add('next_comments', t.array_node_comment(node.next_comments))
obj.add('pos', t.position(node.pos))
@ -458,7 +458,7 @@ fn (t Tree) import_module(node ast.Import) &Node {
fn (t Tree) import_symbol(node ast.ImportSymbol) &Node {
mut obj := new_object()
obj.add('name', t.string_node(node.name))
obj.add_terse('name', t.string_node(node.name))
obj.add('pos', t.position(node.pos))
return obj
}
@ -485,9 +485,10 @@ fn (t Tree) comment(node ast.Comment) &Node {
fn (t Tree) const_decl(node ast.ConstDecl) &Node {
mut obj := new_object()
obj.add_terse('ast_type', t.string_node('ConstDecl'))
obj.add('is_pub', t.bool_node(node.is_pub))
obj.add('is_block', t.bool_node(node.is_block))
obj.add('fields', t.array_node_const_field(node.fields))
obj.add_terse('is_pub', t.bool_node(node.is_pub))
obj.add_terse('is_block', t.bool_node(node.is_block))
obj.add_terse('fields', t.array_node_const_field(node.fields))
obj.add_terse('attrs', t.array_node_attr(node.attrs))
obj.add('end_comments', t.array_node_comment(node.end_comments))
obj.add('pos', t.position(node.pos))
return obj
@ -496,11 +497,12 @@ fn (t Tree) const_decl(node ast.ConstDecl) &Node {
fn (t Tree) const_field(node ast.ConstField) &Node {
mut obj := new_object()
obj.add_terse('ast_type', t.string_node('ConstField'))
obj.add('mod', t.string_node(node.mod))
obj.add('name', t.string_node(node.name))
obj.add('expr', t.expr(node.expr))
obj.add('is_pub', t.bool_node(node.is_pub))
obj.add('typ', t.type_node(node.typ))
obj.add_terse('mod', t.string_node(node.mod))
obj.add_terse('name', t.string_node(node.name))
obj.add_terse('expr', t.expr(node.expr))
obj.add_terse('is_pub', t.bool_node(node.is_pub))
obj.add_terse('is_markused', t.bool_node(node.is_markused))
obj.add_terse('typ', t.type_node(node.typ))
obj.add('comments', t.array_node_comment(node.comments))
obj.add('comptime_expr_value', t.comptime_expr_value(node.comptime_expr_value))
obj.add('pos', t.position(node.pos))
@ -527,18 +529,18 @@ fn (t Tree) fn_decl(node ast.FnDecl) &Node {
obj.add_terse('ast_type', t.string_node('FnDecl'))
obj.add_terse('name', t.string_node(node.name))
obj.add_terse('mod', t.string_node(node.mod))
obj.add('is_deprecated', t.bool_node(node.is_deprecated))
obj.add('is_pub', t.bool_node(node.is_pub))
obj.add('is_variadic', t.bool_node(node.is_variadic))
obj.add_terse('is_deprecated', t.bool_node(node.is_deprecated))
obj.add_terse('is_pub', t.bool_node(node.is_pub))
obj.add_terse('is_variadic', t.bool_node(node.is_variadic))
obj.add('is_anon', t.bool_node(node.is_anon))
obj.add('is_noreturn', t.bool_node(node.is_noreturn))
obj.add('is_manualfree', t.bool_node(node.is_manualfree))
obj.add_terse('is_noreturn', t.bool_node(node.is_noreturn))
obj.add_terse('is_manualfree', t.bool_node(node.is_manualfree))
obj.add('is_main', t.bool_node(node.is_main))
obj.add('is_test', t.bool_node(node.is_test))
obj.add('is_conditional', t.bool_node(node.is_conditional))
obj.add('is_exported', t.bool_node(node.is_exported))
obj.add_terse('is_exported', t.bool_node(node.is_exported))
obj.add('is_keep_alive', t.bool_node(node.is_keep_alive))
obj.add('is_unsafe', t.bool_node(node.is_unsafe))
obj.add_terse('is_unsafe', t.bool_node(node.is_unsafe))
obj.add_terse('receiver', t.struct_field(node.receiver))
obj.add('receiver_pos', t.position(node.receiver_pos))
obj.add_terse('is_method', t.bool_node(node.is_method))
@ -597,8 +599,8 @@ fn (t Tree) struct_decl(node ast.StructDecl) &Node {
obj.add_terse('is_union', t.bool_node(node.is_union))
obj.add('pos', t.position(node.pos))
obj.add_terse('fields', t.array_node_struct_field(node.fields))
obj.add('generic_types', t.array_node_type(node.generic_types))
obj.add('attrs', t.array_node_attr(node.attrs))
obj.add_terse('generic_types', t.array_node_type(node.generic_types))
obj.add_terse('attrs', t.array_node_attr(node.attrs))
obj.add('end_comments', t.array_node_comment(node.end_comments))
obj.add_terse('embeds', t.array_node_embed(node.embeds))
return obj
@ -746,6 +748,7 @@ fn (t Tree) global_field(node ast.GlobalField) &Node {
obj.add_terse('expr', t.expr(node.expr))
obj.add_terse('typ', t.type_node(node.typ))
obj.add_terse('has_expr', t.bool_node(node.has_expr))
obj.add_terse('is_markused', t.bool_node(node.is_markused))
obj.add('comments', t.array_node_comment(node.comments))
obj.add('pos', t.position(node.pos))
obj.add('typ_pos', t.position(node.typ_pos))

View File

@ -128,7 +128,7 @@ pub:
kind AttributeKind
}
[used]
[markused]
fn v_segmentation_fault_handler(signal int) {
eprintln('signal 11: segmentation fault')
print_backtrace()

View File

@ -288,11 +288,12 @@ pub mut:
// const field in const declaration group
pub struct ConstField {
pub:
mod string
name string
expr Expr // the value expr of field; everything after `=`
is_pub bool
pos token.Position
mod string
name string
expr Expr // the value expr of field; everything after `=`
is_pub bool
is_markused bool // an explict `[markused]` tag; the const will NOT be removed by `-skip-unused`, no matter what
pos token.Position
pub mut:
typ Type // the type of the const field, it can be any type in V
comments []Comment // comments before current const field
@ -306,6 +307,7 @@ pub struct ConstDecl {
pub:
is_pub bool
pos token.Position
attrs []Attr // tags like `[markused]`, valid for all the consts in the list
pub mut:
fields []ConstField // all the const fields in the `const (...)` block
end_comments []Comment // comments that after last const field
@ -460,6 +462,7 @@ pub:
is_exported bool // true for `[export: 'exact_C_name']`
is_keep_alive bool // passed memory must not be freed (by GC) before function returns
is_unsafe bool // true, when [unsafe] is used on a fn
is_markused bool // true, when an explict `[markused]` tag was put on a fn; `-skip-unused` will not remove that fn
receiver StructField // TODO this is not a struct field
receiver_pos token.Position // `(u User)` in `fn (u User) name()` position
is_method bool
@ -484,8 +487,8 @@ pub mut:
return_type Type
return_type_pos token.Position // `string` in `fn (u User) name() string` position
has_return bool
should_be_skipped bool
has_await bool // 'true' if this function uses JS.await
should_be_skipped bool // true, when -skip-unused could not find any usages of that function, starting from main + other known used functions
has_await bool // 'true' if this function uses JS.await
//
comments []Comment // comments *after* the header, but *before* `{`; used for InterfaceDecl
next_comments []Comment // coments that are one line after the decl; used for InterfaceDecl
@ -525,7 +528,7 @@ pub mut:
left_type Type // type of `user`
receiver_type Type // User
return_type Type
should_be_skipped bool
should_be_skipped bool // true for calls to `[if someflag?]` functions, when there is no `-d someflag`
concrete_types []Type // concrete types, e.g. <int, string>
concrete_list_pos token.Position
free_receiver bool // true if the receiver expression needs to be freed
@ -596,7 +599,7 @@ pub mut:
// [11, 12, 13] <- cast order (smartcasts)
// 12 <- the current casted type (typ)
pos token.Position
is_used bool
is_used bool // whether the local variable was used in other expressions
is_changed bool // to detect mutable vars that are never changed
//
// (for setting the position after the or block for autofree)
@ -624,10 +627,11 @@ pub:
pub struct GlobalField {
pub:
name string
has_expr bool
pos token.Position
typ_pos token.Position
name string
has_expr bool
pos token.Position
typ_pos token.Position
is_markused bool // an explict `[markused]` tag; the global will NOT be removed by `-skip-unused`
pub mut:
expr Expr
typ Type
@ -638,8 +642,8 @@ pub struct GlobalDecl {
pub:
mod string
pos token.Position
is_block bool // __global() block
attrs []Attr
is_block bool // __global() block
attrs []Attr // tags like `[markused]`, valid for all the globals in the list
pub mut:
fields []GlobalField
end_comments []Comment

View File

@ -776,6 +776,7 @@ mut:
}
pub fn (mut f Fmt) const_decl(node ast.ConstDecl) {
f.attrs(node.attrs)
if node.is_pub {
f.write('pub ')
}

View File

@ -336,6 +336,9 @@ pub fn mark_used(mut table ast.Table, pref &pref.Preferences, ast_files []&ast.F
pref: pref
}
// println( all_fns.keys() )
walker.mark_markused_fns() // tagged with `[markused]`
walker.mark_markused_consts() // tagged with `[markused]`
walker.mark_markused_globals() // tagged with `[markused]`
walker.mark_exported_fns()
walker.mark_root_fns(all_fn_root_names)

View File

@ -72,6 +72,30 @@ pub fn (mut w Walker) mark_exported_fns() {
}
}
pub fn (mut w Walker) mark_markused_fns() {
for _, mut func in w.all_fns {
if func.is_markused {
w.fn_decl(mut func)
}
}
}
pub fn (mut w Walker) mark_markused_consts() {
for ckey, mut constfield in w.all_consts {
if constfield.is_markused {
w.mark_const_as_used(ckey)
}
}
}
pub fn (mut w Walker) mark_markused_globals() {
for gkey, mut globalfield in w.all_globals {
if globalfield.is_markused {
w.mark_global_as_used(gkey)
}
}
}
pub fn (mut w Walker) stmt(node ast.Stmt) {
match mut node {
ast.EmptyStmt {}

View File

@ -180,6 +180,7 @@ fn (mut p Parser) fn_decl() ast.FnDecl {
mut is_noreturn := false
mut is_ctor_new := false
mut is_c2v_variadic := false
mut is_markused := false
for fna in p.attrs {
match fna.name {
'noreturn' { is_noreturn = true }
@ -193,6 +194,7 @@ fn (mut p Parser) fn_decl() ast.FnDecl {
'trusted' { is_trusted = true }
'c2v_variadic' { is_c2v_variadic = true }
'use_new' { is_ctor_new = true }
'markused' { is_markused = true }
else {}
}
}
@ -496,6 +498,7 @@ fn (mut p Parser) fn_decl() ast.FnDecl {
is_test: is_test
is_keep_alive: is_keep_alive
is_unsafe: is_unsafe
is_markused: is_markused
//
attrs: p.attrs
is_conditional: conditional_ctdefine_idx != -1

View File

@ -13,9 +13,7 @@ import v.errors
import os
import hash.fnv1a
pub const (
builtin_functions = ['print', 'println', 'eprint', 'eprintln', 'isnil', 'panic', 'exit']
)
pub const builtin_functions = ['print', 'println', 'eprint', 'eprintln', 'isnil', 'panic', 'exit']
pub struct Parser {
pref &pref.Preferences
@ -3009,6 +3007,18 @@ fn (mut p Parser) import_syms(mut parent ast.Import) {
fn (mut p Parser) const_decl() ast.ConstDecl {
p.top_level_statement_start()
mut attrs := []ast.Attr{}
if p.attrs.len > 0 {
attrs = p.attrs
p.attrs = []
}
mut is_markused := false
for ga in attrs {
match ga.name {
'markused' { is_markused = true }
else {}
}
}
start_pos := p.tok.position()
is_pub := p.tok.kind == .key_pub
if is_pub {
@ -3055,6 +3065,7 @@ fn (mut p Parser) const_decl() ast.ConstDecl {
expr: expr
pos: pos.extend(expr.position())
comments: comments
is_markused: is_markused
}
fields << field
p.table.global_scope.register(field)
@ -3073,6 +3084,7 @@ fn (mut p Parser) const_decl() ast.ConstDecl {
is_pub: is_pub
end_comments: comments
is_block: is_block
attrs: attrs
}
}
@ -3105,6 +3117,15 @@ fn (mut p Parser) global_decl() ast.GlobalDecl {
attrs = p.attrs
p.attrs = []
}
mut is_markused := false
for ga in attrs {
match ga.name {
'markused' { is_markused = true }
else {}
}
}
if !p.has_globals && !p.pref.enable_globals && !p.pref.is_fmt && !p.pref.translated
&& !p.pref.is_livemain && !p.pref.building_v && !p.builtin_mod {
p.error('use `v -enable-globals ...` to enable globals')
@ -3180,6 +3201,7 @@ fn (mut p Parser) global_decl() ast.GlobalDecl {
typ_pos: typ_pos
typ: typ
comments: comments
is_markused: is_markused
}
fields << field
p.table.global_scope.register(field)