Skip to content

Commit c40da32

Browse files
authored
v.builder: fix json-errors with a windows path separator (#25680)
1 parent c560e72 commit c40da32

File tree

2 files changed

+167
-13
lines changed

2 files changed

+167
-13
lines changed

vlib/v/builder/builder.v

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -538,7 +538,7 @@ pub fn (mut b Builder) print_warnings_and_errors() {
538538
if b.pref.json_errors {
539539
json_errors << util.JsonError{
540540
message: err.message
541-
path: err.file_path
541+
path: os.to_slash(err.file_path)
542542
line_nr: err.pos.line_nr + 1
543543
col: err.pos.col + 1
544544
}

vlib/v/tests/vls/autocomplete_module_test.v

Lines changed: 166 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
11
import os
22
import term
33
import v.util.diff
4+
import json
45

56
const vroot = os.real_path(@VMODROOT)
67
const tmp_dir = os.real_path(os.temp_dir())
78
const text_file = os.join_path(vroot, 'vlib', 'v', 'tests', 'vls', 'sample_text.vv')
9+
// note: windows path separator will cause json decode fail
10+
const json_errors_text_file = os.to_slash(text_file)
811
const mod1_text_file = os.join_path(vroot, 'vlib', 'v', 'tests', 'vls', 'sample_mod1',
912
'sample.v')
1013

@@ -45,157 +48,187 @@ const fn_signature_info_for_all_before_last = '{
4548
}
4649
'
4750

51+
enum Method {
52+
unknown @['unknown']
53+
initialize @['initialize']
54+
initialized @['initialized']
55+
did_open @['textDocument/didOpen']
56+
did_change @['textDocument/didChange']
57+
definition @['textDocument/definition']
58+
completion @['textDocument/completion']
59+
signature_help @['textDocument/signatureHelp']
60+
set_trace @['$/setTrace']
61+
cancel_request @['$/cancelRequest']
62+
shutdown @['shutdown']
63+
exit @['exit']
64+
}
65+
4866
struct TestData {
67+
method Method
4968
cmd string
5069
output string
5170
}
5271

5372
const test_data = [
5473
TestData{
74+
method: .completion
5575
cmd: 'v -w -check -json-errors -nocolor -vls-mode -line-info "${text_file}:19:3" ${os.quoted_path(text_file)}'
5676
output: autocomplete_info_for_mod_sample_mod1
5777
},
5878
TestData{
79+
method: .completion
5980
cmd: 'v -w -check -json-errors -nocolor -vls-mode -line-info "${text_file}:20:13" ${os.quoted_path(text_file)}'
6081
output: autocomplete_info_for_mod_sample_mod2
6182
},
6283
TestData{
84+
method: .completion
6385
cmd: 'v -w -check -json-errors -nocolor -vls-mode -line-info "${text_file}:22:3" ${os.quoted_path(text_file)}'
6486
output: autocomplete_info_for_mod_struct
6587
},
6688
TestData{
89+
method: .completion
6790
cmd: 'v -w -check -json-errors -nocolor -vls-mode -line-info "${text_file}:23:3" ${os.quoted_path(text_file)}'
6891
output: autocomplete_info_for_mod_sample_mod1
6992
},
7093
TestData{
94+
method: .completion
7195
cmd: 'v -w -check -json-errors -nocolor -vls-mode -line-info "${text_file}:26:28" ${os.quoted_path(text_file)}'
7296
output: autocomplete_info_for_mod_sample_mod1
7397
},
7498
TestData{
99+
method: .signature_help
75100
cmd: 'v -w -check -json-errors -nocolor -vls-mode -line-info "${text_file}:25:fn^26" ${os.quoted_path(text_file)}'
76101
output: fn_signature_info_for_all_before_last
77102
},
78103
TestData{
104+
method: .completion
79105
cmd: 'v -w -check -json-errors -nocolor -vls-mode -line-info "${text_file}:27:9" ${os.quoted_path(text_file)}'
80106
output: ''
81107
},
82108
TestData{
109+
method: .completion
83110
cmd: 'v -w -check -json-errors -nocolor -vls-mode -line-info "${text_file}:28:9" ${os.quoted_path(text_file)}'
84111
output: 'unresolved type, maybe "builtin" was not defined. otherwise this is a bug, should never happen; please report'
85112
},
86113
TestData{
114+
method: .definition
87115
cmd: 'v -w -check -json-errors -nocolor -vls-mode -line-info "${text_file}:30:gd^10" ${os.quoted_path(text_file)}'
88116
output: '${mod1_text_file}:50:7'
89117
},
90118
TestData{
119+
method: .definition
91120
cmd: 'v -w -check -json-errors -nocolor -vls-mode -line-info "${text_file}:31:gd^12" ${os.quoted_path(text_file)}'
92121
output: '${mod1_text_file}:8:11'
93122
},
94123
TestData{
124+
method: .definition
95125
cmd: 'v -w -check -json-errors -nocolor -vls-mode -line-info "${text_file}:32:gd^11" ${os.quoted_path(text_file)}'
96126
output: '${mod1_text_file}:41:9'
97127
},
98128
TestData{
129+
method: .definition
99130
cmd: 'v -w -check -json-errors -nocolor -vls-mode -line-info "${text_file}:33:gd^15" ${os.quoted_path(text_file)}'
100131
output: '${mod1_text_file}:44:9'
101132
},
102133
TestData{
134+
method: .definition
103135
cmd: 'v -w -check -json-errors -nocolor -vls-mode -line-info "${text_file}:34:gd^13" ${os.quoted_path(text_file)}'
104136
output: '${mod1_text_file}:19:10'
105137
},
106138
TestData{
139+
method: .did_change
107140
cmd: 'v -w -vls-mode -check -json-errors ${os.quoted_path(text_file)}'
108141
output: '[
109142
{
110-
"path":"${text_file}",
143+
"path":"${json_errors_text_file}",
111144
"message":"unexpected token `:=`, expecting `)`",
112145
"line_nr":26,
113146
"col":4,
114147
"len":0
115148
}
116149
,
117150
{
118-
"path":"${text_file}",
151+
"path":"${json_errors_text_file}",
119152
"message":"unexpected name `strings`, expecting `)`",
120153
"line_nr":27,
121154
"col":2,
122155
"len":0
123156
}
124157
,
125158
{
126-
"path":"${text_file}",
159+
"path":"${json_errors_text_file}",
127160
"message":"undefined ident: ``",
128161
"line_nr":19,
129162
"col":3,
130163
"len":0
131164
}
132165
,
133166
{
134-
"path":"${text_file}",
167+
"path":"${json_errors_text_file}",
135168
"message":"undefined ident: ``",
136169
"line_nr":20,
137170
"col":13,
138171
"len":0
139172
}
140173
,
141174
{
142-
"path":"${text_file}",
175+
"path":"${json_errors_text_file}",
143176
"message":"undefined ident: ``",
144177
"line_nr":23,
145178
"col":3,
146179
"len":0
147180
}
148181
,
149182
{
150-
"path":"${text_file}",
183+
"path":"${json_errors_text_file}",
151184
"message":"undefined ident: `j`",
152185
"line_nr":26,
153186
"col":2,
154187
"len":0
155188
}
156189
,
157190
{
158-
"path":"${text_file}",
191+
"path":"${json_errors_text_file}",
159192
"message":"`j` (no value) used as value in argument 1 to `string.all_before_last`",
160193
"line_nr":26,
161194
"col":2,
162195
"len":0
163196
}
164197
,
165198
{
166-
"path":"${text_file}",
199+
"path":"${json_errors_text_file}",
167200
"message":"undefined ident: ``",
168201
"line_nr":26,
169202
"col":28,
170203
"len":0
171204
}
172205
,
173206
{
174-
"path":"${text_file}",
207+
"path":"${json_errors_text_file}",
175208
"message":"`` (no value) used as value in argument 1 to `string.all_before_last`",
176209
"line_nr":26,
177210
"col":27,
178211
"len":0
179212
}
180213
,
181214
{
182-
"path":"${text_file}",
215+
"path":"${json_errors_text_file}",
183216
"message":"`string` has no property ``",
184217
"line_nr":26,
185218
"col":11,
186219
"len":0
187220
}
188221
,
189222
{
190-
"path":"${text_file}",
223+
"path":"${json_errors_text_file}",
191224
"message":"undefined ident: `builtin`",
192225
"line_nr":28,
193226
"col":2,
194227
"len":0
195228
}
196229
,
197230
{
198-
"path":"${text_file}",
231+
"path":"${json_errors_text_file}",
199232
"message":"`builtin` does not return a value",
200233
"line_nr":28,
201234
"col":2,
@@ -206,6 +239,43 @@ const test_data = [
206239
},
207240
]
208241

242+
// copy from `vls`
243+
struct JsonError {
244+
path string
245+
message string
246+
line_nr int
247+
col int
248+
len int
249+
}
250+
251+
struct Detail {
252+
kind int // The type of item (e.g., Method, Function, Field)
253+
label string // The name of the completion item
254+
detail string // Additional info like the function signature or return type
255+
documentation string // The documentation for the item
256+
insert_text ?string @[json: 'insertText']
257+
insert_text_format ?int @[json: 'insertTextFormat'] // 1 for PlainText, 2 for Snippet
258+
}
259+
260+
struct JsonVarAC {
261+
details []Detail
262+
}
263+
264+
struct SignatureHelp {
265+
signatures []SignatureInformation
266+
active_signature int @[json: 'activeSignature']
267+
active_parameter int @[json: 'activeParameter']
268+
}
269+
270+
struct SignatureInformation {
271+
label string
272+
parameters []ParameterInformation
273+
}
274+
275+
struct ParameterInformation {
276+
label string
277+
}
278+
209279
fn test_main() {
210280
mut total_errors := 0
211281

@@ -236,6 +306,90 @@ fn test_main() {
236306
} else {
237307
println('${term.green('OK ')} ${t.cmd}')
238308
}
309+
310+
// Try to decode the response message and verify
311+
// TODO: remove `unresolved type, maybe`
312+
if t.output.trim_space().len > 0 && !t.output.starts_with('unresolved type, maybe') {
313+
dump(t.output)
314+
match t.method {
315+
.definition {
316+
check_valid_goto_definition(t.output)!
317+
}
318+
.completion {
319+
check_valid_auto_completion(t.output)!
320+
}
321+
.did_change {
322+
check_valid_json_errors(t.output)!
323+
}
324+
.signature_help {
325+
check_valid_fn_signature(t.output)!
326+
}
327+
else {}
328+
}
329+
}
239330
}
240331
assert total_errors == 0
241332
}
333+
334+
fn check_valid_goto_definition(message string) ! {
335+
// `/home/path/aaa.v:19:10`
336+
fields := message.split(':')
337+
if fields.len >= 3 {
338+
path := fields[..fields.len - 2].join(':')
339+
line_nr := fields[fields.len - 2].int()
340+
col := fields[fields.len - 1].int()
341+
if line_nr <= 0 {
342+
return error('goto_definition: line_nr should > 0: ${line_nr}')
343+
}
344+
if col <= 0 {
345+
return error('goto_definition: col should > 0: ${col}')
346+
}
347+
if path.len == 0 {
348+
return error('goto_definition: file.len should > 0: ${path}')
349+
}
350+
} else {
351+
return error('goto_definition: goto_definition format error')
352+
}
353+
}
354+
355+
fn check_valid_auto_completion(message string) ! {
356+
// {"kind":5,"label":"a","detail":"int","documentation":""},
357+
result := json.decode(JsonVarAC, message) or { return error('completion: fail to json decode') }
358+
for detail in result.details {
359+
if detail.kind <= 0 || detail.kind > 25 {
360+
return error('completion: kind should in 1-25 : ${detail.kind}')
361+
}
362+
}
363+
}
364+
365+
fn check_valid_json_errors(message string) ! {
366+
results := json.decode([]JsonError, message) or {
367+
return error('json_errors: fail to json decode')
368+
}
369+
for result in results {
370+
if result.path.len == 0 {
371+
return error('json_errors: path.len should > 0')
372+
}
373+
if result.message.len == 0 {
374+
return error('json_errors: message.len should > 0')
375+
}
376+
if result.line_nr <= 0 {
377+
return error('json_errors: line_nr should > 0')
378+
}
379+
if result.col <= 0 {
380+
return error('json_errors: col should > 0')
381+
}
382+
}
383+
}
384+
385+
fn check_valid_fn_signature(message string) ! {
386+
result := json.decode(SignatureHelp, message) or {
387+
return error('fn_signature: fail to json decode')
388+
}
389+
if result.signatures.len != 1 {
390+
return error('fn_signature: signatures.len != 1')
391+
}
392+
if result.signatures[0].label.len == 0 {
393+
return error('fn_signature: label.len == 0')
394+
}
395+
}

0 commit comments

Comments
 (0)