mirror of
https://github.com/github/codeql.git
synced 2026-04-24 16:25:15 +02:00
Merge master into next.
Conflict in `cpp/ql/test/library-tests/sideEffects/functions/sideEffects.expected`, resolved by accepting test output (combining changes).
This commit is contained in:
@@ -49,9 +49,9 @@ class DocuCallable extends Callable {
|
||||
predicate hasAcceptableDocText() { acceptableDocText(this.getDoc().getJavadoc()) }
|
||||
|
||||
string toMethodOrConstructorString() {
|
||||
(this instanceof Method and result = "method")
|
||||
this instanceof Method and result = "method"
|
||||
or
|
||||
(this instanceof Constructor and result = "constructor")
|
||||
this instanceof Constructor and result = "constructor"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@ where
|
||||
callable.(Documentable).getJavadoc().getAChild() = paramTag and
|
||||
(if callable instanceof Constructor then what = "constructor" else what = "method") and
|
||||
if exists(paramTag.getParamName())
|
||||
then (
|
||||
then
|
||||
// The tag's value is neither matched by a callable parameter name ...
|
||||
not callable.getAParameter().getName() = paramTag.getParamName() and
|
||||
// ... nor by a type parameter name.
|
||||
@@ -24,7 +24,7 @@ where
|
||||
) and
|
||||
msg = "@param tag \"" + paramTag.getParamName() + "\" does not match any actual parameter of " +
|
||||
what + " \"" + callable.getName() + "()\"."
|
||||
) else
|
||||
else
|
||||
// The tag has no value at all.
|
||||
msg = "This @param tag does not have a value."
|
||||
select paramTag, msg
|
||||
|
||||
@@ -127,7 +127,7 @@ predicate jdkPackage(Package p) {
|
||||
from JdkInternalAccess ta, string repl, string msg
|
||||
where
|
||||
repl = ta.getReplacement() and
|
||||
(if (repl = "unknown") then msg = "" else msg = " (" + repl + ")") and
|
||||
(if repl = "unknown" then msg = "" else msg = " (" + repl + ")") and
|
||||
not jdkInternalApi(ta.getCompilationUnit().getPackage().getName()) and
|
||||
not jdkPackage(ta.getCompilationUnit().getPackage())
|
||||
select ta, "Access to unsupported JDK-internal API '" + ta.getAccessedApi() + "'." + msg
|
||||
|
||||
@@ -39,13 +39,11 @@ class ImpureStmt extends Stmt {
|
||||
ImpureStmt() {
|
||||
exists(Expr e | e.getEnclosingStmt() = this |
|
||||
// Only permit calls to set of whitelisted targets.
|
||||
(
|
||||
e instanceof Call and
|
||||
not e.(Call).getCallee().getDeclaringType().hasQualifiedName("java.util", "Collections")
|
||||
)
|
||||
e instanceof Call and
|
||||
not e.(Call).getCallee().getDeclaringType().hasQualifiedName("java.util", "Collections")
|
||||
or
|
||||
// Writing to a field that is not an instance field is a no-no
|
||||
(e instanceof FieldWrite and not e instanceof InstanceFieldWrite)
|
||||
e instanceof FieldWrite and not e instanceof InstanceFieldWrite
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -68,22 +66,20 @@ private Stmt getANestedStmt(Block block) {
|
||||
*/
|
||||
class SpringPureClass extends Class {
|
||||
SpringPureClass() {
|
||||
(
|
||||
// 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() |
|
||||
(
|
||||
// A logger field
|
||||
f.getName().toLowerCase() = "logger" or
|
||||
f.getName().toLowerCase() = "log" or
|
||||
// An immutable type
|
||||
f.getType() instanceof ImmutableType
|
||||
) 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)
|
||||
)
|
||||
// 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() |
|
||||
(
|
||||
// A logger field
|
||||
f.getName().toLowerCase() = "logger" or
|
||||
f.getName().toLowerCase() = "log" or
|
||||
// An immutable type
|
||||
f.getType() instanceof ImmutableType
|
||||
) 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)
|
||||
)
|
||||
) and
|
||||
// No constructor, instance initializer or Spring bean init or setter method that is impure.
|
||||
@@ -145,12 +141,10 @@ class SpringBeanFactory extends ClassOrInterface {
|
||||
class LiveSpringBean extends SpringBean {
|
||||
LiveSpringBean() {
|
||||
// Must not be needed for side effects due to construction
|
||||
(
|
||||
// Only loaded by the container when required, so construction cannot have any useful side-effects
|
||||
not isLazyInit() and
|
||||
// or has no side-effects when constructed
|
||||
not getClass() instanceof SpringPureClass
|
||||
)
|
||||
// Only loaded by the container when required, so construction cannot have any useful side-effects
|
||||
not isLazyInit() and
|
||||
// or has no side-effects when constructed
|
||||
not getClass() instanceof SpringPureClass
|
||||
or
|
||||
(
|
||||
// If the class does not exist for this bean, or the class is not a source bean, then this is
|
||||
|
||||
@@ -14,9 +14,6 @@ import java
|
||||
from EmptyStmt empty, string action
|
||||
where
|
||||
if exists(LoopStmt l | l.getBody() = empty)
|
||||
then (
|
||||
action = "turned into '{}'"
|
||||
) else (
|
||||
action = "deleted"
|
||||
)
|
||||
then action = "turned into '{}'"
|
||||
else action = "deleted"
|
||||
select empty, "This empty statement should be " + action + "."
|
||||
|
||||
@@ -27,7 +27,7 @@ RefType aTypeVisibleFrom(TypeVariable var) {
|
||||
result = i.getImportedType()
|
||||
)
|
||||
or
|
||||
(var.getPackage() = result.getPackage() and result instanceof TopLevelType)
|
||||
var.getPackage() = result.getPackage() and result instanceof TopLevelType
|
||||
}
|
||||
|
||||
from RefType hidden, TypeVariable var
|
||||
|
||||
@@ -21,10 +21,8 @@ predicate iteratorWrapper(Iterable it, Field f, boolean wrap) {
|
||||
(
|
||||
f.isFinal()
|
||||
or
|
||||
(
|
||||
strictcount(f.getAnAssignedValue()) = 1 and
|
||||
f.getAnAssignedValue().getEnclosingCallable() instanceof InitializerMethod
|
||||
)
|
||||
strictcount(f.getAnAssignedValue()) = 1 and
|
||||
f.getAnAssignedValue().getEnclosingCallable() instanceof InitializerMethod
|
||||
) and
|
||||
// ... whose type is a sub-type of `java.util.Iterator` and ...
|
||||
f
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
import java
|
||||
|
||||
int integralTypeWidth(IntegralType t) {
|
||||
if (t.hasName("long") or t.hasName("Long")) then result = 64 else result = 32
|
||||
if t.hasName("long") or t.hasName("Long") then result = 64 else result = 32
|
||||
}
|
||||
|
||||
int eval(Expr e) { result = e.(CompileTimeConstantExpr).getIntValue() }
|
||||
|
||||
@@ -71,26 +71,24 @@ class AssocNestedExpr extends BinaryExpr {
|
||||
exists(BinaryExpr parent, int idx | this.isNthChildOf(parent, idx) |
|
||||
// `+`, `*`, `&&`, `||` and the bitwise operations are associative.
|
||||
(
|
||||
(
|
||||
this instanceof AddExpr or
|
||||
this instanceof MulExpr or
|
||||
this instanceof BitwiseExpr or
|
||||
this instanceof LogicalExpr
|
||||
) and
|
||||
parent.getKind() = this.getKind()
|
||||
)
|
||||
this instanceof AddExpr or
|
||||
this instanceof MulExpr or
|
||||
this instanceof BitwiseExpr or
|
||||
this instanceof LogicalExpr
|
||||
) and
|
||||
parent.getKind() = this.getKind()
|
||||
or
|
||||
// Equality tests are associate over each other.
|
||||
(this instanceof EqualityTest and parent instanceof EqualityTest)
|
||||
this instanceof EqualityTest and parent instanceof EqualityTest
|
||||
or
|
||||
// (x*y)/z = x*(y/z)
|
||||
(this instanceof MulExpr and parent instanceof DivExpr and idx = 0)
|
||||
this instanceof MulExpr and parent instanceof DivExpr and idx = 0
|
||||
or
|
||||
// (x/y)%z = x/(y%z)
|
||||
(this instanceof DivExpr and parent instanceof RemExpr and idx = 0)
|
||||
this instanceof DivExpr and parent instanceof RemExpr and idx = 0
|
||||
or
|
||||
// (x+y)-z = x+(y-z)
|
||||
(this instanceof AddExpr and parent instanceof SubExpr and idx = 0)
|
||||
this instanceof AddExpr and parent instanceof SubExpr and idx = 0
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -102,12 +100,10 @@ class AssocNestedExpr extends BinaryExpr {
|
||||
class HarmlessNestedExpr extends BinaryExpr {
|
||||
HarmlessNestedExpr() {
|
||||
exists(BinaryExpr parent | this = parent.getAChildExpr() |
|
||||
(
|
||||
parent instanceof RelationExpr and
|
||||
(this instanceof ArithmeticExpr or this instanceof ShiftExpr)
|
||||
)
|
||||
parent instanceof RelationExpr and
|
||||
(this instanceof ArithmeticExpr or this instanceof ShiftExpr)
|
||||
or
|
||||
(parent instanceof LogicalExpr and this instanceof RelationExpr)
|
||||
parent instanceof LogicalExpr and this instanceof RelationExpr
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,12 +18,10 @@ class SpecialCollectionCreation extends MethodAccess {
|
||||
exists(Method m, RefType rt |
|
||||
m = this.(MethodAccess).getCallee() and rt = m.getDeclaringType()
|
||||
|
|
||||
(rt.hasQualifiedName("java.util", "Arrays") and m.hasName("asList"))
|
||||
rt.hasQualifiedName("java.util", "Arrays") and m.hasName("asList")
|
||||
or
|
||||
(
|
||||
rt.hasQualifiedName("java.util", "Collections") and
|
||||
m.getName().regexpMatch("singleton.*|unmodifiable.*")
|
||||
)
|
||||
rt.hasQualifiedName("java.util", "Collections") and
|
||||
m.getName().regexpMatch("singleton.*|unmodifiable.*")
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,7 +29,7 @@ where
|
||||
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))
|
||||
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() |
|
||||
|
||||
@@ -16,10 +16,8 @@ import java
|
||||
predicate okForEquals(Class c) {
|
||||
c.getAMethod() instanceof EqualsMethod
|
||||
or
|
||||
(
|
||||
not exists(c.getAField()) and
|
||||
okForEquals(c.getASupertype())
|
||||
)
|
||||
not exists(c.getAField()) and
|
||||
okForEquals(c.getASupertype())
|
||||
}
|
||||
|
||||
/** Holds if method `em` implements a reference equality check. */
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
<!DOCTYPE qhelp PUBLIC
|
||||
"-//Semmle//qhelp//EN"
|
||||
"qhelp.dtd">
|
||||
<qhelp>
|
||||
|
||||
<include src="DoubleCheckedLockingShared.qhelp" />
|
||||
|
||||
</qhelp>
|
||||
23
java/ql/src/Likely Bugs/Concurrency/DoubleCheckedLocking.ql
Normal file
23
java/ql/src/Likely Bugs/Concurrency/DoubleCheckedLocking.ql
Normal file
@@ -0,0 +1,23 @@
|
||||
/**
|
||||
* @name Double-checked locking is not thread-safe
|
||||
* @description A repeated check on a non-volatile field is not thread-safe, and
|
||||
* could result in unexpected behavior.
|
||||
* @kind problem
|
||||
* @problem.severity error
|
||||
* @precision high
|
||||
* @id java/unsafe-double-checked-locking
|
||||
* @tags reliability
|
||||
* correctness
|
||||
* concurrency
|
||||
* external/cwe/cwe-609
|
||||
*/
|
||||
|
||||
import java
|
||||
import DoubleCheckedLocking
|
||||
|
||||
from IfStmt if1, IfStmt if2, SynchronizedStmt sync, Field f
|
||||
where
|
||||
doubleCheckedLocking(if1, if2, sync, f) and
|
||||
not f.isVolatile()
|
||||
select sync, "Double-checked locking on the non-volatile field $@ is not thread-safe.", f,
|
||||
f.toString()
|
||||
43
java/ql/src/Likely Bugs/Concurrency/DoubleCheckedLocking.qll
Normal file
43
java/ql/src/Likely Bugs/Concurrency/DoubleCheckedLocking.qll
Normal file
@@ -0,0 +1,43 @@
|
||||
import java
|
||||
import semmle.code.java.dataflow.SSA
|
||||
|
||||
/**
|
||||
* Gets a read of `f`. Gets both direct reads and indirect reads through
|
||||
* assignment to a local variable.
|
||||
*/
|
||||
private Expr getAFieldRead(Field f) {
|
||||
result = f.getAnAccess()
|
||||
or
|
||||
exists(SsaExplicitUpdate v | v.getSourceVariable().getVariable() instanceof LocalScopeVariable |
|
||||
result = v.getAUse() and
|
||||
v.getDefiningExpr().(VariableAssign).getSource() = getAFieldRead(f)
|
||||
)
|
||||
or
|
||||
result.(ParExpr).getExpr() = getAFieldRead(f)
|
||||
or
|
||||
result.(AssignExpr).getSource() = getAFieldRead(f)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an expression that corresponds to `f == null`, either directly testing
|
||||
* `f` or indirectly through a local variable `(x = f) == null`.
|
||||
*/
|
||||
private Expr getANullCheck(Field f) {
|
||||
exists(EqualityTest eq | eq.polarity() = true |
|
||||
eq.hasOperands(any(NullLiteral nl), getAFieldRead(f)) and
|
||||
result = eq
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the sequence `if1`-`sync`-`if2` corresponds to a double-checked
|
||||
* locking pattern for the field `f`. Fields with immutable types are excluded,
|
||||
* as they are always safe to initialize with double-checked locking.
|
||||
*/
|
||||
predicate doubleCheckedLocking(IfStmt if1, IfStmt if2, SynchronizedStmt sync, Field f) {
|
||||
if1.getThen() = sync.getParent*() and
|
||||
sync.getBlock() = if2.getParent*() and
|
||||
if1.getCondition() = getANullCheck(f) and
|
||||
if2.getCondition() = getANullCheck(f) and
|
||||
not f.getType() instanceof ImmutableType
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
private Object lock = new Object();
|
||||
private MyObject f = null;
|
||||
|
||||
public MyObject getMyObject() {
|
||||
if (f == null) {
|
||||
synchronized(lock) {
|
||||
if (f == null) {
|
||||
f = new MyObject(); // BAD
|
||||
}
|
||||
}
|
||||
}
|
||||
return f;
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
private Object lock = new Object();
|
||||
private volatile MyObject f = null;
|
||||
|
||||
public MyObject getMyObject() {
|
||||
if (f == null) {
|
||||
synchronized(lock) {
|
||||
if (f == null) {
|
||||
f = new MyObject();
|
||||
f.init(); // BAD
|
||||
}
|
||||
}
|
||||
}
|
||||
return f;
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
private Object lock = new Object();
|
||||
private volatile MyObject f = null;
|
||||
|
||||
public MyObject getMyObject() {
|
||||
MyObject result = f;
|
||||
if (result == null) {
|
||||
synchronized(lock) {
|
||||
result = f;
|
||||
if (result == null) {
|
||||
result = new MyObject();
|
||||
result.init();
|
||||
f = result; // GOOD
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
<!DOCTYPE qhelp PUBLIC
|
||||
"-//Semmle//qhelp//EN"
|
||||
"qhelp.dtd">
|
||||
<qhelp>
|
||||
|
||||
<overview>
|
||||
<p>
|
||||
Double-checked locking is a common pattern for lazy initialization of a field
|
||||
accessed by multiple threads.
|
||||
Depending on the memory model of the underlying runtime, it can, however, be
|
||||
quite difficult to implement correctly, since reorderings performed by
|
||||
compiler, runtime, or CPU might expose un-initialized or half-way initialized
|
||||
objects to other threads.
|
||||
Java has since version 5 improved its memory model to support double-checked
|
||||
locking if the underlying field is marked <code>volatile</code> and if all
|
||||
initialization happens before the volatile write.
|
||||
</p>
|
||||
</overview>
|
||||
|
||||
<recommendation>
|
||||
|
||||
<p>
|
||||
First, it should be considered whether the getter that performs the lazy
|
||||
initialization is performance critical.
|
||||
If not, a much simpler solution is to completely avoid double-checked locking
|
||||
and simply mark the entire getter as <code>synchronized</code>.
|
||||
This is much easier to get right and guards against hard-to-find concurrency bugs.
|
||||
</p>
|
||||
<p>
|
||||
If double-checked locking is used, it is important that the underlying field is
|
||||
<code>volatile</code> and that the update to the field is the last thing that
|
||||
happens in the synchronized region, that is, all initialization must be done
|
||||
before the field is assigned.
|
||||
Furthermore, the Java version must be 5 or newer.
|
||||
Reading a <code>volatile</code> field has a slight overhead, so it is also
|
||||
useful to use a local variable to minimize the number of volatile reads.
|
||||
</p>
|
||||
|
||||
</recommendation>
|
||||
|
||||
<example>
|
||||
<p>
|
||||
The following code lazily initializes <code>f</code> to <code>new MyObject()</code>.
|
||||
</p>
|
||||
<sample src="DoubleCheckedLockingBad1.java"/>
|
||||
<p>
|
||||
This code is not thread-safe as another thread might see the assignment to
|
||||
<code>f</code> before the constructor finishes evaluating, for example if the
|
||||
compiler inlines the memory allocation and the constructor and reorders the
|
||||
assignment to <code>f</code> to occur just after the memory allocation.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Another example that also is not thread-safe, even when <code>volatile</code>
|
||||
is used, is if additional initialization happens after the assignment to
|
||||
<code>f</code>, since then other threads may access the constructed object
|
||||
before it is fully initialized, even without any reorderings by the compiler or
|
||||
runtime.
|
||||
</p>
|
||||
<sample src="DoubleCheckedLockingBad2.java"/>
|
||||
|
||||
<p>
|
||||
The code above should be rewritten to both use <code>volatile</code> and finish
|
||||
all initialization before <code>f</code> is updated. Additionally, a local
|
||||
variable can be used to avoid reading the field more times than neccessary.
|
||||
</p>
|
||||
<sample src="DoubleCheckedLockingGood.java"/>
|
||||
|
||||
</example>
|
||||
|
||||
<references>
|
||||
|
||||
<li>
|
||||
<a href="http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html">The "Double-Checked Locking is Broken" Declaration</a>.
|
||||
</li>
|
||||
<li>
|
||||
Java Language Specification:
|
||||
<a href="https://docs.oracle.com/javase/specs/jls/se8/html/jls-17.html#jls-17.4">17.4. Memory Model</a>.
|
||||
</li>
|
||||
<li>
|
||||
Wikipedia: <a href="https://en.wikipedia.org/wiki/Double-checked_locking">Double-checked locking</a>.
|
||||
</li>
|
||||
|
||||
</references>
|
||||
|
||||
</qhelp>
|
||||
@@ -0,0 +1,8 @@
|
||||
<!DOCTYPE qhelp PUBLIC
|
||||
"-//Semmle//qhelp//EN"
|
||||
"qhelp.dtd">
|
||||
<qhelp>
|
||||
|
||||
<include src="DoubleCheckedLockingShared.qhelp" />
|
||||
|
||||
</qhelp>
|
||||
@@ -0,0 +1,43 @@
|
||||
/**
|
||||
* @name Race condition in double-checked locking object initialization
|
||||
* @description Performing additional initialization on an object after
|
||||
* assignment to a shared variable guarded by double-checked
|
||||
* locking is not thread-safe, and could result in unexpected
|
||||
* behavior.
|
||||
* @kind problem
|
||||
* @problem.severity warning
|
||||
* @precision high
|
||||
* @id java/unsafe-double-checked-locking-init-order
|
||||
* @tags reliability
|
||||
* correctness
|
||||
* concurrency
|
||||
* external/cwe/cwe-609
|
||||
*/
|
||||
|
||||
import java
|
||||
import DoubleCheckedLocking
|
||||
|
||||
predicate whitelistedMethod(Method m) {
|
||||
m.getDeclaringType().hasQualifiedName("java.io", _) and
|
||||
m.hasName("println")
|
||||
}
|
||||
|
||||
class SideEffect extends Expr {
|
||||
SideEffect() {
|
||||
this instanceof MethodAccess and
|
||||
not whitelistedMethod(this.(MethodAccess).getMethod())
|
||||
or
|
||||
this.(Assignment).getDest() instanceof FieldAccess
|
||||
}
|
||||
}
|
||||
|
||||
from IfStmt if1, IfStmt if2, SynchronizedStmt sync, Field f, AssignExpr a, SideEffect se
|
||||
where
|
||||
doubleCheckedLocking(if1, if2, sync, f) and
|
||||
a.getEnclosingStmt().getParent*() = if2.getThen() and
|
||||
se.getEnclosingStmt().getParent*() = sync.getBlock() and
|
||||
a.(ControlFlowNode).getASuccessor+() = se and
|
||||
a.getDest().(FieldAccess).getField() = f
|
||||
select a,
|
||||
"Potential race condition. This assignment to $@ is visible to other threads before the subsequent statements are executed.",
|
||||
f, f.toString()
|
||||
@@ -25,16 +25,12 @@ class ThreadClass extends Class {
|
||||
(
|
||||
result.getNumberOfParameters() = 0
|
||||
or
|
||||
(
|
||||
result.getNumberOfParameters() = 1 and
|
||||
result.getParameter(0).getType().(RefType).hasQualifiedName("java.lang", "String")
|
||||
)
|
||||
result.getNumberOfParameters() = 1 and
|
||||
result.getParameter(0).getType().(RefType).hasQualifiedName("java.lang", "String")
|
||||
or
|
||||
(
|
||||
result.getNumberOfParameters() = 2 and
|
||||
result.getParameter(0).getType().(RefType).hasQualifiedName("java.lang", "ThreadGroup") and
|
||||
result.getParameter(1).getType().(RefType).hasQualifiedName("java.lang", "String")
|
||||
)
|
||||
result.getNumberOfParameters() = 2 and
|
||||
result.getParameter(0).getType().(RefType).hasQualifiedName("java.lang", "ThreadGroup") and
|
||||
result.getParameter(1).getType().(RefType).hasQualifiedName("java.lang", "String")
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -28,7 +28,7 @@ predicate locallySynchronized(MethodAccess ma) {
|
||||
}
|
||||
|
||||
predicate hasUnsynchronizedCall(Method m) {
|
||||
(m.isPublic() and not m.isSynchronized())
|
||||
m.isPublic() and not m.isSynchronized()
|
||||
or
|
||||
exists(MethodAccess ma, Method caller |
|
||||
ma.getMethod() = m and caller = ma.getEnclosingCallable()
|
||||
|
||||
@@ -94,17 +94,14 @@ where
|
||||
exists(IfStmt unsyncNullCheck | unsyncNullCheck = init.getAnEnclosingNullCheck() |
|
||||
not unsyncNullCheck.getParent+() instanceof ValidSynchStmt
|
||||
) and
|
||||
if (i.getParent+() instanceof ValidSynchStmt)
|
||||
if i.getParent+() instanceof ValidSynchStmt
|
||||
then (
|
||||
not init.getField().isVolatile() and
|
||||
message = "The field must be volatile."
|
||||
) else (
|
||||
if (i.getParent+() instanceof SynchronizedStmt)
|
||||
then (
|
||||
message = "Bad synchronization."
|
||||
) else (
|
||||
message = "Missing synchronization."
|
||||
)
|
||||
if i.getParent+() instanceof SynchronizedStmt
|
||||
then message = "Bad synchronization."
|
||||
else message = "Missing synchronization."
|
||||
)
|
||||
select init, "Incorrect lazy initialization of static field $@: " + message, init.getField() as f,
|
||||
f.getName()
|
||||
|
||||
@@ -47,11 +47,9 @@ class MethodRequiresSynch extends Method {
|
||||
private predicate synchronizedCallable(Callable c) {
|
||||
c.isSynchronized()
|
||||
or
|
||||
(
|
||||
c.isPrivate() and
|
||||
forall(MethodAccess parent | parent.getCallee() = c |
|
||||
synchronizedThisAccess(parent, c.getDeclaringType())
|
||||
)
|
||||
c.isPrivate() and
|
||||
forall(MethodAccess parent | parent.getCallee() = c |
|
||||
synchronizedThisAccess(parent, c.getDeclaringType())
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -56,33 +56,25 @@ private predicate comparisonOfContainerSizeToZero(
|
||||
BinaryExpr e, string containerKind, string trueOrFalse
|
||||
) {
|
||||
exists(Expr l, Expr r | l = e.getLeftOperand() and r = e.getRightOperand() |
|
||||
(
|
||||
e instanceof LTExpr and
|
||||
l.(SizeOfContainer).getContainerKind() = containerKind and
|
||||
r instanceof IntegralZeroLiteral and
|
||||
trueOrFalse = "false"
|
||||
)
|
||||
e instanceof LTExpr and
|
||||
l.(SizeOfContainer).getContainerKind() = containerKind and
|
||||
r instanceof IntegralZeroLiteral and
|
||||
trueOrFalse = "false"
|
||||
or
|
||||
(
|
||||
e instanceof GTExpr and
|
||||
l instanceof IntegralZeroLiteral and
|
||||
r.(SizeOfContainer).getContainerKind() = containerKind and
|
||||
trueOrFalse = "false"
|
||||
)
|
||||
e instanceof GTExpr and
|
||||
l instanceof IntegralZeroLiteral and
|
||||
r.(SizeOfContainer).getContainerKind() = containerKind and
|
||||
trueOrFalse = "false"
|
||||
or
|
||||
(
|
||||
e instanceof GEExpr and
|
||||
l.(SizeOfContainer).getContainerKind() = containerKind and
|
||||
r instanceof IntegralZeroLiteral and
|
||||
trueOrFalse = "true"
|
||||
)
|
||||
e instanceof GEExpr and
|
||||
l.(SizeOfContainer).getContainerKind() = containerKind and
|
||||
r instanceof IntegralZeroLiteral and
|
||||
trueOrFalse = "true"
|
||||
or
|
||||
(
|
||||
e instanceof LEExpr and
|
||||
l instanceof IntegralZeroLiteral and
|
||||
r.(SizeOfContainer).getContainerKind() = containerKind and
|
||||
trueOrFalse = "true"
|
||||
)
|
||||
e instanceof LEExpr and
|
||||
l instanceof IntegralZeroLiteral and
|
||||
r.(SizeOfContainer).getContainerKind() = containerKind and
|
||||
trueOrFalse = "true"
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -83,10 +83,8 @@ private predicate closeableInit(Expr e, Expr parent) {
|
||||
parent = arg
|
||||
)
|
||||
or
|
||||
(
|
||||
not exists(Expr arg | arg = cie.getAnArgument() | closeableType(arg.getType())) and
|
||||
parent = cie
|
||||
)
|
||||
not exists(Expr arg | arg = cie.getAnArgument() | closeableType(arg.getType())) and
|
||||
parent = cie
|
||||
)
|
||||
)
|
||||
or
|
||||
@@ -225,18 +223,16 @@ private predicate closeCalled(Variable v) {
|
||||
exists(MethodAccess e |
|
||||
v = getCloseableVariable(_) or v instanceof Parameter or v instanceof LocalVariableDecl
|
||||
|
|
||||
(
|
||||
e.getMethod().getName().toLowerCase().matches("%close%") and
|
||||
exists(VarAccess va | va = v.getAnAccess() |
|
||||
e.getQualifier() = va or
|
||||
e.getAnArgument() = va
|
||||
)
|
||||
e.getMethod().getName().toLowerCase().matches("%close%") and
|
||||
exists(VarAccess va | va = v.getAnAccess() |
|
||||
e.getQualifier() = va or
|
||||
e.getAnArgument() = va
|
||||
)
|
||||
or
|
||||
// The "close" call could happen indirectly inside a helper method of unknown name.
|
||||
exists(int i | exprs(v.getAnAccess(), _, _, e, i) |
|
||||
exists(Parameter p, int j | params(p, _, j, e.getMethod(), _) |
|
||||
(closeCalled(p) and i = j)
|
||||
closeCalled(p) and i = j
|
||||
or
|
||||
// The helper method could be iterating over a varargs parameter.
|
||||
exists(EnhancedForStmt for | for.getExpr() = p.getAnAccess() |
|
||||
@@ -276,9 +272,9 @@ private predicate immediatelyClosed(ClassInstanceExpr cie) {
|
||||
* A unassigned or locally-assigned "closeable init" that does not escape and is not closed.
|
||||
*/
|
||||
private predicate badCloseableInitImpl(CloseableInitExpr cie) {
|
||||
(unassignedCloseableInit(cie) and not immediatelyClosed(cie) and not escapingCloseableInit(cie))
|
||||
unassignedCloseableInit(cie) and not immediatelyClosed(cie) and not escapingCloseableInit(cie)
|
||||
or
|
||||
(locallyInitializedCloseable(cie) and not closedResource(cie) and not escapingCloseableInit(cie))
|
||||
locallyInitializedCloseable(cie) and not closedResource(cie) and not escapingCloseableInit(cie)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -297,7 +293,7 @@ predicate badCloseableInit(CloseableInitExpr cie) {
|
||||
predicate noNeedToClose(CloseableInitExpr cie) {
|
||||
locallyInitializedCloseable(cie) and
|
||||
(
|
||||
(cie instanceof ClassInstanceExpr and not exists(cie.(ClassInstanceExpr).getAnArgument()))
|
||||
cie instanceof ClassInstanceExpr and not exists(cie.(ClassInstanceExpr).getAnArgument())
|
||||
or
|
||||
exists(RefType t | t = cie.getType() and t.fromSource() |
|
||||
exists(Method close | close.getDeclaringType() = t and close.getName() = "close" |
|
||||
|
||||
@@ -22,7 +22,7 @@ where
|
||||
not exists(Constructor c |
|
||||
c = nonserial.getSourceDeclaration().getAConstructor() and
|
||||
c.hasNoParameters() and
|
||||
not (c.isPrivate())
|
||||
not c.isPrivate()
|
||||
) and
|
||||
serial.fromSource()
|
||||
select serial,
|
||||
|
||||
@@ -35,9 +35,9 @@ predicate sortedCollectionType(RefType t) {
|
||||
string nameFor(Class c) {
|
||||
nonSerializableComparator(c) and
|
||||
(
|
||||
(c instanceof AnonymousClass and result = "This comparator")
|
||||
c instanceof AnonymousClass and result = "This comparator"
|
||||
or
|
||||
(not c instanceof AnonymousClass and result = c.getName())
|
||||
not c instanceof AnonymousClass and result = c.getName()
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -31,14 +31,10 @@ predicate collectionOrMapType(RefType t) { t instanceof CollectionType or t inst
|
||||
predicate serializableType(RefType t) {
|
||||
exists(RefType sup | sup = t.getASupertype*() | serializableOrExternalizable(sup))
|
||||
or
|
||||
(
|
||||
// Collection interfaces are not serializable, but their implementations are
|
||||
// likely to be.
|
||||
collectionOrMapType(t) and
|
||||
forall(RefType param | param = t.(ParameterizedType).getATypeArgument() |
|
||||
serializableType(param)
|
||||
)
|
||||
)
|
||||
// Collection interfaces are not serializable, but their implementations are
|
||||
// likely to be.
|
||||
collectionOrMapType(t) and
|
||||
forall(RefType param | param = t.(ParameterizedType).getATypeArgument() | serializableType(param))
|
||||
or
|
||||
exists(BoundedType bt | bt = t | serializableType(bt.getUpperBoundType()))
|
||||
}
|
||||
|
||||
@@ -54,28 +54,26 @@ predicate exceptions(NestedClass inner) {
|
||||
or
|
||||
// The class `inner` is a local class or non-public member class and
|
||||
// all its instance expressions are cast to non-serializable types.
|
||||
(
|
||||
(inner instanceof LocalClass or not inner.isPublic()) and
|
||||
forall(ClassInstanceExpr cie, RefType target |
|
||||
cie.getConstructedType() = inner and castTo(cie, target)
|
||||
|
|
||||
not isSerializable(target)
|
||||
) and
|
||||
// Exception 1: the expression is used as an argument to `writeObject()`.
|
||||
not exists(Call writeCall, ClassInstanceExpr cie | cie.getConstructedType() = inner |
|
||||
writeCall.getCallee().hasName("writeObject") and
|
||||
writeCall.getAnArgument() = cie
|
||||
) and
|
||||
// Exception 2: the expression is thrown as an exception (exceptions should be serializable
|
||||
// due to use cases such as remote procedure calls, logging, etc.)
|
||||
not exists(ThrowStmt ts, ClassInstanceExpr cie |
|
||||
cie.getConstructedType() = inner and
|
||||
ts.getExpr() = cie
|
||||
) and
|
||||
// Exception 3: if the programmer added a `serialVersionUID`, we interpret that
|
||||
// as an intent to make the class serializable.
|
||||
not exists(Field f | f.getDeclaringType() = inner | f.hasName("serialVersionUID"))
|
||||
)
|
||||
(inner instanceof LocalClass or not inner.isPublic()) and
|
||||
forall(ClassInstanceExpr cie, RefType target |
|
||||
cie.getConstructedType() = inner and castTo(cie, target)
|
||||
|
|
||||
not isSerializable(target)
|
||||
) and
|
||||
// Exception 1: the expression is used as an argument to `writeObject()`.
|
||||
not exists(Call writeCall, ClassInstanceExpr cie | cie.getConstructedType() = inner |
|
||||
writeCall.getCallee().hasName("writeObject") and
|
||||
writeCall.getAnArgument() = cie
|
||||
) and
|
||||
// Exception 2: the expression is thrown as an exception (exceptions should be serializable
|
||||
// due to use cases such as remote procedure calls, logging, etc.)
|
||||
not exists(ThrowStmt ts, ClassInstanceExpr cie |
|
||||
cie.getConstructedType() = inner and
|
||||
ts.getExpr() = cie
|
||||
) and
|
||||
// Exception 3: if the programmer added a `serialVersionUID`, we interpret that
|
||||
// as an intent to make the class serializable.
|
||||
not exists(Field f | f.getDeclaringType() = inner | f.hasName("serialVersionUID"))
|
||||
}
|
||||
|
||||
from NestedClass inner, Class outer, string advice
|
||||
@@ -86,7 +84,7 @@ where
|
||||
not isSerializable(outer) and
|
||||
not exceptions(inner) and
|
||||
(
|
||||
if (inner instanceof LocalClass)
|
||||
if inner instanceof LocalClass
|
||||
then advice = "Consider implementing readObject() and writeObject()."
|
||||
else advice = "Consider making the class static or implementing readObject() and writeObject()."
|
||||
)
|
||||
|
||||
@@ -15,50 +15,44 @@ private predicate nonChaining(Method m) {
|
||||
// The method has a body, and at least one of the return values is not suitable for chaining.
|
||||
exists(ReturnStmt ret | ret.getEnclosingCallable() = m | nonChainingReturn(m, ret))
|
||||
or
|
||||
// The method has no body, and is not chaining because ...
|
||||
not exists(m.getBody()) and
|
||||
(
|
||||
// The method has no body, and is not chaining because ...
|
||||
not exists(m.getBody()) and
|
||||
(
|
||||
// ... it has the wrong return type, ...
|
||||
not hasSubtype*(m.getReturnType(), m.getDeclaringType())
|
||||
or
|
||||
// ... it is defined on an immutable type, or ...
|
||||
m.getDeclaringType() instanceof ImmutableType
|
||||
or
|
||||
// ... it has an override that is non-chaining.
|
||||
exists(Method override | override.overrides(m) | nonChaining(override))
|
||||
)
|
||||
// ... it has the wrong return type, ...
|
||||
not hasSubtype*(m.getReturnType(), m.getDeclaringType())
|
||||
or
|
||||
// ... it is defined on an immutable type, or ...
|
||||
m.getDeclaringType() instanceof ImmutableType
|
||||
or
|
||||
// ... it has an override that is non-chaining.
|
||||
exists(Method override | override.overrides(m) | nonChaining(override))
|
||||
)
|
||||
}
|
||||
|
||||
private predicate nonChainingReturn(Method m, ReturnStmt ret) {
|
||||
// The wrong `this` is returned.
|
||||
(
|
||||
ret.getResult() instanceof ThisAccess and
|
||||
ret.getResult().getType() != m.getDeclaringType()
|
||||
)
|
||||
ret.getResult() instanceof ThisAccess and
|
||||
ret.getResult().getType() != m.getDeclaringType()
|
||||
or
|
||||
// A method call to the wrong method is returned.
|
||||
(
|
||||
ret.getResult() instanceof MethodAccess and
|
||||
exists(MethodAccess delegateCall, Method delegate |
|
||||
delegateCall = ret.getResult() and
|
||||
delegate = delegateCall.getMethod()
|
||||
|
|
||||
delegate.getDeclaringType() != m.getDeclaringType()
|
||||
or
|
||||
delegate.isStatic()
|
||||
or
|
||||
not hasSubtype*(m.getReturnType(), delegate.getReturnType())
|
||||
or
|
||||
// A method on the wrong object is called.
|
||||
not (
|
||||
delegateCall.getQualifier().getProperExpr() instanceof ThisAccess or
|
||||
not exists(delegateCall.getQualifier())
|
||||
)
|
||||
or
|
||||
nonChaining(delegate)
|
||||
ret.getResult() instanceof MethodAccess and
|
||||
exists(MethodAccess delegateCall, Method delegate |
|
||||
delegateCall = ret.getResult() and
|
||||
delegate = delegateCall.getMethod()
|
||||
|
|
||||
delegate.getDeclaringType() != m.getDeclaringType()
|
||||
or
|
||||
delegate.isStatic()
|
||||
or
|
||||
not hasSubtype*(m.getReturnType(), delegate.getReturnType())
|
||||
or
|
||||
// A method on the wrong object is called.
|
||||
not (
|
||||
delegateCall.getQualifier().getProperExpr() instanceof ThisAccess or
|
||||
not exists(delegateCall.getQualifier())
|
||||
)
|
||||
or
|
||||
nonChaining(delegate)
|
||||
)
|
||||
or
|
||||
// Something else is returned.
|
||||
|
||||
@@ -43,18 +43,14 @@ Stmt emptyBody() { result = emptyBlock() or result = emptyStmt() }
|
||||
predicate blockParent(Stmt empty, string msg) {
|
||||
empty = emptyBody() and
|
||||
(
|
||||
(
|
||||
empty.getParent() instanceof IfStmt and
|
||||
msg = "The body of an if statement should not be empty."
|
||||
)
|
||||
empty.getParent() instanceof IfStmt and
|
||||
msg = "The body of an if statement should not be empty."
|
||||
or
|
||||
(empty.getParent() instanceof LoopStmt and msg = "The body of a loop should not be empty.")
|
||||
empty.getParent() instanceof LoopStmt and msg = "The body of a loop should not be empty."
|
||||
or
|
||||
(
|
||||
empty.getParent() instanceof Block and
|
||||
empty instanceof Block and
|
||||
msg = "This block should not be empty."
|
||||
)
|
||||
empty.getParent() instanceof Block and
|
||||
empty instanceof Block and
|
||||
msg = "This block should not be empty."
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -66,11 +66,9 @@ where
|
||||
not rawTypeConversion(source, target) and
|
||||
(
|
||||
// No unchecked operations, so the cast would crash straight away.
|
||||
(
|
||||
not uncheckedCastType(target) and
|
||||
message = "Impossible downcast: the cast from " + source.getName() + "[] to " +
|
||||
target.getName() + "[] will always fail with a ClassCastException."
|
||||
)
|
||||
not uncheckedCastType(target) and
|
||||
message = "Impossible downcast: the cast from " + source.getName() + "[] to " + target.getName()
|
||||
+ "[] will always fail with a ClassCastException."
|
||||
or
|
||||
// For unchecked operations, the crash would not occur at the cast site,
|
||||
// but only if/when the value is assigned to a variable of different array type.
|
||||
@@ -78,16 +76,14 @@ where
|
||||
// APIs. We keep two cases:
|
||||
// - An array that is actually returned from the (non-private) method, or
|
||||
// - an array that is assigned to a field returned from another (non-private) method.
|
||||
(
|
||||
uncheckedCastType(target) and
|
||||
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."
|
||||
)
|
||||
uncheckedCastType(target) and
|
||||
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."
|
||||
or
|
||||
exists(Method m, Variable v |
|
||||
uncheckedCastType(target) and
|
||||
|
||||
@@ -18,7 +18,7 @@ import Chaining
|
||||
|
||||
predicate checkedMethodCall(MethodAccess ma) {
|
||||
relevantMethodCall(ma, _) and
|
||||
not (ma.getParent() instanceof ExprStmt)
|
||||
not ma.getParent() instanceof ExprStmt
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -35,7 +35,7 @@ predicate isMockingMethod(Method m) {
|
||||
|
||||
predicate isReceiverClauseMethod(Method m) {
|
||||
m.getDeclaringType().getASupertype*().hasQualifiedName("org.jmock.syntax", "ReceiverClause") and
|
||||
(m.hasName("of"))
|
||||
m.hasName("of")
|
||||
}
|
||||
|
||||
predicate isCardinalityClauseMethod(Method m) {
|
||||
@@ -70,7 +70,7 @@ predicate isStubberMethod(Method m) {
|
||||
*/
|
||||
predicate isMustBeQualifierMockingMethod(Method m) {
|
||||
m.getDeclaringType().getASupertype*().hasQualifiedName("org.mockito", "Mockito") and
|
||||
(m.hasName("verify"))
|
||||
m.hasName("verify")
|
||||
}
|
||||
|
||||
predicate relevantMethodCall(MethodAccess ma, Method m) {
|
||||
|
||||
@@ -81,5 +81,5 @@ where
|
||||
not exists(MethodAccess ma | ma.getParent*() = cond) and
|
||||
not exists(FieldRead fa | fa.getParent*() = cond) and
|
||||
not exists(ArrayAccess aa | aa.getParent*() = cond)
|
||||
select loop, "Loop might not terminate, as this $@ is constant within the loop.", cond,
|
||||
"loop condition"
|
||||
select cond, "$@ might not terminate, as this loop condition is constant within the loop.", loop,
|
||||
"Loop"
|
||||
|
||||
@@ -24,7 +24,7 @@ predicate realParent(Stmt inner, Stmt outer) {
|
||||
|
||||
predicate skipParent(Stmt s) {
|
||||
exists(Stmt parent | parent = s.getParent() |
|
||||
(s instanceof IfStmt and parent.(IfStmt).getElse() = s)
|
||||
s instanceof IfStmt and parent.(IfStmt).getElse() = s
|
||||
or
|
||||
parent instanceof Block
|
||||
)
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
import java
|
||||
|
||||
private string prefix(Callable c) {
|
||||
if (c instanceof Constructor and c.getDeclaringType() instanceof AnonymousClass)
|
||||
if c instanceof Constructor and c.getDeclaringType() instanceof AnonymousClass
|
||||
then result = "<anonymous constructor>"
|
||||
else result = ""
|
||||
}
|
||||
|
||||
@@ -19,20 +19,18 @@ class RangeCallable extends Callable {
|
||||
exists(int elSuper, int ecSuper | super.hasLocationInfo(path, sl, sc, elSuper, ecSuper) |
|
||||
this.getBody().hasLocationInfo(path, _, _, el, ec)
|
||||
or
|
||||
not exists(this.getBody()) and
|
||||
(
|
||||
not exists(this.getBody()) and
|
||||
(
|
||||
lastParameter().hasLocationInfo(path, _, _, el, ec)
|
||||
or
|
||||
(not exists(this.getAParameter()) and el = elSuper and ec = ecSuper)
|
||||
)
|
||||
lastParameter().hasLocationInfo(path, _, _, el, ec)
|
||||
or
|
||||
not exists(this.getAParameter()) and el = elSuper and ec = ecSuper
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
private Parameter lastParameter() {
|
||||
result = getAParameter() and
|
||||
not (getAParameter().getPosition() > result.getPosition())
|
||||
not getAParameter().getPosition() > result.getPosition()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -45,7 +43,7 @@ class RangeRefType extends RefType {
|
||||
exists(int elSuper, int ecSuper | super.hasLocationInfo(path, sl, sc, elSuper, ecSuper) |
|
||||
lastMember().hasLocationInfo(path, _, _, el, ec)
|
||||
or
|
||||
(not exists(this.getAMember()) and el = elSuper and ec = ecSuper)
|
||||
not exists(this.getAMember()) and el = elSuper and ec = ecSuper
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@ int complexCallableLines(MetricCallable c, RefType owner) {
|
||||
from MetricRefType t, int ccLoc, int loc
|
||||
where
|
||||
t.fromSource() and
|
||||
not (t instanceof GeneratedClass) and
|
||||
not t instanceof GeneratedClass and
|
||||
ccLoc = sum(Callable c, int cLoc | cLoc = complexCallableLines(c, t) | cLoc) and
|
||||
loc = t.getNumberOfLinesOfCode() and
|
||||
loc != 0
|
||||
|
||||
@@ -38,10 +38,8 @@ predicate useAndDef(Assignment a, Variable v) {
|
||||
(
|
||||
a instanceof AssignAddExpr
|
||||
or
|
||||
(
|
||||
exists(VarAccess use | use.getVariable() = v | use.getParent*() = a.getSource()) and
|
||||
a.getSource() instanceof AddExpr
|
||||
)
|
||||
exists(VarAccess use | use.getVariable() = v | use.getParent*() = a.getSource()) and
|
||||
a.getSource() instanceof AddExpr
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ import java
|
||||
predicate inherits(Class c, Field f) {
|
||||
f = c.getAField()
|
||||
or
|
||||
(not f.isPrivate() and c.getASupertype+().getAField() = f)
|
||||
not f.isPrivate() and c.getASupertype+().getAField() = f
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -37,10 +37,10 @@ RefType enclosingInstanceAccess(Expr expr) {
|
||||
exists(RefType enclosing | enclosing = expr.getEnclosingCallable().getDeclaringType() |
|
||||
// A direct qualified `this` access that doesn't refer to the containing
|
||||
// class must refer to an enclosing instance instead.
|
||||
(result = expr.(ThisAccess).getType() and result != enclosing)
|
||||
result = expr.(ThisAccess).getType() and result != enclosing
|
||||
or
|
||||
// A qualified `super` access qualified with a type that isn't the enclosing type.
|
||||
(result = expr.(SuperAccess).getQualifier().(TypeAccess).getType() and result != enclosing)
|
||||
result = expr.(SuperAccess).getQualifier().(TypeAccess).getType() and result != enclosing
|
||||
or
|
||||
// An unqualified `new` expression constructing a
|
||||
// non-static type that needs an enclosing instance.
|
||||
@@ -94,7 +94,7 @@ predicate potentiallyStatic(InnerClass c) {
|
||||
InnerClass other // If nested and non-static, ...
|
||||
|
|
||||
// ... all supertypes (which are from source), ...
|
||||
(other = c.getASourceSupertype() and other.fromSource())
|
||||
other = c.getASourceSupertype() and other.fromSource()
|
||||
or
|
||||
// ... and the enclosing type, ...
|
||||
other = c.getEnclosingType()
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
*/
|
||||
|
||||
import java
|
||||
import semmle.code.java.dataflow.TypeFlow
|
||||
import semmle.code.java.security.Encryption
|
||||
|
||||
class URLConnection extends RefType {
|
||||
@@ -27,11 +28,15 @@ from MethodAccess m, Class c, string type
|
||||
where
|
||||
m.getQualifier().getType() = c and
|
||||
(
|
||||
(c instanceof URLConnection and type = "connection")
|
||||
c instanceof URLConnection and type = "connection"
|
||||
or
|
||||
(c instanceof Socket and type = "socket")
|
||||
c instanceof Socket and type = "socket"
|
||||
) and
|
||||
not c instanceof SSLClass and
|
||||
not exists(RefType t |
|
||||
exprTypeFlow(m.getQualifier(), t, _) and
|
||||
t instanceof SSLClass
|
||||
) and
|
||||
(
|
||||
m.getMethod().getName() = "getInputStream" or
|
||||
m.getMethod().getName() = "getOutputStream"
|
||||
|
||||
@@ -172,20 +172,18 @@ class SafeDocumentBuilderFactory extends VarAccess {
|
||||
config.enables(singleSafeConfig())
|
||||
)
|
||||
or
|
||||
(
|
||||
//These two need to be set together to work
|
||||
exists(DocumentBuilderFactoryConfig config | config.getQualifier() = v.getAnAccess() |
|
||||
config
|
||||
.disables(any(ConstantStringExpr s |
|
||||
s.getStringValue() = "http://xml.org/sax/features/external-general-entities"
|
||||
))
|
||||
) and
|
||||
exists(DocumentBuilderFactoryConfig config | config.getQualifier() = v.getAnAccess() |
|
||||
config
|
||||
.disables(any(ConstantStringExpr s |
|
||||
s.getStringValue() = "http://xml.org/sax/features/external-parameter-entities"
|
||||
))
|
||||
)
|
||||
//These two need to be set together to work
|
||||
exists(DocumentBuilderFactoryConfig config | config.getQualifier() = v.getAnAccess() |
|
||||
config
|
||||
.disables(any(ConstantStringExpr s |
|
||||
s.getStringValue() = "http://xml.org/sax/features/external-general-entities"
|
||||
))
|
||||
) and
|
||||
exists(DocumentBuilderFactoryConfig config | config.getQualifier() = v.getAnAccess() |
|
||||
config
|
||||
.disables(any(ConstantStringExpr s |
|
||||
s.getStringValue() = "http://xml.org/sax/features/external-parameter-entities"
|
||||
))
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -682,25 +680,23 @@ class SafeXMLReaderFlowSink extends Expr {
|
||||
class ExplicitlySafeXMLReader extends VarAccess {
|
||||
ExplicitlySafeXMLReader() {
|
||||
exists(Variable v | v = this.getVariable() |
|
||||
(
|
||||
exists(XMLReaderConfig config | config.getQualifier() = v.getAnAccess() |
|
||||
config
|
||||
.disables(any(ConstantStringExpr s |
|
||||
s.getStringValue() = "http://xml.org/sax/features/external-general-entities"
|
||||
))
|
||||
) and
|
||||
exists(XMLReaderConfig config | config.getQualifier() = v.getAnAccess() |
|
||||
config
|
||||
.disables(any(ConstantStringExpr s |
|
||||
s.getStringValue() = "http://xml.org/sax/features/external-parameter-entities"
|
||||
))
|
||||
) and
|
||||
exists(XMLReaderConfig config | config.getQualifier() = v.getAnAccess() |
|
||||
config
|
||||
.disables(any(ConstantStringExpr s |
|
||||
s.getStringValue() = "http://apache.org/xml/features/nonvalidating/load-external-dtd"
|
||||
))
|
||||
)
|
||||
exists(XMLReaderConfig config | config.getQualifier() = v.getAnAccess() |
|
||||
config
|
||||
.disables(any(ConstantStringExpr s |
|
||||
s.getStringValue() = "http://xml.org/sax/features/external-general-entities"
|
||||
))
|
||||
) and
|
||||
exists(XMLReaderConfig config | config.getQualifier() = v.getAnAccess() |
|
||||
config
|
||||
.disables(any(ConstantStringExpr s |
|
||||
s.getStringValue() = "http://xml.org/sax/features/external-parameter-entities"
|
||||
))
|
||||
) and
|
||||
exists(XMLReaderConfig config | config.getQualifier() = v.getAnAccess() |
|
||||
config
|
||||
.disables(any(ConstantStringExpr s |
|
||||
s.getStringValue() = "http://apache.org/xml/features/nonvalidating/load-external-dtd"
|
||||
))
|
||||
)
|
||||
or
|
||||
exists(XMLReaderConfig config | config.getQualifier() = v.getAnAccess() |
|
||||
|
||||
@@ -104,7 +104,7 @@ private int anyCount(JavadocFirst first) {
|
||||
class CommentedOutCode extends JavadocFirst {
|
||||
CommentedOutCode() {
|
||||
anyCount(this) > 0 and
|
||||
(codeCount(this).(float)) / (anyCount(this).(float)) > 0.5 and
|
||||
codeCount(this).(float) / anyCount(this).(float) > 0.5 and
|
||||
not this instanceof JSNIComment and
|
||||
not this instanceof OCNIComment
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@ predicate nonEmptyArrayLiteralOrNull(Expr e) {
|
||||
// Array creation with dimensions (but without initializers).
|
||||
// Empty if the first dimension is 0.
|
||||
exists(Expr dim | dim = arr.getDimension(0) |
|
||||
not (dim.(CompileTimeConstantExpr).getIntValue() = 0)
|
||||
not dim.(CompileTimeConstantExpr).getIntValue() = 0
|
||||
)
|
||||
)
|
||||
or
|
||||
|
||||
@@ -352,7 +352,7 @@ private predicate candidateConstantForLiteral(
|
||||
}
|
||||
|
||||
private RefType inheritsProtected(Field f) {
|
||||
(f.isProtected() and result.getASupertype() = f.getDeclaringType())
|
||||
f.isProtected() and result.getASupertype() = f.getDeclaringType()
|
||||
or
|
||||
exists(RefType mid | mid = inheritsProtected(f) and result.getASupertype() = mid)
|
||||
}
|
||||
@@ -361,40 +361,32 @@ private predicate constantForLiteral(
|
||||
Field field, string value, RefType fromType, Literal magicLiteral, string context
|
||||
) {
|
||||
//public fields in public classes
|
||||
(
|
||||
candidateConstantForLiteral(field, fromType, magicLiteral, context) and
|
||||
relevantField(field, value) and
|
||||
field.getDeclaringType().isPublic() and
|
||||
field.isPublic() and
|
||||
relevantType(fromType, value, _)
|
||||
)
|
||||
candidateConstantForLiteral(field, fromType, magicLiteral, context) and
|
||||
relevantField(field, value) and
|
||||
field.getDeclaringType().isPublic() and
|
||||
field.isPublic() and
|
||||
relevantType(fromType, value, _)
|
||||
or
|
||||
//in same class
|
||||
(
|
||||
candidateConstantForLiteral(field, fromType, magicLiteral, context) and
|
||||
relevantField(field, value) and
|
||||
fromType = field.getDeclaringType() and
|
||||
relevantType(fromType, value, _)
|
||||
)
|
||||
candidateConstantForLiteral(field, fromType, magicLiteral, context) and
|
||||
relevantField(field, value) and
|
||||
fromType = field.getDeclaringType() and
|
||||
relevantType(fromType, value, _)
|
||||
or
|
||||
//in subclass and not private
|
||||
(
|
||||
candidateConstantForLiteral(field, fromType, magicLiteral, context) and
|
||||
relevantField(field, value) and
|
||||
field.isProtected() and
|
||||
fromType = inheritsProtected(field) and
|
||||
relevantType(fromType, value, _)
|
||||
)
|
||||
candidateConstantForLiteral(field, fromType, magicLiteral, context) and
|
||||
relevantField(field, value) and
|
||||
field.isProtected() and
|
||||
fromType = inheritsProtected(field) and
|
||||
relevantType(fromType, value, _)
|
||||
or
|
||||
//not private and in same package
|
||||
(
|
||||
candidateConstantForLiteral(field, fromType, magicLiteral, context) and
|
||||
relevantField(field, value) and
|
||||
field.isPackageProtected() and
|
||||
exists(Package p |
|
||||
exists(CompilationUnit cu | cu = field.getCompilationUnit() and cu.getPackage() = p) and
|
||||
relevantType(fromType, value, p)
|
||||
)
|
||||
candidateConstantForLiteral(field, fromType, magicLiteral, context) and
|
||||
relevantField(field, value) and
|
||||
field.isPackageProtected() and
|
||||
exists(Package p |
|
||||
exists(CompilationUnit cu | cu = field.getCompilationUnit() and cu.getPackage() = p) and
|
||||
relevantType(fromType, value, p)
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -32,7 +32,7 @@ Variable flowTarget(Expr arg) {
|
||||
*/
|
||||
predicate unboxed(BoxedExpr e) {
|
||||
exists(BinaryExpr bin | e = bin.getAnOperand() |
|
||||
if (bin instanceof EqualityTest or bin instanceof ComparisonExpr)
|
||||
if bin instanceof EqualityTest or bin instanceof ComparisonExpr
|
||||
then bin.getAnOperand() instanceof PrimitiveExpr
|
||||
else bin instanceof PrimitiveExpr
|
||||
)
|
||||
|
||||
@@ -28,7 +28,7 @@ RefType normalised(Type type) {
|
||||
or
|
||||
type.(BoundedType).getUpperBoundType() = result
|
||||
or
|
||||
(not type instanceof RawType and not type instanceof ParameterizedType and type = result)
|
||||
not type instanceof RawType and not type instanceof ParameterizedType and type = result
|
||||
}
|
||||
|
||||
predicate equivalent(Array declared, Array used) {
|
||||
|
||||
@@ -33,7 +33,7 @@ class LocationOverridingMethodAccess extends MethodAccess {
|
||||
super.hasLocationInfo(path, slSuper, scSuper, elSuper, ecSuper)
|
||||
|
|
||||
(
|
||||
if (exists(getTypeArgument(_)))
|
||||
if exists(getTypeArgument(_))
|
||||
then
|
||||
exists(Location locTypeArg |
|
||||
locTypeArg = getTypeArgument(count(getTypeArgument(_)) - 1).getLocation()
|
||||
@@ -56,7 +56,7 @@ class LocationOverridingMethodAccess extends MethodAccess {
|
||||
)
|
||||
) and
|
||||
(
|
||||
if (getNumArgument() > 0)
|
||||
if getNumArgument() > 0
|
||||
then
|
||||
// Note: this needs to be the original (full) location of the first argument, not the modified one.
|
||||
exists(Location locArg | locArg = getArgument(0).getLocation() |
|
||||
@@ -95,7 +95,7 @@ class LocationOverridingTypeAccess extends TypeAccess {
|
||||
)
|
||||
) and
|
||||
(
|
||||
if (exists(getTypeArgument(_)))
|
||||
if exists(getTypeArgument(_))
|
||||
then
|
||||
// Note: this needs to be the original (full) location of the first type argument, not the modified one.
|
||||
exists(Location locArg | locArg = getTypeArgument(0).getLocation() |
|
||||
@@ -119,7 +119,7 @@ class LocationOverridingFieldAccess extends FieldAccess {
|
||||
override predicate hasLocationInfo(string path, int sl, int sc, int el, int ec) {
|
||||
super.hasLocationInfo(path, _, _, el, ec) and
|
||||
sl = el and
|
||||
sc = ec - (getField().getName().length()) + 1
|
||||
sc = ec - getField().getName().length() + 1
|
||||
}
|
||||
}
|
||||
|
||||
@@ -135,7 +135,7 @@ class LocationOverridingImportType extends ImportType {
|
||||
el = elSuper and
|
||||
ec = ecSuper - 1 and
|
||||
sl = el and
|
||||
sc = ecSuper - (getImportedType().getName().length())
|
||||
sc = ecSuper - getImportedType().getName().length()
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -152,7 +152,7 @@ class LocationOverridingImportStaticTypeMember extends ImportStaticTypeMember {
|
||||
el = elSuper and
|
||||
ec = ecSuper - 1 and
|
||||
sl = el and
|
||||
sc = ecSuper - (getName().length())
|
||||
sc = ecSuper - getName().length()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
2
java/ql/src/external/Clover.qll
vendored
2
java/ql/src/external/Clover.qll
vendored
@@ -120,7 +120,7 @@ class CloverClass extends CloverMetricsContainer {
|
||||
this.getName() = "class"
|
||||
}
|
||||
|
||||
CloverPackage getPackage() { result = (getParent().(CloverFile)).getParent() }
|
||||
CloverPackage getPackage() { result = getParent().(CloverFile).getParent() }
|
||||
|
||||
RefType getRealClass() {
|
||||
result
|
||||
|
||||
34
java/ql/src/external/CodeDuplication.qll
vendored
34
java/ql/src/external/CodeDuplication.qll
vendored
@@ -108,7 +108,7 @@ predicate similarLines(File f, int line) {
|
||||
private predicate similarLinesPerEquivalenceClass(int equivClass, int lines, File f) {
|
||||
lines = strictsum(SimilarBlock b, int toSum |
|
||||
(b.sourceFile() = f and b.getEquivalenceClass() = equivClass) and
|
||||
(toSum = b.sourceLines())
|
||||
toSum = b.sourceLines()
|
||||
|
|
||||
toSum
|
||||
)
|
||||
@@ -143,7 +143,7 @@ predicate duplicateLines(File f, int line) {
|
||||
private predicate duplicateLinesPerEquivalenceClass(int equivClass, int lines, File f) {
|
||||
lines = strictsum(DuplicateBlock b, int toSum |
|
||||
(b.sourceFile() = f and b.getEquivalenceClass() = equivClass) and
|
||||
(toSum = b.sourceLines())
|
||||
toSum = b.sourceLines()
|
||||
|
|
||||
toSum
|
||||
)
|
||||
@@ -227,25 +227,21 @@ predicate mostlyDuplicateClass(Class c, Class other, string message) {
|
||||
not c instanceof AnonymousClass and
|
||||
not other instanceof AnonymousClass and
|
||||
(
|
||||
(
|
||||
total != numDup and
|
||||
exists(string s1, string s2, string s3, string name |
|
||||
s1 = " out of " and
|
||||
s2 = " methods in " and
|
||||
s3 = " are duplicated in $@." and
|
||||
name = c.getName()
|
||||
|
|
||||
message = numDup + s1 + total + s2 + name + s3
|
||||
)
|
||||
total != numDup and
|
||||
exists(string s1, string s2, string s3, string name |
|
||||
s1 = " out of " and
|
||||
s2 = " methods in " and
|
||||
s3 = " are duplicated in $@." and
|
||||
name = c.getName()
|
||||
|
|
||||
message = numDup + s1 + total + s2 + name + s3
|
||||
)
|
||||
or
|
||||
(
|
||||
total = numDup and
|
||||
exists(string s1, string s2, string name |
|
||||
s1 = "All methods in " and s2 = " are identical in $@." and name = c.getName()
|
||||
|
|
||||
message = s1 + name + s2
|
||||
)
|
||||
total = numDup and
|
||||
exists(string s1, string s2, string name |
|
||||
s1 = "All methods in " and s2 = " are identical in $@." and name = c.getName()
|
||||
|
|
||||
message = s1 + name + s2
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
4
java/ql/src/external/ExternalArtifact.qll
vendored
4
java/ql/src/external/ExternalArtifact.qll
vendored
@@ -18,9 +18,9 @@ class ExternalData extends @externalDataElement {
|
||||
string toString() { result = getQueryPath() + ": " + buildTupleString(0) }
|
||||
|
||||
private string buildTupleString(int start) {
|
||||
(start = getNumFields() - 1 and result = getField(start))
|
||||
start = getNumFields() - 1 and result = getField(start)
|
||||
or
|
||||
(start < getNumFields() - 1 and result = getField(start) + "," + buildTupleString(start + 1))
|
||||
start < getNumFields() - 1 and result = getField(start) + "," + buildTupleString(start + 1)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -37,7 +37,7 @@ class SuppressionComment extends Javadoc {
|
||||
result = "\\Q" + substring.replaceAll("\\E", "\\E\\\\E\\Q") + "\\E"
|
||||
)
|
||||
or
|
||||
(result = ".*" and getASuppressionDirective() = "NOSEMMLE")
|
||||
result = ".*" and getASuppressionDirective() = "NOSEMMLE"
|
||||
}
|
||||
|
||||
predicate suppresses(DefectResult res) {
|
||||
|
||||
@@ -109,7 +109,7 @@ class Location extends @location {
|
||||
exists(@sourceline s | hasLocation(s, this) |
|
||||
numlines(s, result, _, _)
|
||||
or
|
||||
(not numlines(s, _, _, _) and result = 0)
|
||||
not numlines(s, _, _, _) and result = 0
|
||||
)
|
||||
}
|
||||
|
||||
@@ -118,7 +118,7 @@ class Location extends @location {
|
||||
exists(@sourceline s | hasLocation(s, this) |
|
||||
numlines(s, _, result, _)
|
||||
or
|
||||
(not numlines(s, _, _, _) and result = 0)
|
||||
not numlines(s, _, _, _) and result = 0
|
||||
)
|
||||
}
|
||||
|
||||
@@ -127,7 +127,7 @@ class Location extends @location {
|
||||
exists(@sourceline s | hasLocation(s, this) |
|
||||
numlines(s, _, _, result)
|
||||
or
|
||||
(not numlines(s, _, _, _) and result = 0)
|
||||
not numlines(s, _, _, _) and result = 0
|
||||
)
|
||||
}
|
||||
|
||||
@@ -169,5 +169,5 @@ cached
|
||||
private predicate fixedHasLocation(Top l, Location loc, File f) {
|
||||
hasSourceLocation(l, loc, f)
|
||||
or
|
||||
(hasLocation(l, loc) and not hasSourceLocation(l, _, _) and locations_default(loc, f, _, _, _, _))
|
||||
hasLocation(l, loc) and not hasSourceLocation(l, _, _) and locations_default(loc, f, _, _, _, _)
|
||||
}
|
||||
|
||||
@@ -112,7 +112,7 @@ class Annotatable extends Element {
|
||||
*/
|
||||
predicate suppressesWarningsAbout(string category) {
|
||||
exists(string withQuotes |
|
||||
withQuotes = (getAnAnnotation().(SuppressWarningsAnnotation)).getASuppressedWarning()
|
||||
withQuotes = getAnAnnotation().(SuppressWarningsAnnotation).getASuppressedWarning()
|
||||
|
|
||||
category = withQuotes.substring(1, withQuotes.length() - 1)
|
||||
)
|
||||
|
||||
@@ -51,15 +51,11 @@ private predicate hasChildElement(Element parent, Element e) {
|
||||
or
|
||||
enclInReftype(e, parent)
|
||||
or
|
||||
(
|
||||
not (enclInReftype(e, _)) and
|
||||
e.(Class).getCompilationUnit() = parent
|
||||
)
|
||||
not enclInReftype(e, _) and
|
||||
e.(Class).getCompilationUnit() = parent
|
||||
or
|
||||
(
|
||||
not (enclInReftype(e, _)) and
|
||||
e.(Interface).getCompilationUnit() = parent
|
||||
)
|
||||
not enclInReftype(e, _) and
|
||||
e.(Interface).getCompilationUnit() = parent
|
||||
or
|
||||
methods(e, _, _, _, parent, _)
|
||||
or
|
||||
|
||||
@@ -139,10 +139,8 @@ class CompileTimeConstantExpr extends Expr {
|
||||
// the bitwise and logical operators `&`, `^`, and `|`,
|
||||
// the conditional-and operator `&&` and the conditional-or operator `||`.
|
||||
// These are precisely the operators represented by `BinaryExpr`.
|
||||
(
|
||||
this.(BinaryExpr).getLeftOperand().isCompileTimeConstant() and
|
||||
this.(BinaryExpr).getRightOperand().isCompileTimeConstant()
|
||||
)
|
||||
this.(BinaryExpr).getLeftOperand().isCompileTimeConstant() and
|
||||
this.(BinaryExpr).getRightOperand().isCompileTimeConstant()
|
||||
or
|
||||
// The ternary conditional operator ` ? : `.
|
||||
exists(ConditionalExpr e | this = e |
|
||||
@@ -252,17 +250,13 @@ class CompileTimeConstantExpr extends Expr {
|
||||
if left != right then result = true else result = false
|
||||
)
|
||||
or
|
||||
(
|
||||
(b instanceof AndBitwiseExpr or b instanceof AndLogicalExpr) and
|
||||
result = left.booleanAnd(right)
|
||||
)
|
||||
(b instanceof AndBitwiseExpr or b instanceof AndLogicalExpr) and
|
||||
result = left.booleanAnd(right)
|
||||
or
|
||||
(
|
||||
(b instanceof OrBitwiseExpr or b instanceof OrLogicalExpr) and
|
||||
result = left.booleanOr(right)
|
||||
)
|
||||
(b instanceof OrBitwiseExpr or b instanceof OrLogicalExpr) and
|
||||
result = left.booleanOr(right)
|
||||
or
|
||||
(b instanceof XorBitwiseExpr and result = left.booleanXor(right))
|
||||
b instanceof XorBitwiseExpr and result = left.booleanXor(right)
|
||||
)
|
||||
or
|
||||
// Handle binary expressions that have `String` operands and a boolean result.
|
||||
@@ -342,7 +336,7 @@ class CompileTimeConstantExpr extends Expr {
|
||||
or
|
||||
result = this.(PlusExpr).getExpr().(CompileTimeConstantExpr).getIntValue()
|
||||
or
|
||||
result = -(this.(MinusExpr).getExpr().(CompileTimeConstantExpr).getIntValue())
|
||||
result = -this.(MinusExpr).getExpr().(CompileTimeConstantExpr).getIntValue()
|
||||
or
|
||||
result = this.(BitNotExpr).getExpr().(CompileTimeConstantExpr).getIntValue().bitNot()
|
||||
or
|
||||
@@ -1189,12 +1183,7 @@ abstract class InstanceAccess extends Expr {
|
||||
class ThisAccess extends InstanceAccess, @thisaccess {
|
||||
/** Gets a printable representation of this expression. */
|
||||
override string toString() {
|
||||
if exists(this.getQualifier())
|
||||
then (
|
||||
result = this.getQualifier() + ".this"
|
||||
) else (
|
||||
result = "this"
|
||||
)
|
||||
if exists(this.getQualifier()) then result = this.getQualifier() + ".this" else result = "this"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1208,11 +1197,8 @@ class SuperAccess extends InstanceAccess, @superaccess {
|
||||
/** Gets a printable representation of this expression. */
|
||||
override string toString() {
|
||||
if exists(this.getQualifier())
|
||||
then (
|
||||
result = this.getQualifier() + ".super"
|
||||
) else (
|
||||
result = "super"
|
||||
)
|
||||
then result = this.getQualifier() + ".super"
|
||||
else result = "super"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1257,7 +1243,7 @@ class VarAccess extends Expr, @varaccess {
|
||||
override string toString() {
|
||||
result = this.getQualifier().toString() + "." + this.getVariable().getName()
|
||||
or
|
||||
(not this.hasQualifier() and result = this.getVariable().getName())
|
||||
not this.hasQualifier() and result = this.getVariable().getName()
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1391,7 +1377,7 @@ class TypeAccess extends Expr, Annotatable, @typeaccess {
|
||||
override string toString() {
|
||||
result = this.getQualifier().toString() + "." + this.getType().toString()
|
||||
or
|
||||
(not this.hasQualifier() and result = this.getType().toString())
|
||||
not this.hasQualifier() and result = this.getType().toString()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -56,11 +56,9 @@ class JMXRegistrationCall extends MethodAccess {
|
||||
*/
|
||||
class JMXRegistrationMethod extends Method {
|
||||
JMXRegistrationMethod() {
|
||||
(
|
||||
// A direct registration with the `MBeanServer`.
|
||||
getDeclaringType().hasQualifiedName("javax.management", "MBeanServer") and
|
||||
getName() = "registerMBean"
|
||||
)
|
||||
// A direct registration with the `MBeanServer`.
|
||||
getDeclaringType().hasQualifiedName("javax.management", "MBeanServer") and
|
||||
getName() = "registerMBean"
|
||||
or
|
||||
// The `MBeanServer` is often wrapped by an application specific management class, so identify
|
||||
// methods that wrap a call to another `JMXRegistrationMethod`.
|
||||
@@ -75,12 +73,10 @@ class JMXRegistrationMethod extends Method {
|
||||
* Gets the position of the parameter through which the "object" to be registered is passed.
|
||||
*/
|
||||
int getObjectPosition() {
|
||||
(
|
||||
// Passed as the first argument to `registerMBean`.
|
||||
getDeclaringType().hasQualifiedName("javax.management", "MBeanServer") and
|
||||
getName() = "registerMBean" and
|
||||
result = 0
|
||||
)
|
||||
// Passed as the first argument to `registerMBean`.
|
||||
getDeclaringType().hasQualifiedName("javax.management", "MBeanServer") and
|
||||
getName() = "registerMBean" and
|
||||
result = 0
|
||||
or
|
||||
// Identify the position in this method where the object parameter should be passed.
|
||||
exists(JMXRegistrationCall c |
|
||||
|
||||
@@ -74,7 +74,7 @@ class Callable extends StmtParent, Member, @callable {
|
||||
}
|
||||
|
||||
private string descriptorUpTo(int n) {
|
||||
(n = 0 and result = "")
|
||||
n = 0 and result = ""
|
||||
or
|
||||
exists(Parameter p | p = this.getParameter(n - 1) |
|
||||
result = descriptorUpTo(n - 1) + p.getType().getTypeDescriptor()
|
||||
|
||||
@@ -129,10 +129,8 @@ private Type parameterForSubTypes(ParameterizedType type) {
|
||||
// Must not be a catch-all.
|
||||
not catchallType(arg)
|
||||
|
|
||||
(
|
||||
// Simple case - this type is not a bounded type, so must represent exactly the `arg` class.
|
||||
not arg instanceof BoundedType and result = arg
|
||||
)
|
||||
// Simple case - this type is not a bounded type, so must represent exactly the `arg` class.
|
||||
not arg instanceof BoundedType and result = arg
|
||||
or
|
||||
exists(RefType upperBound |
|
||||
// Upper bound case
|
||||
@@ -173,7 +171,7 @@ Type inferClassParameterType(Expr expr) {
|
||||
// We've been able to identify where this `Class` instance was created, and identified the
|
||||
// particular class that was loaded.
|
||||
result = pointsToReflectiveClassIdentifier(expr).getReflectivelyIdentifiedClass()
|
||||
else (
|
||||
else
|
||||
// If we haven't been able to find where the value for this expression was defined, then we
|
||||
// resort to the type `T` in `Class<T>`.
|
||||
//
|
||||
@@ -183,7 +181,6 @@ Type inferClassParameterType(Expr expr) {
|
||||
// A "catch-all" type is something like `? extends Object` or `? extends Serialization`, which
|
||||
// would return too many sub-types.
|
||||
result = parameterForSubTypes(expr.getType())
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -290,12 +287,10 @@ class NewInstance extends MethodAccess {
|
||||
exists(CastExpr cast | cast.getExpr() = this or cast.getExpr().(ParExpr).getExpr() = this |
|
||||
result = cast.getType()
|
||||
or
|
||||
(
|
||||
// If we cast the result of this method, then this is either the type specified, or a
|
||||
// sub-type of that type. Make sure we exclude overly generic types such as `Object`.
|
||||
not overlyGenericType(cast.getType()) and
|
||||
hasSubtype*(cast.getType(), result)
|
||||
)
|
||||
// If we cast the result of this method, then this is either the type specified, or a
|
||||
// sub-type of that type. Make sure we exclude overly generic types such as `Object`.
|
||||
not overlyGenericType(cast.getType()) and
|
||||
hasSubtype*(cast.getType(), result)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -118,7 +118,7 @@ class IfStmt extends ConditionalStmt, @ifstmt {
|
||||
override string pp() {
|
||||
result = "if (...) " + this.getThen().pp() + " else " + this.getElse().pp()
|
||||
or
|
||||
(not exists(this.getElse()) and result = "if (...) " + this.getThen().pp())
|
||||
not exists(this.getElse()) and result = "if (...) " + this.getThen().pp()
|
||||
}
|
||||
|
||||
/** This statement's Halstead ID (used to compute Halstead metrics). */
|
||||
@@ -495,7 +495,7 @@ class ThrowStmt extends Stmt, @throwstmt {
|
||||
private CatchClause catchClauseForThis(TryStmt try) {
|
||||
result = try.getACatchClause() and
|
||||
result.getEnclosingCallable() = this.getEnclosingCallable() and
|
||||
(getExpr().getType().(RefType)).hasSupertype*(result.getVariable().getType().(RefType)) and
|
||||
getExpr().getType().(RefType).hasSupertype*(result.getVariable().getType().(RefType)) and
|
||||
not this.getParent+() = result
|
||||
}
|
||||
}
|
||||
@@ -538,7 +538,7 @@ class JumpStmt extends Stmt {
|
||||
Stmt getTarget() {
|
||||
result = getLabelTarget()
|
||||
or
|
||||
(not exists(getLabelTarget()) and result = getEnclosingTarget())
|
||||
not exists(getLabelTarget()) and result = getEnclosingTarget()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -20,21 +20,21 @@ import JDK
|
||||
cached
|
||||
predicate hasSubtype(RefType t, Type sub) {
|
||||
// Direct subtype.
|
||||
(extendsReftype(sub, t) and t != sub)
|
||||
extendsReftype(sub, t) and t != sub
|
||||
or
|
||||
implInterface(sub, t)
|
||||
or
|
||||
// A parameterized type `T<A>` is a subtype of the corresponding raw type `T<>`.
|
||||
(parSubtypeRaw(t, sub) and t != sub)
|
||||
parSubtypeRaw(t, sub) and t != sub
|
||||
or
|
||||
// Array subtyping is covariant.
|
||||
(arraySubtype(t, sub) and t != sub)
|
||||
arraySubtype(t, sub) and t != sub
|
||||
or
|
||||
// Type parameter containment for parameterized types.
|
||||
(parContainmentSubtype(t, sub) and t != sub)
|
||||
parContainmentSubtype(t, sub) and t != sub
|
||||
or
|
||||
// Type variables are subtypes of their upper bounds.
|
||||
(typeVarSubtypeBound(t, sub) and t != sub)
|
||||
typeVarSubtypeBound(t, sub) and t != sub
|
||||
}
|
||||
|
||||
private predicate typeVarSubtypeBound(RefType t, TypeVariable tv) {
|
||||
@@ -825,21 +825,21 @@ class PrimitiveType extends Type, @primitive {
|
||||
* Gets the JVM descriptor for this type, as used in bytecode.
|
||||
*/
|
||||
override string getTypeDescriptor() {
|
||||
(this.hasName("float") and result = "F")
|
||||
this.hasName("float") and result = "F"
|
||||
or
|
||||
(this.hasName("double") and result = "D")
|
||||
this.hasName("double") and result = "D"
|
||||
or
|
||||
(this.hasName("int") and result = "I")
|
||||
this.hasName("int") and result = "I"
|
||||
or
|
||||
(this.hasName("boolean") and result = "Z")
|
||||
this.hasName("boolean") and result = "Z"
|
||||
or
|
||||
(this.hasName("short") and result = "S")
|
||||
this.hasName("short") and result = "S"
|
||||
or
|
||||
(this.hasName("byte") and result = "B")
|
||||
this.hasName("byte") and result = "B"
|
||||
or
|
||||
(this.hasName("char") and result = "C")
|
||||
this.hasName("char") and result = "C"
|
||||
or
|
||||
(this.hasName("long") and result = "J")
|
||||
this.hasName("long") and result = "J"
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -896,21 +896,21 @@ class BoxedType extends RefType {
|
||||
|
||||
/** Gets the primitive type corresponding to this boxed type. */
|
||||
PrimitiveType getPrimitiveType() {
|
||||
(this.hasName("Float") and result.hasName("float"))
|
||||
this.hasName("Float") and result.hasName("float")
|
||||
or
|
||||
(this.hasName("Double") and result.hasName("double"))
|
||||
this.hasName("Double") and result.hasName("double")
|
||||
or
|
||||
(this.hasName("Integer") and result.hasName("int"))
|
||||
this.hasName("Integer") and result.hasName("int")
|
||||
or
|
||||
(this.hasName("Boolean") and result.hasName("boolean"))
|
||||
this.hasName("Boolean") and result.hasName("boolean")
|
||||
or
|
||||
(this.hasName("Short") and result.hasName("short"))
|
||||
this.hasName("Short") and result.hasName("short")
|
||||
or
|
||||
(this.hasName("Byte") and result.hasName("byte"))
|
||||
this.hasName("Byte") and result.hasName("byte")
|
||||
or
|
||||
(this.hasName("Character") and result.hasName("char"))
|
||||
this.hasName("Character") and result.hasName("char")
|
||||
or
|
||||
(this.hasName("Long") and result.hasName("long"))
|
||||
this.hasName("Long") and result.hasName("long")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -7,46 +7,46 @@ class OrdPrimitiveType extends PrimitiveType {
|
||||
predicate widerThanOrEqualTo(OrdPrimitiveType that) { getWidthRank() >= that.getWidthRank() }
|
||||
|
||||
OrdPrimitiveType maxType(OrdPrimitiveType that) {
|
||||
(this.widerThan(that) and result = this)
|
||||
this.widerThan(that) and result = this
|
||||
or
|
||||
(not this.widerThan(that) and result = that)
|
||||
not this.widerThan(that) and result = that
|
||||
}
|
||||
|
||||
int getWidthRank() {
|
||||
(this.getName() = "byte" and result = 1)
|
||||
this.getName() = "byte" and result = 1
|
||||
or
|
||||
(this.getName() = "short" and result = 2)
|
||||
this.getName() = "short" and result = 2
|
||||
or
|
||||
(this.getName() = "int" and result = 3)
|
||||
this.getName() = "int" and result = 3
|
||||
or
|
||||
(this.getName() = "long" and result = 4)
|
||||
this.getName() = "long" and result = 4
|
||||
or
|
||||
(this.getName() = "float" and result = 5)
|
||||
this.getName() = "float" and result = 5
|
||||
or
|
||||
(this.getName() = "double" and result = 6)
|
||||
this.getName() = "double" and result = 6
|
||||
}
|
||||
|
||||
float getMaxValue() {
|
||||
(this.getName() = "byte" and result = 127.0)
|
||||
this.getName() = "byte" and result = 127.0
|
||||
or
|
||||
(this.getName() = "short" and result = 32767.0)
|
||||
this.getName() = "short" and result = 32767.0
|
||||
or
|
||||
(this.getName() = "int" and result = 2147483647.0)
|
||||
this.getName() = "int" and result = 2147483647.0
|
||||
or
|
||||
// Long.MAX_VALUE is 9223372036854775807 but floating point only has 53 bits of precision.
|
||||
(this.getName() = "long" and result = 9223372036854776000.0)
|
||||
this.getName() = "long" and result = 9223372036854776000.0
|
||||
// don't try for floats and doubles
|
||||
}
|
||||
|
||||
float getMinValue() {
|
||||
(this.getName() = "byte" and result = -128.0)
|
||||
this.getName() = "byte" and result = -128.0
|
||||
or
|
||||
(this.getName() = "short" and result = -32768.0)
|
||||
this.getName() = "short" and result = -32768.0
|
||||
or
|
||||
(this.getName() = "int" and result = -2147483648.0)
|
||||
this.getName() = "int" and result = -2147483648.0
|
||||
or
|
||||
// Long.MIN_VALUE is -9223372036854775808 but floating point only has 53 bits of precision.
|
||||
(this.getName() = "long" and result = -9223372036854776000.0)
|
||||
this.getName() = "long" and result = -9223372036854776000.0
|
||||
// don't try for floats and doubles
|
||||
}
|
||||
}
|
||||
@@ -59,9 +59,9 @@ class NumType extends Type {
|
||||
|
||||
/** Gets the width-ordered primitive type corresponding to this type. */
|
||||
OrdPrimitiveType getOrdPrimitiveType() {
|
||||
(this instanceof PrimitiveType and result = this)
|
||||
this instanceof PrimitiveType and result = this
|
||||
or
|
||||
(this instanceof BoxedType and result = this.(BoxedType).getPrimitiveType())
|
||||
this instanceof BoxedType and result = this.(BoxedType).getPrimitiveType()
|
||||
}
|
||||
|
||||
predicate widerThan(NumType that) {
|
||||
|
||||
@@ -25,10 +25,8 @@ class ConstantField extends Field {
|
||||
fa.getEnclosingCallable() instanceof InstanceInitializer
|
||||
or
|
||||
// It can be defined in the constructor if there is only one constructor.
|
||||
(
|
||||
fa.getEnclosingCallable() instanceof Constructor and
|
||||
count(getDeclaringType().getAConstructor()) = 1
|
||||
)
|
||||
fa.getEnclosingCallable() instanceof Constructor and
|
||||
count(getDeclaringType().getAConstructor()) = 1
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -93,10 +91,8 @@ class ConstantExpr extends Expr {
|
||||
exists(this.(FieldRead).getField().(ConstantField).getConstantValue())
|
||||
or
|
||||
// A binary expression where both sides are constant
|
||||
(
|
||||
this.(BinaryExpr).getLeftOperand() instanceof ConstantExpr and
|
||||
this.(BinaryExpr).getRightOperand() instanceof ConstantExpr
|
||||
)
|
||||
this.(BinaryExpr).getLeftOperand() instanceof ConstantExpr and
|
||||
this.(BinaryExpr).getRightOperand() instanceof ConstantExpr
|
||||
or
|
||||
this.(ParExpr).getExpr() instanceof ConstantExpr
|
||||
)
|
||||
@@ -179,7 +175,7 @@ class ConstSwitchStmt extends SwitchStmt {
|
||||
SwitchCase getMatchingCase() {
|
||||
// Must be a value we can deduce
|
||||
exists(getExpr().(ConstantExpr).getIntValue()) and
|
||||
if (exists(getMatchingConstCase()))
|
||||
if exists(getMatchingConstCase())
|
||||
then result = getMatchingConstCase()
|
||||
else result = getDefaultCase()
|
||||
}
|
||||
@@ -216,14 +212,12 @@ class UnreachableBasicBlock extends BasicBlock {
|
||||
or
|
||||
// This block is not reachable in the CFG, and is not a callable, a body of a callable, an
|
||||
// expression in an annotation, an expression in an assert statement, or a catch clause.
|
||||
(
|
||||
forall(BasicBlock bb | bb = getABBPredecessor() | bb instanceof UnreachableBasicBlock) and
|
||||
not exists(Callable c | c.getBody() = this) and
|
||||
not this instanceof Callable and
|
||||
not exists(Annotation a | a.getAChildExpr*() = this) and
|
||||
not exists(AssertStmt a | a = this.(Expr).getEnclosingStmt()) and
|
||||
not this instanceof CatchClause
|
||||
)
|
||||
forall(BasicBlock bb | bb = getABBPredecessor() | bb instanceof UnreachableBasicBlock) and
|
||||
not exists(Callable c | c.getBody() = this) and
|
||||
not this instanceof Callable and
|
||||
not exists(Annotation a | a.getAChildExpr*() = this) and
|
||||
not exists(AssertStmt a | a = this.(Expr).getEnclosingStmt()) and
|
||||
not this instanceof CatchClause
|
||||
or
|
||||
// Switch statements with a constant comparison expression may have unreachable cases.
|
||||
exists(ConstSwitchStmt constSwitchStmt, BasicBlock failingCaseBlock |
|
||||
|
||||
@@ -94,6 +94,34 @@ Expr clearlyNotNullExpr() { result = clearlyNotNullExpr(_) }
|
||||
/** Holds if `v` is an SSA variable that is provably not `null`. */
|
||||
predicate clearlyNotNull(SsaVariable v) { clearlyNotNull(v, _) }
|
||||
|
||||
/**
|
||||
* Holds if the evaluation of a call to `m` resulting in the value `branch`
|
||||
* implies that the argument to the call is guaranteed to be null if `isnull`
|
||||
* is true, and non-null if `isnull` is false.
|
||||
*/
|
||||
predicate nullCheckMethod(Method m, boolean branch, boolean isnull) {
|
||||
exists(boolean polarity |
|
||||
m.getDeclaringType().hasQualifiedName("java.util", "Objects") and
|
||||
(
|
||||
m.hasName("isNull") and polarity = true
|
||||
or
|
||||
m.hasName("nonNull") and polarity = false
|
||||
) and
|
||||
(
|
||||
branch = true and isnull = polarity
|
||||
or
|
||||
branch = false and isnull = polarity.booleanNot()
|
||||
)
|
||||
)
|
||||
or
|
||||
m instanceof EqualsMethod and branch = true and isnull = false
|
||||
or
|
||||
m.getDeclaringType().hasQualifiedName("org.apache.commons.lang3", "StringUtils") and
|
||||
m.hasName("isBlank") and
|
||||
branch = false and
|
||||
isnull = false
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an expression that directly tests whether a given expression, `e`, is null or not.
|
||||
*
|
||||
@@ -114,29 +142,10 @@ Expr basicNullGuard(Expr e, boolean branch, boolean isnull) {
|
||||
or
|
||||
result.(InstanceOfExpr).getExpr() = e and branch = true and isnull = false
|
||||
or
|
||||
exists(MethodAccess call, Method m, boolean polarity |
|
||||
call = result and
|
||||
call.getAnArgument() = e and
|
||||
call.getMethod() = m and
|
||||
m.getDeclaringType().hasQualifiedName("java.util", "Objects") and
|
||||
(
|
||||
m.hasName("isNull") and polarity = true
|
||||
or
|
||||
m.hasName("nonNull") and polarity = false
|
||||
) and
|
||||
(
|
||||
branch = true and isnull = polarity
|
||||
or
|
||||
branch = false and isnull = polarity.booleanNot()
|
||||
)
|
||||
)
|
||||
or
|
||||
exists(MethodAccess call |
|
||||
call = result and
|
||||
call.getAnArgument() = e and
|
||||
call.getMethod() instanceof EqualsMethod and
|
||||
branch = true and
|
||||
isnull = false
|
||||
nullCheckMethod(call.getMethod(), branch, isnull)
|
||||
)
|
||||
or
|
||||
exists(EqualityTest eqtest |
|
||||
|
||||
@@ -336,11 +336,11 @@ private predicate nullVarStep(
|
||||
not exists(boolean branch | nullGuard(midssa, branch, false).hasBranchEdge(mid, bb, branch)) and
|
||||
not (leavingFinally(mid, bb, true) and midstoredcompletion = true) and
|
||||
if bb.getFirstNode() = any(TryStmt try | | try.getFinally())
|
||||
then (
|
||||
then
|
||||
if bb.getFirstNode() = mid.getLastNode().getANormalSuccessor()
|
||||
then storedcompletion = false
|
||||
else storedcompletion = true
|
||||
) else
|
||||
else
|
||||
if leavingFinally(mid, bb, _)
|
||||
then storedcompletion = false
|
||||
else storedcompletion = midstoredcompletion
|
||||
|
||||
@@ -232,11 +232,11 @@ private Guard boundFlowCond(SsaVariable v, Expr e, int delta, boolean upper, boo
|
||||
) and
|
||||
(
|
||||
if v.getSourceVariable().getType() instanceof IntegralType
|
||||
then (
|
||||
then
|
||||
upper = true and strengthen = -1
|
||||
or
|
||||
upper = false and strengthen = 1
|
||||
) else strengthen = 0
|
||||
else strengthen = 0
|
||||
) and
|
||||
(
|
||||
exists(int k | modulusComparison(comp, testIsTrue, k) and d2 = strengthen * k)
|
||||
@@ -402,17 +402,14 @@ private predicate boundFlowStep(Expr e2, Expr e1, int delta, boolean upper) {
|
||||
not x instanceof ConstantIntegerExpr and
|
||||
not e1 instanceof ConstantIntegerExpr and
|
||||
if strictlyPositive(x)
|
||||
then (
|
||||
upper = false and delta = 1
|
||||
) else
|
||||
then upper = false and delta = 1
|
||||
else
|
||||
if positive(x)
|
||||
then (
|
||||
upper = false and delta = 0
|
||||
) else
|
||||
then upper = false and delta = 0
|
||||
else
|
||||
if strictlyNegative(x)
|
||||
then (
|
||||
upper = true and delta = -1
|
||||
) else if negative(x) then (upper = true and delta = 0) else none()
|
||||
then upper = true and delta = -1
|
||||
else if negative(x) then upper = true and delta = 0 else none()
|
||||
)
|
||||
or
|
||||
exists(Expr x |
|
||||
@@ -431,17 +428,14 @@ private predicate boundFlowStep(Expr e2, Expr e1, int delta, boolean upper) {
|
||||
// `x instanceof ConstantIntegerExpr` is covered by valueFlowStep
|
||||
not x instanceof ConstantIntegerExpr and
|
||||
if strictlyPositive(x)
|
||||
then (
|
||||
upper = true and delta = -1
|
||||
) else
|
||||
then upper = true and delta = -1
|
||||
else
|
||||
if positive(x)
|
||||
then (
|
||||
upper = true and delta = 0
|
||||
) else
|
||||
then upper = true and delta = 0
|
||||
else
|
||||
if strictlyNegative(x)
|
||||
then (
|
||||
upper = false and delta = 1
|
||||
) else if negative(x) then (upper = false and delta = 0) else none()
|
||||
then upper = false and delta = 1
|
||||
else if negative(x) then upper = false and delta = 0 else none()
|
||||
)
|
||||
or
|
||||
e2.(RemExpr).getRightOperand() = e1 and positive(e1) and delta = -1 and upper = true
|
||||
|
||||
@@ -18,35 +18,29 @@ predicate isLive(Callable c) {
|
||||
* would imply the liveness of `c`.
|
||||
*/
|
||||
Callable possibleLivenessCause(Callable c, string reason) {
|
||||
(
|
||||
c.(Method).overridesOrInstantiates(result.(Method)) and
|
||||
reason = "is overridden or instantiated by"
|
||||
)
|
||||
c.(Method).overridesOrInstantiates(result.(Method)) and
|
||||
reason = "is overridden or instantiated by"
|
||||
or
|
||||
(result.calls(c) and reason = "calls")
|
||||
result.calls(c) and reason = "calls"
|
||||
or
|
||||
(result.callsConstructor(c.(Constructor)) and reason = "calls constructor")
|
||||
result.callsConstructor(c.(Constructor)) and reason = "calls constructor"
|
||||
or
|
||||
exists(ClassInstanceExpr e | e.getEnclosingCallable() = result |
|
||||
e.getConstructor() = c and reason = "constructs"
|
||||
)
|
||||
or
|
||||
(c = result.getSourceDeclaration() and c != result and reason = "instantiates")
|
||||
c = result.getSourceDeclaration() and c != result and reason = "instantiates"
|
||||
or
|
||||
(
|
||||
c.hasName("<clinit>") and
|
||||
reason = "class initialization" and
|
||||
exists(RefType clintedType | c = clintedType.getASupertype*().getACallable() |
|
||||
result.getDeclaringType() = clintedType or
|
||||
result.getAnAccessedField().getDeclaringType() = clintedType
|
||||
)
|
||||
c.hasName("<clinit>") and
|
||||
reason = "class initialization" and
|
||||
exists(RefType clintedType | c = clintedType.getASupertype*().getACallable() |
|
||||
result.getDeclaringType() = clintedType or
|
||||
result.getAnAccessedField().getDeclaringType() = clintedType
|
||||
)
|
||||
or
|
||||
(
|
||||
c.hasName("<obinit>") and
|
||||
reason = "object initialization" and
|
||||
result = c.getDeclaringType().getAConstructor()
|
||||
)
|
||||
c.hasName("<obinit>") and
|
||||
reason = "object initialization" and
|
||||
result = c.getDeclaringType().getAConstructor()
|
||||
}
|
||||
|
||||
Callable possibleLivenessCause(Callable c) { result = possibleLivenessCause(c, _) }
|
||||
@@ -91,7 +85,7 @@ class SuppressedConstructor extends Constructor {
|
||||
isPrivate()
|
||||
or
|
||||
// A protected, suppressed constructor only makes sense in a non-abstract class.
|
||||
(isProtected() and not getDeclaringType().isAbstract())
|
||||
isProtected() and not getDeclaringType().isAbstract()
|
||||
) and
|
||||
// Must be no-arg in order to replace the compiler generated default constructor.
|
||||
getNumberOfParameters() = 0 and
|
||||
@@ -167,13 +161,11 @@ class LiveClass extends SourceClassOrInterface {
|
||||
not f instanceof SerialVersionUIDField
|
||||
)
|
||||
or
|
||||
(
|
||||
// If this is a namespace class, it is live if there is at least one live nested class.
|
||||
// The definition of `NamespaceClass` is such, that the nested classes must all be static.
|
||||
// Static methods are handled above.
|
||||
this instanceof NamespaceClass and
|
||||
exists(NestedType r | r.getEnclosingType() = this | r instanceof LiveClass)
|
||||
)
|
||||
// If this is a namespace class, it is live if there is at least one live nested class.
|
||||
// The definition of `NamespaceClass` is such, that the nested classes must all be static.
|
||||
// Static methods are handled above.
|
||||
this instanceof NamespaceClass and
|
||||
exists(NestedType r | r.getEnclosingType() = this | r instanceof LiveClass)
|
||||
or
|
||||
// An annotation on the class is reflectively accessed.
|
||||
exists(ReflectiveAnnotationAccess reflectiveAnnotationAccess |
|
||||
@@ -298,10 +290,8 @@ class RootdefCallable extends Callable {
|
||||
// Abstract, native and interface methods obviously won't access their own
|
||||
// parameters, so don't flag unless we can see an overriding method with
|
||||
// a body that also doesn't.
|
||||
(
|
||||
not hasUsefulBody(this) and
|
||||
not exists(Method m | hasUsefulBody(m) | m.overridesOrInstantiates+(this))
|
||||
)
|
||||
not hasUsefulBody(this) and
|
||||
not exists(Method m | hasUsefulBody(m) | m.overridesOrInstantiates+(this))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -22,10 +22,8 @@ class Struts1ActionEntryPoint extends EntryPoint, Class {
|
||||
result.(Method).overrides(methodFromAction)
|
||||
)
|
||||
or
|
||||
(
|
||||
this.getASupertype*().hasQualifiedName("org.apache.struts.actions", "DispatchAction") and
|
||||
result.(Method).isPublic()
|
||||
)
|
||||
this.getASupertype*().hasQualifiedName("org.apache.struts.actions", "DispatchAction") and
|
||||
result.(Method).isPublic()
|
||||
or
|
||||
result.(Constructor).getNumberOfParameters() = 0
|
||||
)
|
||||
|
||||
@@ -10,11 +10,9 @@ import semmle.code.java.UnitTests
|
||||
*/
|
||||
class TestMethodEntry extends CallableEntryPoint {
|
||||
TestMethodEntry() {
|
||||
(
|
||||
this instanceof TestMethod and
|
||||
// Ignored tests are not run
|
||||
not this instanceof JUnitIgnoredMethod
|
||||
)
|
||||
this instanceof TestMethod and
|
||||
// Ignored tests are not run
|
||||
not this instanceof JUnitIgnoredMethod
|
||||
or
|
||||
this instanceof JUnit3TestSuite
|
||||
or
|
||||
|
||||
@@ -62,7 +62,7 @@ class JaxbType extends Class {
|
||||
* Gets the `XmlAccessType` associated with this class.
|
||||
*/
|
||||
XmlAccessType getXmlAccessType() {
|
||||
if (exists(getDeclaredAccessType()))
|
||||
if exists(getDeclaredAccessType())
|
||||
then result = getDeclaredAccessType()
|
||||
else
|
||||
// Default access type, if not specified.
|
||||
@@ -136,7 +136,7 @@ class JaxbBoundField extends Field {
|
||||
type.getXmlAccessType().isField()
|
||||
or
|
||||
// Only public fields are automatically bound in this access type.
|
||||
(type.getXmlAccessType().isPublicMember() and isPublic())
|
||||
type.getXmlAccessType().isPublicMember() and isPublic()
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -192,7 +192,7 @@ class JaxbBoundGetterSetter extends GetterOrSetterMethod {
|
||||
isProperty() and
|
||||
(
|
||||
// In the `PUBLIC_MEMBER` case all public properties are considered bound.
|
||||
(c.getXmlAccessType().isPublicMember() and isPublic())
|
||||
c.getXmlAccessType().isPublicMember() and isPublic()
|
||||
or
|
||||
// In "property" all properties are considered bound.
|
||||
c.getXmlAccessType().isProperty()
|
||||
|
||||
@@ -15,11 +15,9 @@ class JaxWsEndpoint extends Class {
|
||||
|
||||
Callable getARemoteMethod() {
|
||||
result = this.getACallable() and
|
||||
(
|
||||
exists(AnnotationType a | a = result.getAnAnnotation().getType() |
|
||||
a.hasName("WebMethod") or
|
||||
a.hasName("WebEndpoint")
|
||||
)
|
||||
exists(AnnotationType a | a = result.getAnAnnotation().getType() |
|
||||
a.hasName("WebMethod") or
|
||||
a.hasName("WebEndpoint")
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -222,24 +222,20 @@ class MockitoInjectedField extends MockitoAnnotatedField {
|
||||
else
|
||||
if usingPropertyInjection()
|
||||
then
|
||||
(
|
||||
// We will call the no-arg constructor if the field wasn't initialized.
|
||||
not exists(getInitializer()) and
|
||||
result = mockInjectedClass.getNoArgsConstructor()
|
||||
)
|
||||
// We will call the no-arg constructor if the field wasn't initialized.
|
||||
not exists(getInitializer()) and
|
||||
result = mockInjectedClass.getNoArgsConstructor()
|
||||
or
|
||||
(
|
||||
// Perform property injection into setter fields, but only where there exists a mock
|
||||
// that can be injected into the method. Otherwise, the setter method is never called.
|
||||
result = mockInjectedClass.getASetterMethod() and
|
||||
exists(MockitoMockedField mockedField |
|
||||
mockedField.getDeclaringType() = this.getDeclaringType() and
|
||||
mockedField.isValid()
|
||||
|
|
||||
// We make a simplifying assumption here - in theory, each mock can only be injected
|
||||
// once, but we instead assume that there are sufficient mocks to go around.
|
||||
mockedField.getType().(RefType).getAnAncestor() = result.getParameterType(0)
|
||||
)
|
||||
// Perform property injection into setter fields, but only where there exists a mock
|
||||
// that can be injected into the method. Otherwise, the setter method is never called.
|
||||
result = mockInjectedClass.getASetterMethod() and
|
||||
exists(MockitoMockedField mockedField |
|
||||
mockedField.getDeclaringType() = this.getDeclaringType() and
|
||||
mockedField.isValid()
|
||||
|
|
||||
// We make a simplifying assumption here - in theory, each mock can only be injected
|
||||
// once, but we instead assume that there are sufficient mocks to go around.
|
||||
mockedField.getType().(RefType).getAnAncestor() = result.getParameterType(0)
|
||||
)
|
||||
else
|
||||
// There's no instance, and no no-arg constructor we can call, so injection fails.
|
||||
|
||||
@@ -30,10 +30,8 @@ class SafeSnakeYamlConstruction extends ClassInstanceExpr {
|
||||
SafeSnakeYamlConstruction() {
|
||||
this.getConstructedType() instanceof SnakeYamlSafeConstructor
|
||||
or
|
||||
(
|
||||
this.getConstructedType() instanceof SnakeYamlConstructor and
|
||||
this.getNumArgument() > 0
|
||||
)
|
||||
this.getConstructedType() instanceof SnakeYamlConstructor and
|
||||
this.getNumArgument() > 0
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -35,10 +35,8 @@ class GwtEntryPointClass extends Class {
|
||||
// are live.
|
||||
isGwtXmlIncluded()
|
||||
implies
|
||||
(
|
||||
// The entry point is live if it is specified in a `*.gwt.xml` file.
|
||||
exists(getAGwtXmlFile())
|
||||
)
|
||||
// The entry point is live if it is specified in a `*.gwt.xml` file.
|
||||
exists(getAGwtXmlFile())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -39,7 +39,7 @@ class GwtXmlFile extends XMLFile {
|
||||
* Either the default `client` folder or as specified by `<source>` tags.
|
||||
*/
|
||||
string getASourceSubPath() {
|
||||
(result = "client" and not exists(getAnExplicitSourceSubPath()))
|
||||
result = "client" and not exists(getAnExplicitSourceSubPath())
|
||||
or
|
||||
result = getAnExplicitSourceSubPath()
|
||||
}
|
||||
|
||||
@@ -68,7 +68,7 @@ class SessionEJB extends EJB {
|
||||
|
||||
/** Any remote interfaces of this EJB. */
|
||||
LegacyEjbRemoteInterface getARemoteInterface() {
|
||||
(result = this.getASupertype() and result instanceof ExtendedRemoteInterface)
|
||||
result = this.getASupertype() and result instanceof ExtendedRemoteInterface
|
||||
or
|
||||
exists(AnnotatedRemoteHomeInterface i | i.getAnEJB() = this |
|
||||
result = i.getAnAssociatedRemoteInterface()
|
||||
@@ -79,7 +79,7 @@ class SessionEJB extends EJB {
|
||||
|
||||
/** Any remote home interfaces of this EJB. */
|
||||
LegacyEjbRemoteHomeInterface getARemoteHomeInterface() {
|
||||
(result = this.getASupertype() and result instanceof ExtendedRemoteHomeInterface)
|
||||
result = this.getASupertype() and result instanceof ExtendedRemoteHomeInterface
|
||||
or
|
||||
result.(AnnotatedRemoteHomeInterface).getAnEJB() = this
|
||||
or
|
||||
@@ -88,7 +88,7 @@ class SessionEJB extends EJB {
|
||||
|
||||
/** Any local interfaces of this EJB. */
|
||||
LegacyEjbLocalInterface getALocalInterface() {
|
||||
(result = this.getASupertype() and result instanceof ExtendedLocalInterface)
|
||||
result = this.getASupertype() and result instanceof ExtendedLocalInterface
|
||||
or
|
||||
exists(AnnotatedLocalHomeInterface i | i.getAnEJB() = this |
|
||||
result = i.getAnAssociatedLocalInterface()
|
||||
@@ -99,7 +99,7 @@ class SessionEJB extends EJB {
|
||||
|
||||
/** Any local home interfaces of this EJB. */
|
||||
LegacyEjbLocalHomeInterface getALocalHomeInterface() {
|
||||
(result = this.getASupertype() and result instanceof ExtendedLocalHomeInterface)
|
||||
result = this.getASupertype() and result instanceof ExtendedLocalHomeInterface
|
||||
or
|
||||
result.(AnnotatedLocalHomeInterface).getAnEJB() = this
|
||||
or
|
||||
@@ -898,10 +898,8 @@ TransactionAttributeAnnotation getInnermostTransactionAttributeAnnotation(Method
|
||||
or
|
||||
// ...or if the declaring class has such an annotation, the annotation applies to
|
||||
// any method declared within the class that does not itself have such an annotation.
|
||||
(
|
||||
not exists(m.getAnAnnotation().(TransactionAttributeAnnotation)) and
|
||||
result = m.getDeclaringType().getSourceDeclaration().getAnAnnotation()
|
||||
)
|
||||
not exists(m.getAnAnnotation().(TransactionAttributeAnnotation)) and
|
||||
result = m.getDeclaringType().getSourceDeclaration().getAnAnnotation()
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -78,30 +78,24 @@ class SpringBeanXMLAutowiredSetterMethod extends Method {
|
||||
exists(string xmlAutowire |
|
||||
xmlAutowire = this.getDeclaringType().(SpringBeanRefType).getSpringBean().getAutowire()
|
||||
|
|
||||
(
|
||||
xmlAutowire = "byName" and
|
||||
// There is a bean whose name is the same as this setter method.
|
||||
this.getName().toLowerCase() = "set" + result.getBeanIdentifier().toLowerCase()
|
||||
)
|
||||
xmlAutowire = "byName" and
|
||||
// There is a bean whose name is the same as this setter method.
|
||||
this.getName().toLowerCase() = "set" + result.getBeanIdentifier().toLowerCase()
|
||||
or
|
||||
(
|
||||
(
|
||||
xmlAutowire = "byType"
|
||||
or
|
||||
(
|
||||
// When it is set to autodetect, we use "byType" if there is a no-arg constructor. This
|
||||
// approach has been removed in Spring 4.x.
|
||||
xmlAutowire = "autodetect" and
|
||||
exists(Constructor c | c = this.getDeclaringType().getAConstructor() |
|
||||
c.getNumberOfParameters() = 0
|
||||
)
|
||||
)
|
||||
) and
|
||||
// The resulting bean is of the right type.
|
||||
result.getClass().getAnAncestor() = getParameter(0).getType() and
|
||||
getNumberOfParameters() = 1 and
|
||||
this.getName().matches("set%")
|
||||
)
|
||||
xmlAutowire = "byType"
|
||||
or
|
||||
// When it is set to autodetect, we use "byType" if there is a no-arg constructor. This
|
||||
// approach has been removed in Spring 4.x.
|
||||
xmlAutowire = "autodetect" and
|
||||
exists(Constructor c | c = this.getDeclaringType().getAConstructor() |
|
||||
c.getNumberOfParameters() = 0
|
||||
)
|
||||
) and
|
||||
// The resulting bean is of the right type.
|
||||
result.getClass().getAnAncestor() = getParameter(0).getType() and
|
||||
getNumberOfParameters() = 1 and
|
||||
this.getName().matches("set%")
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -166,17 +160,17 @@ class SpringBeanAutowiredCallable extends Callable {
|
||||
result = getQualifier(pos).getSpringBean()
|
||||
else
|
||||
if exists(getQualifier()) and getNumberOfParameters() = 1
|
||||
then (
|
||||
then
|
||||
// Resolved by `@Qualifier("qualifier")` on the method
|
||||
pos = 0 and
|
||||
result = getQualifier().getSpringBean()
|
||||
) else
|
||||
else
|
||||
if exists(getResource().getNameValue()) and getNumberOfParameters() = 1
|
||||
then (
|
||||
then
|
||||
// Resolved by looking at the name part of `@Resource(name="qualifier")`
|
||||
pos = 0 and
|
||||
result = getResource().getSpringBean()
|
||||
) else
|
||||
else
|
||||
// Otherwise no restrictions, just by type
|
||||
any()
|
||||
}
|
||||
@@ -195,17 +189,17 @@ class SpringBeanAutowiredCallable extends Callable {
|
||||
result = getQualifier(pos).getSpringComponent()
|
||||
else
|
||||
if exists(getQualifier()) and getNumberOfParameters() = 1
|
||||
then (
|
||||
then
|
||||
// Resolved by `@Qualifier("qualifier")` on the method
|
||||
pos = 0 and
|
||||
result = getQualifier().getSpringComponent()
|
||||
) else
|
||||
else
|
||||
if exists(getResource().getNameValue()) and getNumberOfParameters() = 1
|
||||
then (
|
||||
then
|
||||
// Resolved by looking at the name part of `@Resource(name="qualifier")`
|
||||
pos = 0 and
|
||||
result = getResource().getSpringComponent()
|
||||
) else
|
||||
else
|
||||
// Otherwise no restrictions, just by type
|
||||
any()
|
||||
}
|
||||
|
||||
@@ -279,11 +279,9 @@ class SpringBean extends SpringXMLElement {
|
||||
|
||||
/** Any `<property>` elements inherited from parent beans. */
|
||||
SpringProperty getAnInheritedProperty() {
|
||||
(
|
||||
not exists(SpringProperty thisProperty |
|
||||
thisProperty = this.getADeclaredProperty() and
|
||||
result.getPropertyName() = thisProperty.getPropertyName()
|
||||
)
|
||||
not exists(SpringProperty thisProperty |
|
||||
thisProperty = this.getADeclaredProperty() and
|
||||
result.getPropertyName() = thisProperty.getPropertyName()
|
||||
) and
|
||||
(
|
||||
result = this.getBeanParent().getADeclaredProperty() or
|
||||
@@ -305,11 +303,9 @@ class SpringBean extends SpringXMLElement {
|
||||
|
||||
/** Gets a `<constructor-arg>` element inherited from the parent bean. */
|
||||
SpringConstructorArg getAnInheritedConstructorArg() {
|
||||
(
|
||||
not exists(SpringConstructorArg thisArg |
|
||||
thisArg = this.getADeclaredConstructorArg() and
|
||||
thisArg.conflictsWithArg(result)
|
||||
)
|
||||
not exists(SpringConstructorArg thisArg |
|
||||
thisArg = this.getADeclaredConstructorArg() and
|
||||
thisArg.conflictsWithArg(result)
|
||||
) and
|
||||
(
|
||||
result = this.getBeanParent().getADeclaredConstructorArg() or
|
||||
@@ -331,11 +327,9 @@ class SpringBean extends SpringXMLElement {
|
||||
|
||||
/** Gets a `<lookup-method>` element inherited from the parent bean. */
|
||||
SpringLookupMethod getAnInheritedLookupMethod() {
|
||||
(
|
||||
not exists(SpringLookupMethod thisMethod |
|
||||
thisMethod = this.getADeclaredLookupMethod() and
|
||||
thisMethod.getMethodName() = result.getMethodName()
|
||||
)
|
||||
not exists(SpringLookupMethod thisMethod |
|
||||
thisMethod = this.getADeclaredLookupMethod() and
|
||||
thisMethod.getMethodName() = result.getMethodName()
|
||||
) and
|
||||
(
|
||||
result = this.getBeanParent().getADeclaredLookupMethod() or
|
||||
@@ -357,11 +351,9 @@ class SpringBean extends SpringXMLElement {
|
||||
|
||||
/** Gets a `<replaced-method>` element inherited from the parent bean. */
|
||||
SpringReplacedMethod getAnInheritedReplacedMethod() {
|
||||
(
|
||||
not exists(SpringReplacedMethod thisMethod |
|
||||
thisMethod = this.getADeclaredReplacedMethod() and
|
||||
thisMethod.getMethodName() = result.getMethodName()
|
||||
)
|
||||
not exists(SpringReplacedMethod thisMethod |
|
||||
thisMethod = this.getADeclaredReplacedMethod() and
|
||||
thisMethod.getMethodName() = result.getMethodName()
|
||||
) and
|
||||
(
|
||||
result = this.getBeanParent().getADeclaredReplacedMethod() or
|
||||
|
||||
@@ -178,15 +178,13 @@ class SpringComponent extends RefType {
|
||||
// package.
|
||||
not isSpringXMLEnabled()
|
||||
or
|
||||
exists(SpringBasePackage sbp |
|
||||
this.getPackage().getName().prefix(sbp.length() + 1) = sbp + "." or
|
||||
this.getPackage().getName() = sbp
|
||||
) and
|
||||
(
|
||||
exists(SpringBasePackage sbp |
|
||||
this.getPackage().getName().prefix(sbp.length() + 1) = sbp + "." or
|
||||
this.getPackage().getName() = sbp
|
||||
) and
|
||||
(
|
||||
not exists(getAProfileExpr()) or
|
||||
getAProfileExpr().(SpringProfileExpr).isActive()
|
||||
)
|
||||
not exists(getAProfileExpr()) or
|
||||
getAProfileExpr().(SpringProfileExpr).isActive()
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -44,13 +44,11 @@ class SpringRemotingDestinationClass extends Class {
|
||||
this = remotingDestination.getSpringBean().getClass()
|
||||
)
|
||||
or
|
||||
hasAnnotation("org.springframework.flex.remoting", "RemotingDestination") and
|
||||
// Must either be a live bean, or a live component.
|
||||
(
|
||||
hasAnnotation("org.springframework.flex.remoting", "RemotingDestination") and
|
||||
// Must either be a live bean, or a live component.
|
||||
(
|
||||
this.(SpringComponent).isLive() or
|
||||
this instanceof SpringBeanRefType
|
||||
)
|
||||
this.(SpringComponent).isLive() or
|
||||
this instanceof SpringBeanRefType
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -14,12 +14,10 @@ private string getStrutsMapperClass(RefType refType) {
|
||||
*/
|
||||
class Struts2ActionClass extends Class {
|
||||
Struts2ActionClass() {
|
||||
(
|
||||
// If there are no XML files present, then we assume we any class that extends a struts 2
|
||||
// action must be reflectively constructed, as we have no better indication.
|
||||
not exists(XMLFile xmlFile) and
|
||||
this.getAnAncestor().hasQualifiedName("com.opensymphony.xwork2", "Action")
|
||||
)
|
||||
// If there are no XML files present, then we assume we any class that extends a struts 2
|
||||
// action must be reflectively constructed, as we have no better indication.
|
||||
not exists(XMLFile xmlFile) and
|
||||
this.getAnAncestor().hasQualifiedName("com.opensymphony.xwork2", "Action")
|
||||
or
|
||||
// If there is a struts.xml file, then any class that is specified as an action is considered
|
||||
// to be reflectively constructed.
|
||||
@@ -37,7 +35,7 @@ class Struts2ActionClass extends Class {
|
||||
if
|
||||
getStrutsMapperClass(this) = "org.apache.struts2.dispatcher.mapper.Restful2ActionMapper" or
|
||||
getStrutsMapperClass(this) = "org.apache.struts2.dispatcher.mapper.RestfulActionMapper"
|
||||
then (
|
||||
then
|
||||
// The "Restful" action mapper maps rest APIs to specific methods
|
||||
result.hasName("index") or
|
||||
result.hasName("create") or
|
||||
@@ -45,11 +43,11 @@ class Struts2ActionClass extends Class {
|
||||
result.hasName("view") or
|
||||
result.hasName("remove") or
|
||||
result.hasName("update")
|
||||
) else
|
||||
else
|
||||
if
|
||||
getStrutsMapperClass(this) = "org.apache.struts2.rest.RestActionMapper" or
|
||||
getStrutsMapperClass(this) = "rest"
|
||||
then (
|
||||
then
|
||||
// The "Rest" action mapper is provided with the rest plugin, and maps rest APIs to specific
|
||||
// methods based on a "ruby-on-rails" style.
|
||||
result.hasName("index") or
|
||||
@@ -59,7 +57,7 @@ class Struts2ActionClass extends Class {
|
||||
result.hasName("create") or
|
||||
result.hasName("update") or
|
||||
result.hasName("destroy")
|
||||
) else
|
||||
else
|
||||
if exists(getStrutsMapperClass(this))
|
||||
then
|
||||
// Any method could be live, as this is a custom mapper
|
||||
@@ -73,14 +71,12 @@ class Struts2ActionClass extends Class {
|
||||
or
|
||||
result = this.(Struts2ConventionActionClass).getAnActionMethod()
|
||||
or
|
||||
// In the fall-back case, use both the "execute" and any annotated methods
|
||||
not exists(XMLFile xmlFile) and
|
||||
(
|
||||
// In the fall-back case, use both the "execute" and any annotated methods
|
||||
not exists(XMLFile xmlFile) and
|
||||
(
|
||||
result.hasName("executes") or
|
||||
exists(StrutsActionAnnotation actionAnnotation |
|
||||
result = actionAnnotation.getActionCallable()
|
||||
)
|
||||
result.hasName("executes") or
|
||||
exists(StrutsActionAnnotation actionAnnotation |
|
||||
result = actionAnnotation.getActionCallable()
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
@@ -142,7 +142,7 @@ private string escapeForMatch(string s) { result = s.replaceAll("%", "\\%").repl
|
||||
*/
|
||||
bindingset[matches, wildcardstring]
|
||||
private predicate strutsWildcardMatching(string matches, string wildcardstring) {
|
||||
if (wildcardstring.matches("%{%}%"))
|
||||
if wildcardstring.matches("%{%}%")
|
||||
then matches.matches(escapeForMatch(wildcardstring).regexpReplaceAll("\\{[0-9]\\}", "%"))
|
||||
else matches = wildcardstring
|
||||
}
|
||||
@@ -169,7 +169,7 @@ class StrutsXMLAction extends StrutsXMLElement {
|
||||
*/
|
||||
Method getActionMethod() {
|
||||
getActionClass().inherits(result) and
|
||||
if (exists(getMethodName()))
|
||||
if exists(getMethodName())
|
||||
then strutsWildcardMatching(result.getName(), getMethodName())
|
||||
else result.hasName("execute")
|
||||
}
|
||||
|
||||
@@ -41,20 +41,16 @@ class MetricElement extends Element {
|
||||
*/
|
||||
int getALevel() {
|
||||
this.fromSource() and
|
||||
not (this.getADependencySrc+() = this) and
|
||||
not this.getADependencySrc+() = this and
|
||||
(
|
||||
(
|
||||
not (exists(MetricElement t | t = this.getADependency())) and
|
||||
result = 0
|
||||
)
|
||||
not exists(MetricElement t | t = this.getADependency()) and
|
||||
result = 0
|
||||
or
|
||||
(
|
||||
not (this.getADependency().fromSource()) and
|
||||
exists(MetricElement e | this.getADependency() = e) and
|
||||
result = 1
|
||||
)
|
||||
not this.getADependency().fromSource() and
|
||||
exists(MetricElement e | this.getADependency() = e) and
|
||||
result = 1
|
||||
or
|
||||
(result = this.getADependency().getALevel() + 1)
|
||||
result = this.getADependency().getALevel() + 1
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -61,8 +61,8 @@ class MetricPackage extends Package, MetricElement {
|
||||
*/
|
||||
int getNumberOfPublicCallables() {
|
||||
result = sum(MetricRefType t, int toSum |
|
||||
(t.getPackage() = this) and
|
||||
(toSum = t.getNumberOfPublicCallables())
|
||||
t.getPackage() = this and
|
||||
toSum = t.getNumberOfPublicCallables()
|
||||
|
|
||||
toSum
|
||||
)
|
||||
@@ -138,7 +138,7 @@ class MetricPackage extends Package, MetricElement {
|
||||
ecoupling = this.getEfferentCoupling() and
|
||||
sumcoupling = ecoupling + this.getAfferentCoupling() and
|
||||
sumcoupling > 0 and
|
||||
result = ecoupling / (sumcoupling.(float))
|
||||
result = ecoupling / sumcoupling.(float)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -164,7 +164,7 @@ class MetricPackage extends Package, MetricElement {
|
||||
exists(int i, int j |
|
||||
i = count(RefType t | t.getPackage() = this) and
|
||||
j = count(RefType t | t.getPackage() = this and t.isAbstract()) and
|
||||
result = j / (i.(float)) and
|
||||
result = j / i.(float) and
|
||||
i > 0
|
||||
)
|
||||
}
|
||||
@@ -221,8 +221,8 @@ class MetricPackage extends Package, MetricElement {
|
||||
float relationalCohesion() {
|
||||
result = 1 +
|
||||
avg(RefType t, float toAvg |
|
||||
(t.getPackage() = this) and
|
||||
(toAvg = this.countDependencies(t))
|
||||
t.getPackage() = this and
|
||||
toAvg = this.countDependencies(t)
|
||||
|
|
||||
toAvg
|
||||
)
|
||||
@@ -265,8 +265,8 @@ class MetricPackage extends Package, MetricElement {
|
||||
*/
|
||||
predicate isRepresentative() {
|
||||
this.getName() = min(MetricPackage p, string toMin |
|
||||
(p = this.getACycleMember()) and
|
||||
(toMin = p.getName())
|
||||
p = this.getACycleMember() and
|
||||
toMin = p.getName()
|
||||
|
|
||||
toMin
|
||||
)
|
||||
@@ -280,7 +280,7 @@ class MetricPackage extends Package, MetricElement {
|
||||
float getAverageFanIn() {
|
||||
result = avg(RefType t, MetricCallable c, int toAvg |
|
||||
(c = t.getACallable() and t.getPackage() = this) and
|
||||
(toAvg = c.getAfferentCoupling())
|
||||
toAvg = c.getAfferentCoupling()
|
||||
|
|
||||
toAvg
|
||||
)
|
||||
|
||||
@@ -198,18 +198,18 @@ class MetricRefType extends RefType, MetricElement {
|
||||
// is `C`, is `(C - 1) * C`.
|
||||
n = (((callables - 1) * callables) - (2 * linked)) / 2.0 and
|
||||
(
|
||||
(n < 0 and result = 0)
|
||||
n < 0 and result = 0
|
||||
or
|
||||
(n >= 0 and result = n)
|
||||
n >= 0 and result = n
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/** Gets the length of _some_ path to the root of the hierarchy. */
|
||||
int getADepth() {
|
||||
(this.hasQualifiedName("java.lang", "Object") and result = 0)
|
||||
this.hasQualifiedName("java.lang", "Object") and result = 0
|
||||
or
|
||||
(not cyclic() and result = this.getASupertype().(MetricRefType).getADepth() + 1)
|
||||
not cyclic() and result = this.getASupertype().(MetricRefType).getADepth() + 1
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -229,9 +229,9 @@ class MetricRefType extends RefType, MetricElement {
|
||||
|
||||
/** Gets the length of _some_ path to the specified reference type. */
|
||||
int getADepth(RefType reference) {
|
||||
(this = reference and result = 0)
|
||||
this = reference and result = 0
|
||||
or
|
||||
(not cyclic() and result = this.getASupertype().(MetricRefType).getADepth(reference) + 1)
|
||||
not cyclic() and result = this.getASupertype().(MetricRefType).getADepth(reference) + 1
|
||||
}
|
||||
|
||||
private predicate cyclic() { getASupertype+() = this }
|
||||
@@ -278,9 +278,9 @@ class MetricRefType extends RefType, MetricElement {
|
||||
this.getAMethod() = result and
|
||||
exists(Method c |
|
||||
result.overrides(c) and
|
||||
not (c.isAbstract())
|
||||
not c.isAbstract()
|
||||
) and
|
||||
not (this.ignoreOverride(result))
|
||||
not this.ignoreOverride(result)
|
||||
}
|
||||
|
||||
/** Gets the number of methods that are overridden by this class. */
|
||||
@@ -297,14 +297,14 @@ class MetricRefType extends RefType, MetricElement {
|
||||
float getSpecialisationIndex() {
|
||||
this.getNumberOfCallables() != 0 and
|
||||
result = (this.getNumberOverridden() * this.getInheritanceDepth()) /
|
||||
(this.getNumberOfCallables().(float))
|
||||
this.getNumberOfCallables().(float)
|
||||
}
|
||||
|
||||
/** Gets the Halstead length of a type, estimated as the sum of the Halstead lengths of its callables. */
|
||||
override int getHalsteadLength() {
|
||||
result = sum(Callable c, int toSum |
|
||||
(c = this.getACallable()) and
|
||||
(toSum = c.getMetrics().getHalsteadLength())
|
||||
c = this.getACallable() and
|
||||
toSum = c.getMetrics().getHalsteadLength()
|
||||
|
|
||||
toSum
|
||||
)
|
||||
@@ -313,8 +313,8 @@ class MetricRefType extends RefType, MetricElement {
|
||||
/** Gets the Halstead vocabulary of a type, estimated as the sum of the Halstead vocabularies of its callables. */
|
||||
override int getHalsteadVocabulary() {
|
||||
result = sum(Callable c, int toSum |
|
||||
(c = this.getACallable()) and
|
||||
(toSum = c.getMetrics().getHalsteadVocabulary())
|
||||
c = this.getACallable() and
|
||||
toSum = c.getMetrics().getHalsteadVocabulary()
|
||||
|
|
||||
toSum
|
||||
)
|
||||
@@ -323,8 +323,8 @@ class MetricRefType extends RefType, MetricElement {
|
||||
/** Gets the cyclomatic complexity of a type, estimated as the sum of the cyclomatic complexities of its callables. */
|
||||
override int getCyclomaticComplexity() {
|
||||
result = sum(Callable c, int toSum |
|
||||
(c = this.getACallable()) and
|
||||
(toSum = c.getMetrics().getCyclomaticComplexity())
|
||||
c = this.getACallable() and
|
||||
toSum = c.getMetrics().getCyclomaticComplexity()
|
||||
|
|
||||
toSum
|
||||
)
|
||||
|
||||
@@ -73,17 +73,13 @@ deprecated class FlowSource extends Expr {
|
||||
not isExcluded(tracked)
|
||||
|
|
||||
// Flow within a single method.
|
||||
(
|
||||
flowsTo(tracked, fromArg) and
|
||||
localFlowStep(tracked, sink)
|
||||
)
|
||||
flowsTo(tracked, fromArg) and
|
||||
localFlowStep(tracked, sink)
|
||||
or
|
||||
// Flow through a field.
|
||||
(
|
||||
flowsTo(tracked, _) and
|
||||
staticFieldStep(tracked, sink) and
|
||||
fromArg = false
|
||||
)
|
||||
flowsTo(tracked, _) and
|
||||
staticFieldStep(tracked, sink) and
|
||||
fromArg = false
|
||||
or
|
||||
// Flow through a method that returns one of its arguments.
|
||||
exists(MethodAccess call, int i |
|
||||
@@ -104,11 +100,9 @@ deprecated class FlowSource extends Expr {
|
||||
// Flow out of a method.
|
||||
// This path is only enabled if the flow did not come from the argument;
|
||||
// such cases are handled by `methodReturnsArg`.
|
||||
(
|
||||
flowsTo(tracked, false) and
|
||||
methodStep(tracked, sink) and
|
||||
fromArg = false
|
||||
)
|
||||
flowsTo(tracked, false) and
|
||||
methodStep(tracked, sink) and
|
||||
fromArg = false
|
||||
)
|
||||
}
|
||||
|
||||
@@ -170,10 +164,8 @@ deprecated private Callable responderForArg(Call call, int i, FlowExpr tracked)
|
||||
deprecated private Callable responder(Call call) {
|
||||
result = exactCallable(call)
|
||||
or
|
||||
(
|
||||
not exists(exactCallable(call)) and
|
||||
result = call.getCallee()
|
||||
)
|
||||
not exists(exactCallable(call)) and
|
||||
result = call.getCallee()
|
||||
}
|
||||
|
||||
/** Holds if a method can return its argument. This is public for testing. */
|
||||
@@ -240,7 +232,7 @@ deprecated private predicate localFlowStep(Expr tracked, Expr sink) {
|
||||
argToMethodStep(tracked, sink)
|
||||
or
|
||||
// An unsafe attempt to escape tainted input.
|
||||
(unsafeEscape(sink) and sink.(MethodAccess).getQualifier() = tracked)
|
||||
unsafeEscape(sink) and sink.(MethodAccess).getQualifier() = tracked
|
||||
or
|
||||
// A logic expression.
|
||||
sink.(LogicExpr).getAnOperand() = tracked
|
||||
@@ -349,9 +341,9 @@ deprecated private predicate comparisonStep(Expr tracked, Expr sink) {
|
||||
exists(MethodAccess m | m.getMethod() instanceof EqualsMethod |
|
||||
m = sink and
|
||||
(
|
||||
(m.getQualifier() = tracked and m.getArgument(0) = other)
|
||||
m.getQualifier() = tracked and m.getArgument(0) = other
|
||||
or
|
||||
(m.getQualifier() = other and m.getArgument(0) = tracked)
|
||||
m.getQualifier() = other and m.getArgument(0) = tracked
|
||||
)
|
||||
)
|
||||
) and
|
||||
@@ -605,74 +597,54 @@ deprecated predicate qualifierToMethodStep(Expr tracked, MethodAccess sink) {
|
||||
*/
|
||||
deprecated class DataPreservingMethod extends Method {
|
||||
DataPreservingMethod() {
|
||||
this.getDeclaringType() instanceof TypeString and
|
||||
(
|
||||
this.getDeclaringType() instanceof TypeString and
|
||||
(
|
||||
this.getName() = "endsWith" or
|
||||
this.getName() = "getBytes" or
|
||||
this.getName() = "split" or
|
||||
this.getName() = "substring" or
|
||||
this.getName() = "toCharArray" or
|
||||
this.getName() = "toLowerCase" or
|
||||
this.getName() = "toString" or
|
||||
this.getName() = "toUpperCase" or
|
||||
this.getName() = "trim"
|
||||
)
|
||||
this.getName() = "endsWith" or
|
||||
this.getName() = "getBytes" or
|
||||
this.getName() = "split" or
|
||||
this.getName() = "substring" or
|
||||
this.getName() = "toCharArray" or
|
||||
this.getName() = "toLowerCase" or
|
||||
this.getName() = "toString" or
|
||||
this.getName() = "toUpperCase" or
|
||||
this.getName() = "trim"
|
||||
)
|
||||
or
|
||||
exists(Class c | c.getQualifiedName() = "java.lang.Number" |
|
||||
hasSubtypeStar(c, this.getDeclaringType())
|
||||
) and
|
||||
(
|
||||
exists(Class c | c.getQualifiedName() = "java.lang.Number" |
|
||||
hasSubtypeStar(c, this.getDeclaringType())
|
||||
) and
|
||||
(
|
||||
this.getName().matches("to%String") or
|
||||
this.getName() = "toByteArray" or
|
||||
this.getName().matches("%Value")
|
||||
)
|
||||
this.getName().matches("to%String") or
|
||||
this.getName() = "toByteArray" or
|
||||
this.getName().matches("%Value")
|
||||
)
|
||||
or
|
||||
(
|
||||
this.getDeclaringType().getQualifiedName().matches("%Reader") and
|
||||
this.getName().matches("read%")
|
||||
)
|
||||
this.getDeclaringType().getQualifiedName().matches("%Reader") and
|
||||
this.getName().matches("read%")
|
||||
or
|
||||
this.getDeclaringType().getQualifiedName().matches("%StringWriter") and
|
||||
this.getName() = "toString"
|
||||
or
|
||||
this.getDeclaringType().hasQualifiedName("java.util", "StringTokenizer") and
|
||||
this.getName().matches("next%")
|
||||
or
|
||||
this.getDeclaringType().hasQualifiedName("java.io", "ByteArrayOutputStream") and
|
||||
(this.getName() = "toByteArray" or this.getName() = "toString")
|
||||
or
|
||||
this.getDeclaringType().hasQualifiedName("java.io", "ObjectInputStream") and
|
||||
this.getName().matches("read%")
|
||||
or
|
||||
(
|
||||
this.getDeclaringType().getQualifiedName().matches("%StringWriter") and
|
||||
this.getName() = "toString"
|
||||
)
|
||||
this.getDeclaringType().hasQualifiedName("java.lang", "StringBuilder") or
|
||||
this.getDeclaringType().hasQualifiedName("java.lang", "StringBuffer")
|
||||
) and
|
||||
(this.getName() = "toString" or this.getName() = "append")
|
||||
or
|
||||
(
|
||||
this.getDeclaringType().hasQualifiedName("java.util", "StringTokenizer") and
|
||||
this.getName().matches("next%")
|
||||
)
|
||||
this.getDeclaringType().hasQualifiedName("javax.xml.transform.sax", "SAXSource") and
|
||||
this.hasName("getInputSource")
|
||||
or
|
||||
(
|
||||
this.getDeclaringType().hasQualifiedName("java.io", "ByteArrayOutputStream") and
|
||||
(this.getName() = "toByteArray" or this.getName() = "toString")
|
||||
)
|
||||
or
|
||||
(
|
||||
this.getDeclaringType().hasQualifiedName("java.io", "ObjectInputStream") and
|
||||
this.getName().matches("read%")
|
||||
)
|
||||
or
|
||||
(
|
||||
(
|
||||
this.getDeclaringType().hasQualifiedName("java.lang", "StringBuilder") or
|
||||
this.getDeclaringType().hasQualifiedName("java.lang", "StringBuffer")
|
||||
) and
|
||||
(this.getName() = "toString" or this.getName() = "append")
|
||||
)
|
||||
or
|
||||
(
|
||||
this.getDeclaringType().hasQualifiedName("javax.xml.transform.sax", "SAXSource") and
|
||||
this.hasName("getInputSource")
|
||||
)
|
||||
or
|
||||
(
|
||||
this.getDeclaringType().hasQualifiedName("javax.xml.transform.stream", "StreamSource") and
|
||||
this.hasName("getInputStream")
|
||||
)
|
||||
this.getDeclaringType().hasQualifiedName("javax.xml.transform.stream", "StreamSource") and
|
||||
this.hasName("getInputStream")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -681,89 +653,75 @@ deprecated class DataPreservingMethod extends Method {
|
||||
* is tainted.
|
||||
*/
|
||||
deprecated predicate dataPreservingArgument(Method method, int arg) {
|
||||
method instanceof StringReplaceMethod and
|
||||
arg = 1
|
||||
or
|
||||
exists(Class c | c.getQualifiedName() = "java.lang.Number" |
|
||||
hasSubtypeStar(c, method.getDeclaringType())
|
||||
) and
|
||||
(
|
||||
method instanceof StringReplaceMethod and
|
||||
arg = 1
|
||||
method.getName().matches("parse%") and arg = 0
|
||||
or
|
||||
method.getName().matches("valueOf%") and arg = 0
|
||||
or
|
||||
method.getName().matches("to%String") and arg = 0
|
||||
)
|
||||
or
|
||||
(
|
||||
exists(Class c | c.getQualifiedName() = "java.lang.Number" |
|
||||
hasSubtypeStar(c, method.getDeclaringType())
|
||||
) and
|
||||
(
|
||||
(method.getName().matches("parse%") and arg = 0)
|
||||
or
|
||||
(method.getName().matches("valueOf%") and arg = 0)
|
||||
or
|
||||
(method.getName().matches("to%String") and arg = 0)
|
||||
)
|
||||
method.getDeclaringType().hasQualifiedName("java.lang", "StringBuilder") or
|
||||
method.getDeclaringType().hasQualifiedName("java.lang", "StringBuffer")
|
||||
) and
|
||||
(
|
||||
method.getName() = "append" and arg = 0
|
||||
or
|
||||
method.getName() = "insert" and arg = 1
|
||||
or
|
||||
method.getName() = "replace" and arg = 2
|
||||
)
|
||||
or
|
||||
(
|
||||
(
|
||||
method.getDeclaringType().hasQualifiedName("java.lang", "StringBuilder") or
|
||||
method.getDeclaringType().hasQualifiedName("java.lang", "StringBuffer")
|
||||
) and
|
||||
(
|
||||
method.getName() = "append" and arg = 0
|
||||
or
|
||||
method.getName() = "insert" and arg = 1
|
||||
or
|
||||
method.getName() = "replace" and arg = 2
|
||||
)
|
||||
method.getDeclaringType().hasQualifiedName("java.util", "Base64$Encoder") or
|
||||
method.getDeclaringType().hasQualifiedName("java.util", "Base64$Decoder")
|
||||
) and
|
||||
(
|
||||
method.getName() = "encode" and arg = 0 and method.getNumberOfParameters() = 1
|
||||
or
|
||||
method.getName() = "decode" and arg = 0 and method.getNumberOfParameters() = 1
|
||||
or
|
||||
method.getName() = "encodeToString" and arg = 0
|
||||
or
|
||||
method.getName() = "wrap" and arg = 0
|
||||
)
|
||||
or
|
||||
method.getDeclaringType().hasQualifiedName("org.apache.commons.io", "IOUtils") and
|
||||
(
|
||||
(
|
||||
method.getDeclaringType().hasQualifiedName("java.util", "Base64$Encoder") or
|
||||
method.getDeclaringType().hasQualifiedName("java.util", "Base64$Decoder")
|
||||
) and
|
||||
(
|
||||
method.getName() = "encode" and arg = 0 and method.getNumberOfParameters() = 1
|
||||
or
|
||||
method.getName() = "decode" and arg = 0 and method.getNumberOfParameters() = 1
|
||||
or
|
||||
method.getName() = "encodeToString" and arg = 0
|
||||
or
|
||||
method.getName() = "wrap" and arg = 0
|
||||
)
|
||||
method.getName() = "buffer" and arg = 0
|
||||
or
|
||||
method.getName() = "readLines" and arg = 0
|
||||
or
|
||||
method.getName() = "readFully" and arg = 0 and method.getParameterType(1).hasName("int")
|
||||
or
|
||||
method.getName() = "toBufferedInputStream" and arg = 0
|
||||
or
|
||||
method.getName() = "toBufferedReader" and arg = 0
|
||||
or
|
||||
method.getName() = "toByteArray" and arg = 0
|
||||
or
|
||||
method.getName() = "toCharArray" and arg = 0
|
||||
or
|
||||
method.getName() = "toInputStream" and arg = 0
|
||||
or
|
||||
method.getName() = "toString" and arg = 0
|
||||
)
|
||||
or
|
||||
(
|
||||
(method.getDeclaringType().hasQualifiedName("org.apache.commons.io", "IOUtils")) and
|
||||
(
|
||||
method.getName() = "buffer" and arg = 0
|
||||
or
|
||||
method.getName() = "readLines" and arg = 0
|
||||
or
|
||||
method.getName() = "readFully" and arg = 0 and method.getParameterType(1).hasName("int")
|
||||
or
|
||||
method.getName() = "toBufferedInputStream" and arg = 0
|
||||
or
|
||||
method.getName() = "toBufferedReader" and arg = 0
|
||||
or
|
||||
method.getName() = "toByteArray" and arg = 0
|
||||
or
|
||||
method.getName() = "toCharArray" and arg = 0
|
||||
or
|
||||
method.getName() = "toInputStream" and arg = 0
|
||||
or
|
||||
method.getName() = "toString" and arg = 0
|
||||
)
|
||||
)
|
||||
//A URI created from a tainted string is still tainted.
|
||||
method.getDeclaringType().hasQualifiedName("java.net", "URI") and
|
||||
method.hasName("create") and
|
||||
arg = 0
|
||||
or
|
||||
(
|
||||
//A URI created from a tainted string is still tainted.
|
||||
method.getDeclaringType().hasQualifiedName("java.net", "URI") and
|
||||
method.hasName("create") and
|
||||
arg = 0
|
||||
)
|
||||
or
|
||||
(
|
||||
method.getDeclaringType().hasQualifiedName("javax.xml.transform.sax", "SAXSource") and
|
||||
method.hasName("sourceToInputSource") and
|
||||
arg = 0
|
||||
)
|
||||
method.getDeclaringType().hasQualifiedName("javax.xml.transform.sax", "SAXSource") and
|
||||
method.hasName("sourceToInputSource") and
|
||||
arg = 0
|
||||
}
|
||||
|
||||
deprecated class StringReplaceMethod extends Method {
|
||||
|
||||
@@ -44,17 +44,13 @@ private EnumConstant getAContainedEnumConstant(Expr enumSetRef) {
|
||||
exists(MethodAccess addToSet |
|
||||
addToSet.getQualifier() = enumSetAccess.getVariable().getAnAccess()
|
||||
|
|
||||
(
|
||||
// Call to `add(..)` on the enum set variable.
|
||||
addToSet.getMethod().hasName("add") and
|
||||
result = addToSet.getArgument(0).(VarAccess).getVariable()
|
||||
)
|
||||
// Call to `add(..)` on the enum set variable.
|
||||
addToSet.getMethod().hasName("add") and
|
||||
result = addToSet.getArgument(0).(VarAccess).getVariable()
|
||||
or
|
||||
(
|
||||
// Call to `addAll(..)` on the enum set variable.
|
||||
addToSet.getMethod().hasName("addAll") and
|
||||
result = getAContainedEnumConstant(addToSet.getArgument(0))
|
||||
)
|
||||
// Call to `addAll(..)` on the enum set variable.
|
||||
addToSet.getMethod().hasName("addAll") and
|
||||
result = getAContainedEnumConstant(addToSet.getArgument(0))
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
@@ -148,11 +148,9 @@ abstract class ReturnsPredictableExpr extends Method { }
|
||||
|
||||
class ReturnsSystemTime extends ReturnsPredictableExpr {
|
||||
ReturnsSystemTime() {
|
||||
(
|
||||
this.getDeclaringType().hasQualifiedName("java.lang", "System") and
|
||||
this.hasName("currentTimeMillis")
|
||||
)
|
||||
this.getDeclaringType().hasQualifiedName("java.lang", "System") and
|
||||
this.hasName("currentTimeMillis")
|
||||
or
|
||||
(this.getDeclaringType().hasQualifiedName("java.lang", "System") and this.hasName("nanoTime"))
|
||||
this.getDeclaringType().hasQualifiedName("java.lang", "System") and this.hasName("nanoTime")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -59,7 +59,7 @@ class Pom extends ProtoPom {
|
||||
|
||||
override Group getGroup() {
|
||||
// For a project element, the group may be defined in the parent tags instead
|
||||
if not (exists(super.getGroup()))
|
||||
if not exists(super.getGroup())
|
||||
then exists(Parent p | p = this.getAChild() and result = p.getAChild())
|
||||
else result = super.getGroup()
|
||||
}
|
||||
@@ -94,10 +94,8 @@ class Pom extends ProtoPom {
|
||||
PomProperty getAProperty() {
|
||||
result = getALocalProperty()
|
||||
or
|
||||
(
|
||||
result = getParentPom().getAProperty() and
|
||||
not getALocalProperty().getName() = result.getName()
|
||||
)
|
||||
result = getParentPom().getAProperty() and
|
||||
not getALocalProperty().getName() = result.getName()
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -116,11 +114,9 @@ class Pom extends ProtoPom {
|
||||
// It must either be a child of the pom, or a child of the parent node of the pom
|
||||
result = getAChild()
|
||||
or
|
||||
(
|
||||
result = getParentPom().getAChild() and
|
||||
// The parent project property is not shadowed by a local project property
|
||||
not exists(PomElement p | p = getAChild() and p.getName() = result.getName())
|
||||
)
|
||||
result = getParentPom().getAChild() and
|
||||
// The parent project property is not shadowed by a local project property
|
||||
not exists(PomElement p | p = getAChild() and p.getName() = result.getName())
|
||||
) and
|
||||
// Can't be a property if it has children of its own
|
||||
not exists(result.getAChild())
|
||||
|
||||
@@ -142,15 +142,11 @@ class XMLDTD extends @xmldtd {
|
||||
|
||||
/** Gets a printable representation of this DTD. */
|
||||
string toString() {
|
||||
(
|
||||
this.isPublic() and
|
||||
result = this.getRoot() + " PUBLIC '" + this.getPublicId() + "' '" + this.getSystemId() + "'"
|
||||
)
|
||||
this.isPublic() and
|
||||
result = this.getRoot() + " PUBLIC '" + this.getPublicId() + "' '" + this.getSystemId() + "'"
|
||||
or
|
||||
(
|
||||
not this.isPublic() and
|
||||
result = this.getRoot() + " SYSTEM '" + this.getSystemId() + "'"
|
||||
)
|
||||
not this.isPublic() and
|
||||
result = this.getRoot() + " SYSTEM '" + this.getSystemId() + "'"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -233,9 +229,9 @@ class XMLNamespace extends @xmlnamespace {
|
||||
|
||||
/** Gets a printable representation of this XML namespace. */
|
||||
string toString() {
|
||||
(this.isDefault() and result = this.getURI())
|
||||
this.isDefault() and result = this.getURI()
|
||||
or
|
||||
(not this.isDefault() and result = this.getPrefix() + ":" + this.getURI())
|
||||
not this.isDefault() and result = this.getPrefix() + ":" + this.getURI()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user