checker, cgen: generate .free() methods for custom structs automatically (#11529)

pull/11530/head
yuyi 2021-09-18 14:38:42 +08:00 committed by GitHub
parent 2eeba4758a
commit 39ad6da506
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 90 additions and 0 deletions

View File

@ -2472,6 +2472,8 @@ pub fn (mut c Checker) method_call(mut node ast.CallExpr) ast.Type {
}
c.fail_if_unreadable(node.left, left_type, 'receiver')
return ast.string_type
} else if method_name == 'free' {
return ast.void_type
}
// call struct field fn type
// TODO: can we use SelectorExpr for all? this dosent really belong here

View File

@ -0,0 +1,65 @@
// Copyright (c) 2019-2021 Alexander Medvednikov. All rights reserved.
// Use of this source code is governed by an MIT license that can be found in the LICENSE file.
module c
import v.ast
import strings
fn (mut g Gen) gen_free_method_for_type(typ ast.Type) string {
styp := g.typ(typ).replace('*', '')
mut sym := g.table.get_type_symbol(g.unwrap_generic(typ))
mut fn_name := styp_to_free_fn_name(styp)
if mut sym.info is ast.Alias {
if sym.info.is_import {
sym = g.table.get_type_symbol(sym.info.parent_type)
}
}
if sym.kind == .map {
return 'map_free'
} else if sym.kind == .array {
return 'array_free'
}
if sym.has_method('free') {
return fn_name
}
match mut sym.info {
ast.Struct {
g.gen_free_for_struct(sym.info, styp, fn_name)
}
else {
println(g.table.type_str(typ))
verror("could not generate free method '$fn_name' for type '$styp'")
}
}
return fn_name
}
fn (mut g Gen) gen_free_for_struct(info ast.Struct, styp string, fn_name string) {
g.type_definitions.writeln('void ${fn_name}($styp* it); // auto')
mut fn_builder := strings.new_builder(512)
defer {
g.auto_fn_definitions << fn_builder.str()
}
fn_builder.writeln('void ${fn_name}($styp* it) {')
for field in info.fields {
sym := g.table.get_type_symbol(g.unwrap_generic(field.typ))
if sym.kind !in [.string, .array, .map, .struct_] {
continue
}
mut field_styp := g.typ(field.typ).replace('*', '')
field_styp_fn_name := if sym.has_method('free') {
'${field_styp}_free'
} else {
g.gen_free_method_for_type(field.typ)
}
fn_builder.writeln('\t${field_styp_fn_name}(&(it->$field.name));')
}
fn_builder.writeln('}')
}
[inline]
fn styp_to_free_fn_name(styp string) string {
return styp.replace_each(['*', '', '.', '__', ' ', '__']) + '_free'
}

View File

@ -796,6 +796,12 @@ fn (mut g Gen) method_call(node ast.CallExpr) {
rec_type = rec_type.clear_flag(.shared_f).set_nr_muls(0)
}
g.gen_str_method_for_type(rec_type)
} else if node.name == 'free' {
mut rec_type := node.receiver_type
if rec_type.has_flag(.shared_f) {
rec_type = rec_type.clear_flag(.shared_f).set_nr_muls(0)
}
g.gen_free_method_for_type(rec_type)
}
mut has_cast := false
if left_sym.kind == .map && node.name in ['clone', 'move'] {

View File

@ -0,0 +1,17 @@
struct Info {
name string
notes []string
maps map[int]int
info SubInfo
}
struct SubInfo {
path string
files []string
}
fn test_autogen_free() {
info := &Info{}
info.free()
assert true
}