mirror of
https://github.com/github/codeql.git
synced 2025-12-17 01:03:14 +01:00
Java: Autoformat.
This commit is contained in:
@@ -20,26 +20,24 @@ predicate whitelist(Dependency d) {
|
||||
|
||||
from PomDependency d, Pom source
|
||||
where
|
||||
source.getADependency() = d and
|
||||
// There is not a Pom file for the target of this dependency, so we assume that it was resolved by
|
||||
// a binary file in the local maven repository.
|
||||
not exists(Pom target | target = d.getPom()) and
|
||||
// In order to accurately identify whether this binary dependency is required, we must have identified
|
||||
// a Maven repository. If we have not found a repository, it's likely that it has a custom path of
|
||||
// which we are unaware, so do not report any problems.
|
||||
exists(MavenRepo mr) and
|
||||
// We either haven't indexed a relevant jar file, which suggests that nothing statically depended upon
|
||||
// it, or we have indexed the relevant jar file, but no source code in the project defined by the pom
|
||||
// depends on any code within the detected jar.
|
||||
not pomDependsOnContainer(source, d.getJar()) and
|
||||
// If something that depends on us depends on the jar represented by this dependency, and it doesn't
|
||||
// depend directly on the jar itself, we don't consider it to be "unused".
|
||||
not exists(Pom pomThatDependsOnSource |
|
||||
pomThatDependsOnSource.getAnExportedPom+() = source
|
||||
|
|
||||
pomDependsOnContainer(pomThatDependsOnSource, d.getJar()) and
|
||||
not exists(File f | f = pomThatDependsOnSource.getADependency().getJar() and f = d.getJar())) and
|
||||
// Filter out those dependencies on the whitelist
|
||||
not whitelist(d)
|
||||
source.getADependency() = d and
|
||||
// There is not a Pom file for the target of this dependency, so we assume that it was resolved by
|
||||
// a binary file in the local maven repository.
|
||||
not exists(Pom target | target = d.getPom()) and
|
||||
// In order to accurately identify whether this binary dependency is required, we must have identified
|
||||
// a Maven repository. If we have not found a repository, it's likely that it has a custom path of
|
||||
// which we are unaware, so do not report any problems.
|
||||
exists(MavenRepo mr) and
|
||||
// We either haven't indexed a relevant jar file, which suggests that nothing statically depended upon
|
||||
// it, or we have indexed the relevant jar file, but no source code in the project defined by the pom
|
||||
// depends on any code within the detected jar.
|
||||
not pomDependsOnContainer(source, d.getJar()) and
|
||||
// If something that depends on us depends on the jar represented by this dependency, and it doesn't
|
||||
// depend directly on the jar itself, we don't consider it to be "unused".
|
||||
not exists(Pom pomThatDependsOnSource | pomThatDependsOnSource.getAnExportedPom+() = source |
|
||||
pomDependsOnContainer(pomThatDependsOnSource, d.getJar()) and
|
||||
not exists(File f | f = pomThatDependsOnSource.getADependency().getJar() and f = d.getJar())
|
||||
) and
|
||||
// Filter out those dependencies on the whitelist
|
||||
not whitelist(d)
|
||||
select d, "Maven dependency on the binary package " + d.getShortCoordinate() + " is unused."
|
||||
|
||||
|
||||
@@ -13,18 +13,16 @@ import UnusedMavenDependencies
|
||||
|
||||
from PomDependency d, Pom source, Pom target
|
||||
where
|
||||
source.getADependency() = d and
|
||||
// We have a targetPom file, so this is a "source" dependency, rather than a binary dependency
|
||||
// from the Maven repository. Note, although .pom files exist in the local maven repository, they
|
||||
// are usually not indexed because they are outside the source directory. We assume that they have
|
||||
// not been indexed.
|
||||
target = d.getPom() and
|
||||
// If we have a pom for the target of this dependency, then it is unused iff neither it, nor any
|
||||
// of its transitive dependencies are required.
|
||||
not exists(Pom exported |
|
||||
exported = target.getAnExportedPom*()
|
||||
|
|
||||
pomDependsOnContainer(source, exported.getAnExportedDependency().getJar()) or
|
||||
pomDependsOnPom(source, exported)
|
||||
)
|
||||
source.getADependency() = d and
|
||||
// We have a targetPom file, so this is a "source" dependency, rather than a binary dependency
|
||||
// from the Maven repository. Note, although .pom files exist in the local maven repository, they
|
||||
// are usually not indexed because they are outside the source directory. We assume that they have
|
||||
// not been indexed.
|
||||
target = d.getPom() and
|
||||
// If we have a pom for the target of this dependency, then it is unused iff neither it, nor any
|
||||
// of its transitive dependencies are required.
|
||||
not exists(Pom exported | exported = target.getAnExportedPom*() |
|
||||
pomDependsOnContainer(source, exported.getAnExportedDependency().getJar()) or
|
||||
pomDependsOnPom(source, exported)
|
||||
)
|
||||
select d, "Maven dependency onto " + d.getShortCoordinate() + " is unused."
|
||||
|
||||
@@ -9,20 +9,23 @@
|
||||
* useless-code
|
||||
* external/cwe/cwe-561
|
||||
*/
|
||||
|
||||
import semmle.code.java.deadcode.DeadCode
|
||||
|
||||
from DeadClass c, Element origin, string reason
|
||||
where
|
||||
if exists(DeadRoot root | root = c.getADeadRoot() | not root = c.getACallable()) then (
|
||||
// Report a list of the dead roots.
|
||||
origin = c.getADeadRoot() and
|
||||
not origin = c.getACallable() and
|
||||
// There are uses of this class from outside the class.
|
||||
reason = " is only used from dead code originating at $@."
|
||||
if exists(DeadRoot root | root = c.getADeadRoot() | not root = c.getACallable())
|
||||
then (
|
||||
// Report a list of the dead roots.
|
||||
origin = c.getADeadRoot() and
|
||||
not origin = c.getACallable() and
|
||||
// There are uses of this class from outside the class.
|
||||
reason = " is only used from dead code originating at $@."
|
||||
) else (
|
||||
// There are no dead roots outside this class.
|
||||
origin = c and
|
||||
if c.isUnusedOutsideClass() then
|
||||
if c.isUnusedOutsideClass()
|
||||
then
|
||||
// Never accessed outside this class, so it's entirely unused.
|
||||
reason = " is entirely unused."
|
||||
else
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
* @tags maintainability
|
||||
* external/cwe/cwe-561
|
||||
*/
|
||||
|
||||
import java
|
||||
import semmle.code.java.deadcode.DeadCode
|
||||
|
||||
@@ -16,31 +17,42 @@ from File f, int n
|
||||
where
|
||||
n =
|
||||
// Lines of code contributed by dead classes.
|
||||
sum(DeadClass deadClass | deadClass.getFile() = f |
|
||||
deadClass.getNumberOfLinesOfCode() -
|
||||
// Remove inner and local classes, as they are reported as separate dead classes. Do not
|
||||
// remove anonymous classes, because they aren't reported separately.
|
||||
sum(NestedClass innerClass | innerClass.getEnclosingType() = deadClass and not innerClass.isAnonymous() |
|
||||
innerClass.getNumberOfLinesOfCode()
|
||||
sum(DeadClass deadClass |
|
||||
deadClass.getFile() = f
|
||||
|
|
||||
deadClass.getNumberOfLinesOfCode() -
|
||||
// Remove inner and local classes, as they are reported as separate dead classes. Do not
|
||||
// remove anonymous classes, because they aren't reported separately.
|
||||
sum(NestedClass innerClass |
|
||||
innerClass.getEnclosingType() = deadClass and not innerClass.isAnonymous()
|
||||
|
|
||||
innerClass.getNumberOfLinesOfCode()
|
||||
)
|
||||
) +
|
||||
// Lines of code contributed by dead methods, not in dead classes.
|
||||
sum(DeadMethod deadMethod |
|
||||
deadMethod.getFile() = f and not deadMethod.isInDeadScope()
|
||||
|
|
||||
deadMethod.getNumberOfLinesOfCode() -
|
||||
// Remove local classes defined in the dead method - they are reported separately as a dead
|
||||
// class. We keep anonymous class counts, because anonymous classes are not reported
|
||||
// separately.
|
||||
sum(LocalClass localClass |
|
||||
localClass.getLocalClassDeclStmt().getEnclosingCallable() = deadMethod
|
||||
|
|
||||
localClass.getNumberOfLinesOfCode()
|
||||
)
|
||||
) +
|
||||
// Lines of code contributed by dead fields, not in dead classes.
|
||||
sum(DeadField deadField |
|
||||
deadField.getFile() = f and not deadField.isInDeadScope()
|
||||
|
|
||||
deadField.getNumberOfLinesOfCode()
|
||||
) +
|
||||
// Lines of code contributed by unused enum constants.
|
||||
sum(UnusedEnumConstant deadEnumConstant |
|
||||
deadEnumConstant.getFile() = f
|
||||
|
|
||||
deadEnumConstant.getNumberOfLinesOfCode()
|
||||
)
|
||||
) +
|
||||
// Lines of code contributed by dead methods, not in dead classes.
|
||||
sum(DeadMethod deadMethod | deadMethod.getFile() = f and not deadMethod.isInDeadScope() |
|
||||
deadMethod.getNumberOfLinesOfCode() -
|
||||
// Remove local classes defined in the dead method - they are reported separately as a dead
|
||||
// class. We keep anonymous class counts, because anonymous classes are not reported
|
||||
// separately.
|
||||
sum(LocalClass localClass | localClass.getLocalClassDeclStmt().getEnclosingCallable() = deadMethod |
|
||||
localClass.getNumberOfLinesOfCode()
|
||||
)
|
||||
) +
|
||||
// Lines of code contributed by dead fields, not in dead classes.
|
||||
sum(DeadField deadField | deadField.getFile() = f and not deadField.isInDeadScope() |
|
||||
deadField.getNumberOfLinesOfCode()
|
||||
) +
|
||||
// Lines of code contributed by unused enum constants.
|
||||
sum(UnusedEnumConstant deadEnumConstant | deadEnumConstant.getFile() = f |
|
||||
deadEnumConstant.getNumberOfLinesOfCode()
|
||||
)
|
||||
select f, n
|
||||
order by n desc
|
||||
select f, n order by n desc
|
||||
|
||||
@@ -37,9 +37,7 @@ class InstanceFieldWrite extends FieldWrite {
|
||||
*/
|
||||
class ImpureStmt extends Stmt {
|
||||
ImpureStmt() {
|
||||
exists(Expr e |
|
||||
e.getEnclosingStmt() = this
|
||||
|
|
||||
exists(Expr e | e.getEnclosingStmt() = this |
|
||||
// Only permit calls to set of whitelisted targets.
|
||||
(
|
||||
e instanceof Call and
|
||||
@@ -57,12 +55,12 @@ class ImpureStmt extends Stmt {
|
||||
*/
|
||||
private Stmt getANestedStmt(Block block) {
|
||||
// Any non-block statement
|
||||
not result instanceof Block and result = block.getAStmt() or
|
||||
not result instanceof Block and result = block.getAStmt()
|
||||
or
|
||||
// Or any statement nested in a block
|
||||
result = getANestedStmt(block.getAStmt())
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* A class whose loading and construction by Spring does not have any side-effects outside the class.
|
||||
*
|
||||
@@ -73,12 +71,8 @@ class SpringPureClass extends Class {
|
||||
(
|
||||
// The only permitted statement in static initializers is the initialization of a static
|
||||
// final or effectively final logger fields, or effectively immutable types.
|
||||
forall(Stmt s |
|
||||
s = getANestedStmt(getAMember().(StaticInitializer).getBody())
|
||||
|
|
||||
exists(Field f |
|
||||
f = s.(ExprStmt).getExpr().(AssignExpr).getDest().(FieldWrite).getField()
|
||||
|
|
||||
forall(Stmt s | s = getANestedStmt(getAMember().(StaticInitializer).getBody()) |
|
||||
exists(Field f | f = s.(ExprStmt).getExpr().(AssignExpr).getDest().(FieldWrite).getField() |
|
||||
(
|
||||
// A logger field
|
||||
f.getName().toLowerCase() = "logger" or
|
||||
@@ -88,11 +82,7 @@ class SpringPureClass extends Class {
|
||||
) and
|
||||
f.isStatic() and
|
||||
// Only written to in this statement e.g. final or effectively final
|
||||
forall(FieldWrite fw |
|
||||
fw = f.getAnAccess()
|
||||
|
|
||||
fw.getEnclosingStmt() = s
|
||||
)
|
||||
forall(FieldWrite fw | fw = f.getAnAccess() | fw.getEnclosingStmt() = s)
|
||||
)
|
||||
)
|
||||
) and
|
||||
@@ -103,20 +93,23 @@ class SpringPureClass extends Class {
|
||||
c = getAMember()
|
||||
) and
|
||||
impureStmt.getEnclosingCallable() = c
|
||||
|
|
||||
c instanceof InstanceInitializer or
|
||||
c instanceof Constructor or
|
||||
|
|
||||
c instanceof InstanceInitializer
|
||||
or
|
||||
c instanceof Constructor
|
||||
or
|
||||
// afterPropertiesSet() method called after bean initialization
|
||||
c = this.(InitializingBeanClass).getAfterPropertiesSet() or
|
||||
c = this.(InitializingBeanClass).getAfterPropertiesSet()
|
||||
or
|
||||
// Init and setter methods must be pure, because they are called when the bean is initialized
|
||||
exists(SpringBean bean |
|
||||
this = bean.getClass()
|
||||
|
|
||||
exists(SpringBean bean | this = bean.getClass() |
|
||||
c = bean.getInitMethod() or
|
||||
c = bean.getAProperty().getSetterMethod()
|
||||
) or
|
||||
)
|
||||
or
|
||||
// Setter method by autowiring, either in the XML or by annotation
|
||||
c = this.getAMethod().(SpringBeanAutowiredCallable) or
|
||||
c = this.getAMethod().(SpringBeanAutowiredCallable)
|
||||
or
|
||||
c = this.getAMethod().(SpringBeanXMLAutowiredSetterMethod)
|
||||
)
|
||||
}
|
||||
@@ -130,7 +123,6 @@ class SpringBeanFactory extends ClassOrInterface {
|
||||
getAnAncestor().hasQualifiedName("org.springframework.beans.factory", "BeanFactory")
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get a bean constructed by a call to this bean factory.
|
||||
*/
|
||||
@@ -139,7 +131,7 @@ class SpringBeanFactory extends ClassOrInterface {
|
||||
getBean.hasName("getBean") and
|
||||
call.getMethod() = getBean and
|
||||
getBean.getDeclaringType() = this
|
||||
|
|
||||
|
|
||||
result.getBeanIdentifier() = call.getArgument(0).(CompileTimeConstantExpr).getStringValue()
|
||||
)
|
||||
}
|
||||
@@ -158,7 +150,8 @@ class LiveSpringBean extends SpringBean {
|
||||
not isLazyInit() and
|
||||
// or has no side-effects when constructed
|
||||
not getClass() instanceof SpringPureClass
|
||||
) or
|
||||
)
|
||||
or
|
||||
(
|
||||
// If the class does not exist for this bean, or the class is not a source bean, then this is
|
||||
// likely to be a definition using a library class, in which case we should consider it to be
|
||||
@@ -170,43 +163,45 @@ class LiveSpringBean extends SpringBean {
|
||||
// A live child bean implies this bean is live
|
||||
exists(LiveSpringBean child | this = child.getBeanParent()) or
|
||||
// Beans constructed by a bean factory are considered live
|
||||
exists(SpringBeanFactory beanFactory |
|
||||
this = beanFactory.getAConstructedBean()
|
||||
)
|
||||
) or
|
||||
exists(SpringBeanFactory beanFactory | this = beanFactory.getAConstructedBean())
|
||||
)
|
||||
or
|
||||
(
|
||||
// Referenced by a live bean, either as a property or argument in the XML
|
||||
exists(LiveSpringBean other |
|
||||
this = other.getAConstructorArg().getArgRefBean() or
|
||||
this = other.getAProperty().getPropertyRefBean()
|
||||
) or
|
||||
)
|
||||
or
|
||||
// Referenced as a factory bean
|
||||
exists(LiveSpringBean springBean |
|
||||
this = springBean.getFactoryBean()
|
||||
) or
|
||||
exists(LiveSpringBean springBean | this = springBean.getFactoryBean())
|
||||
or
|
||||
// Injected by @Autowired annotation
|
||||
exists(SpringBeanAutowiredCallable autowiredCallable |
|
||||
// The callable must be in a live class
|
||||
autowiredCallable.getEnclosingSpringBean() instanceof LiveSpringBean or
|
||||
autowiredCallable.getEnclosingSpringComponent().isLive()
|
||||
|
|
||||
|
|
||||
// This bean is injected into it
|
||||
this = autowiredCallable.getAnInjectedBean()
|
||||
) or
|
||||
)
|
||||
or
|
||||
// Injected by @Autowired annotation on field
|
||||
exists(SpringBeanAutowiredField autowiredField |
|
||||
// The field must be in a live class
|
||||
autowiredField.getEnclosingSpringBean() instanceof LiveSpringBean or
|
||||
autowiredField.getEnclosingSpringComponent().isLive()
|
||||
|
|
||||
|
|
||||
// This bean is injected into it
|
||||
this = autowiredField.getInjectedBean()
|
||||
) or
|
||||
)
|
||||
or
|
||||
// Injected by autowired specified in XML
|
||||
exists(SpringBeanXMLAutowiredSetterMethod setterMethod |
|
||||
// The config method must be on a live bean
|
||||
setterMethod.getDeclaringType().(SpringBeanRefType).getSpringBean() instanceof LiveSpringBean
|
||||
|
|
||||
setterMethod.getDeclaringType().(SpringBeanRefType).getSpringBean() instanceof
|
||||
LiveSpringBean
|
||||
|
|
||||
// This bean is injected into it
|
||||
this = setterMethod.getInjectedBean()
|
||||
)
|
||||
@@ -218,9 +213,7 @@ class LiveSpringBean extends SpringBean {
|
||||
* A `SpringBean` that can be safely removed from the program without changing overall behavior.
|
||||
*/
|
||||
class UnusedSpringBean extends SpringBean {
|
||||
UnusedSpringBean() {
|
||||
not this instanceof LiveSpringBean
|
||||
}
|
||||
UnusedSpringBean() { not this instanceof LiveSpringBean }
|
||||
}
|
||||
|
||||
from UnusedSpringBean unused
|
||||
|
||||
@@ -26,11 +26,15 @@ where
|
||||
// Every access to `v` is either...
|
||||
forall(VarAccess va | va = v.getAnAccess() |
|
||||
// ...an assignment storing a fresh container into `v`,
|
||||
exists(AssignExpr assgn | va = assgn.getDest() | assgn.getSource() instanceof FreshContainer) or
|
||||
exists(AssignExpr assgn | va = assgn.getDest() | assgn.getSource() instanceof FreshContainer)
|
||||
or
|
||||
// ...a return (but only if `v` is a local variable)
|
||||
(v instanceof LocalVariableDecl and exists(ReturnStmt ret | ret.getResult() = va)) or
|
||||
(v instanceof LocalVariableDecl and exists(ReturnStmt ret | ret.getResult() = va))
|
||||
or
|
||||
// ...or a call to a query method on `v`.
|
||||
exists(MethodAccess ma | va = ma.getQualifier() | ma.getMethod() instanceof ContainerQueryMethod)
|
||||
exists(MethodAccess ma | va = ma.getQualifier() |
|
||||
ma.getMethod() instanceof ContainerQueryMethod
|
||||
)
|
||||
) and
|
||||
// There is at least one call to a query method.
|
||||
exists(MethodAccess ma | v.getAnAccess() = ma.getQualifier() |
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
* external/cwe/cwe-764
|
||||
* external/cwe/cwe-833
|
||||
*/
|
||||
|
||||
import java
|
||||
import semmle.code.java.controlflow.Guards
|
||||
import semmle.code.java.dataflow.SSA
|
||||
@@ -69,10 +70,12 @@ predicate unlockBlock(LockType t, BasicBlock b, int unlocks) {
|
||||
* equals the number of locks minus the number of unlocks.
|
||||
*/
|
||||
predicate lockUnlockBlock(LockType t, BasicBlock b, int netlocks) {
|
||||
lockBlock(t, b, netlocks) and not unlockBlock(t, b, _) or
|
||||
lockBlock(t, b, netlocks) and not unlockBlock(t, b, _)
|
||||
or
|
||||
exists(int unlocks |
|
||||
not lockBlock(t, b, _) and unlockBlock(t, b, unlocks) and netlocks = -unlocks
|
||||
) or
|
||||
)
|
||||
or
|
||||
exists(int locks, int unlocks |
|
||||
lockBlock(t, b, locks) and unlockBlock(t, b, unlocks) and netlocks = locks - unlocks
|
||||
)
|
||||
@@ -93,8 +96,7 @@ predicate failedLock(LockType t, BasicBlock lockblock, BasicBlock exblock) {
|
||||
lock = lockbool.getAUse() and
|
||||
lockbool.getDefiningExpr().(VariableAssign).getSource() = t.getLockAccess()
|
||||
)
|
||||
)
|
||||
and
|
||||
) and
|
||||
(
|
||||
lock.getAnExceptionSuccessor() = exblock or
|
||||
lock.(ConditionNode).getAFalseSuccessor() = exblock
|
||||
@@ -109,7 +111,7 @@ predicate failedLock(LockType t, BasicBlock lockblock, BasicBlock exblock) {
|
||||
predicate heldByCurrentThreadCheck(LockType t, BasicBlock checkblock, BasicBlock falsesucc) {
|
||||
exists(ConditionBlock conditionBlock |
|
||||
conditionBlock.getCondition() = t.getIsHeldByCurrentThreadAccess()
|
||||
|
|
||||
|
|
||||
conditionBlock.getBasicBlock() = checkblock and
|
||||
conditionBlock.getTestSuccessor(false) = falsesucc
|
||||
)
|
||||
@@ -122,18 +124,23 @@ predicate heldByCurrentThreadCheck(LockType t, BasicBlock checkblock, BasicBlock
|
||||
predicate blockIsLocked(LockType t, BasicBlock src, BasicBlock b, int locks) {
|
||||
lockUnlockBlock(t, b, locks) and src = b and locks > 0
|
||||
or
|
||||
exists(BasicBlock pred, int predlocks, int curlocks, int failedlock | pred = b.getABBPredecessor() |
|
||||
exists(BasicBlock pred, int predlocks, int curlocks, int failedlock |
|
||||
pred = b.getABBPredecessor()
|
||||
|
|
||||
// The number of net locks from the `src` block to the predecessor block `pred` is `predlocks`.
|
||||
blockIsLocked(t, src, pred, predlocks) and
|
||||
// The recursive call ensures that at least one lock is held, so do not consider the false
|
||||
// successor of the `isHeldByCurrentThread()` check.
|
||||
not heldByCurrentThreadCheck(t, pred, b) and
|
||||
// Count a failed lock as an unlock so the net is zero.
|
||||
( if failedLock(t, pred, b) then failedlock = 1 else failedlock = 0 ) and
|
||||
( not lockUnlockBlock(t, b, _) and curlocks = 0 or
|
||||
(if failedLock(t, pred, b) then failedlock = 1 else failedlock = 0) and
|
||||
(
|
||||
not lockUnlockBlock(t, b, _) and curlocks = 0
|
||||
or
|
||||
lockUnlockBlock(t, b, curlocks)
|
||||
) and
|
||||
locks = predlocks + curlocks - failedlock and locks > 0 and
|
||||
locks = predlocks + curlocks - failedlock and
|
||||
locks > 0 and
|
||||
// Arbitrary bound in order to fail gracefully in case of locking in a loop.
|
||||
locks < 10
|
||||
)
|
||||
@@ -145,6 +152,6 @@ where
|
||||
t.getUnlockAccess().getEnclosingCallable() = c and
|
||||
blockIsLocked(t, src, exit, _) and
|
||||
exit.getLastNode() = c and
|
||||
lock = src.getANode() and lock = t.getLockAccess()
|
||||
select
|
||||
lock, "This lock might not be unlocked or might be locked more times than it is unlocked."
|
||||
lock = src.getANode() and
|
||||
lock = t.getLockAccess()
|
||||
select lock, "This lock might not be unlocked or might be locked more times than it is unlocked."
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
* logic
|
||||
* external/cwe/cwe-704
|
||||
*/
|
||||
|
||||
import java
|
||||
|
||||
/**
|
||||
@@ -23,22 +24,14 @@ class ArrayCast extends CastExpr {
|
||||
}
|
||||
|
||||
/** The type of the operand expression of this cast. */
|
||||
Array getSourceType() {
|
||||
result = getExpr().getType()
|
||||
}
|
||||
Array getSourceType() { result = getExpr().getType() }
|
||||
|
||||
/** The result type of this cast. */
|
||||
Array getTargetType() {
|
||||
result = getType()
|
||||
}
|
||||
Array getTargetType() { result = getType() }
|
||||
|
||||
Type getSourceComponentType() {
|
||||
result = getSourceType().getComponentType()
|
||||
}
|
||||
Type getSourceComponentType() { result = getSourceType().getComponentType() }
|
||||
|
||||
Type getTargetComponentType() {
|
||||
result = getTargetType().getComponentType()
|
||||
}
|
||||
Type getTargetComponentType() { result = getTargetType().getComponentType() }
|
||||
}
|
||||
|
||||
predicate uncheckedCastType(RefType t) {
|
||||
@@ -46,14 +39,14 @@ predicate uncheckedCastType(RefType t) {
|
||||
}
|
||||
|
||||
predicate castFlow(ArrayCast ce, Variable v) {
|
||||
ce = v.getAnAssignedValue() or
|
||||
ce = v.getAnAssignedValue()
|
||||
or
|
||||
exists(Variable mid | castFlow(ce, mid) and mid.getAnAccess() = v.getAnAssignedValue())
|
||||
}
|
||||
|
||||
predicate returnedFrom(ArrayCast ce, Method m) {
|
||||
exists(ReturnStmt ret | ret.getEnclosingCallable() = m |
|
||||
ret.getResult() = ce
|
||||
) or
|
||||
exists(ReturnStmt ret | ret.getEnclosingCallable() = m | ret.getResult() = ce)
|
||||
or
|
||||
exists(Variable v | castFlow(ce, v) | returnedVariableFrom(v, m))
|
||||
}
|
||||
|
||||
@@ -76,7 +69,7 @@ where
|
||||
(
|
||||
not uncheckedCastType(target) and
|
||||
message = "Impossible downcast: the cast from " + source.getName() + "[] to " +
|
||||
target.getName() + "[] will always fail with a ClassCastException."
|
||||
target.getName() + "[] will always fail with a ClassCastException."
|
||||
)
|
||||
or
|
||||
// For unchecked operations, the crash would not occur at the cast site,
|
||||
@@ -90,21 +83,22 @@ where
|
||||
returnedFrom(ce, ce.getEnclosingCallable()) and
|
||||
ce.getEnclosingCallable().getReturnType().(Array).getElementType() = target and
|
||||
not ce.getEnclosingCallable().isPrivate() and
|
||||
message =
|
||||
"Impossible downcast: this is returned by " + ce.getEnclosingCallable().getName() +
|
||||
" as a value of type " + target.getName() + "[], but the array has type " + source.getName() +
|
||||
"[]. Callers of " + ce.getEnclosingCallable().getName() + " may fail with a ClassCastException."
|
||||
message = "Impossible downcast: this is returned by " + ce.getEnclosingCallable().getName() +
|
||||
" as a value of type " + target.getName() + "[], but the array has type " +
|
||||
source.getName() + "[]. Callers of " + ce.getEnclosingCallable().getName() +
|
||||
" may fail with a ClassCastException."
|
||||
)
|
||||
or
|
||||
exists(Method m, Variable v |
|
||||
uncheckedCastType(target) and
|
||||
castFlow(ce, v) and returnedVariableFrom(v, m) and
|
||||
castFlow(ce, v) and
|
||||
returnedVariableFrom(v, m) and
|
||||
m.getReturnType().(Array).getElementType() = target and
|
||||
not m.isPrivate() and
|
||||
message =
|
||||
"Impossible downcast: this is assigned to " + v.getName() + " which is returned by " + m +
|
||||
" as a value of type " + target.getName() + "[], but the array has type " + source.getName() +
|
||||
"[]. Callers of " + m.getName() + " may fail with a ClassCastException."
|
||||
message = "Impossible downcast: this is assigned to " + v.getName() + " which is returned by "
|
||||
+ m + " as a value of type " + target.getName() + "[], but the array has type " +
|
||||
source.getName() + "[]. Callers of " + m.getName() +
|
||||
" may fail with a ClassCastException."
|
||||
)
|
||||
)
|
||||
select ce, message
|
||||
|
||||
Reference in New Issue
Block a user