Skip to content

Commit

Permalink
Add more tests for undefined variable detection
Browse files Browse the repository at this point in the history
  • Loading branch information
LucasSte committed Aug 17, 2021
1 parent a76fe17 commit b124f28
Show file tree
Hide file tree
Showing 3 changed files with 159 additions and 5 deletions.
2 changes: 1 addition & 1 deletion src/codegen/statements.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1216,7 +1216,7 @@ impl Type {
)),
None,
)),
Type::InternalFunction { .. } | Type::ExternalFunction { .. } => None,
Type::InternalFunction { .. } | Type::Contract(_) | Type::ExternalFunction { .. } => None,
Type::Array(_, dims) => {
if dims[0].is_none() {
Some(Expression::AllocDynamicArray(
Expand Down
3 changes: 3 additions & 0 deletions src/codegen/undefined_variable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,9 @@ pub fn find_undefined_variables_in_expression(
false
}

// This is a method call whose array will never be undefined
Expression::DynamicArrayLength(..) => false,

_ => true,
}
}
Expand Down
159 changes: 155 additions & 4 deletions tests/undefined_variable_detection.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,10 @@ fn get_errors(ns: &Namespace) -> Vec<&Diagnostic> {
vec
}

fn contains_error_message(errors: &[&Diagnostic], message: &str) -> bool {
fn contains_error_message_and_notes(errors: &[&Diagnostic], message: &str, notes_no: usize) -> bool {
for error in errors {
if error.message == message {
return true;
return true && error.notes.len() == notes_no;
}
}

Expand Down Expand Up @@ -273,8 +273,8 @@ fn for_loop() {
let ns = parse_and_codegen(file);
let errors = get_errors(&ns);
assert_eq!(errors.len(), 2);
assert!(contains_error_message(&errors, "Variable 'p' is undefined"));
assert!(contains_error_message(&errors, "Variable 's' is undefined"));
assert!(contains_error_message_and_notes(&errors, "Variable 'p' is undefined", 1));
assert!(contains_error_message_and_notes(&errors, "Variable 's' is undefined", 1));

let file = r#"
contract testing {
Expand Down Expand Up @@ -408,6 +408,157 @@ fn if_else_condition() {
assert_eq!(errors.len(), 0);
}

#[test]
fn array() {
let file = r#"
contract test {
function testing(int x) public pure returns (int) {
int[] vec;
return vec[0];
}
}
"#;
let ns = parse_and_codegen(file);
let errors = get_errors(&ns);
assert_eq!(errors.len(), 1);
assert_eq!(errors[0].message, "Variable 'vec' is undefined");
assert_eq!(errors[0].notes.len(), 1);
assert_eq!(
errors[0].notes[0].message,
"Variable read before being defined"
);

let file = r#"
contract test {
function testing(int x) public pure returns (int) {
int[] vec;
if(x > 0) {
vec.push(2);
}
return vec[0];
}
}
"#;

let ns = parse_and_codegen(file);
let errors = get_errors(&ns);
assert_eq!(errors.len(), 0);
}

#[test]
fn contract_and_enum() {
let file = r#"
contract other {
int public a;
function testing() public returns (int) {
return 2;
}
}
contract test {
enum FreshJuiceSize{ SMALL, MEDIUM, LARGE }
function testing(int x) public returns (int) {
other o;
FreshJuiceSize choice;
if(x > 0 && o.testing() < 5) {
o = new other();
}
assert(choice == FreshJuiceSize.LARGE);
return o.a();
}
}
"#;

let ns = parse_and_codegen(file);
let errors = get_errors(&ns);
assert!(contains_error_message_and_notes(&errors, "Variable 'o' is undefined", 2));
assert!(contains_error_message_and_notes(&errors, "Variable 'choice' is undefined", 1));
}

#[test]
fn basic_types() {
let file = r#"
contract test {
function testing(int x) public returns (address, int, uint, bool, bytes, int) {
address a;
int i;
uint u;
bool b;
bytes bt;
int[5] vec;
while(x > 0) {
x--;
a = address(this);
i = -2;
u = 2;
b = true;
bt = hex"1234";
vec[0] = 2;
}
return (a, i, u, b, bt, vec[1]);
}
}
"#;
let ns = parse_and_codegen(file);
let errors = get_errors(&ns);
assert!(contains_error_message_and_notes(&errors, "Variable 'bt' is undefined", 1));
assert!(contains_error_message_and_notes(&errors, "Variable 'b' is undefined", 1));
assert!(contains_error_message_and_notes(&errors, "Variable 'a' is undefined", 1));
assert!(contains_error_message_and_notes(&errors, "Variable 'i' is undefined", 1));
assert!(contains_error_message_and_notes(&errors, "Variable 'u' is undefined", 1));

}

#[test]
fn nested_branches() {
let file = r#"
contract test {
function testing(int x) public returns (int) {
int i;
while(x > 0) {
int b;
if(x > 5) {
b = 2;
}
i = b;
}
int a;
if(x < 5) {
if(x < 2) {
a = 2;
} else {
a = 1;
}
} else if(x < 4) {
a = 5;
}
return i + a;
}
}
"#;
let ns = parse_and_codegen(file);
let errors = get_errors(&ns);
assert!(contains_error_message_and_notes(&errors, "Variable 'b' is undefined", 1));
assert!(contains_error_message_and_notes(&errors, "Variable 'a' is undefined", 1));
assert!(contains_error_message_and_notes(&errors, "Variable 'i' is undefined", 2));
}

//TODO: Fix this test

// #[test]
Expand Down

0 comments on commit b124f28

Please sign in to comment.