-
Notifications
You must be signed in to change notification settings - Fork 83
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add diagnostics for mismatched argument type and count #335
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
@@ -354,11 +354,13 @@ fn run_inner(context: &Context, objtree: &ObjectTree, cli: bool) { | |||||||||||||||||||
objtree.root().recurse(&mut |ty| { | ||||||||||||||||||||
for proc in ty.iter_self_procs() { | ||||||||||||||||||||
analyzer.check_kwargs(proc); | ||||||||||||||||||||
analyzer.check_arg_type(proc);//count(proc); | ||||||||||||||||||||
analyzer.propagate_violations(proc); | ||||||||||||||||||||
} | ||||||||||||||||||||
}); | ||||||||||||||||||||
|
||||||||||||||||||||
analyzer.finish_check_kwargs(); | ||||||||||||||||||||
analyzer.finish_check_arg_count(); | ||||||||||||||||||||
|
||||||||||||||||||||
cli_println!("============================================================"); | ||||||||||||||||||||
cli_println!("Analyzing proc call tree...\n"); | ||||||||||||||||||||
|
@@ -564,6 +566,8 @@ pub struct AnalyzeObjectTree<'o> { | |||||||||||||||||||
|
||||||||||||||||||||
sleeping_overrides: ViolatingOverrides<'o>, | ||||||||||||||||||||
impure_overrides: ViolatingOverrides<'o>, | ||||||||||||||||||||
decreasing_argc_overrides: ViolatingOverrides<'o>, | ||||||||||||||||||||
incorrect_arg_type_overrides: ViolatingOverrides<'o>, | ||||||||||||||||||||
} | ||||||||||||||||||||
|
||||||||||||||||||||
impl<'o> AnalyzeObjectTree<'o> { | ||||||||||||||||||||
|
@@ -590,6 +594,8 @@ impl<'o> AnalyzeObjectTree<'o> { | |||||||||||||||||||
waitfor_procs: Default::default(), | ||||||||||||||||||||
sleeping_overrides: Default::default(), | ||||||||||||||||||||
impure_overrides: Default::default(), | ||||||||||||||||||||
decreasing_argc_overrides: Default::default(), | ||||||||||||||||||||
incorrect_arg_type_overrides: Default::default(), | ||||||||||||||||||||
} | ||||||||||||||||||||
} | ||||||||||||||||||||
|
||||||||||||||||||||
|
@@ -692,7 +698,7 @@ impl<'o> AnalyzeObjectTree<'o> { | |||||||||||||||||||
.with_blocking_builtins(self.sleeping_procs.get_violators(*child_violator).unwrap()) | ||||||||||||||||||||
.register(self.context) | ||||||||||||||||||||
} | ||||||||||||||||||||
} | ||||||||||||||||||||
} | ||||||||||||||||||||
if let Some(calledvec) = self.call_tree.get(&nextproc) { | ||||||||||||||||||||
for (proccalled, location, new_context) in calledvec.iter() { | ||||||||||||||||||||
let mut newstack = callstack.clone(); | ||||||||||||||||||||
|
@@ -743,7 +749,7 @@ impl<'o> AnalyzeObjectTree<'o> { | |||||||||||||||||||
.with_blocking_builtins(self.impure_procs.get_violators(*child_violator).unwrap()) | ||||||||||||||||||||
.register(self.context) | ||||||||||||||||||||
} | ||||||||||||||||||||
} | ||||||||||||||||||||
} | ||||||||||||||||||||
if let Some(calledvec) = self.call_tree.get(&nextproc) { | ||||||||||||||||||||
for (proccalled, location, new_context) in calledvec.iter() { | ||||||||||||||||||||
let mut newstack = callstack.clone(); | ||||||||||||||||||||
|
@@ -845,6 +851,109 @@ impl<'o> AnalyzeObjectTree<'o> { | |||||||||||||||||||
} | ||||||||||||||||||||
} | ||||||||||||||||||||
|
||||||||||||||||||||
/// Check that a ProcRef doesn't have fewer arguments than its parent | ||||||||||||||||||||
pub fn check_arg_count(&mut self, proc: ProcRef<'o>) { | ||||||||||||||||||||
if proc.is_builtin() | ||||||||||||||||||||
{ | ||||||||||||||||||||
return; | ||||||||||||||||||||
} | ||||||||||||||||||||
if let Some(parent) = proc.parent_proc() | ||||||||||||||||||||
{ | ||||||||||||||||||||
if parent.is_varargs() /* remove this later, it's a hack for objtree proc parents including root */ || parent.ty().get().is_root() /* seriously remove it */ | ||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. line length
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Only the is_root needs to be removed when #334 is solved. The varargs check is fine. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
this then, or just say that - it's wrong to have incredibly long lines with functionality hidden |
||||||||||||||||||||
{ | ||||||||||||||||||||
return; | ||||||||||||||||||||
} | ||||||||||||||||||||
if parent.get().parameters.len() > proc.get().parameters.len() | ||||||||||||||||||||
{ | ||||||||||||||||||||
self.decreasing_argc_overrides.insert_override(parent, proc) | ||||||||||||||||||||
} | ||||||||||||||||||||
} | ||||||||||||||||||||
} | ||||||||||||||||||||
|
||||||||||||||||||||
/// Check that a ProcRef doesn't change the type or ordering of its args | ||||||||||||||||||||
pub fn check_arg_type(&mut self, proc: ProcRef<'o>) { | ||||||||||||||||||||
if proc.is_builtin() | ||||||||||||||||||||
{ | ||||||||||||||||||||
return; | ||||||||||||||||||||
} | ||||||||||||||||||||
if let Some(parent) = proc.parent_proc() | ||||||||||||||||||||
{ | ||||||||||||||||||||
if parent.is_varargs() /* remove this later, it's a hack for objtree proc parents including root */ || parent.ty().get().is_root() /* seriously remove it */ | ||||||||||||||||||||
{ | ||||||||||||||||||||
return; | ||||||||||||||||||||
} | ||||||||||||||||||||
for (i, parent_argument) in parent.parameters.iter().enumerate() | ||||||||||||||||||||
{ | ||||||||||||||||||||
let proc_arg = proc.parameters.get(i); | ||||||||||||||||||||
if let Some(proc_arg) = proc_arg | ||||||||||||||||||||
{ | ||||||||||||||||||||
//let parent_typepath: &str = &*format!("/{}/", parent_argument.var_type.type_path.join("/")); | ||||||||||||||||||||
//let proc_typepath: &str = &*format!("/{}", proc_arg.var_type.type_path.join("/")); | ||||||||||||||||||||
if let (Some(parent_type), Some(proc_type)) = (self.objtree.type_by_path(&*parent_argument.var_type.type_path), self.objtree.type_by_path(&*proc_arg.var_type.type_path)) | ||||||||||||||||||||
{ | ||||||||||||||||||||
// Argument types may get stricter or more relaxed, but at least one must be a subtype of the other. | ||||||||||||||||||||
if !proc_arg.default.is_some() && !parent_argument.default.is_some() && !parent.is_builtin() && !proc_type.is_subtype_of(&parent_type) && !parent_type.is_subtype_of(&proc_type) | ||||||||||||||||||||
{ | ||||||||||||||||||||
self.incorrect_arg_type_overrides.insert_override(parent, proc); | ||||||||||||||||||||
break | ||||||||||||||||||||
} | ||||||||||||||||||||
} | ||||||||||||||||||||
} | ||||||||||||||||||||
else if !parent_argument.default.is_some() | ||||||||||||||||||||
{ | ||||||||||||||||||||
self.decreasing_argc_overrides.insert_override(parent, proc); | ||||||||||||||||||||
break | ||||||||||||||||||||
} | ||||||||||||||||||||
} | ||||||||||||||||||||
} | ||||||||||||||||||||
} | ||||||||||||||||||||
|
||||||||||||||||||||
/// Finish analyzing args for a changed count or type | ||||||||||||||||||||
pub fn finish_check_arg_count(&self) { | ||||||||||||||||||||
for &parent in self.decreasing_argc_overrides.overrides.keys() | ||||||||||||||||||||
{ | ||||||||||||||||||||
if let Some(violators) = self.decreasing_argc_overrides.get_override_violators(parent) | ||||||||||||||||||||
{ | ||||||||||||||||||||
let msg = match violators.len() { | ||||||||||||||||||||
1 => format!("an override of {}/{} has fewer arguments", parent.ty().path, parent.name()), | ||||||||||||||||||||
len => format!("{} overrides of {}/{} have fewer arguments", len, parent.ty().path, parent.name()), | ||||||||||||||||||||
}; | ||||||||||||||||||||
let mut error = error(parent.get().location, msg) | ||||||||||||||||||||
.set_severity(Severity::Hint) | ||||||||||||||||||||
.with_errortype("override_fewer_arguments"); | ||||||||||||||||||||
if let Some(violations) = self.decreasing_argc_overrides.get_override_violators(parent) | ||||||||||||||||||||
{ | ||||||||||||||||||||
for violating_child in violations.iter() | ||||||||||||||||||||
{ | ||||||||||||||||||||
error.add_note(violating_child.get().location, format!("{}/{} has fewer arguments than its parent", violating_child.ty().path, violating_child.name())); | ||||||||||||||||||||
} | ||||||||||||||||||||
} | ||||||||||||||||||||
error.register(self.context); | ||||||||||||||||||||
} | ||||||||||||||||||||
} | ||||||||||||||||||||
for &parent in self.incorrect_arg_type_overrides.overrides.keys() | ||||||||||||||||||||
{ | ||||||||||||||||||||
if let Some(violators) = self.incorrect_arg_type_overrides.get_override_violators(parent) | ||||||||||||||||||||
{ | ||||||||||||||||||||
let msg = match violators.len() { | ||||||||||||||||||||
1 => format!("an override of {}/{} has mismatched argument types", parent.ty().path, parent.name()), | ||||||||||||||||||||
len => format!("{} overrides of {}/{} have mismatched argument types", len, parent.ty().path, parent.name()), | ||||||||||||||||||||
}; | ||||||||||||||||||||
let mut error = error(parent.get().location, msg) | ||||||||||||||||||||
.set_severity(Severity::Hint) | ||||||||||||||||||||
.with_errortype("override_changed_type"); | ||||||||||||||||||||
if let Some(violations) = self.incorrect_arg_type_overrides.get_override_violators(parent) | ||||||||||||||||||||
{ | ||||||||||||||||||||
for violating_child in violations.iter() | ||||||||||||||||||||
{ | ||||||||||||||||||||
error.add_note(violating_child.get().location, format!("{}/{} has mismatched argument types with its parent", violating_child.ty().path, violating_child.name())); | ||||||||||||||||||||
} | ||||||||||||||||||||
} | ||||||||||||||||||||
error.register(self.context); | ||||||||||||||||||||
} | ||||||||||||||||||||
} | ||||||||||||||||||||
} | ||||||||||||||||||||
|
||||||||||||||||||||
/// Check and build a list of bad overrides of kwargs for a ProcRef | ||||||||||||||||||||
pub fn check_kwargs(&mut self, proc: ProcRef) { | ||||||||||||||||||||
let param_names: HashSet<&String> = proc.parameters.iter().map(|p| &p.name).collect(); | ||||||||||||||||||||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
;)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
whoops. yeah I can probably remove the check_arg_count method entirely since I replaced it with check_arg_type, and I can rename it to check_args