Skip to content

Commit fac92ef

Browse files
authored
QL: Merge pull request #19 from github/more-variables
More variable resolution
2 parents 36248cc + 3e87a05 commit fac92ef

4 files changed

Lines changed: 229 additions & 119 deletions

File tree

ql/src/codeql_ql/ast/Ast.qll

Lines changed: 87 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import ql
22
private import codeql_ql.ast.internal.AstNodes
33
private import codeql_ql.ast.internal.Module
44
private import codeql_ql.ast.internal.Predicate
5-
private import codeql_ql.ast.internal.Type
5+
import codeql_ql.ast.internal.Type
66
private import codeql_ql.ast.internal.Variable
77

88
bindingset[name, i]
@@ -256,18 +256,28 @@ class CharPred extends TCharPred, Predicate {
256256
override AstNode getAChild(string pred_name) { pred_name = "getBody" and result = this.getBody() }
257257
}
258258

259+
/**
260+
* A variable definition. This is either a variable declaration or
261+
* an `as` expression.
262+
*/
263+
class VarDef extends TVarDef, AstNode {
264+
/** Gets the name of the declared variable. */
265+
string getName() { none() }
266+
267+
override string getAPrimaryQlClass() { result = "VarDef" }
268+
269+
override string toString() { result = this.getName() }
270+
}
271+
259272
/**
260273
* A variable declaration, with a type and a name.
261274
*/
262-
class VarDecl extends TVarDecl, AstNode {
275+
class VarDecl extends TVarDecl, VarDef {
263276
Generated::VarDecl var;
264277

265278
VarDecl() { this = TVarDecl(var) }
266279

267-
/**
268-
* Gets the name for this variable declaration.
269-
*/
270-
string getName() { result = var.getChild(1).(Generated::VarName).getChild().getValue() }
280+
override string getName() { result = var.getChild(1).(Generated::VarName).getChild().getValue() }
271281

272282
override string getAPrimaryQlClass() { result = "VarDecl" }
273283

@@ -407,6 +417,8 @@ class ModuleMember extends TModuleMember, AstNode {
407417
class Declaration extends TDeclaration, AstNode {
408418
/** Gets the name of this declaration. */
409419
string getName() { none() }
420+
421+
final override string toString() { result = this.getName() }
410422
}
411423

412424
/** An entity that can be declared in a module. */
@@ -1088,43 +1100,55 @@ class ExprAggregate extends TExprAggregate, Expr {
10881100
/** An aggregate expression, such as `count` or `sum`. */
10891101
class Aggregate extends TAggregate, Expr {
10901102
Generated::Aggregate agg;
1091-
Generated::FullAggregateBody body;
10921103
string kind;
10931104

10941105
Aggregate() {
10951106
this = TAggregate(agg) and
1096-
kind = agg.getChild(0).(Generated::AggId).getValue() and
1097-
body = agg.getChild(_)
1107+
kind = agg.getChild(0).(Generated::AggId).getValue()
10981108
}
10991109

1110+
private Generated::FullAggregateBody getBody1() { result = agg.getChild(_) }
1111+
1112+
private Generated::ExprAggregateBody getBody2() { result = agg.getChild(_) }
1113+
11001114
string getKind() { result = kind }
11011115

11021116
/** Gets the ith declared argument of this quantifier. */
1103-
VarDecl getArgument(int i) { toGenerated(result) = body.getChild(i) }
1117+
VarDecl getArgument(int i) { toGenerated(result) = this.getBody1().getChild(i) }
11041118

11051119
/** Gets an argument of this quantifier. */
11061120
VarDecl getAnArgument() { result = this.getArgument(_) }
11071121

11081122
/**
11091123
* Gets the formula restricting the range of this quantifier, if any.
11101124
*/
1111-
Formula getRange() { toGenerated(result) = body.getGuard() }
1125+
Formula getRange() { toGenerated(result) = this.getBody1().getGuard() }
11121126

11131127
/**
11141128
* Gets the ith "as" expression of this aggregate, if any.
11151129
*/
1116-
AsExpr getAsExpr(int i) { toGenerated(result) = body.getAsExprs().getChild(i) }
1130+
AsExpr getAsExpr(int i) {
1131+
toGenerated(result) = [this.getBody1().getAsExprs(), this.getBody2().getAsExprs()].getChild(i)
1132+
}
11171133

11181134
/**
11191135
* Gets the ith "order by" expression of this aggregate, if any.
11201136
*/
1121-
Expr getOrderBy(int i) { toGenerated(result) = body.getOrderBys().getChild(i).getChild(0) }
1137+
Expr getOrderBy(int i) {
1138+
toGenerated(result) =
1139+
[this.getBody1().getOrderBys(), this.getBody2().getOrderBys()].getChild(i).getChild(0)
1140+
}
11221141

11231142
/**
11241143
* Gets the direction (ascending or descending) of the ith "order by" expression of this aggregate.
11251144
*/
11261145
string getOrderbyDirection(int i) {
1127-
result = body.getOrderBys().getChild(i).getChild(1).(Generated::Direction).getValue()
1146+
result =
1147+
[this.getBody1().getOrderBys(), this.getBody2().getOrderBys()]
1148+
.getChild(i)
1149+
.getChild(1)
1150+
.(Generated::Direction)
1151+
.getValue()
11281152
}
11291153

11301154
override string getAPrimaryQlClass() { result = "Aggregate[" + kind + "]" }
@@ -1159,13 +1183,15 @@ class Rank extends Aggregate {
11591183
/**
11601184
* An "as" expression, such as `foo as bar`.
11611185
*/
1162-
class AsExpr extends TAsExpr, AstNode {
1186+
class AsExpr extends TAsExpr, VarDef {
11631187
Generated::AsExpr asExpr;
11641188

11651189
AsExpr() { this = TAsExpr(asExpr) }
11661190

11671191
override string getAPrimaryQlClass() { result = "AsExpr" }
11681192

1193+
final override string getName() { result = this.getAsName() }
1194+
11691195
/**
11701196
* Gets the name the inner expression gets "saved" under, if it exists.
11711197
* For example this is `bar` in the expression `foo as bar`.
@@ -1189,30 +1215,73 @@ class AsExpr extends TAsExpr, AstNode {
11891215
}
11901216

11911217
override AstNode getAChild(string pred) { pred = "getInnerExpr" and result = this.getInnerExpr() }
1218+
1219+
override string toString() {
1220+
result = this.getName()
1221+
or
1222+
not exists(this.getName()) and
1223+
result = "AsExpr"
1224+
}
11921225
}
11931226

11941227
class Identifier extends TIdentifier, Expr {
11951228
Generated::Variable id;
11961229

11971230
Identifier() { this = TIdentifier(id) }
11981231

1199-
string getName() { result = id.getChild().(Generated::VarName).getChild().getValue() }
1232+
string getName() { none() }
1233+
1234+
final override string toString() { result = this.getName() }
12001235

12011236
override string getAPrimaryQlClass() { result = "Identifier" }
12021237
}
12031238

12041239
/** An access to a variable. */
12051240
class VarAccess extends Identifier {
1206-
private VarDecl decl;
1241+
private VarDef decl;
12071242

12081243
VarAccess() { resolveVariable(this, decl) }
12091244

12101245
/** Gets the accessed variable. */
1211-
VarDecl getDeclaration() { result = decl }
1246+
VarDef getDeclaration() { result = decl }
1247+
1248+
override string getName() { result = id.getChild().(Generated::VarName).getChild().getValue() }
12121249

12131250
override string getAPrimaryQlClass() { result = "VarAccess" }
12141251
}
12151252

1253+
/** An access to a field. */
1254+
class FieldAccess extends Identifier {
1255+
private VarDecl decl;
1256+
1257+
FieldAccess() { resolveField(this, decl) }
1258+
1259+
/** Gets the accessed field. */
1260+
VarDecl getDeclaration() { result = decl }
1261+
1262+
override string getName() { result = id.getChild().(Generated::VarName).getChild().getValue() }
1263+
1264+
override string getAPrimaryQlClass() { result = "FieldAccess" }
1265+
}
1266+
1267+
/** An access to `this`. */
1268+
class ThisAccess extends Identifier {
1269+
ThisAccess() { any(Generated::This t).getParent() = id }
1270+
1271+
override string getName() { result = "this" }
1272+
1273+
override string getAPrimaryQlClass() { result = "ThisAccess" }
1274+
}
1275+
1276+
/** An access to `result`. */
1277+
class ResultAccess extends Identifier {
1278+
ResultAccess() { any(Generated::Result r).getParent() = id }
1279+
1280+
override string getName() { result = "result" }
1281+
1282+
override string getAPrimaryQlClass() { result = "ResultAccess" }
1283+
}
1284+
12161285
/** A `not` formula. */
12171286
class Negation extends TNegation, Formula {
12181287
Generated::Negation neg;

ql/src/codeql_ql/ast/internal/AstNodes.qll

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,10 @@ newtype TAstNode =
2222
TComparisonFormula(Generated::CompTerm comp) or
2323
TComparisonOp(Generated::Compop op) or
2424
TQuantifier(Generated::Quantified quant) or
25-
TAggregate(Generated::Aggregate agg) { agg.getChild(_) instanceof Generated::FullAggregateBody } or
25+
TAggregate(Generated::Aggregate agg) {
26+
agg.getChild(_) instanceof Generated::FullAggregateBody or
27+
agg.getChild(_) instanceof Generated::ExprAggregateBody
28+
} or
2629
TExprAggregate(Generated::Aggregate agg) {
2730
agg.getChild(_) instanceof Generated::ExprAggregateBody
2831
} or
@@ -161,3 +164,5 @@ class TDeclaration = TTypeDeclaration or TModuleDeclaration;
161164
class TTypeDeclaration = TClass or TNewType or TNewTypeBranch;
162165

163166
class TModuleDeclaration = TClasslessPredicate or TModule or TClass or TNewType;
167+
168+
class TVarDef = TVarDecl or TAsExpr;

ql/src/codeql_ql/ast/internal/Variable.qll

Lines changed: 46 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,33 @@ class VariableScope extends TScope, AstNode {
1010
VariableScope getOuterScope() { result = scopeOf(this) }
1111

1212
/** Gets a variable declared directly in this scope. */
13-
VarDecl getADeclaration() { result.getParent() = this }
13+
VarDef getADefinition() { result.getParent() = this }
1414

15-
/** Holds if this scope contains declaration `decl`, either directly or inherited. */
16-
predicate contains(VarDecl decl) {
17-
decl = this.getADeclaration()
15+
/** Holds if this scope contains variable `decl`, either directly or inherited. */
16+
predicate containsVar(VarDef decl) {
17+
not this instanceof Class and
18+
decl = this.getADefinition()
1819
or
19-
this.getOuterScope().contains(decl) and
20-
not this.getADeclaration().getName() = decl.getName()
20+
decl = this.(Select).getAsExpr(_)
21+
or
22+
decl = this.(Aggregate).getAsExpr(_)
23+
or
24+
this.getOuterScope().containsVar(decl) and
25+
not this.getADefinition().getName() = decl.getName()
26+
}
27+
28+
/** Holds if this scope contains field `decl`, either directly or inherited. */
29+
predicate containsField(VarDef decl) {
30+
decl = this.(Class).getAField()
31+
or
32+
this.getOuterScope().containsField(decl) and
33+
not this.getADefinition().getName() = decl.getName()
34+
or
35+
exists(VariableScope sup |
36+
sup = this.(Class).getASuperType().getResolvedType().(ClassType).getDeclaration() and
37+
sup.containsField(decl) and
38+
not this.(Class).getAField().getName() = decl.getName()
39+
)
2140
}
2241
}
2342

@@ -28,14 +47,31 @@ private AstNode parent(AstNode child) {
2847

2948
VariableScope scopeOf(AstNode n) { result = parent*(n.getParent()) }
3049

31-
predicate resolveVariable(Identifier i, VarDecl decl) {
32-
scopeOf(i).contains(decl) and
33-
decl.getName() = i.getName()
50+
private string getName(Identifier i) {
51+
exists(Generated::Variable v |
52+
i = TIdentifier(v) and
53+
result = v.getChild().(Generated::VarName).getChild().getValue()
54+
)
55+
}
56+
57+
predicate resolveVariable(Identifier i, VarDef decl) {
58+
scopeOf(i).containsVar(decl) and
59+
decl.getName() = getName(i)
60+
}
61+
62+
predicate resolveField(Identifier i, VarDef decl) {
63+
scopeOf(i).containsField(decl) and
64+
decl.getName() = getName(i)
3465
}
3566

3667
module VarConsistency {
37-
query predicate multipleVarDecls(VarAccess v, VarDecl decl) {
68+
query predicate multipleVarDefs(VarAccess v, VarDef decl) {
3869
decl = v.getDeclaration() and
3970
strictcount(v.getDeclaration()) > 1
4071
}
72+
73+
query predicate multipleFieldDefs(FieldAccess f, VarDef decl) {
74+
decl = f.getDeclaration() and
75+
strictcount(f.getDeclaration()) > 1
76+
}
4177
}

0 commit comments

Comments
 (0)