Skip to content

Commit

Permalink
feat: add fuzz match for error 'attribute not found' (#715)
Browse files Browse the repository at this point in the history
* feat: add fuzz match for error 'attribute not found'

* fix: add 'suggestions' to supports fuzz match

* fix: rm useless imports

* fix: make fmt
  • Loading branch information
zong-zhe authored Sep 18, 2023
1 parent 8489636 commit 0f453eb
Show file tree
Hide file tree
Showing 6 changed files with 82 additions and 6 deletions.
10 changes: 10 additions & 0 deletions kclvm/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions kclvm/cmd/src/test_data/fuzz_match/main.k
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
schema Person:
aa?: int
aaa?: int

p = Person {}
a = p.a # Error, attribute 'a' not found in schema `Person`, did you mean `aa`?
6 changes: 6 additions & 0 deletions kclvm/cmd/src/test_data/fuzz_match/main_unmatched.k
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
schema Person:
en?: int
sd?: int

p = Person {}
a = p.a # Error, attribute 'a' not found in schema `Person`
37 changes: 37 additions & 0 deletions kclvm/cmd/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -559,3 +559,40 @@ fn test_plugin_not_found() {
Err(msg) => assert!(msg.contains("the plugin package `kcl_plugin.not_exist` is not found, please confirm if plugin mode is enabled")),
}
}

#[test]
fn test_error_message_fuzz_matched() {
let test_case_path = PathBuf::from("./src/test_data/fuzz_match/main.k");
let matches = app().arg_required_else_help(true).get_matches_from(&[
ROOT_CMD,
"run",
&test_case_path.canonicalize().unwrap().display().to_string(),
]);
let settings = must_build_settings(matches.subcommand_matches("run").unwrap());
let sess = Arc::new(ParseSession::default());
match exec_program(sess.clone(), &settings.try_into().unwrap()) {
Ok(_) => panic!("unreachable code."),
Err(msg) => {
assert!(msg
.contains("attribute 'a' not found in schema 'Person', did you mean '[\"aa\"]'?"))
}
}
}

#[test]
fn test_error_message_fuzz_unmatched() {
let test_case_path = PathBuf::from("./src/test_data/fuzz_match/main_unmatched.k");
let matches = app().arg_required_else_help(true).get_matches_from(&[
ROOT_CMD,
"run",
&test_case_path.canonicalize().unwrap().display().to_string(),
]);
let settings = must_build_settings(matches.subcommand_matches("run").unwrap());
let sess = Arc::new(ParseSession::default());
match exec_program(sess.clone(), &settings.try_into().unwrap()) {
Ok(_) => panic!("unreachable code."),
Err(msg) => {
assert!(msg.contains("attribute 'a' not found in schema 'Person'"))
}
}
}
1 change: 1 addition & 0 deletions kclvm/sema/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ compiler_base_span = {path = "../../compiler_base/span", version = "0.0.2"}
compiler_base_session = {path = "../../compiler_base/session"}
compiler_base_macros = "0.0.1"
compiler_base_error = "0.0.8"
suggestions = "0.1.1"

[dev-dependencies]
kclvm-parser = {path = "../parser"}
Expand Down
28 changes: 22 additions & 6 deletions kclvm/sema/src/resolver/attr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use std::rc::Rc;
use crate::builtin::system_module::{get_system_module_members, UNITS, UNITS_NUMBER_MULTIPLIER};
use crate::builtin::{get_system_member_function_ty, STRING_MEMBER_FUNCTIONS};
use crate::resolver::Resolver;
use crate::ty::TypeKind::Schema;
use crate::ty::{DictType, ModuleKind, Type, TypeKind};
use kclvm_error::diagnostic::Range;
use kclvm_error::*;
Expand Down Expand Up @@ -110,16 +111,31 @@ impl<'ctx> Resolver<'ctx> {
}
}
};

if !result {
// The attr user input.
let (attr, suggestion) = if attr.is_empty() {
("[missing name]", "".to_string())
} else {
let mut suggestion = String::new();
// Calculate the closests miss attributes.
if let Schema(schema_ty) = &obj.kind {
// Get all the attrbuets of the schema.
let attrs = schema_ty.attrs.keys().cloned().collect::<Vec<String>>();
let suggs = suggestions::provide_suggestions(attr, &attrs);
if suggs.len() > 0 {
suggestion = format!(", did you mean '{:?}'?", suggs);
}
}
(attr, suggestion)
};

self.handler.add_type_error(
&format!(
"{} has no attribute {}",
"attribute '{}' not found in schema '{}'{}",
attr,
obj.ty_str(),
if attr.is_empty() {
"[missing name]"
} else {
attr
}
suggestion
),
range,
);
Expand Down

0 comments on commit 0f453eb

Please sign in to comment.