Skip to content

Commit 27d0af9

Browse files
authored
QL: Merge pull request #27 from github/newtype-call
Resolve `newtype` constructor calls
2 parents 7e69931 + 22cd284 commit 27d0af9

5 files changed

Lines changed: 102 additions & 45 deletions

File tree

ql/src/codeql_ql/ast/Ast.qll

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -650,6 +650,8 @@ class NewTypeBranch extends TNewTypeBranch, TypeDeclaration {
650650
/** Gets the body of this branch. */
651651
Formula getBody() { toGenerated(result) = branch.getChild(_).(Generated::Body).getChild() }
652652

653+
NewType getNewType() { result.getABranch() = this }
654+
653655
override AstNode getAChild(string pred) {
654656
result = super.getAChild(pred)
655657
or

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

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,11 @@ predicate resolveModuleExpr(ModuleExpr me, FileOrModule m) {
166166
)
167167
}
168168

169-
boolean getPublicBool(ModuleMember m) { if m.isPrivate() then result = false else result = true }
169+
boolean getPublicBool(AstNode n) {
170+
if n.(ModuleMember).isPrivate() or n.(NewTypeBranch).getNewType().isPrivate()
171+
then result = false
172+
else result = true
173+
}
170174

171175
/**
172176
* Holds if `container` defines module `m` with name `name`.

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

Lines changed: 45 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,30 @@
11
import ql
22
private import Builtins
33
private import codeql_ql.ast.internal.Module
4+
private import codeql_ql.ast.internal.AstNodes as AstNodes
45

5-
private predicate definesPredicate(FileOrModule m, string name, ClasslessPredicate p, boolean public) {
6+
private class TClasslessPredicateOrNewTypeBranch =
7+
AstNodes::TClasslessPredicate or AstNodes::TNewTypeBranch;
8+
9+
string getPredicateName(TClasslessPredicateOrNewTypeBranch p) {
10+
result = p.(ClasslessPredicate).getName() or
11+
result = p.(NewTypeBranch).getName()
12+
}
13+
14+
private predicate definesPredicate(
15+
FileOrModule m, string name, int arity, TClasslessPredicateOrNewTypeBranch p, boolean public
16+
) {
617
m = getEnclosingModule(p) and
7-
name = p.getName() and
8-
public = getPublicBool(p)
18+
name = getPredicateName(p) and
19+
public = getPublicBool(p) and
20+
arity = [p.(ClasslessPredicate).getArity(), count(p.(NewTypeBranch).getField(_))]
921
or
1022
// import X
1123
exists(Import imp, FileOrModule m0 |
1224
m = getEnclosingModule(imp) and
1325
m0 = imp.getResolvedModule() and
1426
not exists(imp.importedAs()) and
15-
definesPredicate(m0, name, p, true) and
27+
definesPredicate(m0, name, arity, p, true) and
1628
public = getPublicBool(imp)
1729
)
1830
or
@@ -21,7 +33,8 @@ private predicate definesPredicate(FileOrModule m, string name, ClasslessPredica
2133
m = getEnclosingModule(alias) and
2234
name = alias.getName() and
2335
resolvePredicateExpr(alias.getAlias(), p) and
24-
public = getPublicBool(alias)
36+
public = getPublicBool(alias) and
37+
arity = alias.getArity()
2538
)
2639
}
2740

@@ -34,8 +47,7 @@ predicate resolvePredicateExpr(PredicateExpr pe, ClasslessPredicate p) {
3447
m = pe.getQualifier().getResolvedModule() and
3548
public = true
3649
|
37-
definesPredicate(m, pe.getName(), p, public) and
38-
count(p.getParameter(_)) = pe.getArity()
50+
definesPredicate(m, pe.getName(), count(p.getParameter(_)), p, public)
3951
)
4052
}
4153

@@ -54,8 +66,7 @@ private predicate resolvePredicateCall(PredicateCall pc, PredicateOrBuiltin p) {
5466
m = pc.getQualifier().getResolvedModule() and
5567
public = true
5668
|
57-
definesPredicate(m, pc.getPredicateName(), p.getDeclaration(), public) and
58-
p.getArity() = pc.getNumberOfArguments()
69+
definesPredicate(m, pc.getPredicateName(), pc.getNumberOfArguments(), p.getDeclaration(), public)
5970
)
6071
}
6172

@@ -74,6 +85,7 @@ predicate resolveCall(Call c, PredicateOrBuiltin p) {
7485

7586
private newtype TPredOrBuiltin =
7687
TPred(Predicate p) or
88+
TNewTypeBranch(NewTypeBranch b) or
7789
TBuiltinClassless(string ret, string name, string args) { isBuiltinClassless(ret, name, args) } or
7890
TBuiltinMember(string qual, string ret, string name, string args) {
7991
isBuiltinMember(qual, ret, name, args)
@@ -101,7 +113,7 @@ class PredicateOrBuiltin extends TPredOrBuiltin {
101113
)
102114
}
103115

104-
Predicate getDeclaration() { none() }
116+
AstNode getDeclaration() { none() }
105117

106118
Type getDeclaringType() { none() }
107119

@@ -127,6 +139,7 @@ private class DefinedPredicate extends PredicateOrBuiltin, TPred {
127139

128140
override Type getParameterType(int i) { result = decl.getParameter(i).getType() }
129141

142+
// Can be removed when all types can be resolved
130143
override int getArity() { result = decl.getArity() }
131144

132145
override Type getDeclaringType() {
@@ -140,6 +153,27 @@ private class DefinedPredicate extends PredicateOrBuiltin, TPred {
140153
}
141154
}
142155

156+
private class DefinedNewTypeBranch extends PredicateOrBuiltin, TNewTypeBranch {
157+
NewTypeBranch b;
158+
159+
DefinedNewTypeBranch() { this = TNewTypeBranch(b) }
160+
161+
override NewTypeBranch getDeclaration() { result = b }
162+
163+
override string getName() { result = b.getName() }
164+
165+
override NewTypeBranchType getReturnType() { result.getDeclaration() = b }
166+
167+
override Type getParameterType(int i) { result = b.getField(i).getType() }
168+
169+
// Can be removed when all types can be resolved
170+
override int getArity() { result = count(b.getField(_)) }
171+
172+
override Type getDeclaringType() { none() }
173+
174+
override predicate isPrivate() { b.getNewType().isPrivate() }
175+
}
176+
143177
private class TBuiltin = TBuiltinClassless or TBuiltinMember;
144178

145179
class BuiltinPredicate extends PredicateOrBuiltin, TBuiltin { }
@@ -183,6 +217,7 @@ module PredConsistency {
183217

184218
query predicate noResolveCall(Call c) {
185219
not resolveCall(c, _) and
220+
not c instanceof NoneCall and
186221
not c.getLocation().getFile().getAbsolutePath().regexpMatch(".*/(test|examples)/.*")
187222
}
188223

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

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -61,11 +61,24 @@ class Type extends TType {
6161
)
6262
}
6363

64+
pragma[nomagic]
65+
private predicate getClassPredicate0(string name, int arity, PredicateOrBuiltin p, Type t) {
66+
p = classPredCandidate(this, name, arity) and
67+
t = p.getDeclaringType().getASuperType+()
68+
}
69+
70+
pragma[nomagic]
71+
private predicate getClassPredicate1(
72+
string name, int arity, PredicateOrBuiltin p1, PredicateOrBuiltin p2
73+
) {
74+
getClassPredicate0(name, arity, p1, p2.getDeclaringType()) and
75+
p2 = classPredCandidate(this, name, arity)
76+
}
77+
78+
pragma[nomagic]
6479
PredicateOrBuiltin getClassPredicate(string name, int arity) {
6580
result = classPredCandidate(this, name, arity) and
66-
not exists(PredicateOrBuiltin other | other = classPredCandidate(this, name, arity) |
67-
other.getDeclaringType().getASuperType+() = result.getDeclaringType()
68-
)
81+
not getClassPredicate1(name, arity, _, result)
6982
}
7083
}
7184

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

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

1212
/** Gets a variable declared directly in this scope. */
13-
VarDef getADefinition() { result.getParent() = this }
13+
VarDef getADefinition(string name) {
14+
result.getParent() = this and
15+
name = result.getName()
16+
}
1417

1518
/** 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()
19-
or
20-
decl = this.(Select).getExpr(_).(AsExpr)
21-
or
22-
decl = this.(Aggregate).getExpr(_).(AsExpr)
23-
or
24-
decl = this.(ExprAggregate).getExpr(_).(AsExpr)
25-
or
26-
this.getOuterScope().containsVar(decl) and
27-
not this.getADefinition().getName() = decl.getName()
19+
predicate containsVar(VarDef decl, string name) {
20+
name = decl.getName() and
21+
(
22+
not this instanceof Class and
23+
decl = this.getADefinition(name)
24+
or
25+
decl = this.(Select).getExpr(_).(AsExpr)
26+
or
27+
decl = this.(Aggregate).getExpr(_).(AsExpr)
28+
or
29+
decl = this.(ExprAggregate).getExpr(_).(AsExpr)
30+
or
31+
this.getOuterScope().containsVar(decl, name) and
32+
not exists(this.getADefinition(name))
33+
)
2834
}
2935

3036
/** Holds if this scope contains field `decl`, either directly or inherited. */
31-
predicate containsField(VarDef decl) {
32-
decl = this.(Class).getAField()
33-
or
34-
this.getOuterScope().containsField(decl) and
35-
not this.getADefinition().getName() = decl.getName()
36-
or
37-
exists(VariableScope sup |
38-
sup = this.(Class).getASuperType().getResolvedType().(ClassType).getDeclaration() and
39-
sup.containsField(decl) and
40-
not this.(Class).getAField().getName() = decl.getName()
37+
predicate containsField(VarDef decl, string name) {
38+
name = decl.getName() and
39+
(
40+
decl = this.(Class).getAField()
41+
or
42+
this.getOuterScope().containsField(decl, name) and
43+
not exists(this.getADefinition(name))
44+
or
45+
exists(VariableScope sup |
46+
sup = this.(Class).getASuperType().getResolvedType().(ClassType).getDeclaration() and
47+
sup.containsField(decl, name) and
48+
not this.(Class).getAField().getName() = name
49+
)
4150
)
4251
}
4352
}
@@ -56,15 +65,9 @@ private string getName(Identifier i) {
5665
)
5766
}
5867

59-
predicate resolveVariable(Identifier i, VarDef decl) {
60-
scopeOf(i).containsVar(decl) and
61-
decl.getName() = getName(i)
62-
}
68+
predicate resolveVariable(Identifier i, VarDef decl) { scopeOf(i).containsVar(decl, getName(i)) }
6369

64-
predicate resolveField(Identifier i, VarDef decl) {
65-
scopeOf(i).containsField(decl) and
66-
decl.getName() = getName(i)
67-
}
70+
predicate resolveField(Identifier i, VarDef decl) { scopeOf(i).containsField(decl, getName(i)) }
6871

6972
module VarConsistency {
7073
query predicate multipleVarDefs(VarAccess v, VarDef decl) {

0 commit comments

Comments
 (0)