Skip to content

Commit 88f589e

Browse files
authored
parser,checker: fix vls fn signature (#25572)
1 parent 75e78ab commit 88f589e

6 files changed

Lines changed: 91 additions & 38 deletions

File tree

‎vlib/v/checker/assign.v‎

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -149,8 +149,13 @@ fn (mut c Checker) assign_stmt(mut node ast.AssignStmt) {
149149
for i, mut left in node.left {
150150
if mut left is ast.CallExpr {
151151
// ban `foo() = 10`
152-
c.error('cannot call function `${left.name}()` on the left side of an assignment',
153-
left.pos)
152+
if c.pref.is_vls {
153+
// in `vls` mode, code is incomplete, eval left also
154+
c.expr(mut left)
155+
} else {
156+
c.error('cannot call function `${left.name}()` on the left side of an assignment',
157+
left.pos)
158+
}
154159
} else if mut left is ast.PrefixExpr {
155160
// ban `*foo() = 10`
156161
if left.right is ast.CallExpr && left.op == .mul {
@@ -504,7 +509,7 @@ fn (mut c Checker) assign_stmt(mut node ast.AssignStmt) {
504509
c.error('cannot use infix expression on the left side of `${node.op}`',
505510
left.pos)
506511
}
507-
if is_decl {
512+
if is_decl && !c.pref.is_vls {
508513
c.error('non-name `${left}` on left side of `:=`', left.pos())
509514
}
510515

‎vlib/v/checker/autocomplete.v‎

Lines changed: 54 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -44,23 +44,38 @@ struct Detail {
4444
}
4545

4646
// Autocomplete for function parameters `os.write_bytes(**path string, bytes []u8***)` etc
47-
pub fn (mut c Checker) autocomplete_for_fn_call_expr() {
48-
mut fn_name := if c.pref.linfo.expr.ends_with('(') {
49-
c.pref.linfo.expr[..c.pref.linfo.expr.len - 1].trim_space()
50-
} else {
51-
c.pref.linfo.expr.replace('()', '').trim_space()
47+
pub fn (mut c Checker) autocomplete_for_fn_call_expr(node ast.CallExpr) {
48+
// Make sure this ident is on the same line and same file as request
49+
same_line := c.pref.linfo.line_nr + 1 == node.pos.line_nr
50+
if !same_line {
51+
return
5252
}
53-
mod_name := fn_name.all_before_last('.')
54-
resolved_mod_name := c.try_resolve_to_import_mod_name(mod_name)
55-
if resolved_mod_name.len > 0 {
56-
fn_name = resolved_mod_name + '.' + fn_name.all_after_last('.')
53+
if node.pos.file_idx < 0 {
54+
return
55+
}
56+
if c.pref.linfo.path != c.table.filelist[node.pos.file_idx] {
57+
return
5758
}
58-
f := c.table.find_fn(fn_name) or {
59-
println('failed to find fn "${fn_name}"')
59+
col := c.pref.linfo.expr.all_after_last('^').int()
60+
if node.name_pos.col + node.name_pos.len + 1 != col {
6061
return
6162
}
63+
fn_name := node.name
64+
f := if node.is_method {
65+
left_sym := c.table.sym(c.unwrap_generic(node.left_type))
66+
c.table.find_method(left_sym, fn_name) or {
67+
println('failed to find method "${fn_name}"')
68+
return
69+
}
70+
} else {
71+
c.table.find_fn(fn_name) or {
72+
println('failed to find fn "${fn_name}"')
73+
return
74+
}
75+
}
6276
res := c.build_fn_summary(f)
6377
println(res)
78+
exit(0)
6479
}
6580

6681
fn (mut c Checker) ident_gotodef() {
@@ -139,6 +154,7 @@ fn (mut c Checker) ident_autocomplete(node ast.Ident) {
139154
mut details := []Detail{cap: 10}
140155
c.vls_gen_type_details(mut details, sym)
141156
c.vls_write_details(details)
157+
exit(0)
142158
}
143159

144160
fn (mut c Checker) module_autocomplete(mod string) {
@@ -150,26 +166,39 @@ fn (mut c Checker) module_autocomplete(mod string) {
150166
c.vls_write_details(details)
151167
}
152168

153-
fn (c &Checker) build_fn_summary(method ast.Fn) string {
154-
mut sb := strings.new_builder(64)
155-
sb.write_string(method.name.all_after_last('.'))
156-
sb.write_string('(')
157-
for i, param in method.params {
158-
if method.is_method && i == 0 {
169+
fn (c &Checker) build_fn_summary(func ast.Fn) string {
170+
mut sb := strings.new_builder(128)
171+
fn_name := func.name.all_after_last('.')
172+
sb.writeln('{\n"signatures":[{')
173+
sb.write_string('\t"label":"${fn_name}(')
174+
mut params := []string{cap: func.params.len}
175+
for i, param in func.params {
176+
if func.is_method && i == 0 {
159177
// skip receiver
160178
continue
161179
}
162-
sb.write_string(param.name)
163-
sb.write_string(' ')
164-
sb.write_string(c.table.type_to_str(param.typ))
165-
if i < method.params.len - 1 {
166-
sb.write_string(', ')
167-
}
180+
params << '${param.name} ${c.table.type_to_str(param.typ)}'
168181
}
182+
sb.write_string(params.join(', '))
169183
sb.write_string(')')
170-
if method.return_type != ast.void_type {
171-
sb.write_string(c.table.type_to_str(method.return_type))
184+
if func.return_type != ast.void_type {
185+
sb.write_string(' ')
186+
sb.write_string(c.table.type_to_str(func.return_type))
187+
}
188+
sb.writeln('",\n\t"parameters":[{')
189+
for i, p in params {
190+
sb.write_string('\t\t"label":"${p}"')
191+
if i < params.len - 1 {
192+
sb.write_string(',')
193+
}
194+
sb.writeln('')
172195
}
196+
sb.writeln('\t}]')
197+
sb.writeln('}],')
198+
sb.writeln('"activeSignature":0,')
199+
sb.writeln('"activeParameter":0,')
200+
sb.writeln('"_type":"SignatureHelp"')
201+
sb.writeln('}')
173202
return sb.str()
174203
}
175204

‎vlib/v/checker/checker.v‎

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -453,10 +453,6 @@ pub fn (mut c Checker) check_files(ast_files []&ast.File) {
453453
c.ident_gotodef()
454454
exit(0)
455455
}
456-
if c.pref.linfo.expr.contains('()') || c.pref.linfo.expr.ends_with('(') {
457-
c.autocomplete_for_fn_call_expr()
458-
exit(0)
459-
}
460456
for i, file in ast_files {
461457
// println(file.path)
462458
if file.path == c.pref.linfo.path {

‎vlib/v/checker/fn.v‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -759,6 +759,11 @@ fn (mut c Checker) call_expr(mut node ast.CallExpr) ast.Type {
759759
} else {
760760
c.fn_call(mut node, mut continue_check)
761761
}
762+
if c.pref.is_vls {
763+
if c.pref.linfo.expr.starts_with('fn^') {
764+
c.autocomplete_for_fn_call_expr(node)
765+
}
766+
}
762767
if !continue_check {
763768
return ast.void_type
764769
}

‎vlib/v/parser/fn.v‎

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ fn (mut p Parser) call_expr(language ast.Language, mod string) ast.CallExpr {
5252
}
5353
p.check(.lpar)
5454
args := p.call_args()
55-
if p.tok.kind != .rpar {
55+
if p.tok.kind != .rpar && !p.pref.is_vls {
5656
params := p.table.fns[fn_name] or { unsafe { p.table.fns['${p.mod}.${fn_name}'] } }.params
5757
if args.len < params.len && p.prev_tok.kind != .comma {
5858
pos := if p.tok.kind == .eof { p.prev_tok.pos() } else { p.tok.pos() }
@@ -70,7 +70,9 @@ fn (mut p Parser) call_expr(language ast.Language, mod string) ast.CallExpr {
7070
}
7171
}
7272
last_pos := p.tok.pos()
73-
p.next()
73+
if p.tok.kind == .rpar {
74+
p.next()
75+
}
7476
mut pos := first_pos.extend(last_pos)
7577
mut or_stmts := []ast.Stmt{} // TODO: remove unnecessary allocations by just using .absent
7678
mut or_pos := p.tok.pos()

‎vlib/v/tests/vls/autocomplete_module_test.v‎

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,19 @@ const autocomplete_info_for_mod_struct = '{"details" : [
3131
{"kind":2,"label":"add","detail":"void","documentation":""}
3232
]}'
3333

34+
const fn_signature_info_for_all_before_last = '{
35+
"signatures":[{
36+
"label":"all_before_last(sub string) string",
37+
"parameters":[{
38+
"label":"sub string"
39+
}]
40+
}],
41+
"activeSignature":0,
42+
"activeParameter":0,
43+
"_type":"SignatureHelp"
44+
}
45+
'
46+
3447
struct TestData {
3548
cmd string
3649
output string
@@ -57,6 +70,10 @@ const test_data = [
5770
cmd: 'v -check -json-errors -nocolor -vls-mode -line-info "${text_file}:26:28" ${os.quoted_path(text_file)}'
5871
output: autocomplete_info_for_mod_sample_mod1
5972
},
73+
TestData{
74+
cmd: 'v -check -json-errors -nocolor -vls-mode -line-info "${text_file}:24:fn^26" ${os.quoted_path(text_file)}'
75+
output: fn_signature_info_for_all_before_last
76+
},
6077
TestData{
6178
cmd: 'v -check -json-errors -nocolor -vls-mode -line-info "${text_file}:27:8" ${os.quoted_path(text_file)}'
6279
output: ''
@@ -163,19 +180,18 @@ const test_data = [
163180
fn test_main() {
164181
mut total_errors := 0
165182

166-
dump(text_file)
167183
for t in test_data {
168184
res := os.execute(t.cmd)
169185
if res.exit_code < 0 {
170186
println('fail execute ${t.cmd}')
171187
panic(res.output)
172188
}
173189
res_output := $if windows {
174-
res.output.replace('\r\n', '\n').trim_space()
190+
res.output.replace('\r\n', '\n')
175191
} $else {
176-
res.output.trim_space()
192+
res.output
177193
}
178-
if t.output.trim_space() != res_output {
194+
if t.output.trim_space() != res_output.trim_space() {
179195
println('${term.red('FAIL')} ${t.cmd}')
180196
if diff_ := diff.compare_text(t.output, res_output) {
181197
println(term.header('difference:', '-'))

0 commit comments

Comments
 (0)