Files
codeql/ql/src/codeql_ql/ast/internal/Predicate.qll
Anders Schack-Mulligen 69cf373f21 QL: Refactor
2021-10-14 13:06:41 +02:00

214 lines
6.2 KiB
Plaintext

import ql
private import Builtins
private import codeql_ql.ast.internal.Module
private import codeql_ql.ast.internal.AstNodes
private class TClasslessPredicateOrNewTypeBranch = TClasslessPredicate or TNewTypeBranch;
private string getPredicateName(TClasslessPredicateOrNewTypeBranch p) {
result = p.(ClasslessPredicate).getName() or
result = p.(NewTypeBranch).getName()
}
private predicate definesPredicate(
FileOrModule m, string name, int arity, TClasslessPredicateOrNewTypeBranch p, boolean public
) {
m = getEnclosingModule(p) and
name = getPredicateName(p) and
public = getPublicBool(p) and
arity = [p.(ClasslessPredicate).getArity(), count(p.(NewTypeBranch).getField(_))]
or
// import X
exists(Import imp, FileOrModule m0 |
m = getEnclosingModule(imp) and
m0 = imp.getResolvedModule() and
not exists(imp.importedAs()) and
definesPredicate(m0, name, arity, p, true) and
public = getPublicBool(imp)
)
or
// predicate X = Y
exists(ClasslessPredicate alias |
m = getEnclosingModule(alias) and
name = alias.getName() and
resolvePredicateExpr(alias.getAlias(), p) and
public = getPublicBool(alias) and
arity = alias.getArity()
)
}
cached
private module Cached {
cached
predicate resolvePredicateExpr(PredicateExpr pe, ClasslessPredicate p) {
exists(FileOrModule m, boolean public |
not exists(pe.getQualifier()) and
m = getEnclosingModule(pe).getEnclosing*() and
public = [false, true]
or
m = pe.getQualifier().getResolvedModule() and
public = true
|
definesPredicate(m, pe.getName(), count(p.getParameter(_)), p, public)
)
}
private predicate resolvePredicateCall(PredicateCall pc, PredicateOrBuiltin p) {
exists(Class c, ClassType t |
c = pc.getParent*() and
t = c.getType() and
p = t.getClassPredicate(pc.getPredicateName(), pc.getNumberOfArguments())
)
or
exists(FileOrModule m, boolean public |
not exists(pc.getQualifier()) and
m = getEnclosingModule(pc).getEnclosing*() and
public = [false, true]
or
m = pc.getQualifier().getResolvedModule() and
public = true
|
definesPredicate(m, pc.getPredicateName(), pc.getNumberOfArguments(), p, public)
)
}
private predicate resolveMemberCall(MemberCall mc, PredicateOrBuiltin p) {
exists(Type t |
t = mc.getBase().getType() and
p = t.getClassPredicate(mc.getMemberName(), mc.getNumberOfArguments())
)
or
// super calls
exists(Super sup, ClassType type |
mc.getBase() = sup and
sup.getEnclosingPredicate().(ClassPredicate).getParent().getType() = type and
p = type.getASuperType().getClassPredicate(mc.getMemberName(), mc.getNumberOfArguments())
)
}
pragma[noinline]
private predicate candidate(Relation rel, PredicateCall pc) {
rel.getName() = pc.getPredicateName()
}
private predicate resolveDBRelation(PredicateCall pc, DefinedPredicate p) {
exists(Relation rel | p = TPred(rel) |
candidate(rel, pc) and
rel.getArity() = pc.getNumberOfArguments() and
(
exists(YAML::QLPack libPack, YAML::QLPack qlPack |
rel.getLocation().getFile() = libPack.getDBScheme() and
qlPack.getADependency*() = libPack and
qlPack.getAFileInPack() = pc.getLocation().getFile()
)
or
// upgrade scripts don't have a qlpack
rel.getLocation().getFile().getParentContainer() =
pc.getLocation().getFile().getParentContainer()
)
)
}
cached
predicate resolveCall(Call c, PredicateOrBuiltin p) {
resolvePredicateCall(c, p)
or
resolveMemberCall(c, p)
or
not resolvePredicateCall(c, _) and
resolveDBRelation(c, p)
}
}
import Cached
class PredicateOrBuiltin extends TPredOrBuiltin, AstNode {
string getName() { none() }
Type getDeclaringType() { none() }
Type getParameterType(int i) { none() }
Type getReturnType() { none() }
int getArity() { result = count(getParameterType(_)) }
predicate isPrivate() { none() }
}
private class TBuiltin = TBuiltinClassless or TBuiltinMember;
class BuiltinPredicate extends PredicateOrBuiltin, TBuiltin {
override string toString() { result = getName() }
override string getAPrimaryQlClass() { result = "BuiltinPredicate" }
}
private class BuiltinClassless extends BuiltinPredicate, TBuiltinClassless {
string name;
string ret;
string args;
BuiltinClassless() { this = TBuiltinClassless(ret, name, args) }
override string getName() { result = name }
override PrimitiveType getReturnType() { result.getName() = ret }
override PrimitiveType getParameterType(int i) { result.getName() = getArgType(args, i) }
}
private class BuiltinMember extends BuiltinPredicate, TBuiltinMember {
string name;
string qual;
string ret;
string args;
BuiltinMember() { this = TBuiltinMember(qual, ret, name, args) }
override string getName() { result = name }
override PrimitiveType getReturnType() { result.getName() = ret }
override PrimitiveType getParameterType(int i) { result.getName() = getArgType(args, i) }
override PrimitiveType getDeclaringType() { result.getName() = qual }
}
module PredConsistency {
query predicate noResolvePredicateExpr(PredicateExpr pe) {
not resolvePredicateExpr(pe, _) and
not pe.getLocation()
.getFile()
.getAbsolutePath()
.regexpMatch(".*/(test|examples|ql-training|recorded-call-graph-metrics)/.*")
}
query predicate noResolveCall(Call c) {
not resolveCall(c, _) and
not c instanceof NoneCall and
not c instanceof AnyCall and
not c.getLocation()
.getFile()
.getAbsolutePath()
.regexpMatch(".*/(test|examples|ql-training|recorded-call-graph-metrics)/.*")
}
query predicate multipleResolvePredicateExpr(PredicateExpr pe, int c, ClasslessPredicate p) {
c = strictcount(ClasslessPredicate p0 | resolvePredicateExpr(pe, p0)) and
c > 1 and
resolvePredicateExpr(pe, 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
c > 1 and
resolveCall(call, p)
}
}