checker: prevent usage of imported module name prefix as identifier names

This commit is contained in:
Dylan Donnell 2025-09-11 13:27:45 +02:00
parent 919c68e6f9
commit f53ba363ef
5 changed files with 80 additions and 8 deletions

View file

@ -444,6 +444,7 @@ fn (mut c Checker) assign_stmt(mut node ast.AssignStmt) {
if c.check_import_sym_conflict(left.name) {
c.error('duplicate of an import symbol `${left.name}`', left.pos)
}
c.check_module_name_conflict(left.name, left.pos)
}
if node.op == .assign && left_type.has_flag(.option) && right is ast.UnsafeExpr
&& right.expr.is_nil() {

View file

@ -145,6 +145,7 @@ mut:
variant_data_type ast.Type
fn_return_type ast.Type
orm_table_fields map[string][]ast.StructField // known table structs
short_module_names []string // to check for function names colliding with module functions
v_current_commit_hash string // same as old C.V_CURRENT_COMMIT_HASH
assign_stmt_attr string // for `x := [1,2,3] @[freed]`
@ -331,6 +332,14 @@ pub fn (mut c Checker) change_current_file(file &ast.File) {
c.vmod_file_content = ''
c.mod = file.mod.name
c.is_generated = file.is_generated
c.short_module_names = ['builtin']
for import_sym in c.file.imports {
c.short_module_names << if import_sym.alias == '' {
import_sym.mod.all_after_last('.')
} else {
import_sym.alias
}
}
}
pub fn (mut c Checker) check_files(ast_files []&ast.File) {
@ -5790,6 +5799,16 @@ fn (c &Checker) check_import_sym_conflict(ident string) bool {
return false
}
fn (mut c Checker) check_module_name_conflict(ident string, pos token.Pos) {
if ident.contains('__') {
prefix := ident.all_before('__')
if prefix in c.short_module_names {
c.error('identifier cannot use prefix `${prefix}__` of imported module `${prefix}`',
pos)
}
}
}
// update_unresolved_fixed_sizes updates the unresolved type symbols for array fixed return type and alias type.
pub fn (mut c Checker) update_unresolved_fixed_sizes() {
for mut stmt in c.unresolved_fixed_sizes {

View file

@ -104,6 +104,7 @@ fn (mut c Checker) fn_decl(mut node ast.FnDecl) {
if !node.is_method && node.mod == 'main' && node.short_name in c.table.builtin_pub_fns {
c.error('cannot redefine builtin public function `${node.short_name}`', node.pos)
}
c.check_module_name_conflict(node.short_name, node.pos)
}
if node.name == 'main.main' {
c.main_fn_decl_node = *node

View file

@ -0,0 +1,28 @@
vlib/v/checker/tests/clash_ident_module_name_prefix.vv:7:1: error: identifier cannot use prefix `builtin__` of imported module `builtin`
5 | // os is not imported so the os__ prefix should not produce an error
6 |
7 | fn builtin__string_str() {
| ~~~~~~~~~~~~~~~~~~~~~~~~
8 | }
9 |
vlib/v/checker/tests/clash_ident_module_name_prefix.vv:10:1: error: identifier cannot use prefix `time__` of imported module `time`
8 | }
9 |
10 | fn time__utc() {
| ~~~~~~~~~~~~~~
11 | }
12 |
vlib/v/checker/tests/clash_ident_module_name_prefix.vv:17:2: error: identifier cannot use prefix `builtin__` of imported module `builtin`
15 |
16 | fn main() {
17 | builtin__string_str := 'Hello V!'.str()
| ~~~~~~~~~~~~~~~~~~~
18 | time__now := time.now()
19 | os__log := 'Hello V!'
vlib/v/checker/tests/clash_ident_module_name_prefix.vv:18:2: error: identifier cannot use prefix `time__` of imported module `time`
16 | fn main() {
17 | builtin__string_str := 'Hello V!'.str()
18 | time__now := time.now()
| ~~~~~~~~~
19 | os__log := 'Hello V!'
20 | println(builtin__string_str)

View file

@ -0,0 +1,23 @@
import time
// builtin__ prefix should always produce an error
// time is imported so the time__ prefix should always produce an error
// os is not imported so the os__ prefix should not produce an error
fn builtin__string_str() {
}
fn time__utc() {
}
fn os__getwd() {
}
fn main() {
builtin__string_str := 'Hello V!'.str()
time__now := time.now()
os__log := 'Hello V!'
println(builtin__string_str)
println(time__now)
println(os__log)
}