Skip to content

Commit e104a5f

Browse files
authored
checker: disallow duplicate export names (fix #25301) (#25302)
1 parent b826062 commit e104a5f

5 files changed

Lines changed: 101 additions & 2 deletions

File tree

‎vlib/v/ast/table.v‎

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -99,8 +99,9 @@ pub mut:
9999
anon_union_names map[string]int // anon union name -> union sym idx
100100
anon_union_counter int
101101
comptime_is_true map[string]ComptTimeCondResult // The evaluate cond results for different generic types combination, such as `comptime_is_true['T=int,X=string|main.v|pos ...'] = {true, '!DEFINED(WINDOWS)'}`
102-
new_int bool // use 64bit/32bit platform dependent `int`
103-
new_int_fmt_fix bool // vfmt will fix `int` to `i32`
102+
new_int bool // use 64bit/32bit platform dependent `int`
103+
new_int_fmt_fix bool // vfmt will fix `int` to `i32`
104+
export_names map[string]string // @[export] names
104105
}
105106

106107
pub struct ComptTimeCondResult {

‎vlib/v/checker/checker.v‎

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1937,6 +1937,13 @@ fn (mut c Checker) const_decl(mut node ast.ConstDecl) {
19371937
c.warn('const () groups will be an error after 2025-01-01 (`v fmt -w source.v` will fix that for you)',
19381938
node.pos)
19391939
}
1940+
1941+
mut is_export := false
1942+
mut export_name := ''
1943+
if export_attr := node.attrs.find_first('export') {
1944+
is_export = true
1945+
export_name = export_attr.arg
1946+
}
19401947
for mut field in node.fields {
19411948
if reserved_type_names_chk.matches(util.no_cur_mod(field.name, c.mod)) {
19421949
c.error('invalid use of reserved type `${field.name}` as a const name', field.pos)
@@ -1949,6 +1956,21 @@ fn (mut c Checker) const_decl(mut node ast.ConstDecl) {
19491956
}
19501957
c.error('duplicate const `${field.name}`', name_pos)
19511958
}
1959+
if is_export {
1960+
check_name := if export_name.len == 0 { field.name } else { export_name }
1961+
if !check_name.is_identifier() {
1962+
c.error('export name `${check_name}` should be a valid identifier', node.pos)
1963+
}
1964+
if check_name in c.table.export_names.values() {
1965+
name_pos := token.Pos{
1966+
...field.pos
1967+
len: util.no_cur_mod(field.name, c.mod).len
1968+
}
1969+
c.error('duplicate export name `${check_name}`', name_pos)
1970+
} else {
1971+
c.table.export_names[field.name] = check_name
1972+
}
1973+
}
19521974
if field.expr is ast.CallExpr {
19531975
sym := c.table.sym(c.check_expr_option_or_result_call(field.expr, c.expr(mut field.expr)))
19541976
if sym.kind == .multi_return {
@@ -2522,6 +2544,12 @@ fn (mut c Checker) global_decl(mut node ast.GlobalDecl) {
25222544
if '${c.mod}.${field.name}' in c.const_names {
25232545
c.error('duplicate global and const `${field.name}`', field.pos)
25242546
}
2547+
if field.name in c.table.export_names.values() {
2548+
c.error('duplicate export name `${field.name}`', field.pos)
2549+
} else {
2550+
// add global to exports for duplicate check
2551+
c.table.export_names[field.name] = field.name
2552+
}
25252553
sym := c.table.sym(field.typ)
25262554
if sym.kind == .placeholder {
25272555
c.error('unknown type `${sym.name}`', field.typ_pos)

‎vlib/v/checker/fn.v‎

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,22 @@ fn (mut c Checker) fn_decl(mut node ast.FnDecl) {
115115
if attr := node.attrs.find_first(attr_name) {
116116
if attr.arg == '' {
117117
c.error('missing argument for @[${attr_name}] attribute', attr.pos)
118+
} else if attr_name == 'export' {
119+
// export fn name
120+
fn_name := attr.arg
121+
if !fn_name.is_identifier() {
122+
c.error('export name `${fn_name}` should be a valid identifier',
123+
node.pos)
124+
}
125+
if fn_name in c.table.export_names.values() {
126+
c.error('duplicate export name `${fn_name}`', node.pos)
127+
} else {
128+
mut node_name := node.name
129+
if node.is_method {
130+
node_name = c.table.type_to_str(node.receiver.typ) + '.' + node_name
131+
}
132+
c.table.export_names[node_name] = fn_name
133+
}
118134
}
119135
}
120136
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
vlib/v/checker/tests/redfine_global_const_fn_names.vv:10:7: error: duplicate export name `abc`
2+
8 |
3+
9 | @[export: 'abc']
4+
10 | const abc2 = 3
5+
| ~~~~
6+
11 |
7+
12 | @[export: 'fn1']
8+
vlib/v/checker/tests/redfine_global_const_fn_names.vv:4:10: error: duplicate export name `abc`
9+
2 | module main
10+
3 |
11+
4 | __global abc = 1
12+
| ~~~
13+
5 |
14+
6 | @[export: 'abc']
15+
vlib/v/checker/tests/redfine_global_const_fn_names.vv:17:1: error: duplicate export name `fn1`
16+
15 |
17+
16 | @[export: 'fn1']
18+
17 | fn fn_abc2() {
19+
| ~~~~~~~~~~~~
20+
18 | }
21+
19 |
22+
vlib/v/checker/tests/redfine_global_const_fn_names.vv:21:1: error: export name `abc.dd` should be a valid identifier
23+
19 |
24+
20 | @[export: 'abc.dd']
25+
21 | fn fn_abc3() {
26+
| ~~~~~~~~~~~~
27+
22 | }
28+
23 |
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
@[has_globals]
2+
module main
3+
4+
__global abc = 1
5+
6+
@[export: 'abc']
7+
const abc1 = 2
8+
9+
@[export: 'abc']
10+
const abc2 = 3
11+
12+
@[export: 'fn1']
13+
fn fn_abc1() {
14+
}
15+
16+
@[export: 'fn1']
17+
fn fn_abc2() {
18+
}
19+
20+
@[export: 'abc.dd']
21+
fn fn_abc3() {
22+
}
23+
24+
@[export: xyz]
25+
fn fn_xyz() {
26+
}

0 commit comments

Comments
 (0)