1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
use error::MinusOneResult;
use ps::Powershell;
use ps::Powershell::Raw;
use ps::Value::Bool;
use tree::BranchFlow::{Predictable, Unpredictable};
use tree::ControlFlow::{Break, Continue};
use tree::{ControlFlow, Node, Strategy};
#[derive(Default)]
pub struct PowershellStrategy;
impl Strategy<Powershell> for PowershellStrategy {
fn control(&self, node: Node<Powershell>) -> MinusOneResult<ControlFlow> {
match node.kind() {
"statement_block" => {
let parent = node.parent().unwrap();
match parent.kind() {
"while_statement" => {
// Don't visit node inferred node with a branch set to false
if let Some(condition) = parent.named_child("condition") {
if condition.data() == Some(&Raw(Bool(false))) {
return Ok(Break);
}
}
// Any other inferred type led to unpredictable branch visit
Ok(Continue(Unpredictable))
}
"if_statement" => {
// if ($true) control flow
if let Some(condition) = parent.named_child("condition") {
return match condition.data() {
Some(Raw(Bool(true))) => Ok(Continue(Predictable)),
Some(Raw(Bool(false))) => Ok(Break),
_ => Ok(Continue(Unpredictable)),
};
}
Ok(Continue(Unpredictable))
}
"elseif_clause" => {
// elseif_clause is evaluated only if the if statement if false or unpredictable
// We have to check if previous clause are predictable or not
let elseif_clauses = parent.parent().unwrap();
// loop over all elseif clauses
for elseif_clause in elseif_clauses.iter() {
if elseif_clause == parent {
break;
}
if let Some(condition) = elseif_clause.named_child("condition") {
return match condition.data() {
Some(Raw(Bool(false))) => continue,
Some(Raw(Bool(true))) => return Ok(Break),
_ => Ok(Continue(Unpredictable)),
};
}
return Ok(Continue(Unpredictable));
}
// elseif ($true) control flow
if let Some(condition) = parent.named_child("condition") {
return match condition.data() {
Some(Raw(Bool(true))) => Ok(Continue(Predictable)),
Some(Raw(Bool(false))) => Ok(Break),
_ => Ok(Continue(Unpredictable)),
};
}
Ok(Continue(Unpredictable))
}
"else_clause" => {
// else clause is visited only if the main if is false
// but we have to check elseif_clause
if let Some(elseif_clauses) =
parent.parent().unwrap().named_child("elseif_clauses")
{
for elseif_clause in elseif_clauses.iter() {
if let Some(condition) = elseif_clause.named_child("condition") {
match condition.data() {
Some(Raw(Bool(false))) => continue,
Some(Raw(Bool(true))) => return Ok(Break), // no need to evaluate the else branch
_ => return Ok(Continue(Unpredictable)),
}
} else {
return Ok(Continue(Unpredictable));
}
}
}
Ok(Continue(Predictable))
}
// function are predictable
"function_statement" => Ok(Continue(Predictable)),
_ => Ok(Continue(Predictable)),
}
}
// We can add condition to visit these node depending on the main if condition
"elseif_clauses" | "else_clause" => {
let if_statement = node.parent().unwrap();
if let Some(condition) = if_statement.named_child("condition") {
return match condition.data() {
// don't visit elseif_clauses if the main if is true
Some(Raw(Bool(true))) => Ok(Break),
// We have to evaluate all elseif_clause
Some(Raw(Bool(false))) => Ok(Continue(Predictable)),
// The inferred type is not boolean
// We don't known which clauses will be used
_ => Ok(Continue(Unpredictable)),
};
}
// We were not able to infer type so we are in an unpredictable case
Ok(Continue(Unpredictable))
}
// All this statement are labeled and not inferred at this moment
"trap_statement" | "try_statement" | "catch_clause" | "finally_clause"
| "data_statement" | "parallel_statement" | "sequence_statement"
| "switch_statement" | "foreach_statement" | "for_statement" | "while_statement" => {
Ok(Continue(Unpredictable))
}
// Any other node than statement block become unpredictable
_ => Ok(Continue(Predictable)),
}
}
}