checker: add suggestions for misspelled `mod.func_name()` calls

pull/13927/head
Delyan Angelov 2022-04-03 18:23:35 +03:00
parent 51c1d666c2
commit 44603f8e59
No known key found for this signature in database
GPG Key ID: 66886C0F12D595ED
5 changed files with 51 additions and 4 deletions

View File

@ -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
}

View File

@ -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'))
| ~~~~~~~~~~~~~~~

View File

@ -0,0 +1,3 @@
import os
dump(os.read_fil('abc'))

View File

@ -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())

View File

@ -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)
}