Skip to content

Commit ae8c75a

Browse files
committed
Generalize ConjunctionParent
1 parent 36ca97e commit ae8c75a

File tree

3 files changed

+69
-49
lines changed

3 files changed

+69
-49
lines changed
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
import ql
2+
3+
signature predicate checkAstNodeSig(AstNode p);
4+
5+
module ConjunctionParent<checkAstNodeSig/1 checkAstNode> {
6+
/**
7+
* Gets the top-most parent of `p` that is not a disjunction.
8+
*/
9+
AstNode getConjunctionParent(AstNode p) {
10+
result =
11+
min(int level, AstNode parent |
12+
parent = getConjunctionParentRec(p) and level = level(parent)
13+
|
14+
parent order by level
15+
)
16+
}
17+
18+
/**
19+
* Gets a (transitive) parent of `p`, where the parent is not a negative edge, and `checkAstNode(p)` holds.
20+
*/
21+
private AstNode getConjunctionParentRec(AstNode p) {
22+
checkAstNode(p) and
23+
result = p
24+
or
25+
result = getConjunctionParentRec(p).getParent() and
26+
not result instanceof Disjunction and
27+
not result instanceof IfFormula and
28+
not result instanceof Implication and
29+
not result instanceof Negation and
30+
not result instanceof Predicate and
31+
not result instanceof FullAggregate and
32+
not result instanceof Forex and
33+
not result instanceof Forall
34+
}
35+
36+
/**
37+
* Gets which level in the AST `p` is at.
38+
* E.g. the top-level is 0, the next level is 1, etc.
39+
*/
40+
private int level(AstNode p) {
41+
p instanceof TopLevel and result = 0
42+
or
43+
result = level(p.getParent()) + 1
44+
}
45+
}

ql/ql/src/queries/style/OmittableExists.ql

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -9,23 +9,31 @@
99
*/
1010

1111
import ql
12+
import codeql_ql.style.ConjunctionParent
1213

13-
class AggregateOrForQuantifier extends AstNode {
14-
AggregateOrForQuantifier() {
15-
this instanceof FullAggregate or this instanceof Forex or this instanceof Forall
16-
}
17-
}
18-
19-
from VarDecl existsArgument, VarAccess use
20-
where
14+
/**
15+
* Holds if `existsArgument` is the declaration of a variable in an `exists` formula,
16+
* and `use` is both its only use and an argument of a predicate that doesn't restrict
17+
* the corresponding parameter type.
18+
*/
19+
predicate omittableExists(VarDecl existsArgument, VarAccess use) {
2120
existsArgument = any(Exists e).getAnArgument() and
2221
use = unique( | | existsArgument.getAnAccess()) and
2322
exists(Call c, int argPos, Type paramType |
2423
c.getArgument(argPos) = use and paramType = c.getTarget().getParameterType(argPos)
2524
|
2625
existsArgument.getType() = paramType.getASuperType*() and
2726
not paramType instanceof DatabaseType
28-
) and
29-
not use.getParent*() instanceof AggregateOrForQuantifier
27+
)
28+
}
29+
30+
/** Holds if `p` is an exists variable (either declaration or use) that can be omitted. */
31+
predicate omittableExistsNode(AstNode p) { omittableExists(p, _) or omittableExists(_, p) }
32+
33+
from VarDecl existsArgument, VarAccess use
34+
where
35+
omittableExists(existsArgument, use) and
36+
ConjunctionParent<omittableExistsNode/1>::getConjunctionParent(existsArgument) =
37+
ConjunctionParent<omittableExistsNode/1>::getConjunctionParent(use)
3038
select existsArgument, "This exists variable can be omitted by using a don't-care expression $@.",
3139
use, "in this argument"

ql/ql/src/queries/style/RedundantAssignment.ql

Lines changed: 6 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99
*/
1010

1111
import ql
12+
import codeql_ql.style.ConjunctionParent
13+
import codeql.GlobalValueNumbering as GVN
1214

1315
/**
1416
* A variable that is set equal to (assigned) a value one or more times.
@@ -40,8 +42,6 @@ class AssignedVariable extends VarDecl {
4042
}
4143
}
4244

43-
import codeql.GlobalValueNumbering as GVN
44-
4545
/**
4646
* Holds if `assigned1` and `assigned2` assigns the same value to `var`.
4747
* The assignments may be on different branches of a disjunction.
@@ -58,47 +58,14 @@ predicate candidateRedundantAssignment(AssignedVariable var, Expr assigned1, Exp
5858
assigned1 != assigned2
5959
}
6060

61-
/**
62-
* Gets a (transitive) parent of `p`, where the parent is not a disjunction, and `p` is a candidate assignment from `candidateRedundantAssignment`.
63-
*/
64-
AstNode getConjunctionParentRec(AstNode p) {
65-
candidateRedundantAssignment(_, p, _) and
66-
result = p
67-
or
68-
result = getConjunctionParentRec(p).getParent() and
69-
not result instanceof Disjunction and
70-
not result instanceof IfFormula and
71-
not result instanceof Implication and
72-
not result instanceof Negation and
73-
not result instanceof Predicate
74-
}
75-
76-
/**
77-
* Gets which level in the AST `p` is at.
78-
* E.g. the top-level is 0, the next level is 1, etc.
79-
*/
80-
int level(AstNode p) {
81-
p instanceof TopLevel and result = 0
82-
or
83-
result = level(p.getParent()) + 1
84-
}
85-
86-
/**
87-
* Gets the top-most parent of `p` that is not a disjunction.
88-
*/
89-
AstNode getConjunctionParent(AstNode p) {
90-
result =
91-
min(int level, AstNode parent |
92-
parent = getConjunctionParentRec(p) and level = level(parent)
93-
|
94-
parent order by level
95-
)
96-
}
61+
/** Holds if `p` is a candidate node for redundant assignment. */
62+
predicate candidateNode(AstNode p) { candidateRedundantAssignment(_, p, _) }
9763

9864
from AssignedVariable var, Expr assigned1, Expr assigned2
9965
where
10066
candidateRedundantAssignment(var, assigned1, assigned2) and
101-
getConjunctionParent(assigned1) = getConjunctionParent(assigned2) and
67+
ConjunctionParent<candidateNode/1>::getConjunctionParent(assigned1) =
68+
ConjunctionParent<candidateNode/1>::getConjunctionParent(assigned2) and
10269
// de-duplcation:
10370
(
10471
assigned1.getLocation().getStartLine() < assigned2.getLocation().getStartLine()

0 commit comments

Comments
 (0)