Skip to content
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

Populate errortype on more errors. #201

Merged
merged 1 commit into from
Oct 7, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions CONFIGURING.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,12 @@ Raised by DreamChecker:
* `no_typehint_implicit_new` - Raised on the use of `new` where no typehint is avaliable
* `field_access_static_type` - Raised on using `.field_name` on a variable with no typehint
* `proc_call_static_type` - Raised on using `.proc_name()` on a variable with no typehint
* `proc_has_no_parent` - Raised on calling `..()` in a proc with no parent.
* `no_operator_overload` - Raised on using a unary operator on a non-primative that doesn't define it's own override, eg `somemob++`
* `unreachable_code` - Raised on finding code that can never be executed
* `control_condition_static` - Raised on a control condition such as `if`/`while` having a static condition such as `1` or `"string"`
* `if_condition_determinate` - Raised on if condition being always true or always false
* `loop_condition_determinate` - Raised on loop condition such as in `for` being always true or always false

Raised by Lexer:

Expand Down
10 changes: 9 additions & 1 deletion src/dreamchecker/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1142,6 +1142,7 @@ impl<'o, 's> AnalyzeProc<'o, 's> {
for stmt in block.iter() {
if term.terminates() {
error(stmt.location,"possible unreachable code here")
.with_errortype("unreachable_code")
.register(self.context);
return term // stop evaluating
}
Expand All @@ -1155,10 +1156,12 @@ impl<'o, 's> AnalyzeProc<'o, 's> {
match expression.is_truthy() {
Some(true) => {
error(location,"loop condition is always true")
.with_errortype("loop_condition_determinate")
.register(self.context);
},
Some(false) => {
error(location,"loop condition is always false")
.with_errortype("loop_condition_determinate")
.register(self.context);
}
_ => ()
Expand All @@ -1168,7 +1171,8 @@ impl<'o, 's> AnalyzeProc<'o, 's> {
fn visit_control_condition(&mut self, location: Location, expression: &'o Expression) {
if expression.is_const_eval() {
error(location,"control flow condition is a constant evalutation")
.register(self.context);
.with_errortype("control_condition_static")
.register(self.context);
}
else if let Some(term) = expression.as_term() {
if term.is_static() {
Expand Down Expand Up @@ -1222,6 +1226,7 @@ impl<'o, 's> AnalyzeProc<'o, 's> {
Statement::Throw(expr) => { self.visit_expression(location, expr, None, local_vars); },
Statement::While { condition, block } => {
let mut scoped_locals = local_vars.clone();
// We don't check for static/determine conditions because while(TRUE) is so common.
self.visit_expression(location, condition, None, &mut scoped_locals);
let mut state = self.visit_block(block, &mut scoped_locals);
state.end_loop();
Expand All @@ -1248,6 +1253,7 @@ impl<'o, 's> AnalyzeProc<'o, 's> {
self.visit_control_condition(condition.location, &condition.elem);
if alwaystrue {
error(condition.location,"unreachable if block, preceeding if/elseif condition(s) are always true")
.with_errortype("unreachable_code")
.register(self.context);
}
self.visit_expression(condition.location, &condition.elem, None, &mut scoped_locals);
Expand All @@ -1272,6 +1278,7 @@ impl<'o, 's> AnalyzeProc<'o, 's> {
if alwaystrue {
if let Some(else_expr) = else_arm.first() {
error(else_expr.location ,"unreachable else block, preceeding if/elseif condition(s) are always true")
.with_errortype("unreachable_code")
.register(self.context);
}
}
Expand Down Expand Up @@ -1641,6 +1648,7 @@ impl<'o, 's> AnalyzeProc<'o, 's> {
self.visit_call(location, src, proc, args, true, local_vars)
} else {
error(location, format!("proc has no parent: {}", self.proc_ref))
.with_errortype("proc_has_no_parent")
.register(self.context);
Analysis::empty()
}
Expand Down
21 changes: 21 additions & 0 deletions src/dreamchecker/tests/branch_eval_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -72,3 +72,24 @@ fn do_while() {
"##.trim();
check_errors_match(code, DO_WHILE_ERRORS);
}

pub const FOR_LOOP_CONDITION_ERRORS: &[(u32, u16, &str)] = &[
(2, 5, "loop condition is always true"),
(2, 5, "control flow condition is a static term"),
(4, 5, "control flow condition is a constant evalutation"),
];

#[test]
fn for_loop_condition() {
let code = r##"
/proc/test()
for(var/x = 0; 1; x++)
break
for(var/y = 0; 5 <= 7; y++)
break
for(var/z = 1; z <= 6; z++) // Legit, should have no error
break
return
"##.trim();
check_errors_match(code, FOR_LOOP_CONDITION_ERRORS);
}
18 changes: 18 additions & 0 deletions src/dreamchecker/tests/proc_tests.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@

extern crate dreamchecker as dc;

use dc::test_helpers::check_errors_match;

pub const NO_PARENT_ERRORS: &[(u32, u16, &str)] = &[
(2, 5, "proc has no parent: /mob/proc/test"),
];

#[test]
fn no_parent() {
let code = r##"
/mob/proc/test()
..()
return
"##.trim();
check_errors_match(code, NO_PARENT_ERRORS);
}