checker: add suggestions for method mispellings and unknown types
parent
2c45e601ef
commit
f300f787f3
|
@ -315,13 +315,15 @@ pub fn (mut c Checker) struct_decl(decl ast.StructDecl) {
|
|||
}
|
||||
sym := c.table.get_type_symbol(field.typ)
|
||||
if sym.kind == .placeholder && decl.language != .c && !sym.name.starts_with('C.') {
|
||||
c.error('unknown type `$sym.name`', field.pos)
|
||||
c.error(util.new_suggestion(sym.name, c.table.known_type_names()).say('unknown type `$sym.name`'),
|
||||
field.pos)
|
||||
}
|
||||
if sym.kind == .array {
|
||||
array_info := sym.array_info()
|
||||
elem_sym := c.table.get_type_symbol(array_info.elem_type)
|
||||
if elem_sym.kind == .placeholder {
|
||||
c.error('unknown type `$elem_sym.name`', field.pos)
|
||||
c.error(util.new_suggestion(elem_sym.name, c.table.known_type_names()).say('unknown type `$elem_sym.name`'),
|
||||
field.pos)
|
||||
}
|
||||
}
|
||||
if sym.kind == .struct_ {
|
||||
|
@ -1024,7 +1026,9 @@ pub fn (mut c Checker) call_method(mut call_expr ast.CallExpr) table.Type {
|
|||
}
|
||||
}
|
||||
if left_type != table.void_type {
|
||||
c.error('unknown method: `${left_type_sym.name}.$method_name`', call_expr.pos)
|
||||
suggestion := util.new_suggestion(method_name, left_type_sym.methods.map(it.name))
|
||||
c.error(suggestion.say('unknown method: `${left_type_sym.name}.$method_name`'),
|
||||
call_expr.pos)
|
||||
}
|
||||
return table.void_type
|
||||
}
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
vlib/v/checker/tests/unknown_method_suggest_name.v:7:2: error: unknown type `hash.crc32.Crc33`. Did you mean `crc32.Crc33` ?
|
||||
5 | y int
|
||||
6 | z int
|
||||
7 | ccc crc32.Crc33
|
||||
| ~~~~~~~~~~~~~~~
|
||||
8 | }
|
||||
9 |
|
||||
vlib/v/checker/tests/unknown_method_suggest_name.v:27:9: error: unknown method: `Point.tranzlate`. Did you mean `translate` ?
|
||||
25 | p := Point{1, 2, 3}
|
||||
26 | v := Vector{5, 5, 10}
|
||||
27 | z := p.tranzlate(v)
|
||||
| ~~~~~~~~~~~~
|
||||
28 | println('p: $p')
|
||||
29 | println('v: $v')
|
|
@ -0,0 +1,31 @@
|
|||
import hash.crc32
|
||||
|
||||
struct Point {
|
||||
x int
|
||||
y int
|
||||
z int
|
||||
ccc crc32.Crc33
|
||||
}
|
||||
|
||||
struct Vector {
|
||||
x int
|
||||
y int
|
||||
z int
|
||||
}
|
||||
|
||||
fn (p Point) translate(v Vector) Point {
|
||||
return Point{p.x + v.x, p.y + v.y, p.z + v.z}
|
||||
}
|
||||
|
||||
fn (p Point) identity() Point {
|
||||
return Point{1, 1, 1}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
p := Point{1, 2, 3}
|
||||
v := Vector{5, 5, 10}
|
||||
z := p.tranzlate(v)
|
||||
println('p: $p')
|
||||
println('v: $v')
|
||||
println('z: $z')
|
||||
}
|
|
@ -529,3 +529,14 @@ pub fn (table &Table) sumtype_has_variant(parent, variant Type) bool {
|
|||
return false
|
||||
|
||||
}
|
||||
|
||||
pub fn (table &Table) known_type_names() []string {
|
||||
mut res := []string{}
|
||||
for _, idx in table.type_idxs {
|
||||
if idx == 0 {
|
||||
continue
|
||||
}
|
||||
res << table.type_to_str(idx)
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
|
|
@ -0,0 +1,90 @@
|
|||
module util
|
||||
|
||||
import strings
|
||||
|
||||
struct Possibility {
|
||||
value string
|
||||
svalue string
|
||||
mut:
|
||||
similarity f32
|
||||
}
|
||||
|
||||
fn compare_by_similarity(a, b &Possibility) int {
|
||||
if a.similarity < b.similarity {
|
||||
return -1
|
||||
}
|
||||
if a.similarity > b.similarity {
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
//
|
||||
struct Suggestion {
|
||||
mut:
|
||||
known []Possibility
|
||||
wanted string
|
||||
swanted string
|
||||
}
|
||||
|
||||
pub fn new_suggestion(wanted string, possibilities []string) Suggestion {
|
||||
mut s := Suggestion{
|
||||
wanted: wanted
|
||||
swanted: short_module_name(wanted)
|
||||
}
|
||||
s.add_many(possibilities)
|
||||
s.sort()
|
||||
return s
|
||||
}
|
||||
|
||||
pub fn (mut s Suggestion) add(val string) {
|
||||
if val == s.wanted {
|
||||
return
|
||||
}
|
||||
sval := short_module_name(val)
|
||||
if sval == s.wanted {
|
||||
return
|
||||
}
|
||||
s.known << Possibility{
|
||||
value: val
|
||||
svalue: sval
|
||||
similarity: strings.dice_coefficient(s.swanted, sval)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn (mut s Suggestion) add_many(many []string) {
|
||||
for x in many {
|
||||
s.add(x)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn (mut s Suggestion) sort() {
|
||||
s.known.sort_with_compare(compare_by_similarity)
|
||||
}
|
||||
|
||||
pub fn (s Suggestion) say(msg string) string {
|
||||
mut res := msg
|
||||
if s.known.len > 0 {
|
||||
top_posibility := s.known.last()
|
||||
if top_posibility.similarity > 0.10 {
|
||||
val := top_posibility.value
|
||||
if !val.starts_with('[]') {
|
||||
res += '. Did you mean `$val` ?'
|
||||
}
|
||||
}
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
pub fn short_module_name(name string) string {
|
||||
if !name.contains('.') {
|
||||
return name
|
||||
}
|
||||
vals := name.split('.')
|
||||
if vals.len < 2 {
|
||||
return name
|
||||
}
|
||||
mname := vals[vals.len - 2]
|
||||
symname := vals[vals.len - 1]
|
||||
return '${mname}.$symname'
|
||||
}
|
Loading…
Reference in New Issue