checker: add suggestions for misspelled `mod.func_name()` calls
parent
51c1d666c2
commit
44603f8e59
|
@ -662,6 +662,20 @@ pub fn (mut c Checker) fn_call(mut node ast.CallExpr, mut continue_check &bool)
|
|||
}
|
||||
if !found {
|
||||
continue_check = false
|
||||
if dot_index := fn_name.index('.') {
|
||||
if !fn_name[0].is_capital() {
|
||||
mod_name := fn_name#[..dot_index]
|
||||
mut mod_func_names := []string{}
|
||||
for ctfnk, ctfnv in c.table.fns {
|
||||
if ctfnv.is_pub && ctfnk.starts_with(mod_name) {
|
||||
mod_func_names << ctfnk
|
||||
}
|
||||
}
|
||||
suggestion := util.new_suggestion(fn_name, mod_func_names)
|
||||
c.error(suggestion.say('unknown function: $fn_name '), node.pos)
|
||||
return ast.void_type
|
||||
}
|
||||
}
|
||||
c.error('unknown function: $fn_name', node.pos)
|
||||
return ast.void_type
|
||||
}
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
vlib/v/checker/tests/misspelled_mod_fn_name_should_have_suggestion.vv:3:9: error: unknown function: os.read_fil .
|
||||
Did you mean `os.read_file`?
|
||||
1 | import os
|
||||
2 |
|
||||
3 | dump(os.read_fil('abc'))
|
||||
| ~~~~~~~~~~~~~~~
|
|
@ -0,0 +1,3 @@
|
|||
import os
|
||||
|
||||
dump(os.read_fil('abc'))
|
|
@ -1,4 +1,5 @@
|
|||
vlib/v/checker/tests/unknown_function.vv:4:15: error: unknown function: math.max_i64
|
||||
vlib/v/checker/tests/unknown_function.vv:4:15: error: unknown function: math.max_i64 .
|
||||
Did you mean `math.max`?
|
||||
2 |
|
||||
3 | fn main() {
|
||||
4 | println(math.max_i64())
|
||||
|
|
|
@ -1,14 +1,20 @@
|
|||
module util
|
||||
|
||||
import term
|
||||
import strings
|
||||
|
||||
// Possibility is a simple pair of a string, with a similarity coefficient
|
||||
// determined by the editing distance to a wanted value.
|
||||
struct Possibility {
|
||||
value string
|
||||
svalue string
|
||||
mut:
|
||||
similarity f32
|
||||
similarity f32 // Note: 0.0 for *equal* strings.
|
||||
}
|
||||
|
||||
// Suggestion is set of known possibilities and a wanted string.
|
||||
// It has helper methods for making educated guesses based on the possibilities,
|
||||
// on which of them match best the wanted string.
|
||||
struct Suggestion {
|
||||
mut:
|
||||
known []Possibility
|
||||
|
@ -16,6 +22,7 @@ mut:
|
|||
swanted string
|
||||
}
|
||||
|
||||
// new_suggestion creates a new Suggestion, given a wanted value and a list of possibilities.
|
||||
pub fn new_suggestion(wanted string, possibilities []string) Suggestion {
|
||||
mut s := Suggestion{
|
||||
wanted: wanted
|
||||
|
@ -26,6 +33,8 @@ pub fn new_suggestion(wanted string, possibilities []string) Suggestion {
|
|||
return s
|
||||
}
|
||||
|
||||
// add adds the `val` to the list of known possibilities of the suggestion.
|
||||
// It calculates the similarity metric towards the wanted value.
|
||||
pub fn (mut s Suggestion) add(val string) {
|
||||
if val in [s.wanted, s.swanted] {
|
||||
return
|
||||
|
@ -43,16 +52,21 @@ pub fn (mut s Suggestion) add(val string) {
|
|||
}
|
||||
}
|
||||
|
||||
// add adds all of the `many` to the list of known possibilities of the suggestion
|
||||
pub fn (mut s Suggestion) add_many(many []string) {
|
||||
for x in many {
|
||||
s.add(x)
|
||||
}
|
||||
}
|
||||
|
||||
// sort sorts the list of known possibilities, based on their similarity metric.
|
||||
// Equal strings will be first, followed by less similar ones, very distinct ones will be last.
|
||||
pub fn (mut s Suggestion) sort() {
|
||||
s.known.sort(a.similarity < b.similarity)
|
||||
}
|
||||
|
||||
// say produces a final suggestion message, based on the preset `wanted` and
|
||||
// `possibilities` fields, accumulated in the Suggestion.
|
||||
pub fn (s Suggestion) say(msg string) string {
|
||||
mut res := msg
|
||||
mut found := false
|
||||
|
@ -61,14 +75,14 @@ pub fn (s Suggestion) say(msg string) string {
|
|||
if top_posibility.similarity > 0.5 {
|
||||
val := top_posibility.value
|
||||
if !val.starts_with('[]') {
|
||||
res += '.\nDid you mean `$val`?'
|
||||
res += '.\nDid you mean `${highlight_suggestion(val)}`?'
|
||||
found = true
|
||||
}
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
if s.known.len > 0 {
|
||||
mut values := s.known.map('`$it.svalue`')
|
||||
mut values := s.known.map('`${highlight_suggestion(it.svalue)}`')
|
||||
values.sort()
|
||||
if values.len == 1 {
|
||||
res += '.\n1 possibility: ${values[0]}.'
|
||||
|
@ -81,6 +95,8 @@ pub fn (s Suggestion) say(msg string) string {
|
|||
return res
|
||||
}
|
||||
|
||||
// short_module_name returns a shortened version of the fully qualified `name`,
|
||||
// i.e. `xyz.def.abc.symname` -> `abc.symname`
|
||||
pub fn short_module_name(name string) string {
|
||||
if !name.contains('.') {
|
||||
return name
|
||||
|
@ -93,3 +109,10 @@ pub fn short_module_name(name string) string {
|
|||
symname := vals[vals.len - 1]
|
||||
return '${mname}.$symname'
|
||||
}
|
||||
|
||||
// highlight_suggestion returns a colorfull/highlighted version of `message`,
|
||||
// but only if the standart error output allows for color messages, otherwise
|
||||
// the plain message will be returned.
|
||||
pub fn highlight_suggestion(message string) string {
|
||||
return term.ecolorize(term.bright_blue, message)
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue