Skip to content

Commit f320414

Browse files
committed
QL: move use-instanceof implementation to Query.qll, and rename the .ql file
1 parent 28444c7 commit f320414

File tree

3 files changed

+91
-47
lines changed

3 files changed

+91
-47
lines changed
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
import ql
2+
3+
/**
4+
* Gets a class where the charpred has an `this instanceof type` expression.
5+
*/
6+
predicate instanceofThisInCharPred(Class c, Type type) {
7+
exists(InstanceOf instanceOf |
8+
instanceOf = c.getCharPred().getBody()
9+
or
10+
exists(Conjunction conj |
11+
conj = c.getCharPred().getBody() and
12+
instanceOf = conj.getAnOperand()
13+
)
14+
|
15+
instanceOf.getExpr() instanceof ThisAccess and
16+
type = instanceOf.getType().getResolvedType()
17+
)
18+
}
19+
20+
/**
21+
* Holds if `c` uses the casting based range pattern, which could be replaced with `instanceof type`.
22+
*/
23+
predicate usesCastingBasedInstanceof(Class c, Type type) {
24+
instanceofThisInCharPred(c, type) and
25+
// require that there is a call to the range class that matches the name of the enclosing predicate
26+
exists(InlineCast cast, MemberCall call |
27+
cast = getAThisCast(c, type) and
28+
call.getBase() = cast and
29+
cast.getEnclosingPredicate().getName() = call.getMemberName()
30+
)
31+
}
32+
33+
/** Gets an inline cast that cases `this` to `type` inside a class predicate for `c`. */
34+
InlineCast getAThisCast(Class c, Type type) {
35+
exists(MemberCall call |
36+
call.getEnclosingPredicate() = c.getAClassPredicate() and
37+
result = call.getBase() and
38+
result.getBase() instanceof ThisAccess and
39+
result.getTypeExpr().getResolvedType() = type
40+
)
41+
}
42+
43+
predicate usesFieldBasedInstanceof(Class c, TypeExpr type, VarDecl field, ComparisonFormula comp) {
44+
exists(FieldAccess fieldAccess |
45+
c.getCharPred().getBody() = comp or
46+
c.getCharPred().getBody().(Conjunction).getAnOperand() = comp
47+
|
48+
comp.getOperator() = "=" and
49+
comp.getEnclosingPredicate() = c.getCharPred() and
50+
comp.getAnOperand() instanceof ThisAccess and
51+
comp.getAnOperand() = fieldAccess and
52+
fieldAccess.getDeclaration() = field and
53+
field.getTypeExpr() = type
54+
) and
55+
// require that there is a call to the range field that matches the name of the enclosing predicate
56+
exists(FieldAccess access, MemberCall call |
57+
access = getARangeFieldAccess(c, field, _) and
58+
call.getBase() = access and
59+
access.getEnclosingPredicate().getName() = call.getMemberName()
60+
)
61+
}
62+
63+
FieldAccess getARangeFieldAccess(Class c, VarDecl field, string name) {
64+
exists(MemberCall call |
65+
result = call.getBase() and
66+
result.getDeclaration() = field and
67+
name = call.getMemberName() and
68+
call.getEnclosingPredicate().(ClassPredicate).getParent() = c
69+
)
70+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
/**
2+
* @name Suggest using non-extending subtype relationships.
3+
* @description Non-extending subtypes ("instanceof extensions") are generally preferrable to instanceof expressions in characteristic predicates.
4+
* @kind problem
5+
* @problem.severity warning
6+
* @id ql/suggest-instanceof-extension
7+
* @tags maintainability
8+
* @precision medium
9+
*/
10+
11+
import ql
12+
import codeql_ql.style.UseInstanceofExtensionQuery
13+
14+
from Class c, Type type, string message
15+
where
16+
(
17+
usesCastingBasedInstanceof(c, type) or
18+
usesFieldBasedInstanceof(c, any(TypeExpr te | te.getResolvedType() = type), _, _)
19+
) and
20+
message = "consider defining $@ as non-extending subtype of $@"
21+
select c, message, c, c.getName(), type, type.getName()

ql/src/queries/style/suggestInstanceofExtension.ql

Lines changed: 0 additions & 47 deletions
This file was deleted.

0 commit comments

Comments
 (0)