Skip to content

Commit 810978d

Browse files
committed
PS: Create an entity that represents a local variable and a parameter and introduce those into the AST.
1 parent e99404a commit 810978d

File tree

8 files changed

+202
-6
lines changed

8 files changed

+202
-6
lines changed

powershell/ql/lib/powershell.qll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ import semmle.code.powershell.Attribute
1414
import semmle.code.powershell.NamedAttributeArgument
1515
import semmle.code.powershell.TypeConstraint
1616
import semmle.code.powershell.VariableExpression
17-
import semmle.code.powershell.Parameter
1817
import semmle.code.powershell.ModuleSpecification
1918
import semmle.code.powershell.ParamBlock
2019
import semmle.code.powershell.NamedBlock
@@ -77,3 +76,4 @@ import semmle.code.powershell.IndexExpr
7776
import semmle.code.powershell.HashTable
7877
import semmle.code.powershell.SplitExpr
7978
import semmle.code.powershell.CommentEntity
79+
import semmle.code.powershell.Variable

powershell/ql/lib/semmle/code/powershell/ForEachStmt.qll

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,15 @@ class ForEachStmt extends @foreach_statement, LoopStmt {
77

88
final override StmtBlock getBody() { foreach_statement(this, _, _, result, _) }
99

10-
VarAccess getVariable() { foreach_statement(this, result, _, _, _) }
10+
VarAccess getVarAccess() { foreach_statement(this, result, _, _, _) }
11+
12+
Variable getVariable() {
13+
exists(VarAccess va |
14+
va = this.getVarAccess() and
15+
foreach_statement(this, va, _, _, _) and
16+
result = va.getVariable()
17+
)
18+
}
1119

1220
PipelineBase getIterableExpr() { foreach_statement(this, _, result, _, _) }
1321

powershell/ql/lib/semmle/code/powershell/Function.qll

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ class NonMemberFunction extends @function_definition, Stmt, AbstractFunction {
3535

3636
predicate isWorkflow() { function_definition(this, _, _, _, true) }
3737

38-
override Parameter getFunctionParameter(int i) { function_definition_parameter(this, i, result) }
38+
override Parameter getFunctionParameter(int i) { result.isFunctionParameter(this, i) }
3939
}
4040

4141
class MemberFunction extends @function_member, Member, AbstractFunction {
@@ -57,7 +57,7 @@ class MemberFunction extends @function_member, Member, AbstractFunction {
5757

5858
predicate isConstructor() { function_member(this, _, true, _, _, _, _, _, _) }
5959

60-
override Parameter getFunctionParameter(int i) { function_member_parameter(this, i, result) }
60+
override Parameter getFunctionParameter(int i) { result.isFunctionParameter(this, i) }
6161

6262
TypeConstraint getTypeConstraint() { function_member_return_type(this, result) }
6363
}

powershell/ql/lib/semmle/code/powershell/ParamBlock.qll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ class ParamBlock extends @param_block, Ast {
1313

1414
Attribute getAnAttribute() { result = this.getAttribute(_) }
1515

16-
Parameter getParameter(int i) { param_block_parameter(this, i, result) }
16+
Parameter getParameter(int i) { result.hasParameterBlock(this, i) }
1717

1818
Parameter getAParameter() { result = this.getParameter(_) }
1919
}
Lines changed: 160 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,160 @@
1+
private import powershell
2+
private import semmle.code.powershell.controlflow.internal.Scope
3+
private import internal.Internal as Internal
4+
5+
bindingset[scope]
6+
pragma[inline_late]
7+
private predicate isParameterImpl(string name, Scope scope) {
8+
exists(Internal::Parameter p | p.getName() = name and p.getEnclosingScope() = scope)
9+
or
10+
name = "_"
11+
}
12+
13+
private newtype TParameterImpl =
14+
TInternalParameter(Internal::Parameter p) or
15+
TUnderscore(Scope scope) {
16+
exists(VarAccess va | va.getUserPath() = "_" and scope = va.getEnclosingScope())
17+
}
18+
19+
private class ParameterImpl extends TParameterImpl {
20+
abstract Location getLocation();
21+
22+
string toString() { result = this.getName() }
23+
24+
abstract string getName();
25+
26+
abstract Scope getEnclosingScope();
27+
28+
predicate hasParameterBlock(ParamBlock block, int i) { none() }
29+
30+
predicate isFunctionParameter(Function f, int i) { none() }
31+
32+
Expr getDefaultValue() { none() }
33+
34+
VarAccess getAnAccess() {
35+
// TODO: This won't join order nicely.
36+
result.getUserPath() = this.getName() and
37+
result.getEnclosingScope() = this.getEnclosingScope()
38+
}
39+
}
40+
41+
private class InternalParameter extends ParameterImpl, TInternalParameter {
42+
Internal::Parameter p;
43+
44+
InternalParameter() { this = TInternalParameter(p) }
45+
46+
override Location getLocation() { result = p.getLocation() }
47+
48+
override string getName() { result = p.getName() }
49+
50+
final override Scope getEnclosingScope() { result = p.getEnclosingScope() }
51+
52+
override predicate hasParameterBlock(ParamBlock block, int i) {
53+
param_block_parameter(block, i, p)
54+
}
55+
56+
override predicate isFunctionParameter(Function f, int i) {
57+
function_definition_parameter(f, i, p)
58+
or
59+
function_member_parameter(f, i, p)
60+
}
61+
62+
override Expr getDefaultValue() { result = p.getDefaultValue() }
63+
}
64+
65+
private class Underscore extends ParameterImpl, TUnderscore {
66+
Scope scope;
67+
68+
Underscore() { this = TUnderscore(scope) }
69+
70+
override Location getLocation() {
71+
// The location is the first access (ordered by location) to the variable in the scope
72+
exists(VarAccess va |
73+
va =
74+
min(VarAccess cand, Location location |
75+
cand = this.getAnAccess() and location = cand.getLocation()
76+
|
77+
cand order by location.getStartLine(), location.getStartColumn()
78+
) and
79+
result = va.getLocation()
80+
)
81+
}
82+
83+
override string getName() { result = "_" }
84+
85+
final override Scope getEnclosingScope() { result = scope }
86+
}
87+
88+
private newtype TVariable =
89+
TLocalVariable(string name, Scope scope) {
90+
not isParameterImpl(name, scope) and
91+
exists(VarAccess va | va.getUserPath() = name and scope = va.getEnclosingScope())
92+
} or
93+
TParameter(ParameterImpl p)
94+
95+
private class AbstractVariable extends TVariable {
96+
abstract Location getLocation();
97+
98+
string toString() { result = this.getName() }
99+
100+
abstract string getName();
101+
102+
abstract Scope getDeclaringScope();
103+
104+
VarAccess getAnAccess() {
105+
exists(string s |
106+
s = concat(this.getAQlClass(), ", ") and
107+
// TODO: This won't join order nicely.
108+
result.getUserPath() = this.getName() and
109+
result.getEnclosingScope() = this.getDeclaringScope()
110+
)
111+
}
112+
}
113+
114+
class LocalVariable extends AbstractVariable, TLocalVariable {
115+
string name;
116+
Scope scope;
117+
118+
LocalVariable() { this = TLocalVariable(name, scope) }
119+
120+
override Location getLocation() {
121+
// The location is the first access (ordered by location) to the variable in the scope
122+
exists(VarAccess va |
123+
va =
124+
min(VarAccess cand, Location location |
125+
cand = this.getAnAccess() and location = cand.getLocation()
126+
|
127+
cand order by location.getStartLine(), location.getStartColumn()
128+
) and
129+
result = va.getLocation()
130+
)
131+
}
132+
133+
override string getName() { result = name }
134+
135+
final override Scope getDeclaringScope() { result = scope }
136+
}
137+
138+
class Parameter extends AbstractVariable, TParameter {
139+
ParameterImpl p;
140+
141+
Parameter() { this = TParameter(p) }
142+
143+
override Location getLocation() { result = p.getLocation() }
144+
145+
override string getName() { result = p.getName() }
146+
147+
final override Scope getDeclaringScope() { result = p.getEnclosingScope() }
148+
149+
predicate hasParameterBlock(ParamBlock block, int i) { p.hasParameterBlock(block, i) }
150+
151+
predicate isFunctionParameter(Function f, int i) { p.isFunctionParameter(f, i) }
152+
153+
Expr getDefaultValue() { result = p.getDefaultValue() }
154+
155+
predicate hasDefaultValue() { exists(this.getDefaultValue()) }
156+
157+
int getIndex() { this.isFunctionParameter(_, result) }
158+
}
159+
160+
final class Variable = AbstractVariable;

powershell/ql/lib/semmle/code/powershell/VariableExpression.qll

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
import powershell
22

3+
private predicate isParameterName(@variable_expression ve) { parameter(_, ve, _, _) }
4+
35
class VarAccess extends @variable_expression, Expr {
6+
VarAccess() { not isParameterName(this) }
7+
48
override string toString() { result = this.getUserPath() }
59

610
override SourceLocation getLocation() { variable_expression_location(this, result) }
@@ -26,4 +30,22 @@ class VarAccess extends @variable_expression, Expr {
2630
boolean isVariable() { variable_expression(this, _, _, _, _, _, _, _, _, _, result, _) }
2731

2832
boolean isDriveQualified() { variable_expression(this, _, _, _, _, _, _, _, _, _, _, result) }
33+
34+
Variable getVariable() { result.getAnAccess() = this }
35+
}
36+
37+
private predicate isVariableWriteAccess(Expr e) {
38+
e = any(AssignStmt assign).getLeftHandSide()
39+
or
40+
e = any(ConvertExpr convert | isVariableWriteAccess(convert)).getExpr()
41+
or
42+
e = any(ArrayLiteral array | isVariableWriteAccess(array)).getAnElement()
43+
}
44+
45+
class VarReadAccess extends VarAccess {
46+
VarReadAccess() { not this instanceof VarWriteAccess }
47+
}
48+
49+
class VarWriteAccess extends VarAccess {
50+
VarWriteAccess() { isVariableWriteAccess(this) }
2951
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
import Parameter

powershell/ql/lib/semmle/code/powershell/Parameter.qll renamed to powershell/ql/lib/semmle/code/powershell/internal/Parameter.qll

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,12 @@ import powershell
33
class Parameter extends @parameter, Ast {
44
override string toString() { result = this.getName().toString() }
55

6-
VarAccess getName() { parameter(this, result, _, _) }
6+
string getName() {
7+
exists(@variable_expression ve |
8+
parameter(this, ve, _, _) and
9+
variable_expression(ve, result, _, _, _, _, _, _, _, _, _, _)
10+
)
11+
}
712

813
string getStaticType() { parameter(this, _, result, _) }
914

0 commit comments

Comments
 (0)