Skip to content

Commit 4f410f5

Browse files
authored
QL: Merge pull request #14 from github/predicate-expr-resolution
Resolve predicate expressions
2 parents 93fa56f + 0eabd4f commit 4f410f5

8 files changed

Lines changed: 127 additions & 31 deletions

File tree

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
import codeql_ql.ast.internal.Predicate::PredConsistency

ql/src/codeql_ql/ast/Ast.qll

Lines changed: 39 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import ql
22
private import codeql_ql.ast.internal.AstNodes
33
private import codeql_ql.ast.internal.Module
4+
private import codeql_ql.ast.internal.Predicate
45
private import codeql_ql.ast.internal.Type
56

67
/** An AST node of a QL program */
@@ -82,13 +83,30 @@ class PredicateExpr extends TPredicateExpr, AstNode {
8283

8384
override string toString() { result = "predicate" }
8485

86+
string getName() {
87+
exists(Generated::AritylessPredicateExpr ape, Generated::LiteralId id |
88+
ape.getParent() = pe and
89+
id.getParent() = ape and
90+
result = id.getValue()
91+
)
92+
}
93+
94+
int getArity() {
95+
exists(Generated::Integer i |
96+
i.getParent() = pe and
97+
result = i.getValue().toInt()
98+
)
99+
}
100+
85101
ModuleExpr getQualifier() {
86102
exists(Generated::AritylessPredicateExpr ape |
87103
ape.getParent() = pe and
88104
toGenerated(result).getParent() = ape
89105
)
90106
}
91107

108+
Predicate getResolvedPredicate() { resolvePredicateExpr(this, result) }
109+
92110
override AstNode getParent() {
93111
this in [result.(ClasslessPredicate).getAlias(), result.(HigherOrderFormula).getInput(_)]
94112
}
@@ -99,7 +117,7 @@ class PredicateExpr extends TPredicateExpr, AstNode {
99117
/**
100118
* A classless predicate.
101119
*/
102-
class ClasslessPredicate extends TClasslessPredicate, Predicate, ModuleMember {
120+
class ClasslessPredicate extends TClasslessPredicate, Predicate, ModuleDeclaration {
103121
Generated::ModuleMember member;
104122
Generated::ClasslessPredicate pred;
105123

@@ -253,7 +271,7 @@ class TypeExpr extends TType, AstNode {
253271
/**
254272
* A QL module.
255273
*/
256-
class Module extends TModule, AstNode, ModuleMember {
274+
class Module extends TModule, ModuleDeclaration {
257275
Generated::Module mod;
258276

259277
Module() { this = TModule(mod) }
@@ -267,10 +285,7 @@ class Module extends TModule, AstNode, ModuleMember {
267285
)
268286
}
269287

270-
/**
271-
* Gets the name of the module.
272-
*/
273-
string getName() { result = mod.getName().(Generated::ModuleName).getChild().getValue() }
288+
override string getName() { result = mod.getName().(Generated::ModuleName).getChild().getValue() }
274289

275290
/**
276291
* Gets a member of the module.
@@ -297,10 +312,22 @@ class ModuleMember extends TModuleMember, AstNode {
297312
predicate isPrivate() { none() } // TODO: Implement.
298313
}
299314

315+
/** A declaration. */
316+
class Declaration extends TDeclaration, AstNode {
317+
/** Gets the name of this declaration. */
318+
string getName() { none() }
319+
}
320+
321+
/** An entity that can be declared in a module. */
322+
class ModuleDeclaration extends TModuleDeclaration, Declaration, ModuleMember { }
323+
324+
/** An type declaration. Either a `class` or a `newtype`. */
325+
class TypeDeclaration extends TTypeDeclaration, Declaration { }
326+
300327
/**
301328
* A QL class.
302329
*/
303-
class Class extends TClass, AstNode, ModuleMember {
330+
class Class extends TClass, TypeDeclaration, ModuleDeclaration {
304331
Generated::Dataclass cls;
305332

306333
Class() { this = TClass(cls) }
@@ -314,10 +341,7 @@ class Class extends TClass, AstNode, ModuleMember {
314341
)
315342
}
316343

317-
/**
318-
* Gets the name of the class.
319-
*/
320-
string getName() { result = cls.getName().getValue() }
344+
override string getName() { result = cls.getName().getValue() }
321345

322346
/**
323347
* Gets the charateristic predicate for this class.
@@ -365,12 +389,12 @@ class Class extends TClass, AstNode, ModuleMember {
365389
/**
366390
* A `newtype Foo` declaration.
367391
*/
368-
class NewType extends TNewType, ModuleMember {
392+
class NewType extends TNewType, TypeDeclaration, ModuleDeclaration {
369393
Generated::Datatype type;
370394

371395
NewType() { this = TNewType(type) }
372396

373-
string getName() { result = type.getName().getValue() }
397+
override string getName() { result = type.getName().getValue() }
374398

375399
override string getAPrimaryQlClass() { result = "NewType" }
376400

@@ -390,15 +414,14 @@ class NewType extends TNewType, ModuleMember {
390414
/**
391415
* A branch in a `newtype`.
392416
*/
393-
class NewTypeBranch extends TNewTypeBranch, AstNode {
417+
class NewTypeBranch extends TNewTypeBranch, TypeDeclaration {
394418
Generated::DatatypeBranch branch;
395419

396420
NewTypeBranch() { this = TNewTypeBranch(branch) }
397421

398422
override string getAPrimaryQlClass() { result = "NewTypeBranch" }
399423

400-
/** Gets the name of this branch. */
401-
string getName() { result = branch.getName().getValue() }
424+
override string getName() { result = branch.getName().getValue() }
402425

403426
/** Gets a field in this branch. */
404427
VarDecl getField(int i) {

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

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -154,4 +154,10 @@ Generated::AstNode toGenerated(AST::AstNode n) {
154154

155155
class TPredicate = TCharPred or TClasslessPredicate or TClassPredicate;
156156

157-
class TModuleMember = TClasslessPredicate or TClass or TModule or TNewType or TImport or TSelect;
157+
class TModuleMember = TModuleDeclaration or TImport or TSelect;
158+
159+
class TDeclaration = TTypeDeclaration or TModuleDeclaration;
160+
161+
class TTypeDeclaration = TClass or TNewType or TNewTypeBranch;
162+
163+
class TModuleDeclaration = TClasslessPredicate or TModule or TClass or TNewType;

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

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,7 @@ private predicate resolveQualifiedName(Import imp, ContainerOrModule m, int i) {
121121
m = TFolder(c)
122122
)
123123
or
124-
defines(getEnclosingModule(imp).getEnclosing*(), q, m, _)
124+
definesModule(getEnclosingModule(imp).getEnclosing*(), q, m, _)
125125
)
126126
or
127127
exists(Folder_ mid |
@@ -142,7 +142,7 @@ private predicate resolveSelectionName(Import imp, ContainerOrModule m, int i) {
142142
or
143143
exists(ContainerOrModule mid |
144144
resolveSelectionName(imp, mid, i - 1) and
145-
defines(mid, imp.getSelectionName(i), m, true)
145+
definesModule(mid, imp.getSelectionName(i), m, true)
146146
)
147147
}
148148

@@ -158,20 +158,22 @@ predicate resolve(Import imp, FileOrModule m) {
158158
predicate resolveModuleExpr(ModuleExpr me, FileOrModule m) {
159159
not m = TFile(any(File f | f.getExtension() = "ql")) and
160160
not exists(me.getQualifier()) and
161-
defines(getEnclosingModule(me).getEnclosing*(), me.getName(), m, _)
161+
definesModule(getEnclosingModule(me).getEnclosing*(), me.getName(), m, _)
162162
or
163163
exists(FileOrModule mid |
164164
resolveModuleExpr(me.getQualifier(), mid) and
165-
defines(mid, me.getName(), m, true)
165+
definesModule(mid, me.getName(), m, true)
166166
)
167167
}
168168

169-
private boolean getPublicBool(ModuleMember m) {
170-
if m.isPrivate() then result = false else result = true
171-
}
169+
boolean getPublicBool(ModuleMember m) { if m.isPrivate() then result = false else result = true }
172170

173-
/** Holds if `container` defines module `m` with name `name`. */
174-
private predicate defines(
171+
/**
172+
* Holds if `container` defines module `m` with name `name`.
173+
*
174+
* `m` may be defined either directly or through `import`s.
175+
*/
176+
private predicate definesModule(
175177
ContainerOrModule container, string name, ContainerOrModule m, boolean public
176178
) {
177179
container = m.getEnclosing() and
@@ -188,7 +190,7 @@ private predicate defines(
188190
container = getEnclosingModule(imp) and
189191
resolve(imp, m0) and
190192
not exists(imp.importedAs()) and
191-
defines(m0, name, m, true) and
193+
definesModule(m0, name, m, true) and
192194
public = getPublicBool(imp)
193195
)
194196
or
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
import ql
2+
private import codeql_ql.ast.internal.Module
3+
4+
private predicate definesPredicate(FileOrModule m, string name, ClasslessPredicate p, boolean public) {
5+
m = getEnclosingModule(p) and
6+
name = p.getName() and
7+
public = getPublicBool(p)
8+
or
9+
// import X
10+
exists(Import imp, FileOrModule m0 |
11+
m = getEnclosingModule(imp) and
12+
m0 = imp.getResolvedModule() and
13+
not exists(imp.importedAs()) and
14+
definesPredicate(m0, name, p, true) and
15+
public = getPublicBool(imp)
16+
)
17+
or
18+
// predicate X = Y
19+
exists(ClasslessPredicate alias |
20+
m = getEnclosingModule(alias) and
21+
name = alias.getName() and
22+
resolvePredicateExpr(alias.getAlias(), p) and
23+
public = getPublicBool(alias)
24+
)
25+
}
26+
27+
predicate resolvePredicateExpr(PredicateExpr pe, ClasslessPredicate p) {
28+
exists(FileOrModule m, boolean public |
29+
not exists(pe.getQualifier()) and
30+
m = getEnclosingModule(pe).getEnclosing*() and
31+
public = [false, true]
32+
or
33+
m = pe.getQualifier().getResolvedModule() and
34+
public = true
35+
|
36+
definesPredicate(m, pe.getName(), p, public) and
37+
count(p.getParameter(_)) = pe.getArity()
38+
)
39+
}
40+
41+
module PredConsistency {
42+
query predicate noResolvePredicateExpr(PredicateExpr pe) {
43+
not resolvePredicateExpr(pe, _) and
44+
not pe.getLocation().getFile().getAbsolutePath().regexpMatch(".*/(test|examples)/.*")
45+
}
46+
47+
query predicate multipleResolvePredicateExpr(PredicateExpr pe, int c, ClasslessPredicate p) {
48+
c = strictcount(ClasslessPredicate p0 | resolvePredicateExpr(pe, p0)) and
49+
c > 1 and
50+
resolvePredicateExpr(pe, p)
51+
}
52+
}

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

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -207,10 +207,6 @@ private predicate qualifier(TypeExpr te, FileOrModule m, boolean public) {
207207
)
208208
}
209209

210-
private boolean getPublicBool(ModuleMember m) {
211-
if m.isPrivate() then result = false else result = true
212-
}
213-
214210
private predicate defines(FileOrModule m, string name, Type t, boolean public) {
215211
exists(Class ty | t = TClass(ty) |
216212
getEnclosingModule(ty) = m and

ql/src/ide-contextual-queries/localDefinitions.ql

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,10 +50,18 @@ predicate resolveType(TypeExpr ref, AstNode target, string kind) {
5050
ref.getLocation().getFile() = getFileBySourceArchiveName(selectedSourceFile())
5151
}
5252

53+
predicate resolvePredicate(PredicateExpr ref, Predicate target, string kind) {
54+
target = ref.getResolvedPredicate() and
55+
kind = "predicate" and
56+
ref.getLocation().getFile() = getFileBySourceArchiveName(selectedSourceFile())
57+
}
58+
5359
predicate resolve(Loc ref, Loc target, string kind) {
5460
resolveModule(ref.asAst(), target.asMod(), kind)
5561
or
5662
resolveType(ref.asAst(), target.asAst(), kind)
63+
or
64+
resolvePredicate(ref.asAst(), target.asAst(), kind)
5765
}
5866

5967
from Loc ref, Loc target, string kind

ql/src/ide-contextual-queries/localReferences.ql

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,10 +49,18 @@ predicate resolveType(TypeExpr ref, AstNode target, string kind) {
4949
ref.getLocation().getFile() = getFileBySourceArchiveName(selectedSourceFile())
5050
}
5151

52+
predicate resolvePredicate(PredicateExpr ref, Predicate target, string kind) {
53+
target = ref.getResolvedPredicate() and
54+
kind = "predicate" and
55+
ref.getLocation().getFile() = getFileBySourceArchiveName(selectedSourceFile())
56+
}
57+
5258
predicate resolve(Loc ref, Loc target, string kind) {
5359
resolveModule(ref.asAst(), target.asMod(), kind)
5460
or
5561
resolveType(ref.asAst(), target.asAst(), kind)
62+
or
63+
resolvePredicate(ref.asAst(), target.asAst(), kind)
5664
}
5765

5866
from Loc ref, Loc target, string kind

0 commit comments

Comments
 (0)