Skip to content

Commit c2c0a96

Browse files
authored
Merge pull request #33 from github/fixes
improve callgraph resolution, and other fixes
2 parents 4140ce0 + 48170f5 commit c2c0a96

8 files changed

Lines changed: 245 additions & 103 deletions

File tree

ql/src/codeql_ql/ast/Ast.qll

Lines changed: 66 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,15 @@ class AstNode extends TAstNode {
5656
* Gets the primary QL class for the ast node.
5757
*/
5858
string getAPrimaryQlClass() { result = "???" }
59+
60+
/**
61+
* Gets the predicate that contains this AST node.
62+
*/
63+
pragma[noinline]
64+
Predicate getEnclosingPredicate() {
65+
not this instanceof Predicate and
66+
toGenerated(result) = toGenerated(this).getParent+()
67+
}
5968
}
6069

6170
/** A toplevel QL program, i.e. a file. */
@@ -145,7 +154,14 @@ class Predicate extends TPredicate, AstNode {
145154
/**
146155
* Gets the number of parameters.
147156
*/
148-
int getArity() { result = count(getParameter(_)) }
157+
int getArity() {
158+
not this.(ClasslessPredicate).getAlias() instanceof PredicateExpr and
159+
result = count(getParameter(_))
160+
or
161+
exists(PredicateExpr alias | alias = this.(ClasslessPredicate).getAlias() |
162+
result = alias.getArity()
163+
)
164+
}
149165

150166
/**
151167
* Gets the return type (if any) of the predicate.
@@ -990,6 +1006,21 @@ class Float extends Literal {
9901006
float getValue() { result = lit.getChild().(Generated::Float).getValue().toFloat() }
9911007
}
9921008

1009+
/** A boolean literal */
1010+
class Boolean extends Literal {
1011+
Generated::Bool bool;
1012+
1013+
Boolean() { lit.getChild() = bool }
1014+
1015+
/** Holds if the value is `true` */
1016+
predicate isTrue() { bool.getChild() instanceof Generated::True }
1017+
1018+
/** Holds if the value is `false` */
1019+
predicate isFalse() { bool.getChild() instanceof Generated::False }
1020+
1021+
override string getAPrimaryQlClass() { result = "Boolean" }
1022+
}
1023+
9931024
/** A comparison symbol, such as `"<"` or `"="`. */
9941025
class ComparisonSymbol extends string {
9951026
ComparisonSymbol() {
@@ -1315,6 +1346,19 @@ class ExprAggregate extends TExprAggregate, Expr {
13151346
pred = indexedMember("getOrderBy", i) and result = this.getOrderBy(i)
13161347
)
13171348
}
1349+
1350+
override Type getType() {
1351+
exists(PrimitiveType prim | prim = result |
1352+
kind.regexpMatch("(strict)?count|sum|min|max|rank") and
1353+
result.getName() = "int"
1354+
or
1355+
kind.regexpMatch("(strict)?concat") and
1356+
result.getName() = "string"
1357+
)
1358+
or
1359+
not kind = ["count", "strictcount"] and
1360+
result = getExpr(0).getType()
1361+
}
13181362
}
13191363

13201364
/** An aggregate expression, such as `count` or `sum`. */
@@ -1365,12 +1409,21 @@ class Aggregate extends TAggregate, Expr {
13651409

13661410
override string getAPrimaryQlClass() { result = "Aggregate[" + kind + "]" }
13671411

1368-
override PrimitiveType getType() {
1369-
kind.regexpMatch("(strict)?count|sum|min|max|rank") and
1370-
result.getName() = "int"
1412+
override Type getType() {
1413+
exists(PrimitiveType prim | prim = result |
1414+
kind.regexpMatch("(strict)?count|sum|min|max|rank") and
1415+
result.getName() = "int"
1416+
or
1417+
kind.regexpMatch("(strict)?concat") and
1418+
result.getName() = "string"
1419+
)
1420+
or
1421+
kind = ["any", "min", "max"] and
1422+
not exists(getExpr(_)) and
1423+
result = getArgument(0).getTypeExpr().getResolvedType()
13711424
or
1372-
kind.regexpMatch("(strict)?concat") and
1373-
result.getName() = "string"
1425+
not kind = ["count", "strictcount"] and
1426+
result = getExpr(0).getType()
13741427
}
13751428

13761429
override AstNode getAChild(string pred) {
@@ -1499,6 +1552,13 @@ class ThisAccess extends Identifier {
14991552
override string getAPrimaryQlClass() { result = "ThisAccess" }
15001553
}
15011554

1555+
/** A use of `super`. */
1556+
class Super extends TSuper, Expr {
1557+
Super() { this = TSuper(_) }
1558+
1559+
override string getAPrimaryQlClass() { result = "SuperAccess" }
1560+
}
1561+
15021562
/** An access to `result`. */
15031563
class ResultAccess extends Identifier {
15041564
ResultAccess() { any(Generated::Result r).getParent() = id }

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

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ newtype TAstNode =
2424
TExprAggregate(Generated::Aggregate agg) {
2525
agg.getChild(_) instanceof Generated::ExprAggregateBody
2626
} or
27+
TSuper(Generated::SuperRef sup) or
2728
TIdentifier(Generated::Variable var) or
2829
TAsExpr(Generated::AsExpr asExpr) { asExpr.getChild(1) instanceof Generated::VarName } or
2930
TPredicateCall(Generated::CallOrUnqualAggExpr call) or
@@ -63,7 +64,7 @@ class TBinOpExpr = TAddSubExpr or TMulDivModExpr;
6364

6465
class TExpr =
6566
TBinOpExpr or TLiteral or TAggregate or TExprAggregate or TIdentifier or TInlineCast or TCall or
66-
TUnaryExpr or TExprAnnotation or TDontCare or TRange or TSet or TAsExpr;
67+
TUnaryExpr or TExprAnnotation or TDontCare or TRange or TSet or TAsExpr or TSuper;
6768

6869
class TCall = TPredicateCall or TMemberCall or TNoneCall or TAnyCall;
6970

@@ -154,6 +155,8 @@ Generated::AstNode toGenerated(AST::AstNode n) {
154155
n = TNoneCall(result)
155156
or
156157
n = TAnyCall(result)
158+
or
159+
n = TSuper(result)
157160
}
158161

159162
class TPredicate = TCharPred or TClasslessPredicate or TClassPredicate;

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

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,13 @@ private module Cached {
7979
t = mc.getBase().getType() and
8080
p = t.getClassPredicate(mc.getMemberName(), mc.getNumberOfArguments())
8181
)
82+
or
83+
// super calls
84+
exists(Super sup, ClassType type |
85+
mc.getBase() = sup and
86+
sup.getEnclosingPredicate().(ClassPredicate).getParent().getType() = type and
87+
p = type.getASuperType().getClassPredicate(mc.getMemberName(), mc.getNumberOfArguments())
88+
)
8289
}
8390

8491
cached
@@ -233,6 +240,7 @@ module PredConsistency {
233240
query predicate noResolveCall(Call c) {
234241
not resolveCall(c, _) and
235242
not c instanceof NoneCall and
243+
not c instanceof AnyCall and
236244
not c.getLocation().getFile().getAbsolutePath().regexpMatch(".*/(test|examples)/.*")
237245
}
238246

@@ -243,7 +251,12 @@ module PredConsistency {
243251
}
244252

245253
query predicate multipleResolveCall(Call call, int c, PredicateOrBuiltin p) {
246-
c = strictcount(PredicateOrBuiltin p0 | resolveCall(call, p0)) and
254+
c =
255+
strictcount(PredicateOrBuiltin p0 |
256+
resolveCall(call, p0) and
257+
// aliases are expected to resolve to multiple.
258+
not exists(p0.getDeclaration().(ClasslessPredicate).getAlias())
259+
) and
247260
c > 1 and
248261
resolveCall(call, p)
249262
}

ql/test/callgraph/Foo.qll

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import ql
2+
3+
predicate foo() { none() }
4+
5+
query predicate test() { foo() }
6+
7+
class Foo extends AstNode {
8+
predicate bar() { none() }
9+
10+
predicate baz() { bar() }
11+
}
12+
13+
class Sub extends Foo {
14+
override predicate baz() { super.baz() }
15+
}
16+
17+
query predicate test2() { any(Foo f).bar() }
18+
19+
module Aliases {
20+
predicate myThing2(int i, int j) { i = 2 and j = 3 }
21+
22+
predicate myThing0() { any() }
23+
24+
predicate alias0 = myThing0/0;
25+
26+
predicate alias2 = myThing2/2;
27+
28+
query predicate test3() {
29+
alias2(3, 4) // doesn't work.
30+
or
31+
alias0() // <- works
32+
}
33+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
| Foo.qll:5:26:5:30 | PredicateCall | Foo.qll:3:1:3:26 | foo |
2+
| Foo.qll:10:21:10:25 | PredicateCall | Foo.qll:8:3:8:28 | ClassPredicate |
3+
| Foo.qll:14:30:14:40 | MemberCall | Foo.qll:10:3:10:27 | ClassPredicate |
4+
| Foo.qll:17:27:17:42 | MemberCall | Foo.qll:8:3:8:28 | ClassPredicate |
5+
| Foo.qll:29:5:29:16 | PredicateCall | Foo.qll:20:3:20:54 | myThing2 |
6+
| Foo.qll:29:5:29:16 | PredicateCall | Foo.qll:26:3:26:32 | alias2 |
7+
| Foo.qll:31:5:31:12 | PredicateCall | Foo.qll:22:3:22:32 | myThing0 |
8+
| Foo.qll:31:5:31:12 | PredicateCall | Foo.qll:24:3:24:32 | alias0 |

ql/test/callgraph/callgraph.ql

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
import ql
2+
3+
query AstNode getTarget(Call call) { result = call.getTarget().getDeclaration() }

ql/test/printAst/Foo.qll

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,4 +22,6 @@ predicate calls(Foo f) {
2222
f = any(Foo f)
2323
or
2424
2 = 1 + (2 + (3 + 4))
25+
or
26+
true = false
2527
}

0 commit comments

Comments
 (0)