mirror of
https://github.com/vlang/v.git
synced 2023-08-10 21:13:21 +03:00
table/checker: verify private functions/methods
This commit is contained in:
parent
af30bf939e
commit
06c1b9e95e
@ -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)
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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 {
|
||||||
|
@ -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 {
|
||||||
|
@ -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] {
|
||||||
|
@ -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
|
||||||
|
Loading…
Reference in New Issue
Block a user