Skip to content

Commit 84556fb

Browse files
authored
Merge pull request #9575 from erik-krogh/paramModules
QL: support for parameterized modules
2 parents 92b8c0f + 80f6677 commit 84556fb

File tree

15 files changed

+313
-70
lines changed

15 files changed

+313
-70
lines changed

ql/Cargo.lock

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

ql/extractor/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ edition = "2018"
1010
flate2 = "1.0"
1111
node-types = { path = "../node-types" }
1212
tree-sitter = "0.19"
13-
tree-sitter-ql = { git = "https://github.com/tausbn/tree-sitter-ql.git", rev = "c3d626a77cf5acc5d8c11aaf91c12348880c8eca" }
13+
tree-sitter-ql = { git = "https://github.com/erik-krogh/tree-sitter-ql.git", rev = "343cc5873e20510586ade803659ef8ce153bd603" }
1414
clap = "2.33"
1515
tracing = "0.1"
1616
tracing-subscriber = { version = "0.3.3", features = ["env-filter"] }

ql/generator/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,4 +11,4 @@ clap = "2.33"
1111
node-types = { path = "../node-types" }
1212
tracing = "0.1"
1313
tracing-subscriber = { version = "0.3.3", features = ["env-filter"] }
14-
tree-sitter-ql = { git = "https://github.com/tausbn/tree-sitter-ql.git", rev = "c3d626a77cf5acc5d8c11aaf91c12348880c8eca" }
14+
tree-sitter-ql = { git = "https://github.com/erik-krogh/tree-sitter-ql.git", rev = "343cc5873e20510586ade803659ef8ce153bd603" }

ql/ql/src/codeql_ql/ast/Ast.qll

Lines changed: 78 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,8 @@ class QLDoc extends TQLDoc, AstNode {
162162
string getContents() { result = qldoc.getValue() }
163163

164164
override string getAPrimaryQlClass() { result = "QLDoc" }
165+
166+
override AstNode getParent() { result.getQLDoc() = this }
165167
}
166168

167169
class BlockComment extends TBlockComment, AstNode {
@@ -638,7 +640,7 @@ class FieldDecl extends TFieldDecl, AstNode {
638640
/**
639641
* A type reference, such as `DataFlow::Node`.
640642
*/
641-
class TypeExpr extends TType, AstNode {
643+
class TypeExpr extends TType, TypeRef {
642644
QL::TypeExpr type;
643645

644646
TypeExpr() { this = TType(type) }
@@ -675,10 +677,14 @@ class TypeExpr extends TType, AstNode {
675677
*/
676678
ModuleExpr getModule() { toQL(result) = type.getQualifier() }
677679

678-
/**
679-
* Gets the type that this type reference refers to.
680-
*/
681-
Type getResolvedType() { resolveTypeExpr(this, result) }
680+
/** Gets the type that this type reference refers to. */
681+
override Type getResolvedType() {
682+
// resolve type
683+
resolveTypeExpr(this, result)
684+
or
685+
// if it resolves to a module
686+
exists(FileOrModule mod | resolveModuleRef(this, mod) | result = mod.toType())
687+
}
682688

683689
override AstNode getAChild(string pred) {
684690
result = super.getAChild(pred)
@@ -710,6 +716,9 @@ class Module extends TModule, ModuleDeclaration {
710716
exists(int i | result = this.getMember(i) and m = this.getMember(i + 1))
711717
}
712718

719+
/** Gets a ref to the module that this module implements. */
720+
TypeExpr getImplements(int i) { toQL(result) = mod.getImplements(i).getTypeExpr() }
721+
713722
/** Gets the module expression that this module is an alias for, if any. */
714723
ModuleExpr getAlias() { toQL(result) = mod.getAFieldOrChild().(QL::ModuleAliasBody).getChild() }
715724

@@ -719,6 +728,19 @@ class Module extends TModule, ModuleDeclaration {
719728
pred = directMember("getAlias") and result = this.getAlias()
720729
or
721730
pred = directMember("getAMember") and result = this.getAMember()
731+
or
732+
exists(int i | pred = indexedMember("getImplements", i) and result = this.getImplements(i))
733+
or
734+
exists(int i | pred = indexedMember("hasParameter", i) and this.hasParameter(i, _, result))
735+
}
736+
737+
/** Holds if the `i`th parameter of this module has `name` and type `sig`. */
738+
predicate hasParameter(int i, string name, SignatureExpr sig) {
739+
exists(QL::ModuleParam param |
740+
param = mod.getParameter(i) and
741+
name = param.getParameter().getValue() and
742+
sig.toQL() = param.getSignature()
743+
)
722744
}
723745
}
724746

@@ -1093,16 +1115,18 @@ class InlineCast extends TInlineCast, Expr {
10931115
}
10941116
}
10951117

1096-
/** An entity that resolves to a module. */
1097-
class ModuleRef extends AstNode, TModuleRef {
1098-
/** Gets the module that this entity resolves to. */
1099-
FileOrModule getResolvedModule() { none() }
1118+
/** An entity that resolves to a type. */
1119+
class TypeRef extends AstNode, TTypeRef {
1120+
abstract Type getResolvedType();
1121+
1122+
/** Gets the module that this entity resolves to, if this reference resolves to a module */
1123+
final FileOrModule getResolvedModule() { result.toType() = this.getResolvedType() }
11001124
}
11011125

11021126
/**
11031127
* An import statement.
11041128
*/
1105-
class Import extends TImport, ModuleMember, ModuleRef {
1129+
class Import extends TImport, ModuleMember, TypeRef {
11061130
QL::ImportDirective imp;
11071131

11081132
Import() { this = TImport(imp) }
@@ -1153,7 +1177,9 @@ class Import extends TImport, ModuleMember, ModuleRef {
11531177
)
11541178
}
11551179

1156-
final override FileOrModule getResolvedModule() { resolve(this, result) }
1180+
override Type getResolvedType() {
1181+
exists(FileOrModule mod | resolve(this, mod) | result = mod.toType())
1182+
}
11571183
}
11581184

11591185
/** A formula, such as `x = 6 and y < 5`. */
@@ -2172,7 +2198,7 @@ class DontCare extends TDontCare, Expr {
21722198
}
21732199

21742200
/** A module expression. Such as `DataFlow` in `DataFlow::Node` */
2175-
class ModuleExpr extends TModuleExpr, ModuleRef {
2201+
class ModuleExpr extends TModuleExpr, TypeRef {
21762202
QL::ModuleExpr me;
21772203

21782204
ModuleExpr() { this = TModuleExpr(me) }
@@ -2190,6 +2216,10 @@ class ModuleExpr extends TModuleExpr, ModuleRef {
21902216
result = me.getName().(QL::SimpleId).getValue()
21912217
or
21922218
not exists(me.getName()) and result = me.getChild().(QL::SimpleId).getValue()
2219+
or
2220+
exists(QL::ModuleInstantiation instantiation | instantiation.getParent() = me |
2221+
result = instantiation.getName().getChild().getValue()
2222+
)
21932223
}
21942224

21952225
/**
@@ -2203,7 +2233,9 @@ class ModuleExpr extends TModuleExpr, ModuleRef {
22032233
*/
22042234
ModuleExpr getQualifier() { result = TModuleExpr(me.getChild()) }
22052235

2206-
final override FileOrModule getResolvedModule() { resolveModuleExpr(this, result) }
2236+
override Type getResolvedType() {
2237+
exists(FileOrModule mod | resolveModuleRef(this, mod) | result = mod.toType())
2238+
}
22072239

22082240
final override string toString() { result = this.getName() }
22092241

@@ -2213,9 +2245,41 @@ class ModuleExpr extends TModuleExpr, ModuleRef {
22132245
result = super.getAChild(pred)
22142246
or
22152247
pred = directMember("getQualifier") and result = this.getQualifier()
2248+
or
2249+
exists(int i | pred = indexedMember("getArgument", i) and result = this.getArgument(i))
2250+
}
2251+
2252+
/**
2253+
* Gets the `i`th type argument if this module is a module instantiation.
2254+
* The result is either a `PredicateExpr` or a `TypeExpr`.
2255+
*/
2256+
SignatureExpr getArgument(int i) {
2257+
exists(QL::ModuleInstantiation instantiation | instantiation.getParent() = me |
2258+
result.toQL() = instantiation.getChild(i)
2259+
)
22162260
}
22172261
}
22182262

2263+
/** A signature expression, either a `PredicateExpr` or a `TypeExpr`. */
2264+
class SignatureExpr extends TSignatureExpr, AstNode {
2265+
QL::SignatureExpr sig;
2266+
2267+
SignatureExpr() {
2268+
toQL(this) = sig.getPredicate()
2269+
or
2270+
toQL(this) = sig.getTypeExpr()
2271+
}
2272+
2273+
/** Gets the generated AST node that contains this signature expression. */
2274+
QL::SignatureExpr toQL() { result = sig }
2275+
2276+
/** Gets this signature expression if it represents a predicate expression. */
2277+
PredicateExpr asPredicate() { result = this }
2278+
2279+
/** Gets this signature expression if it represents a type expression. */
2280+
TypeExpr asType() { result = this }
2281+
}
2282+
22192283
/** An argument to an annotation. */
22202284
private class AnnotationArg extends TAnnotationArg, AstNode {
22212285
QL::AnnotArg arg;
@@ -2272,7 +2336,7 @@ class Annotation extends TAnnotation, AstNode {
22722336
/** Gets the node corresponding to the field `name`. */
22732337
string getName() { result = annot.getName().getValue() }
22742338

2275-
override AstNode getParent() { result = AstNode.super.getParent() }
2339+
override AstNode getParent() { result.getAnAnnotation() = this }
22762340

22772341
override AstNode getAChild(string pred) {
22782342
result = super.getAChild(pred)

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

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,10 +83,12 @@ class TExpr =
8383

8484
class TCall = TPredicateCall or TMemberCall or TNoneCall or TAnyCall;
8585

86-
class TModuleRef = TImport or TModuleExpr;
86+
class TTypeRef = TImport or TModuleExpr or TType;
8787

8888
class TYamlNode = TYamlCommemt or TYamlEntry or TYamlKey or TYamlListitem or TYamlValue;
8989

90+
class TSignatureExpr = TPredicateExpr or TType;
91+
9092
/** DEPRECATED: Alias for TYamlNode */
9193
deprecated class TYAMLNode = TYamlNode;
9294

@@ -229,4 +231,6 @@ module AstConsistency {
229231
not node instanceof YAML::YAMLNode and // parents for YAML doens't work
230232
not (node instanceof QLDoc and node.getLocation().getFile().getExtension() = "dbscheme") // qldoc in dbschemes are not hooked up
231233
}
234+
235+
query predicate nonUniqueParent(AstNode node) { count(node.getParent()) >= 2 }
232236
}

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

Lines changed: 51 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -23,24 +23,30 @@ private class ContainerOrModule extends TContainerOrModule {
2323
or
2424
this = TFolder(_) and result = "folder"
2525
}
26-
}
27-
28-
private class TFileOrModule = TFile or TModule;
2926

30-
/** A file or a module. */
31-
class FileOrModule extends TFileOrModule, ContainerOrModule {
3227
/** Gets the module for this imported module. */
3328
Module asModule() { this = TModule(result) }
3429

3530
/** Gets the file for this file. */
3631
File asFile() { this = TFile(result) }
32+
}
33+
34+
private class TFileOrModule = TFile or TModule;
3735

36+
/** A file or a module. */
37+
class FileOrModule extends TFileOrModule, ContainerOrModule {
3838
/** Gets the file that contains this module/file. */
3939
File getFile() {
4040
result = this.asFile()
4141
or
4242
result = this.asModule().getLocation().getFile()
4343
}
44+
45+
Type toType() {
46+
result.(FileType).getDeclaration().getLocation().getFile() = this.asFile()
47+
or
48+
result.(ModuleType).getDeclaration() = this.asModule()
49+
}
4450
}
4551

4652
private class File_ extends FileOrModule, TFile {
@@ -207,31 +213,34 @@ private module Cached {
207213

208214
/** Holds if module expression `me` resolves to `m`. */
209215
cached
210-
predicate resolveModuleExpr(ModuleExpr me, FileOrModule m) {
216+
predicate resolveModuleRef(TypeRef me, FileOrModule m) {
211217
not m = TFile(any(File f | f.getExtension() = "ql")) and
212-
not exists(me.getQualifier()) and
213-
exists(ContainerOrModule enclosing, string name | resolveModuleExprHelper(me, enclosing, name) |
218+
not exists(me.(ModuleExpr).getQualifier()) and
219+
exists(ContainerOrModule enclosing, string name | resolveModuleRefHelper(me, enclosing, name) |
214220
definesModule(enclosing, name, m, _)
215221
)
216222
or
217223
exists(FileOrModule mid |
218-
resolveModuleExpr(me.getQualifier(), mid) and
219-
definesModule(mid, me.getName(), m, true)
224+
resolveModuleRef(me.(ModuleExpr).getQualifier(), mid) and
225+
definesModule(mid, me.(ModuleExpr).getName(), m, true)
220226
)
221227
}
222228

223229
pragma[noinline]
224-
private predicate resolveModuleExprHelper(ModuleExpr me, ContainerOrModule enclosing, string name) {
230+
private predicate resolveModuleRefHelper(TypeRef me, ContainerOrModule enclosing, string name) {
225231
enclosing = getEnclosingModule(me).getEnclosing*() and
226-
name = me.getName()
232+
name = [me.(ModuleExpr).getName(), me.(TypeExpr).getClassName()]
227233
}
228234
}
229235

230236
import Cached
231237
private import NewType
232238

233239
boolean getPublicBool(AstNode n) {
234-
if n.(ModuleMember).isPrivate() or n.(NewTypeBranch).getNewType().isPrivate()
240+
if
241+
n.(ModuleMember).isPrivate() or
242+
n.(NewTypeBranch).getNewType().isPrivate() or
243+
n.(Module).isPrivate()
235244
then result = false
236245
else result = true
237246
}
@@ -253,6 +262,22 @@ private predicate definesModule(
253262
m = TModule(any(Module mod | public = getPublicBool(mod)))
254263
)
255264
or
265+
// signature module in a paramertized module
266+
exists(Module mod, SignatureExpr sig, TypeExpr ty, int i |
267+
mod = container.asModule() and
268+
mod.hasParameter(i, name, sig) and
269+
public = false and
270+
ty = sig.asType()
271+
|
272+
// resolve to the signature module
273+
m = ty.getResolvedModule()
274+
or
275+
// resolve to the arguments of the instantiated module
276+
exists(ModuleExpr inst | inst.getResolvedModule().asModule() = mod |
277+
m = inst.getArgument(i).asType().getResolvedModule()
278+
)
279+
)
280+
or
256281
// import X
257282
exists(Import imp, ContainerOrModule m0 |
258283
container = getEnclosingModule(imp) and
@@ -274,7 +299,7 @@ private predicate definesModule(
274299
exists(Module alias |
275300
container = getEnclosingModule(alias) and
276301
name = alias.getName() and
277-
resolveModuleExpr(alias.getAlias(), m) and
302+
resolveModuleRef(alias.getAlias(), m) and
278303
public = getPublicBool(alias)
279304
)
280305
}
@@ -288,14 +313,6 @@ module ModConsistency {
288313
.regexpMatch(".*/(test|examples|ql-training|recorded-call-graph-metrics)/.*")
289314
}
290315

291-
query predicate noResolveModuleExpr(ModuleExpr me) {
292-
not resolveModuleExpr(me, _) and
293-
not me.getLocation()
294-
.getFile()
295-
.getAbsolutePath()
296-
.regexpMatch(".*/(test|examples|ql-training|recorded-call-graph-metrics)/.*")
297-
}
298-
299316
query predicate multipleResolve(Import imp, int c, ContainerOrModule m) {
300317
c = strictcount(ContainerOrModule m0 | resolve(imp, m0)) and
301318
c > 1 and
@@ -306,9 +323,16 @@ module ModConsistency {
306323
.regexpMatch(".*/(test|examples|ql-training|recorded-call-graph-metrics)/.*")
307324
}
308325

309-
query predicate multipleResolveModuleExpr(ModuleExpr me, int c, ContainerOrModule m) {
310-
c = strictcount(ContainerOrModule m0 | resolveModuleExpr(me, m0)) and
311-
c > 1 and
312-
resolveModuleExpr(me, m)
313-
}
326+
// This can happen with parameterized modules.
327+
/*
328+
* query predicate multipleResolveModuleRef(ModuleExpr me, int c, ContainerOrModule m) {
329+
* c = strictcount(ContainerOrModule m0 | resolveModuleRef(me, m0)) and
330+
* c > 1 and
331+
* resolveModuleRef(me, m)
332+
* }
333+
*/
334+
335+
query predicate noName(Module mod) { not exists(mod.getName()) }
336+
337+
query predicate nonUniqueName(Module mod) { count(mod.getName()) >= 2 }
314338
}

0 commit comments

Comments
 (0)