Merge pull request #129 from github/erik-krogh/cartesian

various new improvements and queries
This commit is contained in:
Erik Krogh Kristensen
2021-11-18 13:16:53 +01:00
committed by GitHub
23 changed files with 924 additions and 408 deletions

View File

@@ -49,6 +49,7 @@ class AstNode extends TAstNode {
/**
* Gets the parent in the AST for this node.
*/
cached
AstNode getParent() { result.getAChild(_) = this }
/**
@@ -74,12 +75,14 @@ class AstNode extends TAstNode {
predicate hasAnnotation(string name) { this.getAnAnnotation().getName() = name }
/** Gets an annotation of this AST node. */
Annotation getAnAnnotation() { toQL(this).getParent() = toQL(result).getParent() }
Annotation getAnAnnotation() {
toQL(this).getParent() = pragma[only_bind_out](toQL(result)).getParent()
}
/**
* Gets the predicate that contains this AST node.
*/
pragma[noinline]
cached
Predicate getEnclosingPredicate() { this = getANodeInPredicate(result) }
}
@@ -563,8 +566,10 @@ class VarDecl extends TVarDecl, VarDef, Declaration {
)
}
/** If this is a field, returns the class type that declares it. */
ClassType getDeclaringType() { result.getDeclaration().getAField() = this }
/** If this is declared in a field, returns the class type that declares it. */
ClassType getDeclaringType() {
exists(FieldDecl f | f.getVarDecl() = this and result = f.getParent().(Class).getType())
}
/**
* Holds if this is a class field that overrides the field `other`.
@@ -580,6 +585,32 @@ class VarDecl extends TVarDecl, VarDef, Declaration {
override string toString() { result = this.getName() }
}
/**
* A field declaration;
*/
class FieldDecl extends TFieldDecl, AstNode {
QL::Field f;
FieldDecl() { this = TFieldDecl(f) }
VarDecl getVarDecl() { toQL(result) = f.getChild() }
override AstNode getAChild(string pred) {
result = super.getAChild(pred)
or
pred = directMember("getVarDecl") and result = this.getVarDecl()
}
override string getAPrimaryQlClass() { result = "FieldDecl" }
/** Holds if this field is annotated as overriding another field. */
predicate isOverride() { this.hasAnnotation("override") }
string getName() { result = getVarDecl().getName() }
override QLDoc getQLDoc() { result = any(Class c).getQLDocFor(this) }
}
/**
* A type reference, such as `DataFlow::Node`.
*/
@@ -716,10 +747,7 @@ class Class extends TClass, TypeDeclaration, ModuleDeclaration {
*/
CharPred getCharPred() { toQL(result) = cls.getChild(_).(QL::ClassMember).getChild(_) }
AstNode getMember(int i) {
toQL(result) = cls.getChild(i).(QL::ClassMember).getChild(_) or
toQL(result) = cls.getChild(i).(QL::ClassMember).getChild(_).(QL::Field).getChild()
}
AstNode getMember(int i) { toQL(result) = cls.getChild(i).(QL::ClassMember).getChild(_) }
QLDoc getQLDocFor(AstNode m) {
exists(int i | result = this.getMember(i) and m = this.getMember(i + 1))
@@ -743,9 +771,7 @@ class Class extends TClass, TypeDeclaration, ModuleDeclaration {
/**
* Gets a field in this class.
*/
VarDecl getAField() {
toQL(result) = cls.getChild(_).(QL::ClassMember).getChild(_).(QL::Field).getChild()
}
FieldDecl getAField() { result = getMember(_) }
/**
* Gets a super-type referenced in the `extends` part of the class declaration.
@@ -1102,9 +1128,15 @@ class Conjunction extends TConjunction, AstNode, Formula {
override string getAPrimaryQlClass() { result = "Conjunction" }
/** Gets an operand to this formula. */
/** Gets an operand to this conjunction. */
Formula getAnOperand() { toQL(result) in [conj.getLeft(), conj.getRight()] }
/** Gets the left operand to this conjunction. */
Formula getLeft() { toQL(result) = conj.getLeft() }
/** Gets the right operand to this conjunction. */
Formula getRight() { toQL(result) = conj.getRight() }
override AstNode getAChild(string pred) {
result = super.getAChild(pred)
or
@@ -1120,9 +1152,15 @@ class Disjunction extends TDisjunction, AstNode, Formula {
override string getAPrimaryQlClass() { result = "Disjunction" }
/** Gets an operand to this formula. */
/** Gets an operand to this disjunction. */
Formula getAnOperand() { toQL(result) in [disj.getLeft(), disj.getRight()] }
/** Gets the left operand to this disjunction */
Formula getLeft() { toQL(result) = disj.getLeft() }
/** Gets the right operand to this disjunction */
Formula getRight() { toQL(result) = disj.getRight() }
override AstNode getAChild(string pred) {
result = super.getAChild(pred)
or
@@ -1130,23 +1168,6 @@ class Disjunction extends TDisjunction, AstNode, Formula {
}
}
/**
* A comparison operator, such as `<` or `=`.
*/
class ComparisonOp extends TComparisonOp, AstNode {
QL::Compop op;
ComparisonOp() { this = TComparisonOp(op) }
/**
* Gets a string representing the operator.
* E.g. "<" or "=".
*/
ComparisonSymbol getSymbol() { result = op.getValue() }
override string getAPrimaryQlClass() { result = "ComparisonOp" }
}
/**
* A literal expression, such as `6` or `true` or `"foo"`.
*/
@@ -1243,10 +1264,7 @@ class ComparisonFormula extends TComparisonFormula, Formula {
Expr getAnOperand() { result in [this.getLeftOperand(), this.getRightOperand()] }
/** Gets the operator of this comparison. */
ComparisonOp getOperator() { toQL(result) = comp.getChild() }
/** Gets the symbol of this comparison (as a string). */
ComparisonSymbol getSymbol() { result = this.getOperator().getSymbol() }
ComparisonSymbol getOperator() { result = comp.getChild().getValue() }
override string getAPrimaryQlClass() { result = "ComparisonFormula" }
@@ -1256,8 +1274,6 @@ class ComparisonFormula extends TComparisonFormula, Formula {
pred = directMember("getLeftOperand") and result = this.getLeftOperand()
or
pred = directMember("getRightOperand") and result = this.getRightOperand()
or
pred = directMember("getOperator") and result = this.getOperator()
}
}
@@ -2218,6 +2234,8 @@ 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 getAChild(string pred) {
result = super.getAChild(pred)
or

View File

@@ -8,6 +8,7 @@ newtype TAstNode =
TQLDoc(QL::Qldoc qldoc) or
TClasslessPredicate(QL::ClasslessPredicate pred) or
TVarDecl(QL::VarDecl decl) or
TFieldDecl(QL::Field field) or
TClass(QL::Dataclass dc) or
TCharPred(QL::Charpred pred) or
TClassPredicate(QL::MemberPredicate pred) or
@@ -21,7 +22,6 @@ newtype TAstNode =
TDisjunction(QL::Disjunction disj) or
TConjunction(QL::Conjunction conj) or
TComparisonFormula(QL::CompTerm comp) or
TComparisonOp(QL::Compop op) or
TQuantifier(QL::Quantified quant) or
TFullAggregate(QL::Aggregate agg) { agg.getChild(_) instanceof QL::FullAggregateBody } or
TExprAggregate(QL::Aggregate agg) { agg.getChild(_) instanceof QL::ExprAggregateBody } or
@@ -90,7 +90,6 @@ private QL::AstNode toQLFormula(AST::AstNode n) {
n = TConjunction(result) or
n = TDisjunction(result) or
n = TComparisonFormula(result) or
n = TComparisonOp(result) or
n = TQuantifier(result) or
n = TFullAggregate(result) or
n = TIdentifier(result) or
@@ -127,6 +126,7 @@ private QL::AstNode toGenerateYAML(AST::AstNode n) {
/**
* Gets the underlying TreeSitter entity for a given AST node.
*/
cached
QL::AstNode toQL(AST::AstNode n) {
result = toQLExpr(n)
or
@@ -150,6 +150,8 @@ QL::AstNode toQL(AST::AstNode n) {
or
n = TVarDecl(result)
or
n = TFieldDecl(result)
or
n = TClass(result)
or
n = TCharPred(result)

View File

@@ -134,7 +134,7 @@ predicate predOverrides(ClassPredicate sub, ClassPredicate sup) {
}
private VarDecl declaredField(ClassType ty, string name) {
result = ty.getDeclaration().getAField() and
result = ty.getDeclaration().getAField().getVarDecl() and
result.getName() = name
}

View File

@@ -37,7 +37,7 @@ class VariableScope extends TScope, AstNode {
predicate containsField(VarDef decl, string name) {
name = decl.getName() and
(
decl = this.(Class).getAField()
decl = this.(Class).getAField().getVarDecl()
or
this.getOuterScope().containsField(decl, name) and
not exists(this.getADefinition(name))

View File

@@ -1,13 +1,3 @@
/**
* @name Prefix or suffix predicate calls when comparing with literal
* @description Using 'myString.prefix(n) = "..."' instead of 'myString.matches("...%")'
* @kind problem
* @problem.severity error
* @id ql/prefix-or-suffix-equality-check
* @tags performance
* @precision high
*/
import ql
import codeql_ql.ast.internal.Predicate
import codeql_ql.ast.internal.Builtins
@@ -29,7 +19,7 @@ class SuffixPredicateCall extends Call {
}
class EqFormula extends ComparisonFormula {
EqFormula() { this.getSymbol() = "=" }
EqFormula() { this.getOperator() = "=" }
}
bindingset[s]
@@ -48,6 +38,17 @@ class FixPredicateCall extends Call {
FixPredicateCall() { this instanceof PrefixPredicateCall or this instanceof SuffixPredicateCall }
}
from EqFormula eq, FixPredicateCall call, String literal
where eq.getAnOperand() = call and eq.getAnOperand() = literal
select eq, "Use " + getMessage(call, literal) + " instead."
class RegexpMatchPredicate extends BuiltinPredicate {
RegexpMatchPredicate() { this = any(StringClass sc).getClassPredicate("regexpMatch", 1) }
}
predicate canUseMatchInsteadOfRegexpMatch(Call c, string matchesStr) {
c.getTarget() instanceof RegexpMatchPredicate and
exists(string raw | raw = c.getArgument(0).(String).getValue() |
matchesStr = "%" + raw.regexpCapture("^\\.\\*(\\w+)$", _)
or
matchesStr = raw.regexpCapture("^(\\w+)\\.\\*$", _) + "%"
or
matchesStr = "%" + raw.regexpCapture("^\\.\\*(\\w+)\\.\\*$", _) + "%"
)
}

View File

@@ -0,0 +1,20 @@
import ql
MemberCall explicitThisCallInFile(File f) {
result.getLocation().getFile() = f and
result.getBase() instanceof ThisAccess and
// Exclude `this.(Type).whatever(...)`, as some files have that as their only instance of `this`.
not result = any(InlineCast c).getBase()
}
PredicateCall implicitThisCallInFile(File f) {
result.getLocation().getFile() = f and
exists(result.getTarget().getDeclaringType().getASuperType()) and
// Exclude `SomeModule::whatever(...)`
not exists(result.getQualifier())
}
PredicateCall confusingImplicitThisCall(File f) {
result = implicitThisCallInFile(f) and
exists(explicitThisCallInFile(f))
}

View File

@@ -0,0 +1,35 @@
import ql
class RedundantInlineCast extends AstNode instanceof InlineCast {
Type t;
RedundantInlineCast() {
t = unique( | | super.getType()) and
(
// The cast is to the type the base expression already has
t = unique( | | super.getBase().getType())
or
// The cast is to the same type as the other expression in an equality comparison
exists(ComparisonFormula comp, Expr other | comp.getOperator() = "=" |
this = comp.getAnOperand() and
other = comp.getAnOperand() and
this != other and
t = unique( | | other.getType()) and
not other instanceof InlineCast // we don't want to risk both sides being "redundant"
)
or
exists(Call call, int i, Predicate target |
this = call.getArgument(i) and
target = unique( | | call.getTarget()) and
t = unique( | | target.getParameterType(i))
)
) and
// noopt can require explicit casts
not exists(Annotation annon | annon = this.getEnclosingPredicate().getAnAnnotation() |
annon.getName() = "pragma" and
annon.getArgs(0).getValue() = "noopt"
)
}
TypeExpr getTypeExpr() { result = super.getTypeExpr() }
}

View File

@@ -0,0 +1,70 @@
import ql
/**
* Gets a class where the charpred has an `this instanceof type` expression.
*/
predicate instanceofThisInCharPred(Class c, Type type) {
exists(InstanceOf instanceOf |
instanceOf = c.getCharPred().getBody()
or
exists(Conjunction conj |
conj = c.getCharPred().getBody() and
instanceOf = conj.getAnOperand()
)
|
instanceOf.getExpr() instanceof ThisAccess and
type = instanceOf.getType().getResolvedType()
)
}
/**
* Holds if `c` uses the casting based range pattern, which could be replaced with `instanceof type`.
*/
predicate usesCastingBasedInstanceof(Class c, Type type) {
instanceofThisInCharPred(c, type) and
// require that there is a call to the range class that matches the name of the enclosing predicate
exists(InlineCast cast, MemberCall call |
cast = getAThisCast(c, type) and
call.getBase() = cast and
cast.getEnclosingPredicate().getName() = call.getMemberName()
)
}
/** Gets an inline cast that cases `this` to `type` inside a class predicate for `c`. */
InlineCast getAThisCast(Class c, Type type) {
exists(MemberCall call |
call.getEnclosingPredicate() = c.getAClassPredicate() and
result = call.getBase() and
result.getBase() instanceof ThisAccess and
result.getTypeExpr().getResolvedType() = type
)
}
predicate usesFieldBasedInstanceof(Class c, TypeExpr type, VarDecl field, ComparisonFormula comp) {
exists(FieldAccess fieldAccess |
c.getCharPred().getBody() = comp or
c.getCharPred().getBody().(Conjunction).getAnOperand() = comp
|
comp.getOperator() = "=" and
comp.getEnclosingPredicate() = c.getCharPred() and
comp.getAnOperand() instanceof ThisAccess and
comp.getAnOperand() = fieldAccess and
fieldAccess.getDeclaration() = field and
field.getTypeExpr() = type
) and
// require that there is a call to the range field that matches the name of the enclosing predicate
exists(FieldAccess access, MemberCall call |
access = getARangeFieldAccess(c, field, _) and
call.getBase() = access and
access.getEnclosingPredicate().getName() = call.getMemberName()
)
}
FieldAccess getARangeFieldAccess(Class c, VarDecl field, string name) {
exists(MemberCall call |
result = call.getBase() and
result.getDeclaration() = field and
name = call.getMemberName() and
call.getEnclosingPredicate().(ClassPredicate).getParent() = c
)
}

View File

@@ -0,0 +1,124 @@
import ql
/**
* A chain of disjunctions treated as one object. For example the following is
* a chain of disjunctions with three operands:
* ```
* a or b or c
* ```
*/
class DisjunctionChain extends Disjunction {
DisjunctionChain() { not exists(Disjunction parent | parent.getAnOperand() = this) }
/**
* Gets any operand of the chain.
*/
Formula getOperand(int i) {
result =
rank[i + 1](Formula operand, Location l |
operand = getAnOperand*() and
not operand instanceof Disjunction and
l = operand.getLocation()
|
operand order by l.getStartLine(), l.getStartColumn()
)
}
}
/**
* An equality comparison with a `Literal`. For example:
* ```
* x = 4
* ```
*/
class EqualsLiteral extends ComparisonFormula {
EqualsLiteral() {
getOperator() = "=" and
getAnOperand() instanceof Literal
}
AstNode getOther() {
result = getAnOperand() and
not result instanceof Literal
}
Literal getLiteral() { result = getAnOperand() }
}
/**
* A chain of disjunctions where each operand is an equality comparison between
* the same thing and various `Literal`s. For example:
* ```
* x = 4 or
* x = 5 or
* x = 6
* ```
*/
class DisjunctionEqualsLiteral extends DisjunctionChain {
AstNode firstOperand;
DisjunctionEqualsLiteral() {
// VarAccess on the same variable
exists(VarDef v |
forex(Formula f | f = getOperand(_) |
f.(EqualsLiteral).getAnOperand().(VarAccess).getDeclaration() = v
) and
firstOperand = getOperand(0).(EqualsLiteral).getAnOperand() and
firstOperand.(VarAccess).getDeclaration() = v
)
or
// FieldAccess on the same variable
exists(VarDecl v |
forex(Formula f | f = getOperand(_) |
f.(EqualsLiteral).getAnOperand().(FieldAccess).getDeclaration() = v
) and
firstOperand = getOperand(0).(EqualsLiteral).getAnOperand() and
firstOperand.(FieldAccess).getDeclaration() = v
)
or
// ThisAccess
forex(Formula f | f = getOperand(_) | f.(EqualsLiteral).getAnOperand() instanceof ThisAccess) and
firstOperand = getOperand(0).(EqualsLiteral).getAnOperand().(ThisAccess)
or
// ResultAccess
forex(Formula f | f = getOperand(_) | f.(EqualsLiteral).getAnOperand() instanceof ResultAccess) and
firstOperand = getOperand(0).(EqualsLiteral).getAnOperand().(ResultAccess)
// (in principle something like GlobalValueNumbering could be used to generalize this)
}
/**
* Gets the first "thing" that is the same thing in this chain of equalities.
*/
AstNode getFirstOperand() { result = firstOperand }
}
/**
* A call with a single `Literal` argument. For example:
* ```
* myPredicate(4)
* ```
*/
class CallLiteral extends Call {
CallLiteral() {
getNumberOfArguments() = 1 and
getArgument(0) instanceof Literal
}
}
/**
* A chain of disjunctions where each operand is a call to the same predicate
* using various `Literal`s. For example:
* ```
* myPredicate(4) or
* myPredicate(5) or
* myPredicate(6)
* ```
*/
class DisjunctionPredicateLiteral extends DisjunctionChain {
DisjunctionPredicateLiteral() {
// Call to the same target
exists(PredicateOrBuiltin target |
forex(Formula f | f = getOperand(_) | f.(CallLiteral).getTarget() = target)
)
}
}

View File

@@ -25,7 +25,7 @@ predicate usesThis(ClassPredicate pred) {
predicate isLiteralComparison(ComparisonFormula eq) {
exists(Expr lhs, Expr rhs |
eq.getSymbol() = "=" and
eq.getOperator() = "=" and
eq.getAnOperand() = lhs and
eq.getAnOperand() = rhs and
(

View File

@@ -0,0 +1,26 @@
/**
* @name Inefficient string comparison
* @description The `.matches` predicate is usually the best performing way to compare strings.
* @kind problem
* @problem.severity error
* @id ql/inefficient-string-comparison
* @tags performance
* @precision high
*/
import ql
import codeql_ql.performance.InefficientStringComparisonQuery
from AstNode node, string msg
where
exists(EqFormula eq, FixPredicateCall call, String literal |
node = eq and msg = "Use " + getMessage(call, literal) + " instead."
|
eq.getAnOperand() = call and eq.getAnOperand() = literal
)
or
exists(string matchesStr |
canUseMatchInsteadOfRegexpMatch(node, matchesStr) and
msg = "Use matches(\"" + matchesStr + "\") instead"
)
select node, msg

View File

@@ -78,7 +78,7 @@ predicate transitivePred(Predicate p, AstNode tc) {
or
exists(ComparisonFormula eq, Call c |
body = eq and
eq.getSymbol() = "=" and
eq.getOperator() = "=" and
transitiveCall(c, tc) and
getArg(c, _) instanceof Identifier and
eq.getAnOperand() = c and
@@ -141,7 +141,7 @@ predicate valueStep(Expr e1, Expr e2) {
)
or
exists(ComparisonFormula eq |
eq.getSymbol() = "=" and
eq.getOperator() = "=" and
eq.getAnOperand() = e1 and
eq.getAnOperand() = e2 and
e1 != e2

View File

@@ -0,0 +1,212 @@
/**
* @name Var only used in one side of disjunct.
* @description Only using a variable on one side of a disjunction can cause a cartesian product.
* @kind problem
* @problem.severity warning
* @id ql/var-unused-in-disjunct
* @tags maintainability
* performance
* @precision high
*/
import ql
/**
* Holds if `node` bind `var` in a (transitive) child node.
* Is a practical approximation that ignores `not` and many other features.
*/
pragma[noinline]
predicate alwaysBindsVar(VarDef var, AstNode node) {
// base case
node.(VarAccess).getDeclaration() = var and
not isSmallType(var.getType()) // <- early pruning
or
// recursive cases
alwaysBindsVar(var, node.getAChild(_)) and // the recursive step, go one step up to the parent.
not node.(FullAggregate).getAnArgument() = var and // except if the parent defines the variable, then we stop.
not node.(Quantifier).getAnArgument() = var and
not node instanceof EffectiveDisjunction // for disjunctions, we need to check both sides.
or
exists(EffectiveDisjunction disj | disj = node |
alwaysBindsVar(var, disj.getLeft()) and
alwaysBindsVar(var, disj.getRight())
)
or
exists(EffectiveDisjunction disj | disj = node |
alwaysBindsVar(var, disj.getAnOperand()) and
disj.getAnOperand() instanceof NoneCall
)
or
exists(IfFormula ifForm | ifForm = node | alwaysBindsVar(var, ifForm.getCondition()))
}
/**
* Holds if we assume `t` is a small type, and
* variables of this type are therefore not an issue in cartesian products.
*/
predicate isSmallType(Type t) {
t.getName() = "string" // DataFlow::Configuration and the like
or
exists(NewType newType | newType = t.getDeclaration() |
forex(NewTypeBranch branch | branch = newType.getABranch() | branch.getArity() = 0)
)
or
t.getName() = "boolean"
or
exists(NewType newType | newType = t.getDeclaration() |
forex(NewTypeBranch branch | branch = newType.getABranch() |
isSmallType(branch.getReturnType())
)
)
or
exists(NewTypeBranch branch | t = branch.getReturnType() |
forall(Type param | param = branch.getParameterType(_) | isSmallType(param))
)
or
isSmallType(t.getASuperType())
}
/**
* Holds if `pred` is inlined.
*/
predicate isInlined(Predicate pred) {
exists(Annotation inline |
inline = pred.getAnAnnotation() and
inline.getName() = "pragma" and
inline.getArgs(0).getValue() = "inline"
)
or
pred.getAnAnnotation().getName() = "bindingset"
}
/**
* An AstNode that acts like a disjunction.
*/
class EffectiveDisjunction extends AstNode {
EffectiveDisjunction() {
this instanceof IfFormula
or
this instanceof Disjunction
}
/** Gets the left operand of this disjunction. */
AstNode getLeft() {
result = this.(IfFormula).getThenPart()
or
result = this.(Disjunction).getLeft()
}
/** Gets the right operand of this disjunction. */
AstNode getRight() {
result = this.(IfFormula).getElsePart()
or
result = this.(Disjunction).getRight()
}
/** Gets any of the operands of this disjunction. */
AstNode getAnOperand() { result = [this.getLeft(), this.getRight()] }
}
/**
* Holds if `disj` only uses `var` in one of its branches.
*/
pragma[noinline]
predicate onlyUseInOneBranch(EffectiveDisjunction disj, VarDef var) {
alwaysBindsVar(var, disj.getLeft()) and
not alwaysBindsVar(var, disj.getRight())
or
not alwaysBindsVar(var, disj.getLeft()) and
alwaysBindsVar(var, disj.getRight())
}
/**
* Holds if `comp` is an equality comparison that has a low number of results.
*/
predicate isTinyAssignment(ComparisonFormula comp) {
comp.getOperator() = "=" and
(
isSmallType(comp.getAnOperand().getType())
or
comp.getAnOperand() instanceof Literal
)
}
/**
* An AstNode that acts like a conjunction.
*/
class EffectiveConjunction extends AstNode {
EffectiveConjunction() {
this instanceof Conjunction
or
this instanceof Exists
}
/** Gets the left operand of this conjunction */
Formula getLeft() {
result = this.(Conjunction).getLeft()
or
result = this.(Exists).getRange()
}
/** Gets the right operand of this conjunction */
Formula getRight() {
result = this.(Conjunction).getRight()
or
result = this.(Exists).getFormula()
}
}
/**
* Holds if `node` is a sub-node of a node that always binds `var`.
*/
predicate varIsAlwaysBound(VarDef var, AstNode node) {
// base case
alwaysBindsVar(var, node) and
onlyUseInOneBranch(_, var) // <- manual magic
or
// recursive cases
exists(AstNode parent | node.getParent() = parent | varIsAlwaysBound(var, parent))
or
exists(EffectiveConjunction parent |
varIsAlwaysBound(var, parent.getLeft()) and
node = parent.getRight()
or
varIsAlwaysBound(var, parent.getRight()) and
node = parent.getLeft()
)
or
exists(IfFormula ifForm | varIsAlwaysBound(var, ifForm.getCondition()) |
node = [ifForm.getThenPart(), ifForm.getElsePart()]
)
or
exists(Forall for | varIsAlwaysBound(var, for.getRange()) | node = for.getFormula())
}
/**
* Holds if `disj` only uses `var` in one of its branches.
* And we should report it as being a bad thing.
*/
predicate badDisjunction(EffectiveDisjunction disj, VarDef var) {
onlyUseInOneBranch(disj, var) and
// it's fine if it's always bound further up
not varIsAlwaysBound(var, disj) and
// none() on one side makes everything fine. (this happens, it's a type-system hack)
not disj.getAnOperand() instanceof NoneCall and
// inlined predicates might bind unused variables in the context they are used in.
not (
isInlined(disj.getEnclosingPredicate()) and
var = disj.getEnclosingPredicate().getParameter(_)
) and
// recursion prevention never runs, it's a compile-time check, so we remove those results here
not disj.getEnclosingPredicate().getParent().(Class).getName().matches("%RecursionPrevention") and // these are by design
// not a small type
not isSmallType(var.getType()) and
// one of the branches is a tiny assignment. These are usually intentional cartesian products (and not too big).
not isTinyAssignment(disj.getAnOperand())
}
from EffectiveDisjunction disj, VarDef var
where
badDisjunction(disj, var) and
not badDisjunction(disj.getParent(), var) // avoid duplicate reporting of the same error
select disj, "The variable " + var.getName() + " is only used in one side of disjunct."

View File

@@ -9,25 +9,7 @@
*/
import ql
MemberCall explicitThisCallInFile(File f) {
result.getLocation().getFile() = f and
result.getBase() instanceof ThisAccess and
// Exclude `this.(Type).whatever(...)`, as some files have that as their only instance of `this`.
not result = any(InlineCast c).getBase()
}
PredicateCall implicitThisCallInFile(File f) {
result.getLocation().getFile() = f and
exists(result.getTarget().getDeclaringType().getASuperType()) and
// Exclude `SomeModule::whatever(...)`
not exists(result.getQualifier())
}
PredicateCall confusingImplicitThisCall(File f) {
result = implicitThisCallInFile(f) and
exists(explicitThisCallInFile(f))
}
import codeql_ql.style.ImplicitThisQuery
from PredicateCall c
where c = confusingImplicitThisCall(_)

View File

@@ -0,0 +1,16 @@
/**
* @name Redundant inline cast
* @description Redundant inline casts
* @kind problem
* @problem.severity error
* @id ql/redundant-inline-cast
* @tags maintainability
* @precision high
*/
import ql
import codeql_ql.style.RedundantInlineCastQuery
from RedundantInlineCast cast
select cast, "Redundant cast to $@", cast.getTypeExpr(),
cast.getTypeExpr().getResolvedType().getName()

View File

@@ -227,7 +227,7 @@ module DataFlow {
)
or
exists(ComparisonFormula eq |
eq.getSymbol() = "=" and
eq.getOperator() = "=" and
eq.getAnOperand() = e1 and
eq.getAnOperand() = e2 and
e1 != e2

View File

@@ -0,0 +1,21 @@
/**
* @name Suggest using non-extending subtype relationships.
* @description Non-extending subtypes ("instanceof extensions") are generally preferrable to instanceof expressions in characteristic predicates.
* @kind problem
* @problem.severity warning
* @id ql/suggest-instanceof-extension
* @tags maintainability
* @precision medium
*/
import ql
import codeql_ql.style.UseInstanceofExtensionQuery
from Class c, Type type, string message
where
(
usesCastingBasedInstanceof(c, type) or
usesFieldBasedInstanceof(c, any(TypeExpr te | te.getResolvedType() = type), _, _)
) and
message = "consider defining $@ as non-extending subtype of $@"
select c, message, c, c.getName(), type, type.getName()

View File

@@ -9,107 +9,7 @@
*/
import ql
/**
* A chain of disjunctions treated as one object. For example the following is
* a chain of disjunctions with three operands:
* ```
* a or b or c
* ```
*/
class DisjunctionChain extends Disjunction {
DisjunctionChain() { not exists(Disjunction parent | parent.getAnOperand() = this) }
/**
* Gets any operand of the chain.
*/
Formula getAnOperandRec() {
result = getAnOperand*() and
not result instanceof Disjunction
}
}
/**
* An equality comparison with a `Literal`. For example:
* ```
* x = 4
* ```
*/
class EqualsLiteral extends ComparisonFormula {
EqualsLiteral() {
getSymbol() = "=" and
getAnOperand() instanceof Literal
}
}
/**
* A chain of disjunctions where each operand is an equality comparison between
* the same thing and various `Literal`s. For example:
* ```
* x = 4 or
* x = 5 or
* x = 6
* ```
*/
class DisjunctionEqualsLiteral extends DisjunctionChain {
DisjunctionEqualsLiteral() {
// VarAccess on the same variable
exists(VarDef v |
forex(Formula f | f = getAnOperandRec() |
f.(EqualsLiteral).getAnOperand().(VarAccess).getDeclaration() = v
)
)
or
// FieldAccess on the same variable
exists(VarDecl v |
forex(Formula f | f = getAnOperandRec() |
f.(EqualsLiteral).getAnOperand().(FieldAccess).getDeclaration() = v
)
)
or
// ThisAccess
forex(Formula f | f = getAnOperandRec() |
f.(EqualsLiteral).getAnOperand() instanceof ThisAccess
)
or
// ResultAccess
forex(Formula f | f = getAnOperandRec() |
f.(EqualsLiteral).getAnOperand() instanceof ResultAccess
)
// (in principle something like GlobalValueNumbering could be used to generalize this)
}
}
/**
* A call with a single `Literal` argument. For example:
* ```
* myPredicate(4)
* ```
*/
class CallLiteral extends Call {
CallLiteral() {
getNumberOfArguments() = 1 and
getArgument(0) instanceof Literal
}
}
/**
* A chain of disjunctions where each operand is a call to the same predicate
* using various `Literal`s. For example:
* ```
* myPredicate(4) or
* myPredicate(5) or
* myPredicate(6)
* ```
*/
class DisjunctionPredicateLiteral extends DisjunctionChain {
DisjunctionPredicateLiteral() {
// Call to the same target
exists(PredicateOrBuiltin target |
forex(Formula f | f = getAnOperandRec() | f.(CallLiteral).getTarget() = target)
)
}
}
import codeql_ql.style.UseSetLiteralQuery
from DisjunctionChain d, string msg, int c
where
@@ -124,6 +24,6 @@ where
"This formula of " + c.toString() +
" predicate calls can be replaced with a single call on a set literal, improving readability."
) and
c = count(d.getAnOperandRec()) and
c = count(d.getOperand(_)) and
c >= 4
select d, msg

View File

@@ -1,47 +0,0 @@
/**
* @name Suggest using non-extending subtype relationships.
* @description Non-extending subtypes ("instanceof extensions") are generally preferrable to instanceof expressions in characteristic predicates.
* @kind problem
* @problem.severity warning
* @id ql/suggest-instanceof-extension
* @tags maintainability
* @precision medium
*/
import ql
InstanceOf instanceofInCharPred(Class c) {
result = c.getCharPred().getBody()
or
exists(Conjunction conj |
conj = c.getCharPred().getBody() and
result = conj.getAnOperand()
)
}
predicate instanceofThisInCharPred(Class c, TypeExpr type) {
exists(InstanceOf instanceOf |
instanceOf = instanceofInCharPred(c) and
instanceOf.getExpr() instanceof ThisAccess and
type = instanceOf.getType()
)
}
predicate classWithInstanceofThis(Class c, TypeExpr type) {
instanceofThisInCharPred(c, type) and
exists(ClassPredicate classPred |
classPred = c.getAClassPredicate() and
exists(MemberCall call, InlineCast cast |
call.getEnclosingPredicate() = classPred and
cast = call.getBase() and
cast.getBase() instanceof ThisAccess and
cast.getTypeExpr().getResolvedType() = type.getResolvedType()
)
)
}
from Class c, TypeExpr type, string message
where
classWithInstanceofThis(c, type) and
message = "consider defining $@ as non-extending subtype of $@"
select c, message, c, c.getName(), type, type.getResolvedType().getName()

View File

@@ -13,164 +13,144 @@ nodes
| Foo.qll:4:11:4:11 | Integer | semmle.order | 6 |
| Foo.qll:4:11:4:15 | ComparisonFormula | semmle.label | [ComparisonFormula] ComparisonFormula |
| Foo.qll:4:11:4:15 | ComparisonFormula | semmle.order | 6 |
| Foo.qll:4:13:4:13 | ComparisonOp | semmle.label | [ComparisonOp] ComparisonOp |
| Foo.qll:4:13:4:13 | ComparisonOp | semmle.order | 8 |
| Foo.qll:4:15:4:15 | Integer | semmle.label | [Integer] Integer |
| Foo.qll:4:15:4:15 | Integer | semmle.order | 9 |
| Foo.qll:4:15:4:15 | Integer | semmle.order | 8 |
| Foo.qll:6:3:6:8 | TypeExpr | semmle.label | [TypeExpr] TypeExpr |
| Foo.qll:6:3:6:8 | TypeExpr | semmle.order | 10 |
| Foo.qll:6:3:6:8 | TypeExpr | semmle.order | 9 |
| Foo.qll:6:3:6:38 | ClassPredicate toString | semmle.label | [ClassPredicate] ClassPredicate toString |
| Foo.qll:6:3:6:38 | ClassPredicate toString | semmle.order | 10 |
| Foo.qll:6:3:6:38 | ClassPredicate toString | semmle.order | 9 |
| Foo.qll:6:23:6:28 | result | semmle.label | [ResultAccess] result |
| Foo.qll:6:23:6:28 | result | semmle.order | 12 |
| Foo.qll:6:23:6:28 | result | semmle.order | 11 |
| Foo.qll:6:23:6:36 | ComparisonFormula | semmle.label | [ComparisonFormula] ComparisonFormula |
| Foo.qll:6:23:6:36 | ComparisonFormula | semmle.order | 12 |
| Foo.qll:6:30:6:30 | ComparisonOp | semmle.label | [ComparisonOp] ComparisonOp |
| Foo.qll:6:30:6:30 | ComparisonOp | semmle.order | 14 |
| Foo.qll:6:23:6:36 | ComparisonFormula | semmle.order | 11 |
| Foo.qll:6:32:6:36 | String | semmle.label | [String] String |
| Foo.qll:6:32:6:36 | String | semmle.order | 15 |
| Foo.qll:6:32:6:36 | String | semmle.order | 13 |
| Foo.qll:9:1:9:5 | annotation | semmle.label | [Annotation] annotation |
| Foo.qll:9:1:9:5 | annotation | semmle.order | 16 |
| Foo.qll:9:1:9:5 | annotation | semmle.order | 14 |
| Foo.qll:9:7:11:1 | ClasslessPredicate foo | semmle.label | [ClasslessPredicate] ClasslessPredicate foo |
| Foo.qll:9:7:11:1 | ClasslessPredicate foo | semmle.order | 17 |
| Foo.qll:9:7:11:1 | ClasslessPredicate foo | semmle.order | 15 |
| Foo.qll:9:21:9:23 | TypeExpr | semmle.label | [TypeExpr] TypeExpr |
| Foo.qll:9:21:9:23 | TypeExpr | semmle.order | 18 |
| Foo.qll:9:21:9:23 | TypeExpr | semmle.order | 16 |
| Foo.qll:9:21:9:25 | f | semmle.label | [VarDecl] f |
| Foo.qll:9:21:9:25 | f | semmle.order | 18 |
| Foo.qll:9:21:9:25 | f | semmle.order | 16 |
| Foo.qll:10:3:10:3 | f | semmle.label | [VarAccess] f |
| Foo.qll:10:3:10:3 | f | semmle.order | 20 |
| Foo.qll:10:3:10:3 | f | semmle.order | 18 |
| Foo.qll:10:3:10:85 | ComparisonFormula | semmle.label | [ComparisonFormula] ComparisonFormula |
| Foo.qll:10:3:10:85 | ComparisonFormula | semmle.order | 20 |
| Foo.qll:10:5:10:5 | ComparisonOp | semmle.label | [ComparisonOp] ComparisonOp |
| Foo.qll:10:5:10:5 | ComparisonOp | semmle.order | 22 |
| Foo.qll:10:3:10:85 | ComparisonFormula | semmle.order | 18 |
| Foo.qll:10:7:10:85 | Rank | semmle.label | [Rank] Rank |
| Foo.qll:10:7:10:85 | Rank | semmle.order | 23 |
| Foo.qll:10:7:10:85 | Rank | semmle.order | 20 |
| Foo.qll:10:12:10:12 | Integer | semmle.label | [Integer] Integer |
| Foo.qll:10:12:10:12 | Integer | semmle.order | 24 |
| Foo.qll:10:12:10:12 | Integer | semmle.order | 21 |
| Foo.qll:10:15:10:17 | TypeExpr | semmle.label | [TypeExpr] TypeExpr |
| Foo.qll:10:15:10:17 | TypeExpr | semmle.order | 25 |
| Foo.qll:10:15:10:17 | TypeExpr | semmle.order | 22 |
| Foo.qll:10:15:10:23 | inner | semmle.label | [VarDecl] inner |
| Foo.qll:10:15:10:23 | inner | semmle.order | 25 |
| Foo.qll:10:15:10:23 | inner | semmle.order | 22 |
| Foo.qll:10:27:10:31 | inner | semmle.label | [VarAccess] inner |
| Foo.qll:10:27:10:31 | inner | semmle.order | 27 |
| Foo.qll:10:27:10:31 | inner | semmle.order | 24 |
| Foo.qll:10:27:10:42 | MemberCall | semmle.label | [MemberCall] MemberCall |
| Foo.qll:10:27:10:42 | MemberCall | semmle.order | 27 |
| Foo.qll:10:27:10:42 | MemberCall | semmle.order | 24 |
| Foo.qll:10:27:10:50 | ComparisonFormula | semmle.label | [ComparisonFormula] ComparisonFormula |
| Foo.qll:10:27:10:50 | ComparisonFormula | semmle.order | 27 |
| Foo.qll:10:44:10:44 | ComparisonOp | semmle.label | [ComparisonOp] ComparisonOp |
| Foo.qll:10:44:10:44 | ComparisonOp | semmle.order | 30 |
| Foo.qll:10:27:10:50 | ComparisonFormula | semmle.order | 24 |
| Foo.qll:10:46:10:50 | String | semmle.label | [String] String |
| Foo.qll:10:46:10:50 | String | semmle.order | 31 |
| Foo.qll:10:46:10:50 | String | semmle.order | 27 |
| Foo.qll:10:54:10:58 | inner | semmle.label | [VarAccess] inner |
| Foo.qll:10:54:10:58 | inner | semmle.order | 32 |
| Foo.qll:10:54:10:58 | inner | semmle.order | 28 |
| Foo.qll:10:69:10:73 | inner | semmle.label | [VarAccess] inner |
| Foo.qll:10:69:10:73 | inner | semmle.order | 33 |
| Foo.qll:10:69:10:73 | inner | semmle.order | 29 |
| Foo.qll:10:69:10:84 | MemberCall | semmle.label | [MemberCall] MemberCall |
| Foo.qll:10:69:10:84 | MemberCall | semmle.order | 33 |
| Foo.qll:10:69:10:84 | MemberCall | semmle.order | 29 |
| Foo.qll:13:1:27:1 | ClasslessPredicate calls | semmle.label | [ClasslessPredicate] ClasslessPredicate calls |
| Foo.qll:13:1:27:1 | ClasslessPredicate calls | semmle.order | 35 |
| Foo.qll:13:1:27:1 | ClasslessPredicate calls | semmle.order | 31 |
| Foo.qll:13:17:13:19 | TypeExpr | semmle.label | [TypeExpr] TypeExpr |
| Foo.qll:13:17:13:19 | TypeExpr | semmle.order | 36 |
| Foo.qll:13:17:13:19 | TypeExpr | semmle.order | 32 |
| Foo.qll:13:17:13:21 | f | semmle.label | [VarDecl] f |
| Foo.qll:13:17:13:21 | f | semmle.order | 36 |
| Foo.qll:13:17:13:21 | f | semmle.order | 32 |
| Foo.qll:14:3:14:10 | PredicateCall | semmle.label | [PredicateCall] PredicateCall |
| Foo.qll:14:3:14:10 | PredicateCall | semmle.order | 38 |
| Foo.qll:14:3:14:10 | PredicateCall | semmle.order | 34 |
| Foo.qll:14:3:16:29 | Disjunction | semmle.label | [Disjunction] Disjunction |
| Foo.qll:14:3:16:29 | Disjunction | semmle.order | 38 |
| Foo.qll:14:3:16:29 | Disjunction | semmle.order | 34 |
| Foo.qll:14:3:18:28 | Disjunction | semmle.label | [Disjunction] Disjunction |
| Foo.qll:14:3:18:28 | Disjunction | semmle.order | 38 |
| Foo.qll:14:3:18:28 | Disjunction | semmle.order | 34 |
| Foo.qll:14:3:20:13 | Disjunction | semmle.label | [Disjunction] Disjunction |
| Foo.qll:14:3:20:13 | Disjunction | semmle.order | 38 |
| Foo.qll:14:3:20:13 | Disjunction | semmle.order | 34 |
| Foo.qll:14:3:22:16 | Disjunction | semmle.label | [Disjunction] Disjunction |
| Foo.qll:14:3:22:16 | Disjunction | semmle.order | 38 |
| Foo.qll:14:3:22:16 | Disjunction | semmle.order | 34 |
| Foo.qll:14:3:24:23 | Disjunction | semmle.label | [Disjunction] Disjunction |
| Foo.qll:14:3:24:23 | Disjunction | semmle.order | 38 |
| Foo.qll:14:3:24:23 | Disjunction | semmle.order | 34 |
| Foo.qll:14:3:26:14 | Disjunction | semmle.label | [Disjunction] Disjunction |
| Foo.qll:14:3:26:14 | Disjunction | semmle.order | 38 |
| Foo.qll:14:3:26:14 | Disjunction | semmle.order | 34 |
| Foo.qll:14:9:14:9 | f | semmle.label | [VarAccess] f |
| Foo.qll:14:9:14:9 | f | semmle.order | 45 |
| Foo.qll:14:9:14:9 | f | semmle.order | 41 |
| Foo.qll:16:3:16:7 | String | semmle.label | [String] String |
| Foo.qll:16:3:16:7 | String | semmle.order | 46 |
| Foo.qll:16:3:16:7 | String | semmle.order | 42 |
| Foo.qll:16:3:16:29 | ComparisonFormula | semmle.label | [ComparisonFormula] ComparisonFormula |
| Foo.qll:16:3:16:29 | ComparisonFormula | semmle.order | 46 |
| Foo.qll:16:9:16:9 | ComparisonOp | semmle.label | [ComparisonOp] ComparisonOp |
| Foo.qll:16:9:16:9 | ComparisonOp | semmle.order | 48 |
| Foo.qll:16:3:16:29 | ComparisonFormula | semmle.order | 42 |
| Foo.qll:16:11:16:11 | f | semmle.label | [VarAccess] f |
| Foo.qll:16:11:16:11 | f | semmle.order | 49 |
| Foo.qll:16:11:16:11 | f | semmle.order | 44 |
| Foo.qll:16:11:16:29 | MemberCall | semmle.label | [MemberCall] MemberCall |
| Foo.qll:16:11:16:29 | MemberCall | semmle.order | 49 |
| Foo.qll:16:11:16:29 | MemberCall | semmle.order | 44 |
| Foo.qll:16:22:16:22 | Integer | semmle.label | [Integer] Integer |
| Foo.qll:16:22:16:22 | Integer | semmle.order | 51 |
| Foo.qll:16:22:16:22 | Integer | semmle.order | 46 |
| Foo.qll:16:25:16:25 | Integer | semmle.label | [Integer] Integer |
| Foo.qll:16:25:16:25 | Integer | semmle.order | 52 |
| Foo.qll:16:25:16:25 | Integer | semmle.order | 47 |
| Foo.qll:16:28:16:28 | Integer | semmle.label | [Integer] Integer |
| Foo.qll:16:28:16:28 | Integer | semmle.order | 53 |
| Foo.qll:16:28:16:28 | Integer | semmle.order | 48 |
| Foo.qll:18:3:18:3 | f | semmle.label | [VarAccess] f |
| Foo.qll:18:3:18:3 | f | semmle.order | 54 |
| Foo.qll:18:3:18:3 | f | semmle.order | 49 |
| Foo.qll:18:3:18:9 | InlineCast | semmle.label | [InlineCast] InlineCast |
| Foo.qll:18:3:18:9 | InlineCast | semmle.order | 54 |
| Foo.qll:18:3:18:9 | InlineCast | semmle.order | 49 |
| Foo.qll:18:3:18:20 | MemberCall | semmle.label | [MemberCall] MemberCall |
| Foo.qll:18:3:18:20 | MemberCall | semmle.order | 54 |
| Foo.qll:18:3:18:20 | MemberCall | semmle.order | 49 |
| Foo.qll:18:3:18:28 | ComparisonFormula | semmle.label | [ComparisonFormula] ComparisonFormula |
| Foo.qll:18:3:18:28 | ComparisonFormula | semmle.order | 54 |
| Foo.qll:18:3:18:28 | ComparisonFormula | semmle.order | 49 |
| Foo.qll:18:6:18:8 | TypeExpr | semmle.label | [TypeExpr] TypeExpr |
| Foo.qll:18:6:18:8 | TypeExpr | semmle.order | 58 |
| Foo.qll:18:22:18:22 | ComparisonOp | semmle.label | [ComparisonOp] ComparisonOp |
| Foo.qll:18:22:18:22 | ComparisonOp | semmle.order | 59 |
| Foo.qll:18:6:18:8 | TypeExpr | semmle.order | 53 |
| Foo.qll:18:24:18:28 | String | semmle.label | [String] String |
| Foo.qll:18:24:18:28 | String | semmle.order | 60 |
| Foo.qll:18:24:18:28 | String | semmle.order | 54 |
| Foo.qll:20:3:20:3 | f | semmle.label | [VarAccess] f |
| Foo.qll:20:3:20:3 | f | semmle.order | 61 |
| Foo.qll:20:3:20:3 | f | semmle.order | 55 |
| Foo.qll:20:3:20:9 | InlineCast | semmle.label | [InlineCast] InlineCast |
| Foo.qll:20:3:20:9 | InlineCast | semmle.order | 61 |
| Foo.qll:20:3:20:9 | InlineCast | semmle.order | 55 |
| Foo.qll:20:3:20:13 | ComparisonFormula | semmle.label | [ComparisonFormula] ComparisonFormula |
| Foo.qll:20:3:20:13 | ComparisonFormula | semmle.order | 61 |
| Foo.qll:20:3:20:13 | ComparisonFormula | semmle.order | 55 |
| Foo.qll:20:6:20:8 | TypeExpr | semmle.label | [TypeExpr] TypeExpr |
| Foo.qll:20:6:20:8 | TypeExpr | semmle.order | 64 |
| Foo.qll:20:11:20:11 | ComparisonOp | semmle.label | [ComparisonOp] ComparisonOp |
| Foo.qll:20:11:20:11 | ComparisonOp | semmle.order | 65 |
| Foo.qll:20:6:20:8 | TypeExpr | semmle.order | 58 |
| Foo.qll:20:13:20:13 | f | semmle.label | [VarAccess] f |
| Foo.qll:20:13:20:13 | f | semmle.order | 66 |
| Foo.qll:20:13:20:13 | f | semmle.order | 59 |
| Foo.qll:22:3:22:3 | f | semmle.label | [VarAccess] f |
| Foo.qll:22:3:22:3 | f | semmle.order | 67 |
| Foo.qll:22:3:22:3 | f | semmle.order | 60 |
| Foo.qll:22:3:22:16 | ComparisonFormula | semmle.label | [ComparisonFormula] ComparisonFormula |
| Foo.qll:22:3:22:16 | ComparisonFormula | semmle.order | 67 |
| Foo.qll:22:5:22:5 | ComparisonOp | semmle.label | [ComparisonOp] ComparisonOp |
| Foo.qll:22:5:22:5 | ComparisonOp | semmle.order | 69 |
| Foo.qll:22:3:22:16 | ComparisonFormula | semmle.order | 60 |
| Foo.qll:22:7:22:16 | FullAggregate[any] | semmle.label | [FullAggregate[any]] FullAggregate[any] |
| Foo.qll:22:7:22:16 | FullAggregate[any] | semmle.order | 70 |
| Foo.qll:22:7:22:16 | FullAggregate[any] | semmle.order | 62 |
| Foo.qll:22:11:22:13 | TypeExpr | semmle.label | [TypeExpr] TypeExpr |
| Foo.qll:22:11:22:13 | TypeExpr | semmle.order | 71 |
| Foo.qll:22:11:22:13 | TypeExpr | semmle.order | 63 |
| Foo.qll:22:11:22:15 | f | semmle.label | [VarDecl] f |
| Foo.qll:22:11:22:15 | f | semmle.order | 71 |
| Foo.qll:22:11:22:15 | f | semmle.order | 63 |
| Foo.qll:24:3:24:3 | Integer | semmle.label | [Integer] Integer |
| Foo.qll:24:3:24:3 | Integer | semmle.order | 73 |
| Foo.qll:24:3:24:3 | Integer | semmle.order | 65 |
| Foo.qll:24:3:24:23 | ComparisonFormula | semmle.label | [ComparisonFormula] ComparisonFormula |
| Foo.qll:24:3:24:23 | ComparisonFormula | semmle.order | 73 |
| Foo.qll:24:5:24:5 | ComparisonOp | semmle.label | [ComparisonOp] ComparisonOp |
| Foo.qll:24:5:24:5 | ComparisonOp | semmle.order | 75 |
| Foo.qll:24:3:24:23 | ComparisonFormula | semmle.order | 65 |
| Foo.qll:24:7:24:7 | Integer | semmle.label | [Integer] Integer |
| Foo.qll:24:7:24:7 | Integer | semmle.order | 76 |
| Foo.qll:24:7:24:7 | Integer | semmle.order | 67 |
| Foo.qll:24:7:24:23 | AddExpr | semmle.label | [AddExpr] AddExpr |
| Foo.qll:24:7:24:23 | AddExpr | semmle.order | 76 |
| Foo.qll:24:7:24:23 | AddExpr | semmle.order | 67 |
| Foo.qll:24:12:24:12 | Integer | semmle.label | [Integer] Integer |
| Foo.qll:24:12:24:12 | Integer | semmle.order | 78 |
| Foo.qll:24:12:24:12 | Integer | semmle.order | 69 |
| Foo.qll:24:12:24:22 | AddExpr | semmle.label | [AddExpr] AddExpr |
| Foo.qll:24:12:24:22 | AddExpr | semmle.order | 78 |
| Foo.qll:24:12:24:22 | AddExpr | semmle.order | 69 |
| Foo.qll:24:17:24:17 | Integer | semmle.label | [Integer] Integer |
| Foo.qll:24:17:24:17 | Integer | semmle.order | 80 |
| Foo.qll:24:17:24:17 | Integer | semmle.order | 71 |
| Foo.qll:24:17:24:21 | AddExpr | semmle.label | [AddExpr] AddExpr |
| Foo.qll:24:17:24:21 | AddExpr | semmle.order | 80 |
| Foo.qll:24:17:24:21 | AddExpr | semmle.order | 71 |
| Foo.qll:24:21:24:21 | Integer | semmle.label | [Integer] Integer |
| Foo.qll:24:21:24:21 | Integer | semmle.order | 82 |
| Foo.qll:24:21:24:21 | Integer | semmle.order | 73 |
| Foo.qll:26:3:26:6 | Boolean | semmle.label | [Boolean] Boolean |
| Foo.qll:26:3:26:6 | Boolean | semmle.order | 83 |
| Foo.qll:26:3:26:6 | Boolean | semmle.order | 74 |
| Foo.qll:26:3:26:14 | ComparisonFormula | semmle.label | [ComparisonFormula] ComparisonFormula |
| Foo.qll:26:3:26:14 | ComparisonFormula | semmle.order | 83 |
| Foo.qll:26:8:26:8 | ComparisonOp | semmle.label | [ComparisonOp] ComparisonOp |
| Foo.qll:26:8:26:8 | ComparisonOp | semmle.order | 85 |
| Foo.qll:26:3:26:14 | ComparisonFormula | semmle.order | 74 |
| Foo.qll:26:10:26:14 | Boolean | semmle.label | [Boolean] Boolean |
| Foo.qll:26:10:26:14 | Boolean | semmle.order | 86 |
| Foo.qll:26:10:26:14 | Boolean | semmle.order | 76 |
| file://:0:0:0:0 | abs | semmle.label | [BuiltinPredicate] abs |
| file://:0:0:0:0 | abs | semmle.label | [BuiltinPredicate] abs |
| file://:0:0:0:0 | acos | semmle.label | [BuiltinPredicate] acos |
@@ -253,183 +233,163 @@ nodes
| file://:0:0:0:0 | trim | semmle.label | [BuiltinPredicate] trim |
| file://:0:0:0:0 | ulp | semmle.label | [BuiltinPredicate] ulp |
| printAst.ql:1:1:1:28 | Import | semmle.label | [Import] Import |
| printAst.ql:1:1:1:28 | Import | semmle.order | 87 |
| printAst.ql:1:1:1:28 | Import | semmle.order | 77 |
| printAst.ql:1:1:1:29 | TopLevel | semmle.label | [TopLevel] TopLevel |
| printAst.ql:1:1:1:29 | TopLevel | semmle.order | 87 |
| printAst.ql:1:1:1:29 | TopLevel | semmle.order | 77 |
edges
| Foo.qll:1:1:27:2 | TopLevel | Foo.qll:1:1:1:17 | Import | semmle.label | getAnImport() |
| Foo.qll:1:1:27:2 | TopLevel | Foo.qll:1:1:1:17 | Import | semmle.order | 1 |
| Foo.qll:1:1:27:2 | TopLevel | Foo.qll:3:1:7:1 | Class Foo | semmle.label | getAClass() |
| Foo.qll:1:1:27:2 | TopLevel | Foo.qll:3:1:7:1 | Class Foo | semmle.order | 3 |
| Foo.qll:1:1:27:2 | TopLevel | Foo.qll:9:7:11:1 | ClasslessPredicate foo | semmle.label | getAPredicate() |
| Foo.qll:1:1:27:2 | TopLevel | Foo.qll:9:7:11:1 | ClasslessPredicate foo | semmle.order | 17 |
| Foo.qll:1:1:27:2 | TopLevel | Foo.qll:9:7:11:1 | ClasslessPredicate foo | semmle.order | 15 |
| Foo.qll:1:1:27:2 | TopLevel | Foo.qll:13:1:27:1 | ClasslessPredicate calls | semmle.label | getAPredicate() |
| Foo.qll:1:1:27:2 | TopLevel | Foo.qll:13:1:27:1 | ClasslessPredicate calls | semmle.order | 35 |
| Foo.qll:1:1:27:2 | TopLevel | Foo.qll:13:1:27:1 | ClasslessPredicate calls | semmle.order | 31 |
| Foo.qll:3:1:7:1 | Class Foo | Foo.qll:3:19:3:22 | TypeExpr | semmle.label | getASuperType() |
| Foo.qll:3:1:7:1 | Class Foo | Foo.qll:3:19:3:22 | TypeExpr | semmle.order | 4 |
| Foo.qll:3:1:7:1 | Class Foo | Foo.qll:4:3:4:17 | CharPred Foo | semmle.label | getCharPred() |
| Foo.qll:3:1:7:1 | Class Foo | Foo.qll:4:3:4:17 | CharPred Foo | semmle.order | 5 |
| Foo.qll:3:1:7:1 | Class Foo | Foo.qll:6:3:6:38 | ClassPredicate toString | semmle.label | getClassPredicate(_) |
| Foo.qll:3:1:7:1 | Class Foo | Foo.qll:6:3:6:38 | ClassPredicate toString | semmle.order | 10 |
| Foo.qll:3:1:7:1 | Class Foo | Foo.qll:6:3:6:38 | ClassPredicate toString | semmle.order | 9 |
| Foo.qll:4:3:4:17 | CharPred Foo | Foo.qll:4:11:4:15 | ComparisonFormula | semmle.label | getBody() |
| Foo.qll:4:3:4:17 | CharPred Foo | Foo.qll:4:11:4:15 | ComparisonFormula | semmle.order | 6 |
| Foo.qll:4:11:4:15 | ComparisonFormula | Foo.qll:4:11:4:11 | Integer | semmle.label | getLeftOperand() |
| Foo.qll:4:11:4:15 | ComparisonFormula | Foo.qll:4:11:4:11 | Integer | semmle.order | 6 |
| Foo.qll:4:11:4:15 | ComparisonFormula | Foo.qll:4:13:4:13 | ComparisonOp | semmle.label | getOperator() |
| Foo.qll:4:11:4:15 | ComparisonFormula | Foo.qll:4:13:4:13 | ComparisonOp | semmle.order | 8 |
| Foo.qll:4:11:4:15 | ComparisonFormula | Foo.qll:4:15:4:15 | Integer | semmle.label | getRightOperand() |
| Foo.qll:4:11:4:15 | ComparisonFormula | Foo.qll:4:15:4:15 | Integer | semmle.order | 9 |
| Foo.qll:4:11:4:15 | ComparisonFormula | Foo.qll:4:15:4:15 | Integer | semmle.order | 8 |
| Foo.qll:6:3:6:38 | ClassPredicate toString | Foo.qll:6:3:6:8 | TypeExpr | semmle.label | getReturnTypeExpr() |
| Foo.qll:6:3:6:38 | ClassPredicate toString | Foo.qll:6:3:6:8 | TypeExpr | semmle.order | 10 |
| Foo.qll:6:3:6:38 | ClassPredicate toString | Foo.qll:6:3:6:8 | TypeExpr | semmle.order | 9 |
| Foo.qll:6:3:6:38 | ClassPredicate toString | Foo.qll:6:23:6:36 | ComparisonFormula | semmle.label | getBody() |
| Foo.qll:6:3:6:38 | ClassPredicate toString | Foo.qll:6:23:6:36 | ComparisonFormula | semmle.order | 12 |
| Foo.qll:6:3:6:38 | ClassPredicate toString | Foo.qll:6:23:6:36 | ComparisonFormula | semmle.order | 11 |
| Foo.qll:6:23:6:36 | ComparisonFormula | Foo.qll:6:23:6:28 | result | semmle.label | getLeftOperand() |
| Foo.qll:6:23:6:36 | ComparisonFormula | Foo.qll:6:23:6:28 | result | semmle.order | 12 |
| Foo.qll:6:23:6:36 | ComparisonFormula | Foo.qll:6:30:6:30 | ComparisonOp | semmle.label | getOperator() |
| Foo.qll:6:23:6:36 | ComparisonFormula | Foo.qll:6:30:6:30 | ComparisonOp | semmle.order | 14 |
| Foo.qll:6:23:6:36 | ComparisonFormula | Foo.qll:6:23:6:28 | result | semmle.order | 11 |
| Foo.qll:6:23:6:36 | ComparisonFormula | Foo.qll:6:32:6:36 | String | semmle.label | getRightOperand() |
| Foo.qll:6:23:6:36 | ComparisonFormula | Foo.qll:6:32:6:36 | String | semmle.order | 15 |
| Foo.qll:6:23:6:36 | ComparisonFormula | Foo.qll:6:32:6:36 | String | semmle.order | 13 |
| Foo.qll:9:1:9:5 | annotation | Foo.qll:9:1:9:5 | annotation | semmle.label | getAnAnnotation() |
| Foo.qll:9:1:9:5 | annotation | Foo.qll:9:1:9:5 | annotation | semmle.order | 16 |
| Foo.qll:9:1:9:5 | annotation | Foo.qll:9:1:9:5 | annotation | semmle.order | 14 |
| Foo.qll:9:7:11:1 | ClasslessPredicate foo | Foo.qll:9:1:9:5 | annotation | semmle.label | getAnAnnotation() |
| Foo.qll:9:7:11:1 | ClasslessPredicate foo | Foo.qll:9:1:9:5 | annotation | semmle.order | 16 |
| Foo.qll:9:7:11:1 | ClasslessPredicate foo | Foo.qll:9:1:9:5 | annotation | semmle.order | 14 |
| Foo.qll:9:7:11:1 | ClasslessPredicate foo | Foo.qll:9:21:9:25 | f | semmle.label | getParameter(_) |
| Foo.qll:9:7:11:1 | ClasslessPredicate foo | Foo.qll:9:21:9:25 | f | semmle.order | 18 |
| Foo.qll:9:7:11:1 | ClasslessPredicate foo | Foo.qll:9:21:9:25 | f | semmle.order | 16 |
| Foo.qll:9:7:11:1 | ClasslessPredicate foo | Foo.qll:10:3:10:85 | ComparisonFormula | semmle.label | getBody() |
| Foo.qll:9:7:11:1 | ClasslessPredicate foo | Foo.qll:10:3:10:85 | ComparisonFormula | semmle.order | 20 |
| Foo.qll:9:7:11:1 | ClasslessPredicate foo | Foo.qll:10:3:10:85 | ComparisonFormula | semmle.order | 18 |
| Foo.qll:9:21:9:25 | f | Foo.qll:9:21:9:23 | TypeExpr | semmle.label | getTypeExpr() |
| Foo.qll:9:21:9:25 | f | Foo.qll:9:21:9:23 | TypeExpr | semmle.order | 18 |
| Foo.qll:9:21:9:25 | f | Foo.qll:9:21:9:23 | TypeExpr | semmle.order | 16 |
| Foo.qll:10:3:10:85 | ComparisonFormula | Foo.qll:10:3:10:3 | f | semmle.label | getLeftOperand() |
| Foo.qll:10:3:10:85 | ComparisonFormula | Foo.qll:10:3:10:3 | f | semmle.order | 20 |
| Foo.qll:10:3:10:85 | ComparisonFormula | Foo.qll:10:5:10:5 | ComparisonOp | semmle.label | getOperator() |
| Foo.qll:10:3:10:85 | ComparisonFormula | Foo.qll:10:5:10:5 | ComparisonOp | semmle.order | 22 |
| Foo.qll:10:3:10:85 | ComparisonFormula | Foo.qll:10:3:10:3 | f | semmle.order | 18 |
| Foo.qll:10:3:10:85 | ComparisonFormula | Foo.qll:10:7:10:85 | Rank | semmle.label | getRightOperand() |
| Foo.qll:10:3:10:85 | ComparisonFormula | Foo.qll:10:7:10:85 | Rank | semmle.order | 23 |
| Foo.qll:10:3:10:85 | ComparisonFormula | Foo.qll:10:7:10:85 | Rank | semmle.order | 20 |
| Foo.qll:10:7:10:85 | Rank | Foo.qll:10:12:10:12 | Integer | semmle.label | getRankExpr() |
| Foo.qll:10:7:10:85 | Rank | Foo.qll:10:12:10:12 | Integer | semmle.order | 24 |
| Foo.qll:10:7:10:85 | Rank | Foo.qll:10:12:10:12 | Integer | semmle.order | 21 |
| Foo.qll:10:7:10:85 | Rank | Foo.qll:10:15:10:23 | inner | semmle.label | getArgument(_) |
| Foo.qll:10:7:10:85 | Rank | Foo.qll:10:15:10:23 | inner | semmle.order | 25 |
| Foo.qll:10:7:10:85 | Rank | Foo.qll:10:15:10:23 | inner | semmle.order | 22 |
| Foo.qll:10:7:10:85 | Rank | Foo.qll:10:27:10:50 | ComparisonFormula | semmle.label | getRange() |
| Foo.qll:10:7:10:85 | Rank | Foo.qll:10:27:10:50 | ComparisonFormula | semmle.order | 27 |
| Foo.qll:10:7:10:85 | Rank | Foo.qll:10:27:10:50 | ComparisonFormula | semmle.order | 24 |
| Foo.qll:10:7:10:85 | Rank | Foo.qll:10:54:10:58 | inner | semmle.label | getExpr(_) |
| Foo.qll:10:7:10:85 | Rank | Foo.qll:10:54:10:58 | inner | semmle.order | 32 |
| Foo.qll:10:7:10:85 | Rank | Foo.qll:10:54:10:58 | inner | semmle.order | 28 |
| Foo.qll:10:7:10:85 | Rank | Foo.qll:10:69:10:84 | MemberCall | semmle.label | getOrderBy(_) |
| Foo.qll:10:7:10:85 | Rank | Foo.qll:10:69:10:84 | MemberCall | semmle.order | 33 |
| Foo.qll:10:7:10:85 | Rank | Foo.qll:10:69:10:84 | MemberCall | semmle.order | 29 |
| Foo.qll:10:15:10:23 | inner | Foo.qll:10:15:10:17 | TypeExpr | semmle.label | getTypeExpr() |
| Foo.qll:10:15:10:23 | inner | Foo.qll:10:15:10:17 | TypeExpr | semmle.order | 25 |
| Foo.qll:10:15:10:23 | inner | Foo.qll:10:15:10:17 | TypeExpr | semmle.order | 22 |
| Foo.qll:10:27:10:42 | MemberCall | Foo.qll:10:27:10:31 | inner | semmle.label | getBase() |
| Foo.qll:10:27:10:42 | MemberCall | Foo.qll:10:27:10:31 | inner | semmle.order | 27 |
| Foo.qll:10:27:10:42 | MemberCall | Foo.qll:10:27:10:31 | inner | semmle.order | 24 |
| Foo.qll:10:27:10:50 | ComparisonFormula | Foo.qll:10:27:10:42 | MemberCall | semmle.label | getLeftOperand() |
| Foo.qll:10:27:10:50 | ComparisonFormula | Foo.qll:10:27:10:42 | MemberCall | semmle.order | 27 |
| Foo.qll:10:27:10:50 | ComparisonFormula | Foo.qll:10:44:10:44 | ComparisonOp | semmle.label | getOperator() |
| Foo.qll:10:27:10:50 | ComparisonFormula | Foo.qll:10:44:10:44 | ComparisonOp | semmle.order | 30 |
| Foo.qll:10:27:10:50 | ComparisonFormula | Foo.qll:10:27:10:42 | MemberCall | semmle.order | 24 |
| Foo.qll:10:27:10:50 | ComparisonFormula | Foo.qll:10:46:10:50 | String | semmle.label | getRightOperand() |
| Foo.qll:10:27:10:50 | ComparisonFormula | Foo.qll:10:46:10:50 | String | semmle.order | 31 |
| Foo.qll:10:27:10:50 | ComparisonFormula | Foo.qll:10:46:10:50 | String | semmle.order | 27 |
| Foo.qll:10:69:10:84 | MemberCall | Foo.qll:10:69:10:73 | inner | semmle.label | getBase() |
| Foo.qll:10:69:10:84 | MemberCall | Foo.qll:10:69:10:73 | inner | semmle.order | 33 |
| Foo.qll:10:69:10:84 | MemberCall | Foo.qll:10:69:10:73 | inner | semmle.order | 29 |
| Foo.qll:13:1:27:1 | ClasslessPredicate calls | Foo.qll:13:17:13:21 | f | semmle.label | getParameter(_) |
| Foo.qll:13:1:27:1 | ClasslessPredicate calls | Foo.qll:13:17:13:21 | f | semmle.order | 36 |
| Foo.qll:13:1:27:1 | ClasslessPredicate calls | Foo.qll:13:17:13:21 | f | semmle.order | 32 |
| Foo.qll:13:1:27:1 | ClasslessPredicate calls | Foo.qll:14:3:26:14 | Disjunction | semmle.label | getBody() |
| Foo.qll:13:1:27:1 | ClasslessPredicate calls | Foo.qll:14:3:26:14 | Disjunction | semmle.order | 38 |
| Foo.qll:13:1:27:1 | ClasslessPredicate calls | Foo.qll:14:3:26:14 | Disjunction | semmle.order | 34 |
| Foo.qll:13:17:13:21 | f | Foo.qll:13:17:13:19 | TypeExpr | semmle.label | getTypeExpr() |
| Foo.qll:13:17:13:21 | f | Foo.qll:13:17:13:19 | TypeExpr | semmle.order | 36 |
| Foo.qll:13:17:13:21 | f | Foo.qll:13:17:13:19 | TypeExpr | semmle.order | 32 |
| Foo.qll:14:3:14:10 | PredicateCall | Foo.qll:14:9:14:9 | f | semmle.label | getArgument(_) |
| Foo.qll:14:3:14:10 | PredicateCall | Foo.qll:14:9:14:9 | f | semmle.order | 45 |
| Foo.qll:14:3:14:10 | PredicateCall | Foo.qll:14:9:14:9 | f | semmle.order | 41 |
| Foo.qll:14:3:16:29 | Disjunction | Foo.qll:14:3:14:10 | PredicateCall | semmle.label | getAnOperand() |
| Foo.qll:14:3:16:29 | Disjunction | Foo.qll:14:3:14:10 | PredicateCall | semmle.order | 38 |
| Foo.qll:14:3:16:29 | Disjunction | Foo.qll:14:3:14:10 | PredicateCall | semmle.order | 34 |
| Foo.qll:14:3:16:29 | Disjunction | Foo.qll:16:3:16:29 | ComparisonFormula | semmle.label | getAnOperand() |
| Foo.qll:14:3:16:29 | Disjunction | Foo.qll:16:3:16:29 | ComparisonFormula | semmle.order | 46 |
| Foo.qll:14:3:16:29 | Disjunction | Foo.qll:16:3:16:29 | ComparisonFormula | semmle.order | 42 |
| Foo.qll:14:3:18:28 | Disjunction | Foo.qll:14:3:16:29 | Disjunction | semmle.label | getAnOperand() |
| Foo.qll:14:3:18:28 | Disjunction | Foo.qll:14:3:16:29 | Disjunction | semmle.order | 38 |
| Foo.qll:14:3:18:28 | Disjunction | Foo.qll:14:3:16:29 | Disjunction | semmle.order | 34 |
| Foo.qll:14:3:18:28 | Disjunction | Foo.qll:18:3:18:28 | ComparisonFormula | semmle.label | getAnOperand() |
| Foo.qll:14:3:18:28 | Disjunction | Foo.qll:18:3:18:28 | ComparisonFormula | semmle.order | 54 |
| Foo.qll:14:3:18:28 | Disjunction | Foo.qll:18:3:18:28 | ComparisonFormula | semmle.order | 49 |
| Foo.qll:14:3:20:13 | Disjunction | Foo.qll:14:3:18:28 | Disjunction | semmle.label | getAnOperand() |
| Foo.qll:14:3:20:13 | Disjunction | Foo.qll:14:3:18:28 | Disjunction | semmle.order | 38 |
| Foo.qll:14:3:20:13 | Disjunction | Foo.qll:14:3:18:28 | Disjunction | semmle.order | 34 |
| Foo.qll:14:3:20:13 | Disjunction | Foo.qll:20:3:20:13 | ComparisonFormula | semmle.label | getAnOperand() |
| Foo.qll:14:3:20:13 | Disjunction | Foo.qll:20:3:20:13 | ComparisonFormula | semmle.order | 61 |
| Foo.qll:14:3:20:13 | Disjunction | Foo.qll:20:3:20:13 | ComparisonFormula | semmle.order | 55 |
| Foo.qll:14:3:22:16 | Disjunction | Foo.qll:14:3:20:13 | Disjunction | semmle.label | getAnOperand() |
| Foo.qll:14:3:22:16 | Disjunction | Foo.qll:14:3:20:13 | Disjunction | semmle.order | 38 |
| Foo.qll:14:3:22:16 | Disjunction | Foo.qll:14:3:20:13 | Disjunction | semmle.order | 34 |
| Foo.qll:14:3:22:16 | Disjunction | Foo.qll:22:3:22:16 | ComparisonFormula | semmle.label | getAnOperand() |
| Foo.qll:14:3:22:16 | Disjunction | Foo.qll:22:3:22:16 | ComparisonFormula | semmle.order | 67 |
| Foo.qll:14:3:22:16 | Disjunction | Foo.qll:22:3:22:16 | ComparisonFormula | semmle.order | 60 |
| Foo.qll:14:3:24:23 | Disjunction | Foo.qll:14:3:22:16 | Disjunction | semmle.label | getAnOperand() |
| Foo.qll:14:3:24:23 | Disjunction | Foo.qll:14:3:22:16 | Disjunction | semmle.order | 38 |
| Foo.qll:14:3:24:23 | Disjunction | Foo.qll:14:3:22:16 | Disjunction | semmle.order | 34 |
| Foo.qll:14:3:24:23 | Disjunction | Foo.qll:24:3:24:23 | ComparisonFormula | semmle.label | getAnOperand() |
| Foo.qll:14:3:24:23 | Disjunction | Foo.qll:24:3:24:23 | ComparisonFormula | semmle.order | 73 |
| Foo.qll:14:3:24:23 | Disjunction | Foo.qll:24:3:24:23 | ComparisonFormula | semmle.order | 65 |
| Foo.qll:14:3:26:14 | Disjunction | Foo.qll:14:3:24:23 | Disjunction | semmle.label | getAnOperand() |
| Foo.qll:14:3:26:14 | Disjunction | Foo.qll:14:3:24:23 | Disjunction | semmle.order | 38 |
| Foo.qll:14:3:26:14 | Disjunction | Foo.qll:14:3:24:23 | Disjunction | semmle.order | 34 |
| Foo.qll:14:3:26:14 | Disjunction | Foo.qll:26:3:26:14 | ComparisonFormula | semmle.label | getAnOperand() |
| Foo.qll:14:3:26:14 | Disjunction | Foo.qll:26:3:26:14 | ComparisonFormula | semmle.order | 83 |
| Foo.qll:14:3:26:14 | Disjunction | Foo.qll:26:3:26:14 | ComparisonFormula | semmle.order | 74 |
| Foo.qll:16:3:16:29 | ComparisonFormula | Foo.qll:16:3:16:7 | String | semmle.label | getLeftOperand() |
| Foo.qll:16:3:16:29 | ComparisonFormula | Foo.qll:16:3:16:7 | String | semmle.order | 46 |
| Foo.qll:16:3:16:29 | ComparisonFormula | Foo.qll:16:9:16:9 | ComparisonOp | semmle.label | getOperator() |
| Foo.qll:16:3:16:29 | ComparisonFormula | Foo.qll:16:9:16:9 | ComparisonOp | semmle.order | 48 |
| Foo.qll:16:3:16:29 | ComparisonFormula | Foo.qll:16:3:16:7 | String | semmle.order | 42 |
| Foo.qll:16:3:16:29 | ComparisonFormula | Foo.qll:16:11:16:29 | MemberCall | semmle.label | getRightOperand() |
| Foo.qll:16:3:16:29 | ComparisonFormula | Foo.qll:16:11:16:29 | MemberCall | semmle.order | 49 |
| Foo.qll:16:3:16:29 | ComparisonFormula | Foo.qll:16:11:16:29 | MemberCall | semmle.order | 44 |
| Foo.qll:16:11:16:29 | MemberCall | Foo.qll:16:11:16:11 | f | semmle.label | getBase() |
| Foo.qll:16:11:16:29 | MemberCall | Foo.qll:16:11:16:11 | f | semmle.order | 49 |
| Foo.qll:16:11:16:29 | MemberCall | Foo.qll:16:11:16:11 | f | semmle.order | 44 |
| Foo.qll:16:11:16:29 | MemberCall | Foo.qll:16:22:16:22 | Integer | semmle.label | getArgument(_) |
| Foo.qll:16:11:16:29 | MemberCall | Foo.qll:16:22:16:22 | Integer | semmle.order | 51 |
| Foo.qll:16:11:16:29 | MemberCall | Foo.qll:16:22:16:22 | Integer | semmle.order | 46 |
| Foo.qll:16:11:16:29 | MemberCall | Foo.qll:16:25:16:25 | Integer | semmle.label | getArgument(_) |
| Foo.qll:16:11:16:29 | MemberCall | Foo.qll:16:25:16:25 | Integer | semmle.order | 52 |
| Foo.qll:16:11:16:29 | MemberCall | Foo.qll:16:25:16:25 | Integer | semmle.order | 47 |
| Foo.qll:16:11:16:29 | MemberCall | Foo.qll:16:28:16:28 | Integer | semmle.label | getArgument(_) |
| Foo.qll:16:11:16:29 | MemberCall | Foo.qll:16:28:16:28 | Integer | semmle.order | 53 |
| Foo.qll:16:11:16:29 | MemberCall | Foo.qll:16:28:16:28 | Integer | semmle.order | 48 |
| Foo.qll:18:3:18:9 | InlineCast | Foo.qll:18:3:18:3 | f | semmle.label | getBase() |
| Foo.qll:18:3:18:9 | InlineCast | Foo.qll:18:3:18:3 | f | semmle.order | 54 |
| Foo.qll:18:3:18:9 | InlineCast | Foo.qll:18:3:18:3 | f | semmle.order | 49 |
| Foo.qll:18:3:18:9 | InlineCast | Foo.qll:18:6:18:8 | TypeExpr | semmle.label | getTypeExpr() |
| Foo.qll:18:3:18:9 | InlineCast | Foo.qll:18:6:18:8 | TypeExpr | semmle.order | 58 |
| Foo.qll:18:3:18:9 | InlineCast | Foo.qll:18:6:18:8 | TypeExpr | semmle.order | 53 |
| Foo.qll:18:3:18:20 | MemberCall | Foo.qll:18:3:18:9 | InlineCast | semmle.label | getBase() |
| Foo.qll:18:3:18:20 | MemberCall | Foo.qll:18:3:18:9 | InlineCast | semmle.order | 54 |
| Foo.qll:18:3:18:20 | MemberCall | Foo.qll:18:3:18:9 | InlineCast | semmle.order | 49 |
| Foo.qll:18:3:18:28 | ComparisonFormula | Foo.qll:18:3:18:20 | MemberCall | semmle.label | getLeftOperand() |
| Foo.qll:18:3:18:28 | ComparisonFormula | Foo.qll:18:3:18:20 | MemberCall | semmle.order | 54 |
| Foo.qll:18:3:18:28 | ComparisonFormula | Foo.qll:18:22:18:22 | ComparisonOp | semmle.label | getOperator() |
| Foo.qll:18:3:18:28 | ComparisonFormula | Foo.qll:18:22:18:22 | ComparisonOp | semmle.order | 59 |
| Foo.qll:18:3:18:28 | ComparisonFormula | Foo.qll:18:3:18:20 | MemberCall | semmle.order | 49 |
| Foo.qll:18:3:18:28 | ComparisonFormula | Foo.qll:18:24:18:28 | String | semmle.label | getRightOperand() |
| Foo.qll:18:3:18:28 | ComparisonFormula | Foo.qll:18:24:18:28 | String | semmle.order | 60 |
| Foo.qll:18:3:18:28 | ComparisonFormula | Foo.qll:18:24:18:28 | String | semmle.order | 54 |
| Foo.qll:20:3:20:9 | InlineCast | Foo.qll:20:3:20:3 | f | semmle.label | getBase() |
| Foo.qll:20:3:20:9 | InlineCast | Foo.qll:20:3:20:3 | f | semmle.order | 61 |
| Foo.qll:20:3:20:9 | InlineCast | Foo.qll:20:3:20:3 | f | semmle.order | 55 |
| Foo.qll:20:3:20:9 | InlineCast | Foo.qll:20:6:20:8 | TypeExpr | semmle.label | getTypeExpr() |
| Foo.qll:20:3:20:9 | InlineCast | Foo.qll:20:6:20:8 | TypeExpr | semmle.order | 64 |
| Foo.qll:20:3:20:9 | InlineCast | Foo.qll:20:6:20:8 | TypeExpr | semmle.order | 58 |
| Foo.qll:20:3:20:13 | ComparisonFormula | Foo.qll:20:3:20:9 | InlineCast | semmle.label | getLeftOperand() |
| Foo.qll:20:3:20:13 | ComparisonFormula | Foo.qll:20:3:20:9 | InlineCast | semmle.order | 61 |
| Foo.qll:20:3:20:13 | ComparisonFormula | Foo.qll:20:11:20:11 | ComparisonOp | semmle.label | getOperator() |
| Foo.qll:20:3:20:13 | ComparisonFormula | Foo.qll:20:11:20:11 | ComparisonOp | semmle.order | 65 |
| Foo.qll:20:3:20:13 | ComparisonFormula | Foo.qll:20:3:20:9 | InlineCast | semmle.order | 55 |
| Foo.qll:20:3:20:13 | ComparisonFormula | Foo.qll:20:13:20:13 | f | semmle.label | getRightOperand() |
| Foo.qll:20:3:20:13 | ComparisonFormula | Foo.qll:20:13:20:13 | f | semmle.order | 66 |
| Foo.qll:20:3:20:13 | ComparisonFormula | Foo.qll:20:13:20:13 | f | semmle.order | 59 |
| Foo.qll:22:3:22:16 | ComparisonFormula | Foo.qll:22:3:22:3 | f | semmle.label | getLeftOperand() |
| Foo.qll:22:3:22:16 | ComparisonFormula | Foo.qll:22:3:22:3 | f | semmle.order | 67 |
| Foo.qll:22:3:22:16 | ComparisonFormula | Foo.qll:22:5:22:5 | ComparisonOp | semmle.label | getOperator() |
| Foo.qll:22:3:22:16 | ComparisonFormula | Foo.qll:22:5:22:5 | ComparisonOp | semmle.order | 69 |
| Foo.qll:22:3:22:16 | ComparisonFormula | Foo.qll:22:3:22:3 | f | semmle.order | 60 |
| Foo.qll:22:3:22:16 | ComparisonFormula | Foo.qll:22:7:22:16 | FullAggregate[any] | semmle.label | getRightOperand() |
| Foo.qll:22:3:22:16 | ComparisonFormula | Foo.qll:22:7:22:16 | FullAggregate[any] | semmle.order | 70 |
| Foo.qll:22:3:22:16 | ComparisonFormula | Foo.qll:22:7:22:16 | FullAggregate[any] | semmle.order | 62 |
| Foo.qll:22:7:22:16 | FullAggregate[any] | Foo.qll:22:11:22:15 | f | semmle.label | getArgument(_) |
| Foo.qll:22:7:22:16 | FullAggregate[any] | Foo.qll:22:11:22:15 | f | semmle.order | 71 |
| Foo.qll:22:7:22:16 | FullAggregate[any] | Foo.qll:22:11:22:15 | f | semmle.order | 63 |
| Foo.qll:22:11:22:15 | f | Foo.qll:22:11:22:13 | TypeExpr | semmle.label | getTypeExpr() |
| Foo.qll:22:11:22:15 | f | Foo.qll:22:11:22:13 | TypeExpr | semmle.order | 71 |
| Foo.qll:22:11:22:15 | f | Foo.qll:22:11:22:13 | TypeExpr | semmle.order | 63 |
| Foo.qll:24:3:24:23 | ComparisonFormula | Foo.qll:24:3:24:3 | Integer | semmle.label | getLeftOperand() |
| Foo.qll:24:3:24:23 | ComparisonFormula | Foo.qll:24:3:24:3 | Integer | semmle.order | 73 |
| Foo.qll:24:3:24:23 | ComparisonFormula | Foo.qll:24:5:24:5 | ComparisonOp | semmle.label | getOperator() |
| Foo.qll:24:3:24:23 | ComparisonFormula | Foo.qll:24:5:24:5 | ComparisonOp | semmle.order | 75 |
| Foo.qll:24:3:24:23 | ComparisonFormula | Foo.qll:24:3:24:3 | Integer | semmle.order | 65 |
| Foo.qll:24:3:24:23 | ComparisonFormula | Foo.qll:24:7:24:23 | AddExpr | semmle.label | getRightOperand() |
| Foo.qll:24:3:24:23 | ComparisonFormula | Foo.qll:24:7:24:23 | AddExpr | semmle.order | 76 |
| Foo.qll:24:3:24:23 | ComparisonFormula | Foo.qll:24:7:24:23 | AddExpr | semmle.order | 67 |
| Foo.qll:24:7:24:23 | AddExpr | Foo.qll:24:7:24:7 | Integer | semmle.label | getLeftOperand() |
| Foo.qll:24:7:24:23 | AddExpr | Foo.qll:24:7:24:7 | Integer | semmle.order | 76 |
| Foo.qll:24:7:24:23 | AddExpr | Foo.qll:24:7:24:7 | Integer | semmle.order | 67 |
| Foo.qll:24:7:24:23 | AddExpr | Foo.qll:24:12:24:22 | AddExpr | semmle.label | getRightOperand() |
| Foo.qll:24:7:24:23 | AddExpr | Foo.qll:24:12:24:22 | AddExpr | semmle.order | 78 |
| Foo.qll:24:7:24:23 | AddExpr | Foo.qll:24:12:24:22 | AddExpr | semmle.order | 69 |
| Foo.qll:24:12:24:22 | AddExpr | Foo.qll:24:12:24:12 | Integer | semmle.label | getLeftOperand() |
| Foo.qll:24:12:24:22 | AddExpr | Foo.qll:24:12:24:12 | Integer | semmle.order | 78 |
| Foo.qll:24:12:24:22 | AddExpr | Foo.qll:24:12:24:12 | Integer | semmle.order | 69 |
| Foo.qll:24:12:24:22 | AddExpr | Foo.qll:24:17:24:21 | AddExpr | semmle.label | getRightOperand() |
| Foo.qll:24:12:24:22 | AddExpr | Foo.qll:24:17:24:21 | AddExpr | semmle.order | 80 |
| Foo.qll:24:12:24:22 | AddExpr | Foo.qll:24:17:24:21 | AddExpr | semmle.order | 71 |
| Foo.qll:24:17:24:21 | AddExpr | Foo.qll:24:17:24:17 | Integer | semmle.label | getLeftOperand() |
| Foo.qll:24:17:24:21 | AddExpr | Foo.qll:24:17:24:17 | Integer | semmle.order | 80 |
| Foo.qll:24:17:24:21 | AddExpr | Foo.qll:24:17:24:17 | Integer | semmle.order | 71 |
| Foo.qll:24:17:24:21 | AddExpr | Foo.qll:24:21:24:21 | Integer | semmle.label | getRightOperand() |
| Foo.qll:24:17:24:21 | AddExpr | Foo.qll:24:21:24:21 | Integer | semmle.order | 82 |
| Foo.qll:24:17:24:21 | AddExpr | Foo.qll:24:21:24:21 | Integer | semmle.order | 73 |
| Foo.qll:26:3:26:14 | ComparisonFormula | Foo.qll:26:3:26:6 | Boolean | semmle.label | getLeftOperand() |
| Foo.qll:26:3:26:14 | ComparisonFormula | Foo.qll:26:3:26:6 | Boolean | semmle.order | 83 |
| Foo.qll:26:3:26:14 | ComparisonFormula | Foo.qll:26:8:26:8 | ComparisonOp | semmle.label | getOperator() |
| Foo.qll:26:3:26:14 | ComparisonFormula | Foo.qll:26:8:26:8 | ComparisonOp | semmle.order | 85 |
| Foo.qll:26:3:26:14 | ComparisonFormula | Foo.qll:26:3:26:6 | Boolean | semmle.order | 74 |
| Foo.qll:26:3:26:14 | ComparisonFormula | Foo.qll:26:10:26:14 | Boolean | semmle.label | getRightOperand() |
| Foo.qll:26:3:26:14 | ComparisonFormula | Foo.qll:26:10:26:14 | Boolean | semmle.order | 86 |
| Foo.qll:26:3:26:14 | ComparisonFormula | Foo.qll:26:10:26:14 | Boolean | semmle.order | 76 |
| printAst.ql:1:1:1:29 | TopLevel | printAst.ql:1:1:1:28 | Import | semmle.label | getAnImport() |
| printAst.ql:1:1:1:29 | TopLevel | printAst.ql:1:1:1:28 | Import | semmle.order | 87 |
| printAst.ql:1:1:1:29 | TopLevel | printAst.ql:1:1:1:28 | Import | semmle.order | 77 |
graphProperties
| semmle.graphKind | tree |

View File

@@ -0,0 +1,167 @@
import ql
class Big = Expr;
class Small extends boolean {
Small() { this = [true, false] }
}
class MyStr extends string {
MyStr() { this = ["foo", "bar"] }
}
predicate bad1(Big b) {
b.toString().matches("%foo")
or
any()
}
int bad2() {
exists(Big big, Small small |
result = big.toString().toInt()
or
result = small.toString().toInt()
)
}
float bad3(Big t) {
result = [1 .. 10].toString().toFloat() or
result = [11 .. 20].toString().toFloat() or
result = t.toString().toFloat() or
result = [21 .. 30].toString().toFloat()
}
string good1(Big t) {
(
result = t.toString()
or
result instanceof MyStr // <- t unused here, but that's ok because of the conjunct that binds t.
) and
t.toString().regexpMatch(".*foo")
}
predicate helper(Big a, Big b) {
a = b and
a.toString().matches("%foo")
}
predicate bad4(Big fromType, Big toType) {
helper(fromType, toType)
or
fromType.toString().matches("%foo")
or
helper(toType, fromType)
}
predicate good2(Big t) {
exists(Small other |
t.toString().matches("%foo")
or
other.toString().matches("%foo") // <- t unused here, but that's ok because of the conjunct (exists) that binds t.
|
t.toString().regexpMatch(".*foo")
)
}
predicate mixed1(Big good, Small small) {
good.toString().matches("%foo")
or
good =
any(Big bad |
small.toString().matches("%foo") and
// the use of good is fine, the comparison futher up binds it.
// the same is not true for bad.
(bad.toString().matches("%foo") or good.toString().regexpMatch("foo.*")) and
small.toString().regexpMatch(".*foo")
)
}
newtype OtherSmall =
Small1() or
Small2(boolean b) { b = true } or
Small3(boolean b, Small o) {
b = true and
o.toString().matches("%foo")
}
predicate good3(OtherSmall small) {
small = Small1()
or
1 = 1
}
predicate good4(Big big, Small small) {
big.toString().matches("%foo")
or
// assignment to small type, intentional cartesian product
small = any(Small s | s.toString().matches("%foo"))
}
predicate good5(Big bb, Big v, boolean certain) {
exists(Big read |
read = bb and
read = v and
certain = true
)
or
v =
any(Big lsv |
lsv.getEnclosingPredicate() = bb.(Expr).getEnclosingPredicate() and
(lsv.toString().matches("%foo") or v.toString().matches("%foo")) and
certain = false
)
}
predicate bad5(Big bb) { if none() then bb.toString().matches("%foo") else any() }
pragma[inline]
predicate good5(Big a, Big b) {
// fine. Assumes it's used somewhere where `a` and `b` are bound.
b = any(Big bb | bb.toString().matches("%foo"))
or
a = any(Big bb | bb.toString().matches("%foo"))
}
predicate bad6(Big a) {
(
a.toString().matches("%foo") // bad
or
any()
) and
(
a.toString().matches("%foo") // also bad
or
any()
)
}
predicate good6(Big a) {
a.toString().matches("%foo") and
(
a.toString().matches("%foo") // good, `a` is bound on the branch of the conjunction.
or
any()
)
}
predicate good7() {
exists(Big l, Big r |
l.toString().matches("%foo1") and
r.toString().matches("%foo2")
or
l.toString().matches("%foo3") and
r.toString().matches("%foo4")
|
not (l.toString().regexpMatch("%foo5") or r.toString().regexpMatch("%foo6")) and
(l.toString().regexpMatch("%foo7") or r.toString().regexpMatch("%foo8"))
)
}
// TOOD: Next test, this one is
string good8(int bitSize) {
if bitSize != 0
then bitSize = 1 and result = bitSize.toString()
else (
if 1 = 0 then result = "foo" else result = "bar"
)
}

View File

@@ -0,0 +1,8 @@
| Test.qll:14:3:16:7 | Disjunction | The variable b is only used in one side of disjunct. |
| Test.qll:21:5:23:37 | Disjunction | The variable big is only used in one side of disjunct. |
| Test.qll:28:3:30:33 | Disjunction | The variable t is only used in one side of disjunct. |
| Test.qll:49:3:53:26 | Disjunction | The variable toType is only used in one side of disjunct. |
| Test.qll:74:8:74:77 | Disjunction | The variable bad is only used in one side of disjunct. |
| Test.qll:115:26:115:80 | IfFormula | The variable bb is only used in one side of disjunct. |
| Test.qll:127:5:129:9 | Disjunction | The variable a is only used in one side of disjunct. |
| Test.qll:132:5:134:9 | Disjunction | The variable a is only used in one side of disjunct. |

View File

@@ -0,0 +1 @@
queries/performance/VarUnusedInDisjunct.ql