move use-instanceof implementation to Query.qll, and rename the .ql file

This commit is contained in:
Erik Krogh Kristensen
2021-11-18 12:12:47 +01:00
parent 45def1b124
commit 33d363eb94
3 changed files with 91 additions and 47 deletions

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,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

@@ -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()