table/checker: verify private functions/methods

pull/4465/head
Alexander Medvednikov 2020-04-17 17:16:14 +02:00
parent af30bf939e
commit 06c1b9e95e
7 changed files with 66 additions and 51 deletions

View File

@ -35,6 +35,8 @@ mut:
// checked_ident string // to avoid infinit checker loops // checked_ident string // to avoid infinit checker loops
var_decl_name string var_decl_name string
returns bool returns bool
mod string // current module name
is_builtin_mod bool // are we in `builtin`?
} }
pub fn new_checker(table &table.Table, pref &pref.Preferences) Checker { pub fn new_checker(table &table.Table, pref &pref.Preferences) Checker {
@ -150,7 +152,7 @@ pub fn (c mut Checker) struct_init(struct_init mut ast.StructInit) table.Type {
} }
} }
if !exists { if !exists {
c.error('struct init: no such field `$field.name` for struct `$type_sym.name`', field.pos) c.error('unknown field `$field.name` in struct literal of type `$type_sym.name`', field.pos)
continue continue
} }
if field_name in inited_fields { if field_name in inited_fields {
@ -320,6 +322,12 @@ pub fn (c mut Checker) call_method(call_expr mut ast.CallExpr) table.Type {
return info.elem_type return info.elem_type
} }
if method := c.table.type_find_method(left_type_sym, method_name) { if method := c.table.type_find_method(left_type_sym, method_name) {
if !method.is_pub && !c.is_builtin_mod && left_type_sym.mod != c.mod && left_type_sym.mod != '' { // method.mod != c.mod {
// If a private method is called outside of the module
// its receiver type is defined in, show an error.
//println('warn $method_name lef.mod=$left_type_sym.mod c.mod=$c.mod')
c.error('method `${left_type_sym.name}.$method_name` is private', call_expr.pos)
}
no_args := method.args.len - 1 no_args := method.args.len - 1
min_required_args := method.args.len - if method.is_variadic && method.args.len > 1 { 2 } else { 1 } min_required_args := method.args.len - if method.is_variadic && method.args.len > 1 { 2 } else { 1 }
if call_expr.args.len < min_required_args { if call_expr.args.len < min_required_args {
@ -1012,6 +1020,11 @@ fn (c mut Checker) stmt(node ast.Stmt) {
} }
// ast.HashStmt {} // ast.HashStmt {}
ast.Import {} ast.Import {}
ast.Module {
c.mod = it.name
c.is_builtin_mod = it.name == 'builtin'
}
// ast.GlobalDecl {} // ast.GlobalDecl {}
ast.Return { ast.Return {
c.returns = true c.returns = true
@ -1635,7 +1648,14 @@ fn (c mut Checker) warn_or_error(message string, pos token.Position, warn bool)
// if c.pref.is_verbose { // if c.pref.is_verbose {
// print_backtrace() // print_backtrace()
// } // }
if !warn { if warn {
c.warnings << scanner.Warning{
reporter: scanner.Reporter.checker
pos: pos
file_path: c.file.path
message: message
}
} else {
c.nr_errors++ c.nr_errors++
if !(pos.line_nr in c.error_lines) { if !(pos.line_nr in c.error_lines) {
c.errors << scanner.Error{ c.errors << scanner.Error{
@ -1646,16 +1666,10 @@ fn (c mut Checker) warn_or_error(message string, pos token.Position, warn bool)
} }
c.error_lines << pos.line_nr c.error_lines << pos.line_nr
} }
} else {
c.warnings << scanner.Warning{
reporter: scanner.Reporter.checker
pos: pos
file_path: c.file.path
message: message
}
} }
} }
// for debugging only
fn (p Checker) fileis(s string) bool { fn (p Checker) fileis(s string) bool {
return p.file.path.contains(s) return p.file.path.contains(s)
} }

View File

@ -1,4 +1,4 @@
vlib/v/checker/tests/inout/struct_unknown_field.v:8:9: error: struct init: no such field `bar` for struct `Test` vlib/v/checker/tests/inout/struct_unknown_field.v:8:9: error: unknown field `bar` in struct literal `Test`
6| t := Test{ 6| t := Test{
7| foo: true 7| foo: true
8| bar: false 8| bar: false

View File

@ -180,6 +180,7 @@ fn (var p Parser) fn_decl() ast.FnDecl {
return_type: return_type return_type: return_type
is_variadic: is_variadic is_variadic: is_variadic
is_generic: is_generic is_generic: is_generic
is_pub: is_pub
}) })
} else { } else {
if is_c { if is_c {
@ -200,6 +201,7 @@ fn (var p Parser) fn_decl() ast.FnDecl {
is_c: is_c is_c: is_c
is_js: is_js is_js: is_js
is_generic: is_generic is_generic: is_generic
is_pub: is_pub
}) })
} }
// Body // Body

View File

@ -26,8 +26,8 @@ mut:
inside_for bool inside_for bool
inside_fn bool inside_fn bool
pref &pref.Preferences pref &pref.Preferences
builtin_mod bool builtin_mod bool // are we in the `builtin` module?
mod string mod string // current module name
attr string attr string
expr_mod string expr_mod string
scope &ast.Scope scope &ast.Scope
@ -1690,6 +1690,7 @@ fn (var p Parser) struct_decl() ast.StructDecl {
is_typedef: is_typedef is_typedef: is_typedef
is_union: is_union is_union: is_union
} }
mod: p.mod
} }
var ret := 0 var ret := 0
if p.builtin_mod && t.name in table.builtin_type_names { if p.builtin_mod && t.name in table.builtin_type_names {

View File

@ -11,10 +11,8 @@
// idx: u16(type) & 0xffff // idx: u16(type) & 0xffff
module table module table
import ( import strings
strings import v.ast
v.ast
)
pub type Type int pub type Type int
@ -28,6 +26,7 @@ mut:
kind Kind kind Kind
name string name string
methods []Fn methods []Fn
mod string
} }
pub enum TypeFlag { pub enum TypeFlag {
@ -310,7 +309,7 @@ pub fn (t TypeSymbol) str() string {
return t.name return t.name
} }
*/ */
pub fn (t mut Table) register_builtin_type_symbols() { pub fn (var t Table) register_builtin_type_symbols() {
// reserve index 0 so nothing can go there // reserve index 0 so nothing can go there
// save index check, 0 will mean not found // save index check, 0 will mean not found
t.register_type_symbol(TypeSymbol{ t.register_type_symbol(TypeSymbol{
@ -527,7 +526,7 @@ pub fn (k Kind) str() string {
} }
pub fn (kinds []Kind) str() string { pub fn (kinds []Kind) str() string {
mut kinds_str := '' var kinds_str := ''
for i, k in kinds { for i, k in kinds {
kinds_str += k.str() kinds_str += k.str()
if i < kinds.len - 1 { if i < kinds.len - 1 {
@ -594,7 +593,7 @@ pub:
pub fn (table &Table) type_to_str(t Type) string { pub fn (table &Table) type_to_str(t Type) string {
sym := table.get_type_symbol(t) sym := table.get_type_symbol(t)
if sym.kind == .multi_return { if sym.kind == .multi_return {
mut res := '(' var res := '('
mr_info := sym.info as MultiReturn mr_info := sym.info as MultiReturn
for i, typ in mr_info.types { for i, typ in mr_info.types {
res += table.type_to_str(typ) res += table.type_to_str(typ)
@ -605,7 +604,7 @@ pub fn (table &Table) type_to_str(t Type) string {
res += ')' res += ')'
return res return res
} }
mut res := sym.name var res := sym.name
if sym.kind == .array { if sym.kind == .array {
res = res.replace('array_', '[]') res = res.replace('array_', '[]')
} else if sym.kind == .map { } else if sym.kind == .map {

View File

@ -17,15 +17,15 @@ fn (table &Table) has_cflag(cflag builder.CFlag) bool {
// parse the flags to (table.cflags) []CFlag // parse the flags to (table.cflags) []CFlag
// Note: clean up big time (joe-c) // Note: clean up big time (joe-c)
fn (table mut Table) parse_cflag(cflag, mod string, ctimedefines []string) ?bool { pub fn (var table Table) parse_cflag(cflag, mod string, ctimedefines []string) ?bool {
allowed_flags := ['framework', 'library', 'Wa', 'Wl', 'Wp', 'I', 'l', 'L'] allowed_flags := ['framework', 'library', 'Wa', 'Wl', 'Wp', 'I', 'l', 'L']
flag_orig := cflag.trim_space() flag_orig := cflag.trim_space()
mut flag := flag_orig var flag := flag_orig
if flag == '' { if flag == '' {
return true return true
} }
mut fos := '' var fos := ''
mut allowed_os_overrides := ['linux', 'darwin', 'freebsd', 'windows', 'mingw', 'solaris'] var allowed_os_overrides := ['linux', 'darwin', 'freebsd', 'windows', 'mingw', 'solaris']
allowed_os_overrides << ctimedefines allowed_os_overrides << ctimedefines
for os_override in allowed_os_overrides { for os_override in allowed_os_overrides {
if !flag.starts_with(os_override) { if !flag.starts_with(os_override) {
@ -38,8 +38,8 @@ fn (table mut Table) parse_cflag(cflag, mod string, ctimedefines []string) ?bool
flag = flag[pos..].trim_space() flag = flag[pos..].trim_space()
} }
for { for {
mut name := '' var name := ''
mut value := '' var value := ''
if flag[0] == `-` { if flag[0] == `-` {
for f in allowed_flags { for f in allowed_flags {
i := 1 + f.len i := 1 + f.len
@ -50,11 +50,11 @@ fn (table mut Table) parse_cflag(cflag, mod string, ctimedefines []string) ?bool
} }
} }
} }
mut index := flag.index(' -') or { var index := flag.index(' -') or {
-1 -1
} }
for index > -1 { for index > -1 {
mut has_next := false var has_next := false
for f in allowed_flags { for f in allowed_flags {
i := index + 2 + f.len i := index + 2 + f.len
if i <= flag.len && f == flag[index + 2..i] { if i <= flag.len && f == flag[index + 2..i] {

View File

@ -3,10 +3,8 @@
// that can be found in the LICENSE file. // that can be found in the LICENSE file.
module table module table
import ( import os
os import v.builder
v.builder
)
pub struct Table { pub struct Table {
pub mut: pub mut:
@ -27,6 +25,8 @@ pub:
is_c bool is_c bool
is_js bool is_js bool
is_generic bool is_generic bool
is_pub bool
mod string
} }
pub struct Arg { pub struct Arg {
@ -45,14 +45,14 @@ mut:
} }
pub fn new_table() &Table { pub fn new_table() &Table {
mut t := &Table{} var t := &Table{}
t.register_builtin_type_symbols() t.register_builtin_type_symbols()
return t return t
} }
// used to compare fn's & for naming anon fn's // used to compare fn's & for naming anon fn's
pub fn (f &Fn) signature() string { pub fn (f &Fn) signature() string {
mut sig := '' var sig := ''
for i, arg in f.args { for i, arg in f.args {
// TODO: for now ignore mut/pts in sig for now // TODO: for now ignore mut/pts in sig for now
typ := type_set_nr_muls(arg.typ, 0) typ := type_set_nr_muls(arg.typ, 0)
@ -85,12 +85,12 @@ pub fn (t &Table) known_fn(name string) bool {
return true return true
} }
pub fn (t mut Table) register_fn(new_fn Fn) { pub fn (var t Table) register_fn(new_fn Fn) {
// println('reg fn $new_fn.name nr_args=$new_fn.args.len') // println('reg fn $new_fn.name nr_args=$new_fn.args.len')
t.fns[new_fn.name] = new_fn t.fns[new_fn.name] = new_fn
} }
pub fn (t mut TypeSymbol) register_method(new_fn Fn) { pub fn (var t TypeSymbol) register_method(new_fn Fn) {
t.methods << new_fn t.methods << new_fn
} }
@ -142,7 +142,7 @@ pub fn (t &Table) type_has_method(s &TypeSymbol, name string) bool {
// search from current type up through each parent looking for method // search from current type up through each parent looking for method
pub fn (t &Table) type_find_method(s &TypeSymbol, name string) ?Fn { pub fn (t &Table) type_find_method(s &TypeSymbol, name string) ?Fn {
// println('type_find_method($s.name, $name) types.len=$t.types.len s.parent_idx=$s.parent_idx') // println('type_find_method($s.name, $name) types.len=$t.types.len s.parent_idx=$s.parent_idx')
mut ts := s var ts := s
for { for {
if method := ts.find_method(name) { if method := ts.find_method(name) {
return method return method
@ -166,7 +166,7 @@ pub fn (t &Table) struct_has_field(s &TypeSymbol, name string) bool {
// search from current type up through each parent looking for field // search from current type up through each parent looking for field
pub fn (t &Table) struct_find_field(s &TypeSymbol, name string) ?Field { pub fn (t &Table) struct_find_field(s &TypeSymbol, name string) ?Field {
// println('struct_find_field($s.name, $name) types.len=$t.types.len s.parent_idx=$s.parent_idx') // println('struct_find_field($s.name, $name) types.len=$t.types.len s.parent_idx=$s.parent_idx')
mut ts := s var ts := s
for { for {
if field := ts.find_field(name) { if field := ts.find_field(name) {
return field return field
@ -210,12 +210,11 @@ pub fn (t &Table) get_type_name(typ Type) string {
return typ_sym.name return typ_sym.name
} }
// this will override or register builtin type // this will override or register builtin type
// allows prexisitng types added in register_builtins // allows prexisitng types added in register_builtins
// to be overriden with their real type info // to be overriden with their real type info
[inline] [inline]
pub fn (t mut Table) register_builtin_type_symbol(typ TypeSymbol) int { pub fn (var t Table) register_builtin_type_symbol(typ TypeSymbol) int {
existing_idx := t.type_idxs[typ.name] existing_idx := t.type_idxs[typ.name]
if existing_idx > 0 { if existing_idx > 0 {
if existing_idx >= string_type_idx { if existing_idx >= string_type_idx {
@ -235,7 +234,7 @@ pub fn (t mut Table) register_builtin_type_symbol(typ TypeSymbol) int {
} }
[inline] [inline]
pub fn (t mut Table) register_type_symbol(typ TypeSymbol) int { pub fn (var t Table) register_type_symbol(typ TypeSymbol) int {
// println('register_type_symbol( $typ.name )') // println('register_type_symbol( $typ.name )')
existing_idx := t.type_idxs[typ.name] existing_idx := t.type_idxs[typ.name]
if existing_idx > 0 { if existing_idx > 0 {
@ -309,7 +308,7 @@ pub fn (t &Table) map_name(key_type, value_type Type) string {
// return 'map_${value_type_sym.name}' + suffix // return 'map_${value_type_sym.name}' + suffix
} }
pub fn (t mut Table) find_or_register_map(key_type, value_type Type) int { pub fn (var t Table) find_or_register_map(key_type, value_type Type) int {
name := t.map_name(key_type, value_type) name := t.map_name(key_type, value_type)
// existing // existing
existing_idx := t.type_idxs[name] existing_idx := t.type_idxs[name]
@ -329,7 +328,7 @@ pub fn (t mut Table) find_or_register_map(key_type, value_type Type) int {
return t.register_type_symbol(map_typ) return t.register_type_symbol(map_typ)
} }
pub fn (t mut Table) find_or_register_array(elem_type Type, nr_dims int) int { pub fn (var t Table) find_or_register_array(elem_type Type, nr_dims int) int {
name := t.array_name(elem_type, nr_dims) name := t.array_name(elem_type, nr_dims)
// existing // existing
existing_idx := t.type_idxs[name] existing_idx := t.type_idxs[name]
@ -349,7 +348,7 @@ pub fn (t mut Table) find_or_register_array(elem_type Type, nr_dims int) int {
return t.register_type_symbol(array_type) return t.register_type_symbol(array_type)
} }
pub fn (t mut Table) find_or_register_array_fixed(elem_type Type, size, nr_dims int) int { pub fn (var t Table) find_or_register_array_fixed(elem_type Type, size, nr_dims int) int {
name := t.array_fixed_name(elem_type, size, nr_dims) name := t.array_fixed_name(elem_type, size, nr_dims)
// existing // existing
existing_idx := t.type_idxs[name] existing_idx := t.type_idxs[name]
@ -369,8 +368,8 @@ pub fn (t mut Table) find_or_register_array_fixed(elem_type Type, size, nr_dims
return t.register_type_symbol(array_fixed_type) return t.register_type_symbol(array_fixed_type)
} }
pub fn (t mut Table) find_or_register_multi_return(mr_typs []Type) int { pub fn (var t Table) find_or_register_multi_return(mr_typs []Type) int {
mut name := 'multi_return' var name := 'multi_return'
for mr_typ in mr_typs { for mr_typ in mr_typs {
mr_type_sym := t.get_type_symbol(mr_typ) mr_type_sym := t.get_type_symbol(mr_typ)
name += '_$mr_type_sym.name' name += '_$mr_type_sym.name'
@ -391,7 +390,7 @@ pub fn (t mut Table) find_or_register_multi_return(mr_typs []Type) int {
return t.register_type_symbol(mr_type) return t.register_type_symbol(mr_type)
} }
pub fn (t mut Table) find_or_register_fn_type(f Fn, has_decl bool) int { pub fn (var t Table) find_or_register_fn_type(f Fn, has_decl bool) int {
is_anon := f.name.len == 0 is_anon := f.name.len == 0
name := if is_anon { 'anon_fn_$f.signature()' } else { f.name } name := if is_anon { 'anon_fn_$f.signature()' } else { f.name }
return t.register_type_symbol(TypeSymbol{ return t.register_type_symbol(TypeSymbol{
@ -405,7 +404,7 @@ pub fn (t mut Table) find_or_register_fn_type(f Fn, has_decl bool) int {
}) })
} }
pub fn (t mut Table) add_placeholder_type(name string) int { pub fn (var t Table) add_placeholder_type(name string) int {
ph_type := TypeSymbol{ ph_type := TypeSymbol{
kind: .placeholder kind: .placeholder
name: name name: name