mirror of
https://github.com/github/codeql.git
synced 2025-12-16 16:53:25 +01:00
Merge pull request #9575 from erik-krogh/paramModules
QL: support for parameterized modules
This commit is contained in:
BIN
ql/Cargo.lock
generated
BIN
ql/Cargo.lock
generated
Binary file not shown.
@@ -10,7 +10,7 @@ edition = "2018"
|
||||
flate2 = "1.0"
|
||||
node-types = { path = "../node-types" }
|
||||
tree-sitter = "0.19"
|
||||
tree-sitter-ql = { git = "https://github.com/tausbn/tree-sitter-ql.git", rev = "c3d626a77cf5acc5d8c11aaf91c12348880c8eca" }
|
||||
tree-sitter-ql = { git = "https://github.com/erik-krogh/tree-sitter-ql.git", rev = "343cc5873e20510586ade803659ef8ce153bd603" }
|
||||
clap = "2.33"
|
||||
tracing = "0.1"
|
||||
tracing-subscriber = { version = "0.3.3", features = ["env-filter"] }
|
||||
|
||||
@@ -11,4 +11,4 @@ clap = "2.33"
|
||||
node-types = { path = "../node-types" }
|
||||
tracing = "0.1"
|
||||
tracing-subscriber = { version = "0.3.3", features = ["env-filter"] }
|
||||
tree-sitter-ql = { git = "https://github.com/tausbn/tree-sitter-ql.git", rev = "c3d626a77cf5acc5d8c11aaf91c12348880c8eca" }
|
||||
tree-sitter-ql = { git = "https://github.com/erik-krogh/tree-sitter-ql.git", rev = "343cc5873e20510586ade803659ef8ce153bd603" }
|
||||
|
||||
@@ -162,6 +162,8 @@ class QLDoc extends TQLDoc, AstNode {
|
||||
string getContents() { result = qldoc.getValue() }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "QLDoc" }
|
||||
|
||||
override AstNode getParent() { result.getQLDoc() = this }
|
||||
}
|
||||
|
||||
class BlockComment extends TBlockComment, AstNode {
|
||||
@@ -638,7 +640,7 @@ class FieldDecl extends TFieldDecl, AstNode {
|
||||
/**
|
||||
* A type reference, such as `DataFlow::Node`.
|
||||
*/
|
||||
class TypeExpr extends TType, AstNode {
|
||||
class TypeExpr extends TType, TypeRef {
|
||||
QL::TypeExpr type;
|
||||
|
||||
TypeExpr() { this = TType(type) }
|
||||
@@ -675,10 +677,14 @@ class TypeExpr extends TType, AstNode {
|
||||
*/
|
||||
ModuleExpr getModule() { toQL(result) = type.getQualifier() }
|
||||
|
||||
/**
|
||||
* Gets the type that this type reference refers to.
|
||||
*/
|
||||
Type getResolvedType() { resolveTypeExpr(this, result) }
|
||||
/** Gets the type that this type reference refers to. */
|
||||
override Type getResolvedType() {
|
||||
// resolve type
|
||||
resolveTypeExpr(this, result)
|
||||
or
|
||||
// if it resolves to a module
|
||||
exists(FileOrModule mod | resolveModuleRef(this, mod) | result = mod.toType())
|
||||
}
|
||||
|
||||
override AstNode getAChild(string pred) {
|
||||
result = super.getAChild(pred)
|
||||
@@ -710,6 +716,9 @@ class Module extends TModule, ModuleDeclaration {
|
||||
exists(int i | result = this.getMember(i) and m = this.getMember(i + 1))
|
||||
}
|
||||
|
||||
/** Gets a ref to the module that this module implements. */
|
||||
TypeExpr getImplements(int i) { toQL(result) = mod.getImplements(i).getTypeExpr() }
|
||||
|
||||
/** Gets the module expression that this module is an alias for, if any. */
|
||||
ModuleExpr getAlias() { toQL(result) = mod.getAFieldOrChild().(QL::ModuleAliasBody).getChild() }
|
||||
|
||||
@@ -719,6 +728,19 @@ class Module extends TModule, ModuleDeclaration {
|
||||
pred = directMember("getAlias") and result = this.getAlias()
|
||||
or
|
||||
pred = directMember("getAMember") and result = this.getAMember()
|
||||
or
|
||||
exists(int i | pred = indexedMember("getImplements", i) and result = this.getImplements(i))
|
||||
or
|
||||
exists(int i | pred = indexedMember("hasParameter", i) and this.hasParameter(i, _, result))
|
||||
}
|
||||
|
||||
/** Holds if the `i`th parameter of this module has `name` and type `sig`. */
|
||||
predicate hasParameter(int i, string name, SignatureExpr sig) {
|
||||
exists(QL::ModuleParam param |
|
||||
param = mod.getParameter(i) and
|
||||
name = param.getParameter().getValue() and
|
||||
sig.toQL() = param.getSignature()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1093,16 +1115,18 @@ class InlineCast extends TInlineCast, Expr {
|
||||
}
|
||||
}
|
||||
|
||||
/** An entity that resolves to a module. */
|
||||
class ModuleRef extends AstNode, TModuleRef {
|
||||
/** Gets the module that this entity resolves to. */
|
||||
FileOrModule getResolvedModule() { none() }
|
||||
/** An entity that resolves to a type. */
|
||||
class TypeRef extends AstNode, TTypeRef {
|
||||
abstract Type getResolvedType();
|
||||
|
||||
/** Gets the module that this entity resolves to, if this reference resolves to a module */
|
||||
final FileOrModule getResolvedModule() { result.toType() = this.getResolvedType() }
|
||||
}
|
||||
|
||||
/**
|
||||
* An import statement.
|
||||
*/
|
||||
class Import extends TImport, ModuleMember, ModuleRef {
|
||||
class Import extends TImport, ModuleMember, TypeRef {
|
||||
QL::ImportDirective imp;
|
||||
|
||||
Import() { this = TImport(imp) }
|
||||
@@ -1153,7 +1177,9 @@ class Import extends TImport, ModuleMember, ModuleRef {
|
||||
)
|
||||
}
|
||||
|
||||
final override FileOrModule getResolvedModule() { resolve(this, result) }
|
||||
override Type getResolvedType() {
|
||||
exists(FileOrModule mod | resolve(this, mod) | result = mod.toType())
|
||||
}
|
||||
}
|
||||
|
||||
/** A formula, such as `x = 6 and y < 5`. */
|
||||
@@ -2172,7 +2198,7 @@ class DontCare extends TDontCare, Expr {
|
||||
}
|
||||
|
||||
/** A module expression. Such as `DataFlow` in `DataFlow::Node` */
|
||||
class ModuleExpr extends TModuleExpr, ModuleRef {
|
||||
class ModuleExpr extends TModuleExpr, TypeRef {
|
||||
QL::ModuleExpr me;
|
||||
|
||||
ModuleExpr() { this = TModuleExpr(me) }
|
||||
@@ -2190,6 +2216,10 @@ class ModuleExpr extends TModuleExpr, ModuleRef {
|
||||
result = me.getName().(QL::SimpleId).getValue()
|
||||
or
|
||||
not exists(me.getName()) and result = me.getChild().(QL::SimpleId).getValue()
|
||||
or
|
||||
exists(QL::ModuleInstantiation instantiation | instantiation.getParent() = me |
|
||||
result = instantiation.getName().getChild().getValue()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2203,7 +2233,9 @@ class ModuleExpr extends TModuleExpr, ModuleRef {
|
||||
*/
|
||||
ModuleExpr getQualifier() { result = TModuleExpr(me.getChild()) }
|
||||
|
||||
final override FileOrModule getResolvedModule() { resolveModuleExpr(this, result) }
|
||||
override Type getResolvedType() {
|
||||
exists(FileOrModule mod | resolveModuleRef(this, mod) | result = mod.toType())
|
||||
}
|
||||
|
||||
final override string toString() { result = this.getName() }
|
||||
|
||||
@@ -2213,7 +2245,39 @@ class ModuleExpr extends TModuleExpr, ModuleRef {
|
||||
result = super.getAChild(pred)
|
||||
or
|
||||
pred = directMember("getQualifier") and result = this.getQualifier()
|
||||
or
|
||||
exists(int i | pred = indexedMember("getArgument", i) and result = this.getArgument(i))
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the `i`th type argument if this module is a module instantiation.
|
||||
* The result is either a `PredicateExpr` or a `TypeExpr`.
|
||||
*/
|
||||
SignatureExpr getArgument(int i) {
|
||||
exists(QL::ModuleInstantiation instantiation | instantiation.getParent() = me |
|
||||
result.toQL() = instantiation.getChild(i)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/** A signature expression, either a `PredicateExpr` or a `TypeExpr`. */
|
||||
class SignatureExpr extends TSignatureExpr, AstNode {
|
||||
QL::SignatureExpr sig;
|
||||
|
||||
SignatureExpr() {
|
||||
toQL(this) = sig.getPredicate()
|
||||
or
|
||||
toQL(this) = sig.getTypeExpr()
|
||||
}
|
||||
|
||||
/** Gets the generated AST node that contains this signature expression. */
|
||||
QL::SignatureExpr toQL() { result = sig }
|
||||
|
||||
/** Gets this signature expression if it represents a predicate expression. */
|
||||
PredicateExpr asPredicate() { result = this }
|
||||
|
||||
/** Gets this signature expression if it represents a type expression. */
|
||||
TypeExpr asType() { result = this }
|
||||
}
|
||||
|
||||
/** An argument to an annotation. */
|
||||
@@ -2272,7 +2336,7 @@ class Annotation extends TAnnotation, AstNode {
|
||||
/** Gets the node corresponding to the field `name`. */
|
||||
string getName() { result = annot.getName().getValue() }
|
||||
|
||||
override AstNode getParent() { result = AstNode.super.getParent() }
|
||||
override AstNode getParent() { result.getAnAnnotation() = this }
|
||||
|
||||
override AstNode getAChild(string pred) {
|
||||
result = super.getAChild(pred)
|
||||
|
||||
@@ -83,10 +83,12 @@ class TExpr =
|
||||
|
||||
class TCall = TPredicateCall or TMemberCall or TNoneCall or TAnyCall;
|
||||
|
||||
class TModuleRef = TImport or TModuleExpr;
|
||||
class TTypeRef = TImport or TModuleExpr or TType;
|
||||
|
||||
class TYamlNode = TYamlCommemt or TYamlEntry or TYamlKey or TYamlListitem or TYamlValue;
|
||||
|
||||
class TSignatureExpr = TPredicateExpr or TType;
|
||||
|
||||
/** DEPRECATED: Alias for TYamlNode */
|
||||
deprecated class TYAMLNode = TYamlNode;
|
||||
|
||||
@@ -229,4 +231,6 @@ module AstConsistency {
|
||||
not node instanceof YAML::YAMLNode and // parents for YAML doens't work
|
||||
not (node instanceof QLDoc and node.getLocation().getFile().getExtension() = "dbscheme") // qldoc in dbschemes are not hooked up
|
||||
}
|
||||
|
||||
query predicate nonUniqueParent(AstNode node) { count(node.getParent()) >= 2 }
|
||||
}
|
||||
|
||||
@@ -23,24 +23,30 @@ private class ContainerOrModule extends TContainerOrModule {
|
||||
or
|
||||
this = TFolder(_) and result = "folder"
|
||||
}
|
||||
|
||||
/** Gets the module for this imported module. */
|
||||
Module asModule() { this = TModule(result) }
|
||||
|
||||
/** Gets the file for this file. */
|
||||
File asFile() { this = TFile(result) }
|
||||
}
|
||||
|
||||
private class TFileOrModule = TFile or TModule;
|
||||
|
||||
/** A file or a module. */
|
||||
class FileOrModule extends TFileOrModule, ContainerOrModule {
|
||||
/** Gets the module for this imported module. */
|
||||
Module asModule() { this = TModule(result) }
|
||||
|
||||
/** Gets the file for this file. */
|
||||
File asFile() { this = TFile(result) }
|
||||
|
||||
/** Gets the file that contains this module/file. */
|
||||
File getFile() {
|
||||
result = this.asFile()
|
||||
or
|
||||
result = this.asModule().getLocation().getFile()
|
||||
}
|
||||
|
||||
Type toType() {
|
||||
result.(FileType).getDeclaration().getLocation().getFile() = this.asFile()
|
||||
or
|
||||
result.(ModuleType).getDeclaration() = this.asModule()
|
||||
}
|
||||
}
|
||||
|
||||
private class File_ extends FileOrModule, TFile {
|
||||
@@ -207,23 +213,23 @@ private module Cached {
|
||||
|
||||
/** Holds if module expression `me` resolves to `m`. */
|
||||
cached
|
||||
predicate resolveModuleExpr(ModuleExpr me, FileOrModule m) {
|
||||
predicate resolveModuleRef(TypeRef me, FileOrModule m) {
|
||||
not m = TFile(any(File f | f.getExtension() = "ql")) and
|
||||
not exists(me.getQualifier()) and
|
||||
exists(ContainerOrModule enclosing, string name | resolveModuleExprHelper(me, enclosing, name) |
|
||||
not exists(me.(ModuleExpr).getQualifier()) and
|
||||
exists(ContainerOrModule enclosing, string name | resolveModuleRefHelper(me, enclosing, name) |
|
||||
definesModule(enclosing, name, m, _)
|
||||
)
|
||||
or
|
||||
exists(FileOrModule mid |
|
||||
resolveModuleExpr(me.getQualifier(), mid) and
|
||||
definesModule(mid, me.getName(), m, true)
|
||||
resolveModuleRef(me.(ModuleExpr).getQualifier(), mid) and
|
||||
definesModule(mid, me.(ModuleExpr).getName(), m, true)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
private predicate resolveModuleExprHelper(ModuleExpr me, ContainerOrModule enclosing, string name) {
|
||||
private predicate resolveModuleRefHelper(TypeRef me, ContainerOrModule enclosing, string name) {
|
||||
enclosing = getEnclosingModule(me).getEnclosing*() and
|
||||
name = me.getName()
|
||||
name = [me.(ModuleExpr).getName(), me.(TypeExpr).getClassName()]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -231,7 +237,10 @@ import Cached
|
||||
private import NewType
|
||||
|
||||
boolean getPublicBool(AstNode n) {
|
||||
if n.(ModuleMember).isPrivate() or n.(NewTypeBranch).getNewType().isPrivate()
|
||||
if
|
||||
n.(ModuleMember).isPrivate() or
|
||||
n.(NewTypeBranch).getNewType().isPrivate() or
|
||||
n.(Module).isPrivate()
|
||||
then result = false
|
||||
else result = true
|
||||
}
|
||||
@@ -253,6 +262,22 @@ private predicate definesModule(
|
||||
m = TModule(any(Module mod | public = getPublicBool(mod)))
|
||||
)
|
||||
or
|
||||
// signature module in a paramertized module
|
||||
exists(Module mod, SignatureExpr sig, TypeExpr ty, int i |
|
||||
mod = container.asModule() and
|
||||
mod.hasParameter(i, name, sig) and
|
||||
public = false and
|
||||
ty = sig.asType()
|
||||
|
|
||||
// resolve to the signature module
|
||||
m = ty.getResolvedModule()
|
||||
or
|
||||
// resolve to the arguments of the instantiated module
|
||||
exists(ModuleExpr inst | inst.getResolvedModule().asModule() = mod |
|
||||
m = inst.getArgument(i).asType().getResolvedModule()
|
||||
)
|
||||
)
|
||||
or
|
||||
// import X
|
||||
exists(Import imp, ContainerOrModule m0 |
|
||||
container = getEnclosingModule(imp) and
|
||||
@@ -274,7 +299,7 @@ private predicate definesModule(
|
||||
exists(Module alias |
|
||||
container = getEnclosingModule(alias) and
|
||||
name = alias.getName() and
|
||||
resolveModuleExpr(alias.getAlias(), m) and
|
||||
resolveModuleRef(alias.getAlias(), m) and
|
||||
public = getPublicBool(alias)
|
||||
)
|
||||
}
|
||||
@@ -288,14 +313,6 @@ module ModConsistency {
|
||||
.regexpMatch(".*/(test|examples|ql-training|recorded-call-graph-metrics)/.*")
|
||||
}
|
||||
|
||||
query predicate noResolveModuleExpr(ModuleExpr me) {
|
||||
not resolveModuleExpr(me, _) and
|
||||
not me.getLocation()
|
||||
.getFile()
|
||||
.getAbsolutePath()
|
||||
.regexpMatch(".*/(test|examples|ql-training|recorded-call-graph-metrics)/.*")
|
||||
}
|
||||
|
||||
query predicate multipleResolve(Import imp, int c, ContainerOrModule m) {
|
||||
c = strictcount(ContainerOrModule m0 | resolve(imp, m0)) and
|
||||
c > 1 and
|
||||
@@ -306,9 +323,16 @@ module ModConsistency {
|
||||
.regexpMatch(".*/(test|examples|ql-training|recorded-call-graph-metrics)/.*")
|
||||
}
|
||||
|
||||
query predicate multipleResolveModuleExpr(ModuleExpr me, int c, ContainerOrModule m) {
|
||||
c = strictcount(ContainerOrModule m0 | resolveModuleExpr(me, m0)) and
|
||||
c > 1 and
|
||||
resolveModuleExpr(me, m)
|
||||
}
|
||||
// This can happen with parameterized modules.
|
||||
/*
|
||||
* query predicate multipleResolveModuleRef(ModuleExpr me, int c, ContainerOrModule m) {
|
||||
* c = strictcount(ContainerOrModule m0 | resolveModuleRef(me, m0)) and
|
||||
* c > 1 and
|
||||
* resolveModuleRef(me, m)
|
||||
* }
|
||||
*/
|
||||
|
||||
query predicate noName(Module mod) { not exists(mod.getName()) }
|
||||
|
||||
query predicate nonUniqueName(Module mod) { count(mod.getName()) >= 2 }
|
||||
}
|
||||
|
||||
@@ -69,6 +69,20 @@ private module Cached {
|
||||
|
|
||||
definesPredicate(m, pc.getPredicateName(), pc.getNumberOfArguments(), p, public)
|
||||
)
|
||||
or
|
||||
exists(Module mod, PredicateExpr sig, int i |
|
||||
mod.hasParameter(i, pc.getPredicateName(), sig) and
|
||||
sig.getArity() = pc.getNumberOfArguments()
|
||||
|
|
||||
// resolve to the signature predicate
|
||||
p = sig.getResolvedPredicate() // <- this is a `signature predicate`, but that's fine.
|
||||
or
|
||||
// resolve to the instantiations
|
||||
exists(ModuleExpr inst, SignatureExpr arg | inst.getResolvedModule().asModule() = mod |
|
||||
arg = inst.getArgument(i) and
|
||||
p = arg.asPredicate().getResolvedPredicate()
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
private predicate resolveMemberCall(MemberCall mc, PredicateOrBuiltin p) {
|
||||
@@ -162,17 +176,20 @@ module PredConsistency {
|
||||
c > 1 and
|
||||
resolvePredicateExpr(pe, p)
|
||||
}
|
||||
// This can happen with parametarized modules
|
||||
/*
|
||||
* query predicate multipleResolveCall(Call call, int c, PredicateOrBuiltin p) {
|
||||
* c =
|
||||
* strictcount(PredicateOrBuiltin p0 |
|
||||
* resolveCall(call, p0) and
|
||||
* // aliases are expected to resolve to multiple.
|
||||
* not exists(p0.(ClasslessPredicate).getAlias()) and
|
||||
* // overridden predicates may have multiple targets
|
||||
* not p0.(ClassPredicate).isOverride()
|
||||
* ) and
|
||||
* c > 1 and
|
||||
* resolveCall(call, p)
|
||||
* }
|
||||
*/
|
||||
|
||||
query predicate multipleResolveCall(Call call, int c, PredicateOrBuiltin p) {
|
||||
c =
|
||||
strictcount(PredicateOrBuiltin p0 |
|
||||
resolveCall(call, p0) and
|
||||
// aliases are expected to resolve to multiple.
|
||||
not exists(p0.(ClasslessPredicate).getAlias()) and
|
||||
// overridden predicates may have multiple targets
|
||||
not p0.(ClassPredicate).isOverride()
|
||||
) and
|
||||
c > 1 and
|
||||
resolveCall(call, p)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -999,11 +999,16 @@ module QL {
|
||||
/** Gets the name of the primary QL class for this element. */
|
||||
final override string getAPrimaryQlClass() { result = "ModuleInstantiation" }
|
||||
|
||||
/** Gets the node corresponding to the field `name`. */
|
||||
final ModuleName getName() { ql_module_instantiation_def(this, result) }
|
||||
|
||||
/** Gets the `i`th child of this node. */
|
||||
final SignatureExpr getChild(int i) { ql_module_instantiation_child(this, i, result) }
|
||||
|
||||
/** Gets a field or child node of this node. */
|
||||
final override AstNode getAFieldOrChild() { ql_module_instantiation_child(this, _, result) }
|
||||
final override AstNode getAFieldOrChild() {
|
||||
ql_module_instantiation_def(this, result) or ql_module_instantiation_child(this, _, result)
|
||||
}
|
||||
}
|
||||
|
||||
/** A class representing `moduleMember` nodes. */
|
||||
|
||||
@@ -14,7 +14,9 @@ private newtype TType =
|
||||
TDontCare() or
|
||||
TClassChar(Class c) { isActualClass(c) } or
|
||||
TClassDomain(Class c) { isActualClass(c) } or
|
||||
TDatabase(string s) { exists(TypeExpr t | t.isDBType() and s = t.getClassName()) }
|
||||
TDatabase(string s) { exists(TypeExpr t | t.isDBType() and s = t.getClassName()) } or
|
||||
TFile(TopLevel t) or
|
||||
TModule(Module m)
|
||||
|
||||
private predicate primTypeName(string s) { s = ["int", "float", "string", "boolean", "date"] }
|
||||
|
||||
@@ -110,6 +112,26 @@ class ClassType extends Type, TClass {
|
||||
}
|
||||
}
|
||||
|
||||
class FileType extends Type, TFile {
|
||||
TopLevel decl;
|
||||
|
||||
FileType() { this = TFile(decl) }
|
||||
|
||||
override string getName() { result = decl.getLocation().getFile().getBaseName() }
|
||||
|
||||
override TopLevel getDeclaration() { result = decl }
|
||||
}
|
||||
|
||||
class ModuleType extends Type, TModule {
|
||||
Module decl;
|
||||
|
||||
ModuleType() { this = TModule(decl) }
|
||||
|
||||
override string getName() { result = decl.getName() }
|
||||
|
||||
override Module getDeclaration() { result = decl }
|
||||
}
|
||||
|
||||
private PredicateOrBuiltin declaredPred(Type ty, string name, int arity) {
|
||||
result.getDeclaringType() = ty and
|
||||
result.getName() = name and
|
||||
@@ -323,22 +345,42 @@ private predicate defines(FileOrModule m, string name, Type t, boolean public) {
|
||||
public = getPublicBool(im) and
|
||||
defines(im.getResolvedModule(), name, t, true)
|
||||
)
|
||||
or
|
||||
// classes in parameterized modules.
|
||||
exists(Module mod, SignatureExpr param, int i |
|
||||
m.asModule() = mod and
|
||||
mod.hasParameter(i, name, param) and
|
||||
public = true
|
||||
|
|
||||
// resolve to the signature class
|
||||
t = param.asType().getResolvedType()
|
||||
or
|
||||
// resolve to the instantiations
|
||||
exists(ModuleExpr inst, SignatureExpr arg |
|
||||
inst.getArgument(i) = arg and
|
||||
inst.getResolvedModule() = m and
|
||||
t = arg.asType().getResolvedType()
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
module TyConsistency {
|
||||
query predicate noResolve(TypeExpr te) {
|
||||
not resolveTypeExpr(te, _) and
|
||||
query predicate noResolve(TypeRef te) {
|
||||
not exists(te.getResolvedType()) and
|
||||
not te.getLocation()
|
||||
.getFile()
|
||||
.getAbsolutePath()
|
||||
.regexpMatch(".*/(test|examples|ql-training|recorded-call-graph-metrics)/.*")
|
||||
}
|
||||
|
||||
query predicate multipleResolve(TypeExpr te, int c, Type t) {
|
||||
c = strictcount(Type t0 | resolveTypeExpr(te, t0)) and
|
||||
c > 1 and
|
||||
resolveTypeExpr(te, t)
|
||||
}
|
||||
// This can happen with parameterized modules.
|
||||
/*
|
||||
* query predicate multipleResolve(TypeExpr te, int c, Type t) {
|
||||
* c = strictcount(Type t0 | resolveTypeExpr(te, t0)) and
|
||||
* c > 1 and
|
||||
* resolveTypeExpr(te, t)
|
||||
* }
|
||||
*/
|
||||
|
||||
query predicate multiplePrimitives(TypeExpr te, int c, PrimitiveType t) {
|
||||
c = strictcount(PrimitiveType t0 | resolveTypeExpr(te, t0)) and
|
||||
|
||||
@@ -164,6 +164,12 @@ private AstNode aliveStep(AstNode prev) {
|
||||
result = prev.(Annotation).getAChild()
|
||||
or
|
||||
result = prev.(Predicate).getReturnType().getDeclaration()
|
||||
or
|
||||
// a module parameter is alive is the module is alive
|
||||
prev.(Module).hasParameter(_, _, result)
|
||||
or
|
||||
// the implements of a module
|
||||
result = prev.(Module).getImplements(_)
|
||||
}
|
||||
|
||||
private AstNode deprecated() {
|
||||
|
||||
@@ -28,14 +28,15 @@ class Loc extends TLoc {
|
||||
}
|
||||
}
|
||||
|
||||
private predicate resolveModule(ModuleRef ref, FileOrModule target, string kind) {
|
||||
private predicate resolveModule(TypeRef ref, FileOrModule target, string kind) {
|
||||
target = ref.getResolvedModule() and
|
||||
kind = "module"
|
||||
}
|
||||
|
||||
private predicate resolveType(TypeExpr ref, AstNode target, string kind) {
|
||||
target = ref.getResolvedType().getDeclaration() and
|
||||
kind = "type"
|
||||
kind = "type" and
|
||||
not resolveModule(ref, _, _) // modules are types, so we exclude them here.
|
||||
}
|
||||
|
||||
private predicate resolvePredicate(PredicateExpr ref, Predicate target, string kind) {
|
||||
|
||||
@@ -656,7 +656,8 @@ ql_module_instantiation_child(
|
||||
);
|
||||
|
||||
ql_module_instantiation_def(
|
||||
unique int id: @ql_module_instantiation
|
||||
unique int id: @ql_module_instantiation,
|
||||
int name: @ql_module_name ref
|
||||
);
|
||||
|
||||
@ql_moduleMember_child_type = @ql_annotation | @ql_classless_predicate | @ql_dataclass | @ql_datatype | @ql_import_directive | @ql_module | @ql_select | @ql_token_qldoc
|
||||
|
||||
@@ -33,11 +33,15 @@ where
|
||||
or
|
||||
AstConsistency::nonTotalGetParent(node) and msg = "AstConsistency::nonTotalGetParent"
|
||||
or
|
||||
AstConsistency::nonUniqueParent(node) and msg = "AstConsistency::nonUniqueParent"
|
||||
or
|
||||
TypeConsistency::noResolve(node) and msg = "TypeConsistency::noResolve"
|
||||
or
|
||||
ModConsistency::noResolve(node) and msg = "ModConsistency::noResolve"
|
||||
or
|
||||
ModConsistency::noResolveModuleExpr(node) and msg = "ModConsistency::noResolveModuleExpr"
|
||||
ModConsistency::noName(node) and msg = "ModConsistency::noName"
|
||||
or
|
||||
ModConsistency::nonUniqueName(node) and msg = "ModConsistency::nonUniqueName"
|
||||
or
|
||||
VarConsistency::noFieldDef(node) and msg = "VarConsistency::noFieldDef"
|
||||
or
|
||||
|
||||
63
ql/ql/test/callgraph/ParamModules.qll
Normal file
63
ql/ql/test/callgraph/ParamModules.qll
Normal file
@@ -0,0 +1,63 @@
|
||||
module PredicateSig {
|
||||
signature predicate fooSig(int i);
|
||||
|
||||
module UsesFoo<fooSig/1 fooImpl> {
|
||||
predicate bar(int i) { fooImpl(i + 1) }
|
||||
}
|
||||
|
||||
predicate myFoo(int i) { i = 42 }
|
||||
|
||||
predicate use(int i) { UsesFoo<myFoo/1>::bar(i) }
|
||||
}
|
||||
|
||||
module ClassSig {
|
||||
signature class FooSig extends int;
|
||||
|
||||
module UsesFoo<FooSig FooImpl> {
|
||||
FooImpl getAnEven() { result % 2 = 0 }
|
||||
}
|
||||
|
||||
class MyFoo extends int {
|
||||
MyFoo() { this = [0 .. 10] }
|
||||
|
||||
string myFoo() { result = "myFoo" }
|
||||
}
|
||||
|
||||
string use() { result = UsesFoo<MyFoo>::getAnEven().myFoo() }
|
||||
}
|
||||
|
||||
module ModuleSig {
|
||||
signature module FooSig {
|
||||
class A;
|
||||
|
||||
A getThing();
|
||||
}
|
||||
|
||||
module UsesFoo<FooSig FooImpl> {
|
||||
B getThing() { result = FooImpl::getThing() }
|
||||
|
||||
class B = FooImpl::A;
|
||||
}
|
||||
|
||||
module MyFoo implements FooSig {
|
||||
class C extends int {
|
||||
C() { this = [0 .. 10] }
|
||||
|
||||
string myFoo() { result = "myFoo" }
|
||||
}
|
||||
|
||||
class A = C;
|
||||
|
||||
C getThing() { any() }
|
||||
}
|
||||
|
||||
module ImplStuff {
|
||||
module Inst = UsesFoo<MyFoo>;
|
||||
|
||||
class D = Inst::B;
|
||||
|
||||
string use1() { result = Inst::getThing().myFoo() }
|
||||
|
||||
string use2(Inst::B b) { result = b.myFoo() }
|
||||
}
|
||||
}
|
||||
@@ -21,6 +21,16 @@ getTarget
|
||||
| Overrides.qll:24:39:24:48 | MemberCall | Overrides.qll:22:12:22:44 | ClassPredicate bar |
|
||||
| Overrides.qll:28:3:28:9 | MemberCall | Overrides.qll:6:3:6:29 | ClassPredicate bar |
|
||||
| Overrides.qll:29:3:29:10 | MemberCall | Overrides.qll:8:3:8:41 | ClassPredicate baz |
|
||||
| ParamModules.qll:5:28:5:41 | PredicateCall | ParamModules.qll:2:13:2:36 | ClasslessPredicate fooSig |
|
||||
| ParamModules.qll:5:28:5:41 | PredicateCall | ParamModules.qll:8:3:8:35 | ClasslessPredicate myFoo |
|
||||
| ParamModules.qll:10:26:10:49 | PredicateCall | ParamModules.qll:5:5:5:43 | ClasslessPredicate bar |
|
||||
| ParamModules.qll:26:27:26:53 | PredicateCall | ParamModules.qll:17:5:17:42 | ClasslessPredicate getAnEven |
|
||||
| ParamModules.qll:26:27:26:61 | MemberCall | ParamModules.qll:23:5:23:39 | ClassPredicate myFoo |
|
||||
| ParamModules.qll:37:29:37:47 | PredicateCall | ParamModules.qll:33:5:33:17 | ClasslessPredicate getThing |
|
||||
| ParamModules.qll:37:29:37:47 | PredicateCall | ParamModules.qll:51:5:51:26 | ClasslessPredicate getThing |
|
||||
| ParamModules.qll:59:30:59:45 | PredicateCall | ParamModules.qll:37:5:37:49 | ClasslessPredicate getThing |
|
||||
| ParamModules.qll:59:30:59:53 | MemberCall | ParamModules.qll:46:7:46:41 | ClassPredicate myFoo |
|
||||
| ParamModules.qll:61:39:61:47 | MemberCall | ParamModules.qll:46:7:46:41 | ClassPredicate myFoo |
|
||||
| packs/other/OtherThing.qll:5:3:5:8 | PredicateCall | packs/lib/LibThing/Foo.qll:1:1:1:30 | ClasslessPredicate foo |
|
||||
| packs/other/OtherThing.qll:6:3:6:8 | PredicateCall | packs/src/SrcThing.qll:8:1:8:30 | ClasslessPredicate bar |
|
||||
| packs/src/SrcThing.qll:4:3:4:8 | PredicateCall | packs/lib/LibThing/Foo.qll:1:1:1:30 | ClasslessPredicate foo |
|
||||
@@ -33,3 +43,5 @@ exprPredicate
|
||||
| Foo.qll:26:22:26:31 | predicate | Foo.qll:20:3:20:54 | ClasslessPredicate myThing2 |
|
||||
| Foo.qll:47:55:47:62 | predicate | Foo.qll:42:20:42:27 | NewTypeBranch MkRoot |
|
||||
| Foo.qll:47:65:47:70 | predicate | Foo.qll:44:9:44:56 | ClasslessPredicate edge |
|
||||
| ParamModules.qll:4:18:4:25 | predicate | ParamModules.qll:2:13:2:36 | ClasslessPredicate fooSig |
|
||||
| ParamModules.qll:10:34:10:40 | predicate | ParamModules.qll:8:3:8:35 | ClasslessPredicate myFoo |
|
||||
|
||||
Reference in New Issue
Block a user