v2 / vlib / v / checker / used_features.v
248 lines · 234 sloc · 7.98 KB · 021c9535e0cbcd1e528ae89c6d4c95aa3bc7e4e4
Raw
1// Copyright (c) 2019-2024 Felipe Pena. All rights reserved.
2// Use of this source code is governed by an MIT license that can be found in the LICENSE file.
3module checker
4
5import v.ast
6
7@[inline]
8fn (mut c Checker) markused_comptime_call(check bool, key string) {
9 if check {
10 c.table.used_features.comptime_calls[key] = true
11 }
12}
13
14fn comptime_call_last_arg_type(arg ast.CallArg) ast.Type {
15 return if arg.expr is ast.ArrayDecompose {
16 arg.expr.expr_type
17 } else {
18 arg.typ
19 }
20}
21
22fn (mut c Checker) markused_assertstmt_auto_str(mut node ast.AssertStmt) {
23 if !c.table.used_features.auto_str && !c.is_builtin_mod && mut node.expr is ast.InfixExpr {
24 if !c.table.sym(c.unwrap_generic(node.expr.left_type)).has_method('str') {
25 c.table.used_features.auto_str = true
26 return
27 }
28 if !c.table.sym(c.unwrap_generic(node.expr.right_type)).has_method('str') {
29 c.table.used_features.auto_str = true
30 }
31 }
32}
33
34fn (mut c Checker) markused_dumpexpr(mut node ast.DumpExpr) {
35 if c.is_builtin_mod {
36 return
37 }
38 unwrapped_type := c.unwrap_generic(node.expr_type)
39 if node.expr_type.has_flag(.generic) {
40 c.table.used_features.comptime_syms[unwrapped_type] = true
41 }
42 if !c.table.sym(unwrapped_type).has_method('str') {
43 c.table.used_features.auto_str = true
44 if node.expr_type.is_ptr() {
45 c.table.used_features.auto_str_ptr = true
46 }
47 if !c.table.used_features.auto_str_arr {
48 c.table.used_features.auto_str_arr = c.table.final_sym(unwrapped_type).kind == .array
49 }
50 } else {
51 c.table.used_features.print_types[node.expr_type.idx()] = true
52 }
53 c.table.used_features.print_types[ast.int_type_idx] = true
54}
55
56@[inline]
57fn (mut c Checker) markused_used_maps(check bool) {
58 if check {
59 c.table.used_features.used_maps++
60 }
61}
62
63fn (mut c Checker) markused_castexpr(mut _ ast.CastExpr, _ ast.Type, mut final_to_sym ast.TypeSymbol) {
64 if c.is_builtin_mod {
65 return
66 }
67 if c.table.used_features.used_maps == 0 && mut final_to_sym.info is ast.SumType {
68 if final_to_sym.info.variants.any(c.table.final_sym(it).kind == .map) {
69 c.table.used_features.used_maps++
70 }
71 }
72}
73
74fn (mut c Checker) markused_comptimecall(mut node ast.ComptimeCall) {
75 c.markused_comptime_call(true,
76 '${int(c.unwrap_generic(c.comptime.comptime_for_method.receiver_type))}.${c.comptime.comptime_for_method.name}')
77 if c.inside_anon_fn {
78 // $method passed to anon fn, mark all methods as used
79 sym := c.table.sym(c.unwrap_generic(node.left_type))
80 for m in sym.get_methods() {
81 c.table.used_features.comptime_calls['${int(c.unwrap_generic(m.receiver_type))}.${m.name}'] = true
82 if node.args.len > 0 && m.params.len > 0 {
83 last_param := m.params.last().typ
84 last_arg_type := comptime_call_last_arg_type(node.args.last())
85 if (last_param.is_int() || last_param.is_float()
86 || last_param.is_bool()) && c.table.final_sym(last_arg_type).kind == .array {
87 c.table.used_features.comptime_calls['${ast.string_type_idx}.${c.table.type_to_str(m.params.last().typ)}'] = true
88 }
89 }
90 }
91 } else {
92 m := c.comptime.comptime_for_method
93 if node.args.len > 0 && m.params.len > 0 {
94 last_param := m.params.last().typ
95 last_arg_type := comptime_call_last_arg_type(node.args.last())
96 if (last_param.is_int() || last_param.is_float() || last_param.is_bool())
97 && c.table.final_sym(last_arg_type).kind == .array {
98 c.table.used_features.comptime_calls['${ast.string_type_idx}.${c.table.type_to_str(m.params.last().typ)}'] = true
99 }
100 }
101 }
102}
103
104fn (mut c Checker) markused_comptimefor(mut _ ast.ComptimeFor, unwrapped_expr_type ast.Type) {
105 if c.table.used_features.used_maps == 0 {
106 final_sym := c.table.final_sym(unwrapped_expr_type)
107 if final_sym.info is ast.Map {
108 c.table.used_features.used_maps++
109 } else if final_sym.info is ast.SumType {
110 if final_sym.info.variants.any(c.table.final_sym(it).kind == .map) {
111 c.table.used_features.used_maps++
112 }
113 }
114 }
115}
116
117fn (mut c Checker) markused_call_expr(left_type ast.Type, mut node ast.CallExpr) {
118 if left_type != 0 && left_type.is_ptr() && !c.table.used_features.auto_str_ptr
119 && node.name == 'str' {
120 c.table.used_features.auto_str_ptr = true
121 if !c.table.used_features.auto_str_arr {
122 c.table.used_features.auto_str_arr = c.table.final_sym(left_type).kind == .array
123 }
124 }
125}
126
127fn (mut c Checker) markused_print_call(mut node ast.CallExpr) {
128 if !c.is_builtin_mod && c.mod != 'math.bits' && node.args[0].expr !is ast.StringLiteral {
129 arg_typ := c.unwrap_generic(node.args[0].typ)
130 if arg_typ == 0 {
131 return
132 }
133 if (node.args[0].expr is ast.CallExpr && node.args[0].expr.is_method
134 && node.args[0].expr.name == 'str')
135 || !c.table.sym(arg_typ).has_method('str') {
136 c.table.used_features.auto_str = true
137 } else {
138 c.mark_type_str_method_as_referenced(arg_typ)
139 if arg_typ.has_option_or_result() {
140 c.table.used_features.print_options = true
141 }
142 c.table.used_features.print_types[arg_typ.idx()] = true
143 if !c.table.used_features.auto_str_ptr && node.args[0].expr is ast.Ident {
144 var_obj := node.args[0].expr.obj
145 if var_obj is ast.Var {
146 if var_obj.orig_type != 0 {
147 fsym := c.table.final_sym(var_obj.orig_type)
148 if fsym.kind == .interface {
149 c.table.used_features.auto_str_ptr = true
150 } else if fsym.kind == .array {
151 c.table.used_features.auto_str_arr = true
152 }
153 return
154 }
155 }
156 }
157 }
158 if arg_typ.is_ptr() {
159 c.table.used_features.auto_str_ptr = true
160 }
161 if !c.table.used_features.auto_str_arr || !c.table.used_features.auto_str_ptr {
162 sym := c.table.final_sym(arg_typ)
163 if sym.kind == .array {
164 c.table.used_features.auto_str_arr = true
165 } else if sym.info is ast.Struct {
166 if !c.table.used_features.auto_str_ptr {
167 c.table.used_features.auto_str_ptr = sym.info.fields.any(it.typ.is_ptr()
168 || it.typ.is_pointer())
169 }
170 c.table.used_features.auto_str_arr =
171 sym.info.fields.any(c.table.final_sym(it.typ).kind == .array)
172 }
173 }
174 }
175}
176
177fn (mut c Checker) markused_method_call(mut node ast.CallExpr, mut left_expr ast.Expr, left_type ast.Type) {
178 if !left_type.has_flag(.generic) && mut left_expr is ast.Ident {
179 if left_expr.obj is ast.Var && left_expr.obj.ct_type_var == .smartcast {
180 c.table.used_features.comptime_calls['${int(left_type)}.${node.name}'] = true
181 }
182 if c.table.sym(left_type).kind == .alias {
183 c.table.used_features.comptime_calls['${int(left_type)}.${node.name}'] = true
184 // Alias method calls can also auto-resolve to pointer receivers in cgen.
185 if !left_type.is_ptr() {
186 c.table.used_features.comptime_calls['${int(left_type.ref())}.${node.name}'] = true
187 }
188 }
189 } else if left_type.has_flag(.generic) {
190 unwrapped_left := c.unwrap_generic(left_type)
191 c.table.used_features.comptime_calls['${int(unwrapped_left)}.${node.name}'] = true
192 // Generic method calls can resolve to pointer receivers during cgen (`x.name()` -> `(&x).name()`).
193 // Mark both forms so skip-unused does not drop pointer receiver methods.
194 if !unwrapped_left.is_ptr() {
195 c.table.used_features.comptime_calls['${int(unwrapped_left.ref())}.${node.name}'] = true
196 }
197 }
198}
199
200fn (mut c Checker) markused_string_inter_lit(mut _ ast.StringInterLiteral, ftyp ast.Type) {
201 if c.is_builtin_mod {
202 return
203 }
204 if !c.table.sym(ftyp).has_method('str') {
205 c.table.used_features.auto_str = true
206 } else {
207 c.mark_type_str_method_as_referenced(ftyp)
208 c.table.used_features.print_types[ftyp.idx()] = true
209 }
210 if ftyp.is_ptr() {
211 c.table.used_features.auto_str_ptr = true
212 }
213 if !c.table.used_features.auto_str_arr {
214 c.table.used_features.auto_str_arr = c.table.final_sym(ftyp).kind == .array
215 }
216 if ftyp.has_option_or_result() {
217 c.table.used_features.print_options = true
218 }
219}
220
221fn (mut c Checker) markused_array_method(check bool, method_name string) {
222 if !check {
223 return
224 }
225 match method_name {
226 '' { // array init
227 }
228 'first' {
229 c.table.used_features.arr_first = true
230 }
231 'last' {
232 c.table.used_features.arr_last = true
233 }
234 'pop_left' {
235 c.table.used_features.arr_pop_left = true
236 }
237 'pop' {
238 c.table.used_features.arr_pop = true
239 }
240 'delete' {
241 c.table.used_features.arr_delete = true
242 }
243 'map' {
244 c.table.used_features.arr_map = true
245 }
246 else {}
247 }
248}
249