diff --git a/java/ql/src/semmle/code/java/Annotation.qll b/java/ql/src/semmle/code/java/Annotation.qll index 377e57bcc92..329ac702b76 100755 --- a/java/ql/src/semmle/code/java/Annotation.qll +++ b/java/ql/src/semmle/code/java/Annotation.qll @@ -38,14 +38,10 @@ class Annotation extends @annotation, Expr { Expr getAValue() { filteredAnnotValue(this, _, result) } /** Gets the value of the annotation element with the specified `name`. */ - Expr getValue(string name) { - filteredAnnotValue(this, this.getAnnotationElement(name), result) - } + Expr getValue(string name) { filteredAnnotValue(this, this.getAnnotationElement(name), result) } /** Gets the element being annotated. */ - Element getTarget() { - exprs(this, _, _, result, _) - } + Element getTarget() { exprs(this, _, _, result, _) } override string toString() { result = this.getType().getName() } @@ -63,35 +59,28 @@ class Annotation extends @annotation, Expr { Expr getAValue(string name) { getType().getAnnotationElement(name).getType() instanceof Array and exists(Expr value | value = getValue(name) | - if value instanceof ArrayInit then - result = value.(ArrayInit).getAnInit() - else - result = value + if value instanceof ArrayInit then result = value.(ArrayInit).getAnInit() else result = value ) } } /** An `Annotation` that applies to a declaration. */ -class DeclAnnotation extends @declannotation, Annotation { -} +class DeclAnnotation extends @declannotation, Annotation { } /** An `Annotation` that applies to a type. */ -class TypeAnnotation extends @typeannotation, Annotation { -} +class TypeAnnotation extends @typeannotation, Annotation { } /** * There may be duplicate entries in annotValue(...) - one entry for * information populated from bytecode, and one for information populated * from source. This removes the duplication. */ -private -predicate filteredAnnotValue(Annotation a, Method m, Expr val) { +private predicate filteredAnnotValue(Annotation a, Method m, Expr val) { annotValue(a, m, val) and (sourceAnnotValue(a, m, val) or not sourceAnnotValue(a, m, _)) } -private -predicate sourceAnnotValue(Annotation a, Method m, Expr val) { +private predicate sourceAnnotValue(Annotation a, Method m, Expr val) { annotValue(a, m, val) and val.getFile().getExtension() = "java" } @@ -103,7 +92,9 @@ class Annotatable extends Element { /** Holds if this element has the specified annotation. */ predicate hasAnnotation(string package, string name) { - exists(AnnotationType at | at = getAnAnnotation().getType() | at.nestedName() = name and at.getPackage().getName() = package) + exists(AnnotationType at | at = getAnAnnotation().getType() | + at.nestedName() = name and at.getPackage().getName() = package + ) } /** Gets an annotation that applies to this element. */ @@ -114,14 +105,20 @@ class Annotatable extends Element { * annotation attached to it for the specified `category`. */ predicate suppressesWarningsAbout(string category) { - exists(string withQuotes - | withQuotes = ((SuppressWarningsAnnotation) getAnAnnotation()).getASuppressedWarning() - | category = withQuotes.substring(1, withQuotes.length() - 1) - ) or - this.(Member).getDeclaringType().suppressesWarningsAbout(category) or - this.(Expr).getEnclosingCallable().suppressesWarningsAbout(category) or - this.(Stmt).getEnclosingCallable().suppressesWarningsAbout(category) or - this.(NestedClass).getEnclosingType().suppressesWarningsAbout(category) or + exists(string withQuotes | + withQuotes = (getAnAnnotation().(SuppressWarningsAnnotation)).getASuppressedWarning() + | + category = withQuotes.substring(1, withQuotes.length() - 1) + ) + or + this.(Member).getDeclaringType().suppressesWarningsAbout(category) + or + this.(Expr).getEnclosingCallable().suppressesWarningsAbout(category) + or + this.(Stmt).getEnclosingCallable().suppressesWarningsAbout(category) + or + this.(NestedClass).getEnclosingType().suppressesWarningsAbout(category) + or this.(LocalVariableDecl).getCallable().suppressesWarningsAbout(category) } } @@ -132,13 +129,11 @@ class AnnotationType extends Interface { /** Gets the annotation element with the specified `name`. */ AnnotationElement getAnnotationElement(string name) { - methods(result,_,_,_,this,_) and result.hasName(name) + methods(result, _, _, _, this, _) and result.hasName(name) } /** Gets an annotation element that is a member of this annotation type. */ - AnnotationElement getAnAnnotationElement() { - methods(result,_,_,_,this,_) - } + AnnotationElement getAnAnnotationElement() { methods(result, _, _, _, this, _) } /** Holds if this annotation type is annotated with the meta-annotation `@Inherited`. */ predicate isInherited() { @@ -154,5 +149,5 @@ class AnnotationElement extends Member { AnnotationElement() { isAnnotElem(this) } /** Gets the type of this annotation element. */ - Type getType() { methods(this,_,_,result,_,_) } + Type getType() { methods(this, _, _, result, _, _) } } diff --git a/java/ql/src/semmle/code/java/Collections.qll b/java/ql/src/semmle/code/java/Collections.qll index 7e64456bc4d..a270eda65b8 100644 --- a/java/ql/src/semmle/code/java/Collections.qll +++ b/java/ql/src/semmle/code/java/Collections.qll @@ -9,9 +9,11 @@ import java * `List`, instantiating the type parameter to `Object`. */ predicate instantiates(RefType t, GenericType g, int i, RefType arg) { - t = g.getAParameterizedType() and exists(g.getTypeParameter(i)) and + t = g.getAParameterizedType() and + exists(g.getTypeParameter(i)) and ( - arg = t.(ParameterizedType).getTypeArgument(i) or + arg = t.(ParameterizedType).getTypeArgument(i) + or t instanceof RawType and arg instanceof TypeObject ) } @@ -40,7 +42,7 @@ predicate indirectlyInstantiates(RefType t, GenericType g, int i, RefType arg) { (extendsReftype(tsrc, sup) or implInterface(tsrc, sup)) and // check whether the subtype instantiates `g` indirectlyInstantiates(sup, g, i, suparg) - | + | // if `t` is itself an instantiation of `tsrc` and `sup` instantiates // `g` to one of the type parameters of `tsrc`, we return the corresponding // instantiation in `t` @@ -63,7 +65,7 @@ class CollectionType extends RefType { CollectionType() { exists(ParameterizedInterface coll | coll.getSourceDeclaration().hasQualifiedName("java.util", "Collection") - | + | this.hasSupertype*(coll) ) } @@ -78,9 +80,7 @@ class CollectionType extends RefType { /** A method declared in a collection type. */ class CollectionMethod extends Method { - CollectionMethod() { - this.getDeclaringType() instanceof CollectionType - } + CollectionMethod() { this.getDeclaringType() instanceof CollectionType } /** Gets the type of elements of the collection to which this method belongs. */ RefType getReceiverElementType() { @@ -90,34 +90,24 @@ class CollectionMethod extends Method { /** The `size` method on `java.util.Collection`. */ class CollectionSizeMethod extends CollectionMethod { - CollectionSizeMethod() { - this.hasName("size") and this.hasNoParameters() - } + CollectionSizeMethod() { this.hasName("size") and this.hasNoParameters() } } /** A method that mutates the collection it belongs to. */ class CollectionMutator extends CollectionMethod { - CollectionMutator() { - this.getName().regexpMatch("add.*|remove.*|push|pop|clear") - } + CollectionMutator() { this.getName().regexpMatch("add.*|remove.*|push|pop|clear") } } /** A method call that mutates a collection. */ class CollectionMutation extends MethodAccess { - CollectionMutation() { - this.getMethod() instanceof CollectionMutator - } + CollectionMutation() { this.getMethod() instanceof CollectionMutator } - predicate resultIsChecked() { - not this.getParent() instanceof ExprStmt - } + predicate resultIsChecked() { not this.getParent() instanceof ExprStmt } } /** A method that queries the contents of a collection without mutating it. */ class CollectionQueryMethod extends CollectionMethod { - CollectionQueryMethod() { - this.getName().regexpMatch("contains|containsAll|get|size|peek") - } + CollectionQueryMethod() { this.getName().regexpMatch("contains|containsAll|get|size|peek") } } /** A `new` expression that allocates a fresh, empty collection. */ diff --git a/java/ql/src/semmle/code/java/CompilationUnit.qll b/java/ql/src/semmle/code/java/CompilationUnit.qll index c2661a498db..a9e3ee8ac7f 100755 --- a/java/ql/src/semmle/code/java/CompilationUnit.qll +++ b/java/ql/src/semmle/code/java/CompilationUnit.qll @@ -10,29 +10,21 @@ import semmle.code.FileSystem * A compilation unit is a `.java` or `.class` file. */ class CompilationUnit extends Element, File { - CompilationUnit() { - cupackage(this,_) - } + CompilationUnit() { cupackage(this, _) } /** Gets the name of the compilation unit (not including its extension). */ - override string getName() { - result = Element.super.getName() - } + override string getName() { result = Element.super.getName() } /** * Holds if this compilation unit has the specified `name`, * which must not include the file extension. */ - override predicate hasName(string name) { - Element.super.hasName(name) - } + override predicate hasName(string name) { Element.super.hasName(name) } - override string toString() { - result = Element.super.toString() - } + override string toString() { result = Element.super.toString() } /** Gets the declared package of this compilation unit. */ - Package getPackage() { cupackage(this,result) } + Package getPackage() { cupackage(this, result) } /** * Gets the module associated with this compilation unit, if any. diff --git a/java/ql/src/semmle/code/java/Completion.qll b/java/ql/src/semmle/code/java/Completion.qll index bd32ca4af5b..b94a2305652 100644 --- a/java/ql/src/semmle/code/java/Completion.qll +++ b/java/ql/src/semmle/code/java/Completion.qll @@ -24,12 +24,12 @@ import java */ newtype Label = MkLabel(string l) { exists(LabeledStmt lbl | l = lbl.getLabel()) } - /** * Either a `Label` or nothing. */ -newtype MaybeLabel = JustLabel(Label l) or NoLabel() - +newtype MaybeLabel = + JustLabel(Label l) or + NoLabel() /** * A completion of a statement or an expression. @@ -48,7 +48,8 @@ newtype Completion = * flow node having value `innerValue`. */ BooleanCompletion(boolean outerValue, boolean innerValue) { - (outerValue = true or outerValue = false) and (innerValue = true or innerValue = false) + (outerValue = true or outerValue = false) and + (innerValue = true or innerValue = false) } or /** * The expression or statement completes via a `break` statement. @@ -63,25 +64,13 @@ newtype Completion = */ ThrowCompletion(ThrowableType tt) +ContinueCompletion anonymousContinueCompletion() { result = ContinueCompletion(NoLabel()) } -ContinueCompletion anonymousContinueCompletion() { - result = ContinueCompletion(NoLabel()) -} +ContinueCompletion labelledContinueCompletion(Label l) { result = ContinueCompletion(JustLabel(l)) } -ContinueCompletion labelledContinueCompletion(Label l) { - result = ContinueCompletion(JustLabel(l)) -} +BreakCompletion anonymousBreakCompletion() { result = BreakCompletion(NoLabel()) } -BreakCompletion anonymousBreakCompletion() { - result = BreakCompletion(NoLabel()) -} - -BreakCompletion labelledBreakCompletion(Label l) { - result = BreakCompletion(JustLabel(l)) -} +BreakCompletion labelledBreakCompletion(Label l) { result = BreakCompletion(JustLabel(l)) } /** Gets the completion `booleanCompletion(value, value)`. */ -Completion basicBooleanCompletion(boolean value) { - result = BooleanCompletion(value, value) -} - +Completion basicBooleanCompletion(boolean value) { result = BooleanCompletion(value, value) } diff --git a/java/ql/src/semmle/code/java/Concurrency.qll b/java/ql/src/semmle/code/java/Concurrency.qll index d6f4660a39f..74d4eaa8ce1 100644 --- a/java/ql/src/semmle/code/java/Concurrency.qll +++ b/java/ql/src/semmle/code/java/Concurrency.qll @@ -1,4 +1,3 @@ - import java /** diff --git a/java/ql/src/semmle/code/java/ControlFlowGraph.qll b/java/ql/src/semmle/code/java/ControlFlowGraph.qll index 94a4f633e5a..8a7c2c85123 100644 --- a/java/ql/src/semmle/code/java/ControlFlowGraph.qll +++ b/java/ql/src/semmle/code/java/ControlFlowGraph.qll @@ -80,7 +80,6 @@ */ import java - private import Completion /** A node in the expression-level control-flow graph. */ @@ -99,19 +98,13 @@ class ControlFlowNode extends Top, @exprparent { } /** Gets an immediate successor of this node. */ - ControlFlowNode getASuccessor() { - result = succ(this) - } + ControlFlowNode getASuccessor() { result = succ(this) } /** Gets an immediate predecessor of this node. */ - ControlFlowNode getAPredecessor() { - this = succ(result) - } + ControlFlowNode getAPredecessor() { this = succ(result) } /** Gets an exception successor of this node. */ - ControlFlowNode getAnExceptionSuccessor() { - result = succ(this, ThrowCompletion(_)) - } + ControlFlowNode getAnExceptionSuccessor() { result = succ(this, ThrowCompletion(_)) } /** Gets a successor of this node that is neither an exception successor nor a jump (break, continue, return). */ ControlFlowNode getANormalSuccessor() { @@ -119,18 +112,14 @@ class ControlFlowNode extends Top, @exprparent { result = succ(this, NormalCompletion()) } - BasicBlock getBasicBlock() { - result.getANode() = this - } + BasicBlock getBasicBlock() { result.getANode() = this } } /** Gets the intra-procedural successor of `n`. */ -private ControlFlowNode succ(ControlFlowNode n) { - result = succ(n, _) -} - -private cached module ControlFlowGraphImpl { +private ControlFlowNode succ(ControlFlowNode n) { result = succ(n, _) } +cached +private module ControlFlowGraphImpl { /** * Gets a label that applies to this statement. */ @@ -153,14 +142,18 @@ private cached module ControlFlowGraphImpl { this instanceof UncheckedThrowableType } - /** An unchecked throwable that is a subtype of this `UncheckedThrowableSuperType` and + /** + * An unchecked throwable that is a subtype of this `UncheckedThrowableSuperType` and * sits as high as possible in the type hierarchy. This is mostly unique except for * `TypeThrowable` which results in both `TypeError` and `TypeRuntimeException`. */ UncheckedThrowableType getAnUncheckedSubtype() { - result = (UncheckedThrowableType)this or - result instanceof TypeError and this instanceof TypeThrowable or - result instanceof TypeRuntimeException and (this instanceof TypeThrowable or this instanceof TypeException) + result = this.(UncheckedThrowableType) + or + result instanceof TypeError and this instanceof TypeThrowable + or + result instanceof TypeRuntimeException and + (this instanceof TypeThrowable or this instanceof TypeException) } } @@ -171,12 +164,14 @@ private cached module ControlFlowGraphImpl { * `ClassCastException` is expected. */ private predicate mayThrow(ControlFlowNode n, ThrowableType t) { - t = n.(ThrowStmt).getThrownExceptionType() or + t = n.(ThrowStmt).getThrownExceptionType() + or exists(Call c | c = n | t = c.getCallee().getAThrownExceptionType() or uncheckedExceptionFromCatch(n, t) or uncheckedExceptionFromFinally(n, t) - ) or + ) + or exists(CastExpr c | c = n | t instanceof TypeClassCastException and uncheckedExceptionFromCatch(n, t) @@ -191,7 +186,7 @@ private cached module ControlFlowGraphImpl { exists(TryStmt try | n.getEnclosingStmt().getParent+() = try.getBlock() or n.(Expr).getParent*() = try.getAResource() - | + | exists(try.getFinally()) and (t instanceof TypeError or t instanceof TypeRuntimeException) ) @@ -205,7 +200,7 @@ private cached module ControlFlowGraphImpl { exists(TryStmt try, UncheckedThrowableSuperType caught | n.getEnclosingStmt().getParent+() = try.getBlock() or n.(Expr).getParent*() = try.getAResource() - | + | t = caught.getAnUncheckedSubtype() and try.getACatchClause().getACaughtType() = caught ) @@ -253,7 +248,8 @@ private cached module ControlFlowGraphImpl { * `c` belongs, such that `c` possibly catches that exception. */ private predicate mayCatch(CatchClause c, ThrowableType thrown) { - mustCatch(c, thrown) or + mustCatch(c, thrown) + or mayNotCatch(c, thrown) and exists(c.getACaughtType().commonSubtype(thrown)) } @@ -275,24 +271,24 @@ private cached module ControlFlowGraphImpl { */ private predicate inBooleanContext(Expr b) { exists(LogicExpr logexpr | - logexpr.(BinaryExpr).getLeftOperand() = b or + logexpr.(BinaryExpr).getLeftOperand() = b + or // Cannot use LogicExpr.getAnOperand or BinaryExpr.getAnOperand as they remove parentheses. - logexpr.(BinaryExpr).getRightOperand() = b and inBooleanContext(logexpr) or + logexpr.(BinaryExpr).getRightOperand() = b and inBooleanContext(logexpr) + or logexpr.(UnaryExpr).getExpr() = b and inBooleanContext(logexpr) ) or - exists(ParExpr parexpr | - parexpr.getExpr() = b and inBooleanContext(parexpr) - ) + exists(ParExpr parexpr | parexpr.getExpr() = b and inBooleanContext(parexpr)) or exists(ConditionalExpr condexpr | - condexpr.getCondition() = b or - (condexpr.getTrueExpr() = b or condexpr.getFalseExpr() = b) and inBooleanContext(condexpr) + condexpr.getCondition() = b + or + (condexpr.getTrueExpr() = b or condexpr.getFalseExpr() = b) and + inBooleanContext(condexpr) ) or - exists(ConditionalStmt condstmt | - condstmt.getCondition() = b - ) + exists(ConditionalStmt condstmt | condstmt.getCondition() = b) } /** @@ -323,9 +319,7 @@ private cached module ControlFlowGraphImpl { } /** Gets a `MethodAccess` that calls this method. */ - MethodAccess getAnAccess() { - result.getMethod().getAPossibleImplementation() = this - } + MethodAccess getAnAccess() { result.getMethod().getAPossibleImplementation() = this } } /** Holds if a call to `m` indicates that `m` is expected to return. */ @@ -341,12 +335,13 @@ private cached module ControlFlowGraphImpl { * Gets a non-overridable method that always throws an exception or calls `exit`. */ private Method nonReturningMethod() { - result instanceof MethodExit or + result instanceof MethodExit + or not result.isOverridable() and exists(Block body | body = result.getBody() and not exists(ReturnStmt ret | ret.getEnclosingCallable() = result) - | + | not result.getReturnType() instanceof VoidType or body.getLastStmt() = nonReturningStmt() ) @@ -375,13 +370,17 @@ private cached module ControlFlowGraphImpl { * Gets a statement that always throws an exception or calls `exit`. */ private Stmt nonReturningStmt() { - result instanceof ThrowStmt or - result.(ExprStmt).getExpr() = nonReturningMethodAccess() or - result.(Block).getLastStmt() = nonReturningStmt() or + result instanceof ThrowStmt + or + result.(ExprStmt).getExpr() = nonReturningMethodAccess() + or + result.(Block).getLastStmt() = nonReturningStmt() + or exists(IfStmt ifstmt | ifstmt = result | ifstmt.getThen() = nonReturningStmt() and ifstmt.getElse() = nonReturningStmt() - ) or + ) + or exists(TryStmt try | try = result | try.getBlock() = nonReturningStmt() and forall(CatchClause cc | cc = try.getACatchClause() | cc.getBlock() = nonReturningStmt()) @@ -398,87 +397,129 @@ private cached module ControlFlowGraphImpl { * and `ThrowStmt`. CFG nodes without child nodes in the CFG that may complete * normally are also included. */ - private - class PostOrderNode extends ControlFlowNode { + private class PostOrderNode extends ControlFlowNode { PostOrderNode() { // For VarAccess and ArrayAccess only read accesses (r-values) are included, // as write accesses aren't included in the CFG. - this instanceof ArrayAccess and not exists(AssignExpr a | this = a.getDest()) or - this instanceof ArrayCreationExpr or - this instanceof ArrayInit or - this instanceof Assignment or - this instanceof BinaryExpr and not this instanceof LogicExpr or - this instanceof UnaryExpr and not this instanceof LogNotExpr or - this instanceof CastExpr or - this instanceof InstanceOfExpr or - this instanceof LocalVariableDeclExpr or - this instanceof RValue or - this instanceof Call or // includes both expressions and statements - this instanceof ReturnStmt or - this instanceof ThrowStmt or - this instanceof Literal or - this instanceof TypeLiteral or - this instanceof ThisAccess or - this instanceof SuperAccess or - this.(Block).getNumStmt() = 0 or - this instanceof SwitchCase or - this instanceof EmptyStmt or - this instanceof LocalClassDeclStmt or + this instanceof ArrayAccess and not exists(AssignExpr a | this = a.getDest()) + or + this instanceof ArrayCreationExpr + or + this instanceof ArrayInit + or + this instanceof Assignment + or + this instanceof BinaryExpr and not this instanceof LogicExpr + or + this instanceof UnaryExpr and not this instanceof LogNotExpr + or + this instanceof CastExpr + or + this instanceof InstanceOfExpr + or + this instanceof LocalVariableDeclExpr + or + this instanceof RValue + or + this instanceof Call // includes both expressions and statements + or + this instanceof ReturnStmt + or + this instanceof ThrowStmt + or + this instanceof Literal + or + this instanceof TypeLiteral + or + this instanceof ThisAccess + or + this instanceof SuperAccess + or + this.(Block).getNumStmt() = 0 + or + this instanceof SwitchCase + or + this instanceof EmptyStmt + or + this instanceof LocalClassDeclStmt + or this instanceof AssertStmt } /** Gets child nodes in their order of execution. Indexing starts at either -1 or 0. */ ControlFlowNode getChildNode(int index) { exists(ArrayAccess e | e = this | - index = 0 and result = e.getArray() or + index = 0 and result = e.getArray() + or index = 1 and result = e.getIndexExpr() - ) or + ) + or exists(ArrayCreationExpr e | e = this | - result = e.getDimension(index) or + result = e.getDimension(index) + or index = count(e.getADimension()) and result = e.getInit() - ) or - result = this.(ArrayInit).getInit(index) and index >= 0 or + ) + or + result = this.(ArrayInit).getInit(index) and index >= 0 + or exists(AssignExpr e, ArrayAccess lhs | e = this and lhs = e.getDest() | - index = 0 and result = lhs.getArray() or - index = 1 and result = lhs.getIndexExpr() or + index = 0 and result = lhs.getArray() + or + index = 1 and result = lhs.getIndexExpr() + or index = 2 and result = e.getSource() - ) or + ) + or exists(AssignExpr e, VarAccess lhs | e = this and lhs = e.getDest() | - index = -1 and result = lhs.getQualifier() and not result instanceof TypeAccess or + index = -1 and result = lhs.getQualifier() and not result instanceof TypeAccess + or index = 0 and result = e.getSource() - ) or + ) + or exists(AssignOp e | e = this | - index = 0 and result = e.getDest() or + index = 0 and result = e.getDest() + or index = 1 and result = e.getRhs() - ) or + ) + or exists(BinaryExpr e | e = this | - index = 0 and result = e.getLeftOperand() or + index = 0 and result = e.getLeftOperand() + or index = 1 and result = e.getRightOperand() - ) or - index = 0 and result = this.(UnaryExpr).getExpr() or - index = 0 and result = this.(CastExpr).getExpr() or - index = 0 and result = this.(InstanceOfExpr).getExpr() or - index = 0 and result = this.(LocalVariableDeclExpr).getInit() or - index = 0 and result = this.(RValue).getQualifier() and not result instanceof TypeAccess or + ) + or + index = 0 and result = this.(UnaryExpr).getExpr() + or + index = 0 and result = this.(CastExpr).getExpr() + or + index = 0 and result = this.(InstanceOfExpr).getExpr() + or + index = 0 and result = this.(LocalVariableDeclExpr).getInit() + or + index = 0 and result = this.(RValue).getQualifier() and not result instanceof TypeAccess + or exists(Call e | e = this | - index = -1 and result = e.getQualifier() and not result instanceof TypeAccess or + index = -1 and result = e.getQualifier() and not result instanceof TypeAccess + or result = e.getArgument(index) - ) or - index = 0 and result = this.(ReturnStmt).getResult() or - index = 0 and result = this.(ThrowStmt).getExpr() or + ) + or + index = 0 and result = this.(ReturnStmt).getResult() + or + index = 0 and result = this.(ThrowStmt).getExpr() + or index = 0 and result = this.(AssertStmt).getExpr() } /** Gets the first child node, if any. */ ControlFlowNode firstChild() { - result = getChildNode(-1) or + result = getChildNode(-1) + or result = getChildNode(0) and not exists(getChildNode(-1)) } /** Holds if this CFG node has any child nodes. */ - predicate isLeafNode() { - not exists(getChildNode(_)) - } + predicate isLeafNode() { not exists(getChildNode(_)) } /** Holds if this node can finish with a `normalCompletion`. */ predicate mayCompleteNormally() { @@ -494,7 +535,8 @@ private cached module ControlFlowGraphImpl { * continue executing (provided the loop condition still holds). */ private predicate continues(Completion completion, LoopStmt loop) { - completion = NormalCompletion() or + completion = NormalCompletion() + or // only consider continue completions if there actually is a `continue` // somewhere inside this loop; we don't particularly care whether that // `continue` could actually target this loop, we just want to restrict @@ -509,15 +551,22 @@ private cached module ControlFlowGraphImpl { * Determine the part of the AST node `n` that will be executed first. */ private ControlFlowNode first(ControlFlowNode n) { - result = n and n instanceof LogicExpr or - result = n and n instanceof ConditionalExpr or - result = n and n.(PostOrderNode).isLeafNode() or - result = first(n.(PostOrderNode).firstChild()) or - result = first(n.(ParExpr).getExpr()) or - result = first(n.(SynchronizedStmt).getExpr()) or - result = n and n instanceof Stmt and - not n instanceof PostOrderNode and - not n instanceof SynchronizedStmt + result = n and n instanceof LogicExpr + or + result = n and n instanceof ConditionalExpr + or + result = n and n.(PostOrderNode).isLeafNode() + or + result = first(n.(PostOrderNode).firstChild()) + or + result = first(n.(ParExpr).getExpr()) + or + result = first(n.(SynchronizedStmt).getExpr()) + or + result = n and + n instanceof Stmt and + not n instanceof PostOrderNode and + not n instanceof SynchronizedStmt } /** @@ -528,8 +577,11 @@ private cached module ControlFlowGraphImpl { * node in the `try` block that may not complete normally, or a node in * the `try` block that has no control flow successors inside the block. */ - private predicate catchOrFinallyCompletion(TryStmt try, ControlFlowNode last, Completion completion) { - last(try.getBlock(), last, completion) or + private predicate catchOrFinallyCompletion( + TryStmt try, ControlFlowNode last, Completion completion + ) { + last(try.getBlock(), last, completion) + or last(try.getAResource(), last, completion) and completion = ThrowCompletion(_) } @@ -544,12 +596,22 @@ private cached module ControlFlowGraphImpl { catchOrFinallyCompletion(try, last, completion) and ( exists(ThrowableType thrown | - thrown = thrownInBody(try) and completion = ThrowCompletion(thrown) and + thrown = thrownInBody(try) and + completion = ThrowCompletion(thrown) and not mustCatch(try.getACatchClause(), thrown) - ) or - completion = NormalCompletion() or completion = ReturnCompletion() or - completion = anonymousBreakCompletion() or completion = labelledBreakCompletion(_) or - completion = anonymousContinueCompletion() or completion = labelledContinueCompletion(_) + ) + or + completion = NormalCompletion() + or + completion = ReturnCompletion() + or + completion = anonymousBreakCompletion() + or + completion = labelledBreakCompletion(_) + or + completion = anonymousContinueCompletion() + or + completion = labelledContinueCompletion(_) ) } @@ -579,92 +641,116 @@ private cached module ControlFlowGraphImpl { */ private predicate last(ControlFlowNode n, ControlFlowNode last, Completion completion) { // Exceptions are propagated from any sub-expression. - exists(Expr e | e.getParent() = n | last(e, last, completion) and completion = ThrowCompletion(_)) or - + exists(Expr e | e.getParent() = n | + last(e, last, completion) and completion = ThrowCompletion(_) + ) + or // If an expression doesn't finish with a throw completion, then it executes normally with // either a `normalCompletion` or a `booleanCompletion`. - // A boolean completion in a non-boolean context just indicates a normal completion // and a normal completion in a boolean context indicates an arbitrary boolean completion. - last(n, last, NormalCompletion()) and inBooleanContext(n) and completion = basicBooleanCompletion(_) or - last(n, last, BooleanCompletion(_, _)) and not inBooleanContext(n) and completion = NormalCompletion() or - + last(n, last, NormalCompletion()) and + inBooleanContext(n) and + completion = basicBooleanCompletion(_) + or + last(n, last, BooleanCompletion(_, _)) and + not inBooleanContext(n) and + completion = NormalCompletion() + or // Logic expressions and conditional expressions are executed in AST pre-order to facilitate // proper short-circuit representation. All other expressions are executed in post-order. - // The last node of a logic expression is either in the right operand with an arbitrary // completion, or in the left operand with the corresponding boolean completion. exists(AndLogicalExpr andexpr | andexpr = n | - last(andexpr.getLeftOperand(), last, completion) and completion = BooleanCompletion(false, _) or + last(andexpr.getLeftOperand(), last, completion) and completion = BooleanCompletion(false, _) + or last(andexpr.getRightOperand(), last, completion) - ) or + ) + or exists(OrLogicalExpr orexpr | orexpr = n | - last(orexpr.getLeftOperand(), last, completion) and completion = BooleanCompletion(true, _) or + last(orexpr.getLeftOperand(), last, completion) and completion = BooleanCompletion(true, _) + or last(orexpr.getRightOperand(), last, completion) - ) or - + ) + or // The last node of a `LogNotExpr` is in its sub-expression with an inverted boolean completion // (or a `normalCompletion`). exists(Completion subcompletion | last(n.(LogNotExpr).getExpr(), last, subcompletion) | - subcompletion = NormalCompletion() and completion = NormalCompletion() and not inBooleanContext(n) or + subcompletion = NormalCompletion() and + completion = NormalCompletion() and + not inBooleanContext(n) + or exists(boolean outervalue, boolean innervalue | subcompletion = BooleanCompletion(outervalue, innervalue) and completion = BooleanCompletion(outervalue.booleanNot(), innervalue) ) - ) or - + ) + or // The last node of a `ConditionalExpr` is in either of its branches. exists(ConditionalExpr condexpr | condexpr = n | last(condexpr.getFalseExpr(), last, completion) or last(condexpr.getTrueExpr(), last, completion) - ) or - + ) + or // Parentheses are skipped in the CFG. - last(n.(ParExpr).getExpr(), last, completion) or - + last(n.(ParExpr).getExpr(), last, completion) + or // The last node of a node executed in post-order is the node itself. - n.(PostOrderNode).mayCompleteNormally() and last = n and completion = NormalCompletion() or - - last = n and completion = basicBooleanCompletion(n.(BooleanLiteral).getBooleanValue()) or - + n.(PostOrderNode).mayCompleteNormally() and last = n and completion = NormalCompletion() + or + last = n and completion = basicBooleanCompletion(n.(BooleanLiteral).getBooleanValue()) + or // The last statement in a block is any statement that does not complete normally, // or the last statement. exists(Block blk | blk = n | - last(blk.getAStmt(), last, completion) and completion != NormalCompletion() or - last(blk.getStmt(blk.getNumStmt()-1), last, completion) - ) or - + last(blk.getAStmt(), last, completion) and completion != NormalCompletion() + or + last(blk.getStmt(blk.getNumStmt() - 1), last, completion) + ) + or // The last node in an `if` statement is the last node in either of its branches or // the last node of the condition with a false-completion in the absence of an else-branch. exists(IfStmt ifstmt | ifstmt = n | - last(ifstmt.getCondition(), last, BooleanCompletion(false, _)) and completion = NormalCompletion() and not exists(ifstmt.getElse()) or - last(ifstmt.getThen(), last, completion) or + last(ifstmt.getCondition(), last, BooleanCompletion(false, _)) and + completion = NormalCompletion() and + not exists(ifstmt.getElse()) + or + last(ifstmt.getThen(), last, completion) + or last(ifstmt.getElse(), last, completion) - ) or - + ) + or // A loop may terminate normally if its condition is false... exists(LoopStmt loop | loop = n | - last(loop.getCondition(), last, BooleanCompletion(false, _)) and completion = NormalCompletion() or + last(loop.getCondition(), last, BooleanCompletion(false, _)) and + completion = NormalCompletion() + or // ...or if it's an enhanced for loop running out of items to iterate over... // ...which may happen either immediately after the loop expression... - last(loop.(EnhancedForStmt).getExpr(), last, completion) and completion = NormalCompletion() or + last(loop.(EnhancedForStmt).getExpr(), last, completion) and completion = NormalCompletion() + or exists(Completion bodyCompletion | last(loop.getBody(), last, bodyCompletion) | // ...or after the last node in the loop's body in an iteration that would otherwise continue. - loop instanceof EnhancedForStmt and continues(bodyCompletion, loop) and completion = NormalCompletion() or + loop instanceof EnhancedForStmt and + continues(bodyCompletion, loop) and + completion = NormalCompletion() + or // Otherwise the last node is the last node in the loop's body... // ...if it is an unlabelled `break` (causing the entire loop to complete normally) - (if bodyCompletion = anonymousBreakCompletion() then - completion = NormalCompletion() - // ...or if it is some other completion that does not continue the loop. - else - (not continues(bodyCompletion, loop) and completion = bodyCompletion)) + ( + if bodyCompletion = anonymousBreakCompletion() + then completion = NormalCompletion() + else ( + // ...or if it is some other completion that does not continue the loop. + not continues(bodyCompletion, loop) and completion = bodyCompletion + ) + ) ) - ) or - + ) + or // `try` statements are a bit more complicated: exists(TryStmt try | try = n | // the last node in a `try` is the last node in its `finally` block - // if the `finally` block completes normally, it resumes any completion that // was current before the `finally` block was entered lastInFinally(try, last) and @@ -674,12 +760,11 @@ private cached module ControlFlowGraphImpl { last(try.getFinally(), last, completion) and completion != NormalCompletion() or - // if there is no `finally` block, take the last node of the body or // any of the `catch` clauses not exists(try.getFinally()) and finallyPred(try, last, completion) - ) or - + ) + or // handle `switch` statements exists(SwitchStmt switch | switch = n | // unlabelled `break` causes the whole `switch` to complete normally @@ -692,54 +777,58 @@ private cached module ControlFlowGraphImpl { completion != NormalCompletion() or // if the last case completes normally, then so does the switch - last(switch.getStmt(strictcount(switch.getAStmt())-1), last, NormalCompletion()) and + last(switch.getStmt(strictcount(switch.getAStmt()) - 1), last, NormalCompletion()) and completion = NormalCompletion() or // if no default case exists, then normal completion of the expression may terminate the switch not exists(switch.getDefaultCase()) and last(switch.getExpr(), last, completion) and completion = NormalCompletion() - ) or - + ) + or // the last statement of a synchronized statement is the last statement of its body - last(n.(SynchronizedStmt).getBlock(), last, completion) or - + last(n.(SynchronizedStmt).getBlock(), last, completion) + or // `return` statements give rise to a `Return` completion - last = (ReturnStmt)n and completion = ReturnCompletion() or - + last = n.(ReturnStmt) and completion = ReturnCompletion() + or // `throw` statements or throwing calls give rise to ` Throw` completion - exists(ThrowableType tt | mayThrow(n, tt) | last = n and completion = ThrowCompletion(tt)) or - + exists(ThrowableType tt | mayThrow(n, tt) | last = n and completion = ThrowCompletion(tt)) + or // `break` statements give rise to a `Break` completion exists(BreakStmt break | break = n and last = n | - completion = labelledBreakCompletion(MkLabel(break.getLabel())) or + completion = labelledBreakCompletion(MkLabel(break.getLabel())) + or not exists(break.getLabel()) and completion = anonymousBreakCompletion() - ) or - + ) + or // `continue` statements give rise to a `Continue` completion exists(ContinueStmt cont | cont = n and last = n | - completion = labelledContinueCompletion(MkLabel(cont.getLabel())) or + completion = labelledContinueCompletion(MkLabel(cont.getLabel())) + or not exists(cont.getLabel()) and completion = anonymousContinueCompletion() - ) or - + ) + or // the last node in an `ExprStmt` is the last node in the expression - last(n.(ExprStmt).getExpr(), last, completion) and completion = NormalCompletion() or - + last(n.(ExprStmt).getExpr(), last, completion) and completion = NormalCompletion() + or // the last statement of a labeled statement is the last statement of its body... - exists(LabeledStmt lbl, Completion bodyCompletion | lbl = n and last(lbl.getStmt(), last, bodyCompletion) | + exists(LabeledStmt lbl, Completion bodyCompletion | + lbl = n and last(lbl.getStmt(), last, bodyCompletion) + | // ...except if it's a `break` that refers to this labelled statement - if bodyCompletion = labelledBreakCompletion(MkLabel(lbl.getLabel())) then - completion = NormalCompletion() - else - completion = bodyCompletion - ) or - + if bodyCompletion = labelledBreakCompletion(MkLabel(lbl.getLabel())) + then completion = NormalCompletion() + else completion = bodyCompletion + ) + or // the last statement of a `catch` clause is the last statement of its block - last(n.(CatchClause).getBlock(), last, completion) or - + last(n.(CatchClause).getBlock(), last, completion) + or // the last node in a variable declaration statement is in the last of its individual declarations exists(LocalVariableDeclStmt s | s = n | - last(s.getVariable(count(s.getAVariable())), last, completion) and completion = NormalCompletion() + last(s.getVariable(count(s.getAVariable())), last, completion) and + completion = NormalCompletion() ) } @@ -750,165 +839,229 @@ private cached module ControlFlowGraphImpl { cached ControlFlowNode succ(ControlFlowNode n, Completion completion) { // Callables serve as their own exit nodes. - exists(Callable c | last(c.getBody(), n, completion) | result = c) or - + exists(Callable c | last(c.getBody(), n, completion) | result = c) + or // Logic expressions and conditional expressions execute in AST pre-order. completion = NormalCompletion() and - (result = first(n.(AndLogicalExpr).getLeftOperand()) or - result = first(n.(OrLogicalExpr).getLeftOperand()) or - result = first(n.(LogNotExpr).getExpr()) or - result = first(n.(ConditionalExpr).getCondition())) or - + ( + result = first(n.(AndLogicalExpr).getLeftOperand()) or + result = first(n.(OrLogicalExpr).getLeftOperand()) or + result = first(n.(LogNotExpr).getExpr()) or + result = first(n.(ConditionalExpr).getCondition()) + ) + or // If a logic expression doesn't short-circuit then control flows from its left operand to its right. exists(AndLogicalExpr e | - last(e.getLeftOperand(), n, completion) and completion = BooleanCompletion(true, _) and + last(e.getLeftOperand(), n, completion) and + completion = BooleanCompletion(true, _) and result = first(e.getRightOperand()) - ) or + ) + or exists(OrLogicalExpr e | - last(e.getLeftOperand(), n, completion) and completion = BooleanCompletion(false, _) and + last(e.getLeftOperand(), n, completion) and + completion = BooleanCompletion(false, _) and result = first(e.getRightOperand()) - ) or - + ) + or // Control flows to the corresponding branch depending on the boolean completion of the condition. exists(ConditionalExpr e | - last(e.getCondition(), n, completion) and completion = BooleanCompletion(true, _) and result = first(e.getTrueExpr()) or - last(e.getCondition(), n, completion) and completion = BooleanCompletion(false, _) and result = first(e.getFalseExpr()) - ) or - + last(e.getCondition(), n, completion) and + completion = BooleanCompletion(true, _) and + result = first(e.getTrueExpr()) + or + last(e.getCondition(), n, completion) and + completion = BooleanCompletion(false, _) and + result = first(e.getFalseExpr()) + ) + or // In other expressions control flows from left to right and ends in the node itself. - exists(PostOrderNode p, int i | last(p.getChildNode(i), n, completion) and completion = NormalCompletion() | - result = first(p.getChildNode(i+1)) or - not exists(p.getChildNode(i+1)) and result = p - ) or - + exists(PostOrderNode p, int i | + last(p.getChildNode(i), n, completion) and completion = NormalCompletion() + | + result = first(p.getChildNode(i + 1)) + or + not exists(p.getChildNode(i + 1)) and result = p + ) + or // Statements within a block execute sequentially. - result = first(n.(Block).getStmt(0)) and completion = NormalCompletion() or + result = first(n.(Block).getStmt(0)) and completion = NormalCompletion() + or exists(Block blk, int i | - last(blk.getStmt(i), n, completion) and completion = NormalCompletion() and result = first(blk.getStmt(i+1)) - ) or - + last(blk.getStmt(i), n, completion) and + completion = NormalCompletion() and + result = first(blk.getStmt(i + 1)) + ) + or // Control flows to the corresponding branch depending on the boolean completion of the condition. exists(IfStmt s | - n = s and result = first(s.getCondition()) and completion = NormalCompletion() or - last(s.getCondition(), n, completion) and completion = BooleanCompletion(true, _) and result = first(s.getThen()) or - last(s.getCondition(), n, completion) and completion = BooleanCompletion(false, _) and result = first(s.getElse()) - ) or - + n = s and result = first(s.getCondition()) and completion = NormalCompletion() + or + last(s.getCondition(), n, completion) and + completion = BooleanCompletion(true, _) and + result = first(s.getThen()) + or + last(s.getCondition(), n, completion) and + completion = BooleanCompletion(false, _) and + result = first(s.getElse()) + ) + or // For statements: exists(ForStmt for, ControlFlowNode condentry | // Any part of the control flow that aims for the condition needs to hit either the condition... - condentry = first(for.getCondition()) or + condentry = first(for.getCondition()) + or // ...or the body if the for doesn't include a condition. not exists(for.getCondition()) and condentry = first(for.getStmt()) - | + | // From the entry point, which is the for statement itself, control goes to either the first init expression... - n = for and result = first(for.getInit(0)) and completion = NormalCompletion() or + n = for and result = first(for.getInit(0)) and completion = NormalCompletion() + or // ...or the condition if the for doesn't include init expressions. - n = for and not exists(for.getAnInit()) and result = condentry and completion = NormalCompletion() or + n = for and + not exists(for.getAnInit()) and + result = condentry and + completion = NormalCompletion() + or // Init expressions execute sequentially, after which control is transferred to the condition. exists(int i | last(for.getInit(i), n, completion) and completion = NormalCompletion() | - result = first(for.getInit(i+1)) or - not exists(for.getInit(i+1)) and result = condentry - ) or + result = first(for.getInit(i + 1)) + or + not exists(for.getInit(i + 1)) and result = condentry + ) + or // The true-successor of the condition is the body of the for loop. - last(for.getCondition(), n, completion) and completion = BooleanCompletion(true, _) and result = first(for.getStmt()) or + last(for.getCondition(), n, completion) and + completion = BooleanCompletion(true, _) and + result = first(for.getStmt()) + or // The updates execute sequentially, after which control is transferred to the condition. exists(int i | last(for.getUpdate(i), n, completion) and completion = NormalCompletion() | - result = first(for.getUpdate(i+1)) or - not exists(for.getUpdate(i+1)) and result = condentry - ) or + result = first(for.getUpdate(i + 1)) + or + not exists(for.getUpdate(i + 1)) and result = condentry + ) + or // The back edge of the loop: control goes to either the first update or the condition if no updates exist. - last(for.getStmt(), n, completion) and continues(completion, for) and - (result = first(for.getUpdate(0)) or - result = condentry and not exists(for.getAnUpdate())) - ) or - + last(for.getStmt(), n, completion) and + continues(completion, for) and + ( + result = first(for.getUpdate(0)) + or + result = condentry and not exists(for.getAnUpdate()) + ) + ) + or // Enhanced for statements: exists(EnhancedForStmt for | // First the expression gets evaluated... - n = for and result = first(for.getExpr()) and completion = NormalCompletion() or + n = for and result = first(for.getExpr()) and completion = NormalCompletion() + or // ...then the variable gets assigned... - last(for.getExpr(), n, completion) and completion = NormalCompletion() and result = for.getVariable() or + last(for.getExpr(), n, completion) and + completion = NormalCompletion() and + result = for.getVariable() + or // ...and then control goes to the body of the loop. - n = for.getVariable() and result = first(for.getStmt()) and completion = NormalCompletion() or + n = for.getVariable() and result = first(for.getStmt()) and completion = NormalCompletion() + or // Finally, the back edge of the loop goes to reassign the variable. - last(for.getStmt(), n, completion) and continues(completion, for) and result = for.getVariable() - ) or - + last(for.getStmt(), n, completion) and + continues(completion, for) and + result = for.getVariable() + ) + or // While loops start at the condition... - result = first(n.(WhileStmt).getCondition()) and completion = NormalCompletion() or + result = first(n.(WhileStmt).getCondition()) and completion = NormalCompletion() + or // ...and do-while loops start at the body. - result = first(n.(DoStmt).getStmt()) and completion = NormalCompletion() or + result = first(n.(DoStmt).getStmt()) and completion = NormalCompletion() + or exists(LoopStmt loop | loop instanceof WhileStmt or loop instanceof DoStmt | // Control goes from the condition via a true-completion to the body... - last(loop.getCondition(), n, completion) and completion = BooleanCompletion(true, _) and result = first(loop.getBody()) or + last(loop.getCondition(), n, completion) and + completion = BooleanCompletion(true, _) and + result = first(loop.getBody()) + or // ...and through the back edge from the body back to the condition. - last(loop.getBody(), n, completion) and continues(completion, loop) and result = first(loop.getCondition()) - ) or - + last(loop.getBody(), n, completion) and + continues(completion, loop) and + result = first(loop.getCondition()) + ) + or // Resource declarations in a try-with-resources execute sequentially. - exists(TryStmt try, int i | last(try.getResource(i), n, completion) and completion = NormalCompletion() | - result = first(try.getResource(i+1)) or - not exists(try.getResource(i+1)) and result = first(try.getBlock()) - ) or - + exists(TryStmt try, int i | + last(try.getResource(i), n, completion) and completion = NormalCompletion() + | + result = first(try.getResource(i + 1)) + or + not exists(try.getResource(i + 1)) and result = first(try.getBlock()) + ) + or // After the last resource declaration, control transfers to the body. exists(TryStmt try | n = try and completion = NormalCompletion() | - result = first(try.getResource(0)) or + result = first(try.getResource(0)) + or not exists(try.getAResource()) and result = first(try.getBlock()) - ) or - + ) + or // exceptional control flow exists(TryStmt try | catchOrFinallyCompletion(try, n, completion) | // if the body of the `try` throws... exists(ThrowableType tt | completion = ThrowCompletion(tt) | // ...control transfers to a catch clause... - result = first(handlingCatchClause(try, tt)) or + result = first(handlingCatchClause(try, tt)) + or // ...or to the finally block not mustCatch(try.getACatchClause(), tt) and result = first(try.getFinally()) - ) or - + ) + or // if the body completes normally, control transfers to the finally block not completion = ThrowCompletion(_) and result = first(try.getFinally()) - ) or - + ) + or // after each catch clause, control transfers to the finally block exists(TryStmt try | last(try.getACatchClause(), n, completion) | result = first(try.getFinally()) - ) or - + ) + or // Catch clauses first assign their variable and then execute their block exists(CatchClause cc | completion = NormalCompletion() | - n = cc and result = first(cc.getVariable()) or + n = cc and result = first(cc.getVariable()) + or last(cc.getVariable(), n, completion) and result = first(cc.getBlock()) - ) or - + ) + or // Switch statements exists(SwitchStmt switch | completion = NormalCompletion() | // From the entry point control is transferred first to the expression... - n = switch and result = first(switch.getExpr()) or + n = switch and result = first(switch.getExpr()) + or // ...and then to one of the cases. - last(switch.getExpr(), n, completion) and result = first(switch.getACase()) or + last(switch.getExpr(), n, completion) and result = first(switch.getACase()) + or // Statements within a switch body execute sequentially. - exists(int i | last(switch.getStmt(i), n, completion) and result = first(switch.getStmt(i+1))) - ) or - + exists(int i | + last(switch.getStmt(i), n, completion) and result = first(switch.getStmt(i + 1)) + ) + ) + or // No edges in a SwitchCase - the constant expression in a ConstCase isn't included in the CFG. - // Synchronized statements execute their expression _before_ synchronization, so the CFG reflects that. exists(SynchronizedStmt synch | completion = NormalCompletion() | - last(synch.getExpr(), n, completion) and result = synch or + last(synch.getExpr(), n, completion) and result = synch + or n = synch and result = first(synch.getBlock()) - ) or - - result = first(n.(ExprStmt).getExpr()) and completion = NormalCompletion() or - - result = first(n.(LabeledStmt).getStmt()) and completion = NormalCompletion() or - + ) + or + result = first(n.(ExprStmt).getExpr()) and completion = NormalCompletion() + or + result = first(n.(LabeledStmt).getStmt()) and completion = NormalCompletion() + or // Variable declarations in a variable declaration statement are executed sequentially. exists(LocalVariableDeclStmt s | completion = NormalCompletion() | - n = s and result = first(s.getVariable(1)) or - exists(int i | last(s.getVariable(i), n, completion) and result = first(s.getVariable(i+1))) + n = s and result = first(s.getVariable(1)) + or + exists(int i | last(s.getVariable(i), n, completion) and result = first(s.getVariable(i + 1))) ) } @@ -941,7 +1094,8 @@ private cached module ControlFlowGraphImpl { * completion of the `finally`. */ private Completion resumption(ControlFlowNode n) { - exists(TryStmt try | lastInFinally(try, n) and finallyPred(try, _, result)) or + exists(TryStmt try | lastInFinally(try, n) and finallyPred(try, _, result)) + or not lastInFinally(_, n) and result = NormalCompletion() } @@ -977,33 +1131,22 @@ private cached module ControlFlowGraphImpl { result = mainBranchSucc(n, branch) or result = otherBranchSucc(n, branch) } - } private import ControlFlowGraphImpl /** A control-flow node that branches based on a condition. */ class ConditionNode extends ControlFlowNode { - ConditionNode() { - exists(branchSuccessor(this, _)) - } + ConditionNode() { exists(branchSuccessor(this, _)) } /** Gets a true- or false-successor of the `ConditionNode`. */ - ControlFlowNode getABranchSuccessor(boolean branch) { - result = branchSuccessor(this, branch) - } + ControlFlowNode getABranchSuccessor(boolean branch) { result = branchSuccessor(this, branch) } /** Gets a true-successor of the `ConditionNode`. */ - ControlFlowNode getATrueSuccessor() { - result = getABranchSuccessor(true) - } + ControlFlowNode getATrueSuccessor() { result = getABranchSuccessor(true) } /** Gets a false-successor of the `ConditionNode`. */ - ControlFlowNode getAFalseSuccessor() { - result = getABranchSuccessor(false) - } + ControlFlowNode getAFalseSuccessor() { result = getABranchSuccessor(false) } /** Gets the condition of this `ConditionNode`. This is equal to the node itself. */ - Expr getCondition() { - result = this - } + Expr getCondition() { result = this } } diff --git a/java/ql/src/semmle/code/java/Conversions.qll b/java/ql/src/semmle/code/java/Conversions.qll index 2916b8b5404..fe8ce36d6ed 100644 --- a/java/ql/src/semmle/code/java/Conversions.qll +++ b/java/ql/src/semmle/code/java/Conversions.qll @@ -4,6 +4,7 @@ * * See the Java Language Specification, Section 5, for details. */ + import java import semmle.code.java.arithmetic.Overflow @@ -21,23 +22,17 @@ abstract class ConversionSite extends Expr { /** * Gets the type that is converted from. */ - Type getConversionSource() { - result = this.getType() - } + Type getConversionSource() { result = this.getType() } /** * Whether this conversion site actually induces a conversion. */ - predicate isTrivial() { - getConversionTarget() = getConversionSource() - } + predicate isTrivial() { getConversionTarget() = getConversionSource() } /** * Whether this conversion is implicit. */ - predicate isImplicit() { - any() - } + predicate isImplicit() { any() } abstract string kind(); } @@ -50,18 +45,16 @@ abstract class ConversionSite extends Expr { */ class AssignmentConversionContext extends ConversionSite { Variable v; + AssignmentConversionContext() { - this = v.getAnAssignedValue() or + this = v.getAnAssignedValue() + or exists(Assignment a | a.getDest().getProperExpr() = v.getAnAccess() and this = a.getSource()) } - override Type getConversionTarget() { - result = v.getType() - } + override Type getConversionTarget() { result = v.getType() } - override string kind() { - result = "assignment context" - } + override string kind() { result = "assignment context" } } /** @@ -73,16 +66,12 @@ class AssignmentConversionContext extends ConversionSite { */ class ReturnConversionSite extends ConversionSite { ReturnStmt r; - ReturnConversionSite() { - this = r.getResult() - } - override Type getConversionTarget() { - result = r.getEnclosingCallable().getReturnType() - } - override string kind() { - result = "return context" - } + ReturnConversionSite() { this = r.getResult() } + + override Type getConversionTarget() { result = r.getEnclosingCallable().getReturnType() } + + override string kind() { result = "return context" } } /** @@ -93,18 +82,14 @@ class ReturnConversionSite extends ConversionSite { */ class InvocationConversionContext extends ConversionSite { Call c; + int index; - InvocationConversionContext() { - this = c.getArgument(index) - } - override Type getConversionTarget() { - result = c.getCallee().getParameter(index).getType() - } + InvocationConversionContext() { this = c.getArgument(index) } - override string kind() { - result = "invocation context" - } + override Type getConversionTarget() { result = c.getCallee().getParameter(index).getType() } + + override string kind() { result = "invocation context" } } /** @@ -115,38 +100,28 @@ class InvocationConversionContext extends ConversionSite { */ class StringConversionContext extends ConversionSite { AddExpr a; + StringConversionContext() { a.getAnOperand() = this and not this.getType() instanceof TypeString and a.getAnOperand().getType() instanceof TypeString } - override Type getConversionTarget() { - result instanceof TypeString - } + override Type getConversionTarget() { result instanceof TypeString } - override string kind() { - result = "string context" - } + override string kind() { result = "string context" } } class CastConversionContext extends ConversionSite { CastExpr c; - CastConversionContext() { - this = c.getExpr() - } - override Type getConversionTarget() { - result = c.getType() - } + CastConversionContext() { this = c.getExpr() } - override predicate isImplicit() { - none() - } + override Type getConversionTarget() { result = c.getType() } - override string kind() { - result = "cast context" - } + override predicate isImplicit() { none() } + + override string kind() { result = "cast context" } } /** @@ -157,16 +132,10 @@ class CastConversionContext extends ConversionSite { */ class NumericConversionContext extends ConversionSite { ArithExpr e; - NumericConversionContext() { - this = e.getAnOperand() - } - override Type getConversionTarget() { - result = e.getType() - } + NumericConversionContext() { this = e.getAnOperand() } - override string kind() { - result = "numeric context" - } + override Type getConversionTarget() { result = e.getType() } + override string kind() { result = "numeric context" } } diff --git a/java/ql/src/semmle/code/java/Dependency.qll b/java/ql/src/semmle/code/java/Dependency.qll index a682b115149..c9bc8cc44d4 100755 --- a/java/ql/src/semmle/code/java/Dependency.qll +++ b/java/ql/src/semmle/code/java/Dependency.qll @@ -34,57 +34,48 @@ predicate depends(RefType t, RefType dep) { usesType(t.(NestedType).getEnclosingType(), dep) or // the type of any field declared in `t`, - exists(Field f | f.getDeclaringType() = t | - usesType(f.getType(), dep) - ) or + exists(Field f | f.getDeclaringType() = t | usesType(f.getType(), dep)) + or // the return type of any method declared in `t`, - exists(Method m | m.getDeclaringType() = t | - usesType(m.getReturnType(), dep) - ) or + exists(Method m | m.getDeclaringType() = t | usesType(m.getReturnType(), dep)) + or // the type of any parameter of a callable in `t`, - exists(Callable c | c.getDeclaringType() = t | - usesType(c.getAParamType(), dep) - ) or + exists(Callable c | c.getDeclaringType() = t | usesType(c.getAParamType(), dep)) + or // the type of any exception in the `throws` clause of a callable declared in `t`, - exists(Exception e | e.getCallable().getDeclaringType() = t | - usesType(e.getType(), dep) - ) or + exists(Exception e | e.getCallable().getDeclaringType() = t | usesType(e.getType(), dep)) + or // the declaring type of a callable accessed in `t`, - exists(Callable c | - c.getAReference().getEnclosingCallable().getDeclaringType() = t - | + exists(Callable c | c.getAReference().getEnclosingCallable().getDeclaringType() = t | usesType(c.getSourceDeclaration().getDeclaringType(), dep) - ) or + ) + or // the declaring type of a field accessed in `t`, - exists(Field f | - f.getAnAccess().getEnclosingCallable().getDeclaringType() = t - | + exists(Field f | f.getAnAccess().getEnclosingCallable().getDeclaringType() = t | usesType(f.getSourceDeclaration().getDeclaringType(), dep) - ) or + ) + or // the type of a local variable declared in `t`, - exists(LocalVariableDeclExpr decl | - decl.getEnclosingCallable().getDeclaringType() = t - | + exists(LocalVariableDeclExpr decl | decl.getEnclosingCallable().getDeclaringType() = t | usesType(decl.getType(), dep) - ) or + ) + or // the type of a type literal accessed in `t`, - exists(TypeLiteral l | - l.getEnclosingCallable().getDeclaringType() = t - | + exists(TypeLiteral l | l.getEnclosingCallable().getDeclaringType() = t | usesType(l.getTypeName().getType(), dep) - ) or + ) + or // the type of an annotation (or one of its element values) that annotates `t` or one of its members, exists(Annotation a | a.getAnnotatedElement() = t or a.getAnnotatedElement().(Member).getDeclaringType() = t - | + | usesType(a.getType(), dep) or usesType(a.getAValue().getType(), dep) - ) or + ) + or // the type accessed in an `instanceof` expression in `t`. - exists(InstanceOfExpr ioe | - t = ioe.getEnclosingCallable().getDeclaringType() - | + exists(InstanceOfExpr ioe | t = ioe.getEnclosingCallable().getDeclaringType() | usesType(ioe.getTypeName().getType(), dep) ) ) @@ -108,8 +99,7 @@ predicate usesType(Type t, RefType dep) { * the element type of an array type, or * a bound of a type variable or wildcard. */ -private -RefType inside(Type t) { +private RefType inside(Type t) { result = t.(TypeVariable).getATypeBound().getType() or result = t.(Wildcard).getATypeBound().getType() or result = t.(ParameterizedType).getATypeArgument() or diff --git a/java/ql/src/semmle/code/java/DependencyCounts.qll b/java/ql/src/semmle/code/java/DependencyCounts.qll index fefa16ab216..8dd5c71f0fa 100644 --- a/java/ql/src/semmle/code/java/DependencyCounts.qll +++ b/java/ql/src/semmle/code/java/DependencyCounts.qll @@ -28,89 +28,98 @@ predicate numDepends(RefType t, RefType dep, int value) { not t = dep and // Type `t` depends on: value = strictcount(Element elem | - // its supertypes, - exists(RefType s | elem = s and t.hasSupertype(s) | - usesType(s, dep) - ) or - // its enclosing types, - exists(RefType s | elem = s and t.getEnclosingType() = s | - usesType(s, dep) - ) or - // the type of any field declared in `t`, - exists(Field f | elem = f and f.getDeclaringType() = t | - usesType(f.getType(), dep) - ) or - // the return type of any method declared in `t`, - exists(Method m | elem = m and m.getDeclaringType() = t | - usesType(m.getReturnType(), dep) - ) or - // the type of any parameter of a callable in `t`, - exists(Parameter p | elem = p and p.getCallable().getDeclaringType() = t | - usesType(p.getType(), dep) - ) or - // the type of any exception in the `throws` clause of a callable declared in `t`, - exists(Exception e | elem = e and e.getCallable().getDeclaringType() = t | - usesType(e.getType(), dep) - ) or - // the declaring type of a callable accessed in `t`, - exists(Call c | elem = c and - c.getEnclosingCallable().getDeclaringType() = t + // its supertypes, + exists(RefType s | elem = s and t.hasSupertype(s) | usesType(s, dep)) + or + // its enclosing types, + exists(RefType s | elem = s and t.getEnclosingType() = s | usesType(s, dep)) + or + // the type of any field declared in `t`, + exists(Field f | elem = f and f.getDeclaringType() = t | usesType(f.getType(), dep)) + or + // the return type of any method declared in `t`, + exists(Method m | elem = m and m.getDeclaringType() = t | usesType(m.getReturnType(), dep)) + or + // the type of any parameter of a callable in `t`, + exists(Parameter p | elem = p and p.getCallable().getDeclaringType() = t | + usesType(p.getType(), dep) + ) + or + // the type of any exception in the `throws` clause of a callable declared in `t`, + exists(Exception e | elem = e and e.getCallable().getDeclaringType() = t | + usesType(e.getType(), dep) + ) + or + // the declaring type of a callable accessed in `t`, + exists(Call c | + elem = c and + c.getEnclosingCallable().getDeclaringType() = t | - usesType(c.getCallee().getSourceDeclaration().getDeclaringType(), dep) - ) or - // the declaring type of a field accessed in `t`, - exists(FieldAccess fa | elem = fa and - fa.getEnclosingCallable().getDeclaringType() = t + usesType(c.getCallee().getSourceDeclaration().getDeclaringType(), dep) + ) + or + // the declaring type of a field accessed in `t`, + exists(FieldAccess fa | + elem = fa and + fa.getEnclosingCallable().getDeclaringType() = t | - usesType(fa.getField().getSourceDeclaration().getDeclaringType(), dep) - ) or - // the type of a local variable declared in `t`, - exists(LocalVariableDeclExpr decl | elem = decl and - decl.getEnclosingCallable().getDeclaringType() = t + usesType(fa.getField().getSourceDeclaration().getDeclaringType(), dep) + ) + or + // the type of a local variable declared in `t`, + exists(LocalVariableDeclExpr decl | + elem = decl and + decl.getEnclosingCallable().getDeclaringType() = t | - usesType(decl.getType(), dep) - ) or - // the type of a type literal accessed in `t`, - exists(TypeLiteral l | elem = l and - l.getEnclosingCallable().getDeclaringType() = t + usesType(decl.getType(), dep) + ) + or + // the type of a type literal accessed in `t`, + exists(TypeLiteral l | + elem = l and + l.getEnclosingCallable().getDeclaringType() = t | - usesType(l.getTypeName().getType(), dep) - ) or - // the type of an annotation (or one of its element values) that annotates `t` or one of its members, - exists(Annotation a | - a.getAnnotatedElement() = t or - a.getAnnotatedElement().(Member).getDeclaringType() = t + usesType(l.getTypeName().getType(), dep) + ) + or + // the type of an annotation (or one of its element values) that annotates `t` or one of its members, + exists(Annotation a | + a.getAnnotatedElement() = t or + a.getAnnotatedElement().(Member).getDeclaringType() = t | - elem = a and usesType(a.getType(), dep) or - elem = a.getAValue() and elem.getFile().getExtension() = "java" and usesType(elem.(Expr).getType(), dep) - ) or - // the type accessed in an `instanceof` expression in `t`. - exists(InstanceOfExpr ioe | elem = ioe and - t = ioe.getEnclosingCallable().getDeclaringType() + elem = a and usesType(a.getType(), dep) + or + elem = a.getAValue() and + elem.getFile().getExtension() = "java" and + usesType(elem.(Expr).getType(), dep) + ) + or + // the type accessed in an `instanceof` expression in `t`. + exists(InstanceOfExpr ioe | + elem = ioe and + t = ioe.getEnclosingCallable().getDeclaringType() | - usesType(ioe.getTypeName().getType(), dep) + usesType(ioe.getTypeName().getType(), dep) + ) ) - ) } predicate filePackageDependencyCount(File sourceFile, int total, string entity) { exists(Package targetPackage | total = strictsum(RefType sourceType, RefType targetType, int num | - sourceType.getFile() = sourceFile and - sourceType.fromSource() and - sourceType.getPackage() != targetPackage and - targetType.getPackage() = targetPackage and - numDepends(sourceType, targetType, num) + sourceType.getFile() = sourceFile and + sourceType.fromSource() and + sourceType.getPackage() != targetPackage and + targetType.getPackage() = targetPackage and + numDepends(sourceType, targetType, num) | - num) - and + num + ) and entity = "/" + sourceFile.getRelativePath() + "<|>" + targetPackage + "<|>N/A" ) } -private string nameVersionRegex() { - result = "([_.A-Za-z0-9-]*)-([0-9][A-Za-z0-9.+_-]*)" -} +private string nameVersionRegex() { result = "([_.A-Za-z0-9-]*)-([0-9][A-Za-z0-9.+_-]*)" } /** * Given a JAR filename, try to split it into a name and version. @@ -122,7 +131,8 @@ bindingset[target] predicate hasDashedVersion(string target, string name, string version) { exists(string regex | regex = nameVersionRegex() | name = target.regexpCapture(regex, 1) and - version = target.regexpCapture(regex, 2)) + version = target.regexpCapture(regex, 2) + ) } predicate fileJarDependencyCount(File sourceFile, int total, string entity) { @@ -130,20 +140,22 @@ predicate fileJarDependencyCount(File sourceFile, int total, string entity) { jarStem = targetJar.getStem() and targetJar.(File).getExtension() = "jar" and jarStem != "rt" - | + | total = strictsum(RefType r, RefType dep, int num | - r.getFile() = sourceFile and - r.fromSource() and - dep.getFile().getParentContainer*() = targetJar and - numDepends(r, dep, num) + r.getFile() = sourceFile and + r.fromSource() and + dep.getFile().getParentContainer*() = targetJar and + numDepends(r, dep, num) | - num) and + num + ) and exists(string name, string version | - if hasDashedVersion(jarStem, _, _) then - hasDashedVersion(jarStem, name, version) - else - (name = jarStem and version = "unknown") - | + if hasDashedVersion(jarStem, _, _) + then hasDashedVersion(jarStem, name, version) + else ( + name = jarStem and version = "unknown" + ) + | entity = "/" + sourceFile.getRelativePath() + "<|>" + name + "<|>" + version ) ) diff --git a/java/ql/src/semmle/code/java/Element.qll b/java/ql/src/semmle/code/java/Element.qll index f4496a0bc93..12c386d231e 100755 --- a/java/ql/src/semmle/code/java/Element.qll +++ b/java/ql/src/semmle/code/java/Element.qll @@ -9,7 +9,7 @@ import Javadoc /** A program element that has a name. */ class Element extends @element, Top { /** Holds if this element has the specified `name`. */ - predicate hasName(string name) { hasName(this,name) } + predicate hasName(string name) { hasName(this, name) } /** Gets the name of this element. */ string getName() { this.hasName(result) } @@ -34,9 +34,7 @@ class Element extends @element, Top { * Elements pertaining to source files may include generated elements * not visible in source code, such as implicit default constructors. */ - predicate fromSource() { - getCompilationUnit().getExtension() = "java" - } + predicate fromSource() { getCompilationUnit().getExtension() = "java" } /** Gets the compilation unit that this element belongs to. */ CompilationUnit getCompilationUnit() { result = getFile() } @@ -49,13 +47,27 @@ class Element extends @element, Top { * Holds if element `parent` is immediately above element `e` in the syntax tree. */ private predicate hasChildElement(Element parent, Element e) { - cupackage(e,parent) or - enclInReftype(e,parent) or - (not(enclInReftype(e,_)) and e.(Class).getCompilationUnit() = parent) or - (not(enclInReftype(e,_)) and e.(Interface).getCompilationUnit() = parent) or - methods(e,_,_,_,parent,_) or - constrs(e,_,_,_,parent,_) or - params(e,_,_,parent,_) or - fields(e,_,_,parent,_) or - typeVars(e,_,_,_,parent) + cupackage(e, parent) + or + enclInReftype(e, parent) + or + ( + not (enclInReftype(e, _)) and + e.(Class).getCompilationUnit() = parent + ) + or + ( + not (enclInReftype(e, _)) and + e.(Interface).getCompilationUnit() = parent + ) + or + methods(e, _, _, _, parent, _) + or + constrs(e, _, _, _, parent, _) + or + params(e, _, _, parent, _) + or + fields(e, _, _, parent, _) + or + typeVars(e, _, _, _, parent) } diff --git a/java/ql/src/semmle/code/java/Exception.qll b/java/ql/src/semmle/code/java/Exception.qll index 1b4e0ba85a2..242478aa6c8 100755 --- a/java/ql/src/semmle/code/java/Exception.qll +++ b/java/ql/src/semmle/code/java/Exception.qll @@ -15,10 +15,10 @@ import Type */ class Exception extends Element, @exception { /** Gets the type of this exception. */ - RefType getType() { exceptions(this,result,_) } + RefType getType() { exceptions(this, result, _) } /** Gets the callable whose `throws` clause contains this exception. */ - Callable getCallable() { exceptions(this,_,result) } + Callable getCallable() { exceptions(this, _, result) } /** Gets the name of this exception, that is, the name of its type. */ override string getName() { result = this.getType().getName() } diff --git a/java/ql/src/semmle/code/java/Expr.qll b/java/ql/src/semmle/code/java/Expr.qll index 64eac31dff3..4d411c54f1e 100755 --- a/java/ql/src/semmle/code/java/Expr.qll +++ b/java/ql/src/semmle/code/java/Expr.qll @@ -14,23 +14,19 @@ class Expr extends ExprParent, @expr { /** * Gets the callable in which this expression occurs, if any. */ - Callable getEnclosingCallable() { - callableEnclosingExpr(this,result) - } + Callable getEnclosingCallable() { callableEnclosingExpr(this, result) } /** Gets the index of this expression as a child of its parent. */ - int getIndex() { exprs(this,_,_,_,result) } + int getIndex() { exprs(this, _, _, _, result) } /** Gets the parent of this expression. */ - ExprParent getParent() { exprs(this,_,_,result,_) } + ExprParent getParent() { exprs(this, _, _, result, _) } /** Holds if this expression is the child of the specified parent at the specified (zero-based) position. */ - predicate isNthChildOf(ExprParent parent, int index) { - exprs(this,_,_,parent,index) - } + predicate isNthChildOf(ExprParent parent, int index) { exprs(this, _, _, parent, index) } /** Gets the type of this expression. */ - Type getType() { exprs(this,_,result,_,_) } + Type getType() { exprs(this, _, result, _, _) } /** Gets the compilation unit in which this expression occurs. */ CompilationUnit getCompilationUnit() { result = this.getFile() } @@ -48,21 +44,20 @@ class Expr extends ExprParent, @expr { * comparing whether two expressions have the same kind (as opposed * to checking whether an expression has a particular kind). */ - int getKind() { exprs(this,result,_,_,_) } + int getKind() { exprs(this, result, _, _, _) } /** Gets this expression with any surrounding parentheses removed. */ Expr getProperExpr() { - result = this.(ParExpr).getExpr().getProperExpr() or + result = this.(ParExpr).getExpr().getProperExpr() + or result = this and not this instanceof ParExpr } /** Gets the statement containing this expression, if any. */ - Stmt getEnclosingStmt() { - statementEnclosingExpr(this,result) - } + Stmt getEnclosingStmt() { statementEnclosingExpr(this, result) } /** Gets a child of this expression. */ - Expr getAChildExpr() { exprs(result,_,_,this,_) } + Expr getAChildExpr() { exprs(result, _, _, this, _) } /** Gets the basic block in which this expression occurs, if any. */ BasicBlock getBasicBlock() { result.getANode() = this } @@ -91,9 +86,13 @@ class Expr extends ExprParent, @expr { * initializer, the variable initializer of a static variable, or an * explicit constructor invocation statement. */ - getEnclosingCallable().isStatic() or - getParent+() instanceof ThisConstructorInvocationStmt or - getParent+() instanceof SuperConstructorInvocationStmt or + + getEnclosingCallable().isStatic() + or + getParent+() instanceof ThisConstructorInvocationStmt + or + getParent+() instanceof SuperConstructorInvocationStmt + or exists(LambdaExpr lam | lam.asMethod() = getEnclosingCallable() and lam.isInStaticContext()) } } @@ -103,8 +102,7 @@ class Expr extends ExprParent, @expr { * * Auxiliary predicate used by `CompileTimeConstantExpr`. */ -private -predicate primitiveOrString(Type t) { +private predicate primitiveOrString(Type t) { t instanceof PrimitiveType or t instanceof TypeString } @@ -116,16 +114,23 @@ predicate primitiveOrString(Type t) { */ class CompileTimeConstantExpr extends Expr { CompileTimeConstantExpr() { - primitiveOrString(getType()) and ( + primitiveOrString(getType()) and + ( // Literals of primitive type and literals of type `String`. - this instanceof Literal or + this instanceof Literal + or // Casts to primitive types and casts to type `String`. - this.(CastExpr).getExpr().isCompileTimeConstant() or + this.(CastExpr).getExpr().isCompileTimeConstant() + or // The unary operators `+`, `-`, `~`, and `!` (but not `++` or `--`). - this.(PlusExpr).getExpr().isCompileTimeConstant() or - this.(MinusExpr).getExpr().isCompileTimeConstant() or - this.(BitNotExpr).getExpr().isCompileTimeConstant() or - this.(LogNotExpr).getExpr().isCompileTimeConstant() or + this.(PlusExpr).getExpr().isCompileTimeConstant() + or + this.(MinusExpr).getExpr().isCompileTimeConstant() + or + this.(BitNotExpr).getExpr().isCompileTimeConstant() + or + this.(LogNotExpr).getExpr().isCompileTimeConstant() + or // The multiplicative operators `*`, `/`, and `%`, // the additive operators `+` and `-`, // the shift operators `<<`, `>>`, and `>>>`, @@ -137,15 +142,18 @@ class CompileTimeConstantExpr extends Expr { ( this.(BinaryExpr).getLeftOperand().isCompileTimeConstant() and this.(BinaryExpr).getRightOperand().isCompileTimeConstant() - ) or + ) + or // The ternary conditional operator ` ? : `. exists(ConditionalExpr e | this = e | e.getCondition().isCompileTimeConstant() and e.getTrueExpr().isCompileTimeConstant() and e.getFalseExpr().isCompileTimeConstant() - ) or + ) + or // Parenthesized expressions whose contained expression is a constant expression. - this.(ParExpr).getExpr().isCompileTimeConstant() or + this.(ParExpr).getExpr().isCompileTimeConstant() + or // Access to a final variable initialized by a compile-time constant. exists(Variable v | this = v.getAnAccess() | v.isFinal() and @@ -162,19 +170,19 @@ class CompileTimeConstantExpr extends Expr { or result = this.(ParExpr).getExpr().(CompileTimeConstantExpr).getStringValue() or - result = this.(AddExpr).getLeftOperand().(CompileTimeConstantExpr).getStringValue() - + this.(AddExpr).getRightOperand().(CompileTimeConstantExpr).getStringValue() + result = this.(AddExpr).getLeftOperand().(CompileTimeConstantExpr).getStringValue() + + this.(AddExpr).getRightOperand().(CompileTimeConstantExpr).getStringValue() or // Ternary conditional, with compile-time constant condition. exists(ConditionalExpr ce, boolean condition | ce = this and condition = ce.getCondition().(CompileTimeConstantExpr).getBooleanValue() - | - if condition = true then - result = ce.getTrueExpr().(CompileTimeConstantExpr).getStringValue() - else - result = ce.getFalseExpr().(CompileTimeConstantExpr).getStringValue() - ) or + | + if condition = true + then result = ce.getTrueExpr().(CompileTimeConstantExpr).getStringValue() + else result = ce.getFalseExpr().(CompileTimeConstantExpr).getStringValue() + ) + or exists(Variable v | this = v.getAnAccess() | result = v.getInitializer().(CompileTimeConstantExpr).getStringValue() ) @@ -185,61 +193,114 @@ class CompileTimeConstantExpr extends Expr { */ boolean getBooleanValue() { // Literal value. - result = this.(BooleanLiteral).getBooleanValue() or + result = this.(BooleanLiteral).getBooleanValue() + or // No casts relevant to booleans. // `!` is the only unary operator that evaluates to a boolean. - result = this.(LogNotExpr).getExpr().(CompileTimeConstantExpr).getBooleanValue().booleanNot() or + result = this.(LogNotExpr).getExpr().(CompileTimeConstantExpr).getBooleanValue().booleanNot() + or // Handle binary expressions that have integer operands and a boolean result. exists(BinaryExpr b, int left, int right | b = this and left = b.getLeftOperand().(CompileTimeConstantExpr).getIntValue() and right = b.getRightOperand().(CompileTimeConstantExpr).getIntValue() - | - (b instanceof LTExpr and if left < right then result = true else result = false) or - (b instanceof LEExpr and if left <= right then result = true else result = false) or - (b instanceof GTExpr and if left > right then result = true else result = false) or - (b instanceof GEExpr and if left >= right then result = true else result = false) or - (b instanceof EQExpr and if left = right then result = true else result = false) or - (b instanceof NEExpr and if left != right then result = true else result = false) - ) or + | + ( + b instanceof LTExpr and + if left < right then result = true else result = false + ) + or + ( + b instanceof LEExpr and + if left <= right then result = true else result = false + ) + or + ( + b instanceof GTExpr and + if left > right then result = true else result = false + ) + or + ( + b instanceof GEExpr and + if left >= right then result = true else result = false + ) + or + ( + b instanceof EQExpr and + if left = right then result = true else result = false + ) + or + ( + b instanceof NEExpr and + if left != right then result = true else result = false + ) + ) + or // Handle binary expressions that have boolean operands and a boolean result. exists(BinaryExpr b, boolean left, boolean right | b = this and left = b.getLeftOperand().(CompileTimeConstantExpr).getBooleanValue() and right = b.getRightOperand().(CompileTimeConstantExpr).getBooleanValue() - | - (b instanceof EQExpr and if left = right then result = true else result = false) or - (b instanceof NEExpr and if left != right then result = true else result = false) or - ((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)) or + | + ( + b instanceof EQExpr and + if left = right then result = true else result = false + ) + or + ( + b instanceof NEExpr and + if left != right then result = true else result = false + ) + or + ( + (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) + ) + or (b instanceof XorBitwiseExpr and result = left.booleanXor(right)) - ) or + ) + or // Handle binary expressions that have `String` operands and a boolean result. exists(BinaryExpr b, string left, string right | b = this and left = b.getLeftOperand().(CompileTimeConstantExpr).getStringValue() and right = b.getRightOperand().(CompileTimeConstantExpr).getStringValue() - | + | /* * JLS 15.28 specifies that compile-time `String` constants are interned. Therefore `==` * equality can be interpreted as equality over the constant values, not the references. */ - (b instanceof EQExpr and if left = right then result = true else result = false) or - (b instanceof NEExpr and if left != right then result = true else result = false) - ) or + + ( + b instanceof EQExpr and + if left = right then result = true else result = false + ) + or + ( + b instanceof NEExpr and + if left != right then result = true else result = false + ) + ) + or // Note: no `getFloatValue()`, so we cannot support binary expressions with float or double operands. // Ternary expressions, where the `true` and `false` expressions are boolean compile-time constants. exists(ConditionalExpr ce, boolean condition | ce = this and condition = ce.getCondition().(CompileTimeConstantExpr).getBooleanValue() - | - if condition = true then - result = ce.getTrueExpr().(CompileTimeConstantExpr).getBooleanValue() - else - result = ce.getFalseExpr().(CompileTimeConstantExpr).getBooleanValue() - ) or + | + if condition = true + then result = ce.getTrueExpr().(CompileTimeConstantExpr).getBooleanValue() + else result = ce.getFalseExpr().(CompileTimeConstantExpr).getBooleanValue() + ) + or // Parenthesized expressions containing a boolean value. - result = this.(ParExpr).getExpr().(CompileTimeConstantExpr).getBooleanValue() or + result = this.(ParExpr).getExpr().(CompileTimeConstantExpr).getBooleanValue() + or // Simple or qualified names where the variable is final and the initializer is a constant. exists(Variable v | this = v.getAnAccess() | result = v.getInitializer().(CompileTimeConstantExpr).getBooleanValue() @@ -260,10 +321,7 @@ class CompileTimeConstantExpr extends Expr { */ cached int getIntValue() { - exists(IntegralType t | this.getType() = t | - t.getName().toLowerCase() != "long" - ) - and + exists(IntegralType t | this.getType() = t | t.getName().toLowerCase() != "long") and ( exists(string lit | lit = this.(Literal).getValue() | // `char` literals may get parsed incorrectly, so disallow. @@ -271,22 +329,29 @@ class CompileTimeConstantExpr extends Expr { result = lit.toInt() ) or - exists(CastExpr cast, int val | cast = this and val = cast.getExpr().(CompileTimeConstantExpr).getIntValue() | - if cast.getType().hasName("byte") then result = (val + 128).bitAnd(255) - 128 - else if cast.getType().hasName("short") then result = (val + 32768).bitAnd(65535) - 32768 - else result = val - ) or + exists(CastExpr cast, int val | + cast = this and val = cast.getExpr().(CompileTimeConstantExpr).getIntValue() + | + if cast.getType().hasName("byte") + then result = (val + 128).bitAnd(255) - 128 + else + if cast.getType().hasName("short") + then result = (val + 32768).bitAnd(65535) - 32768 + else result = val + ) + or result = this.(PlusExpr).getExpr().(CompileTimeConstantExpr).getIntValue() or result = -(this.(MinusExpr).getExpr().(CompileTimeConstantExpr).getIntValue()) or result = this.(BitNotExpr).getExpr().(CompileTimeConstantExpr).getIntValue().bitNot() - // No `int` value for `LogNotExpr`. or - exists(BinaryExpr b, int v1, int v2 | b = this and + // No `int` value for `LogNotExpr`. + exists(BinaryExpr b, int v1, int v2 | + b = this and v1 = b.getLeftOperand().(CompileTimeConstantExpr).getIntValue() and v2 = b.getRightOperand().(CompileTimeConstantExpr).getIntValue() - | + | b instanceof MulExpr and result = v1 * v2 or b instanceof DivExpr and result = v1 / v2 @@ -310,17 +375,16 @@ class CompileTimeConstantExpr extends Expr { b instanceof XorBitwiseExpr and result = v1.bitXor(v2) // No `int` value for `AndLogicalExpr` or `OrLogicalExpr`. // No `int` value for `LTExpr`, `GTExpr`, `LEExpr`, `GEExpr`, `EQExpr` or `NEExpr`. - ) + ) or // Ternary conditional, with compile-time constant condition. exists(ConditionalExpr ce, boolean condition | ce = this and condition = ce.getCondition().(CompileTimeConstantExpr).getBooleanValue() - | - if condition = true then - result = ce.getTrueExpr().(CompileTimeConstantExpr).getIntValue() - else - result = ce.getFalseExpr().(CompileTimeConstantExpr).getIntValue() + | + if condition = true + then result = ce.getTrueExpr().(CompileTimeConstantExpr).getIntValue() + else result = ce.getFalseExpr().(CompileTimeConstantExpr).getIntValue() ) or result = this.(ParExpr).getExpr().(CompileTimeConstantExpr).getIntValue() @@ -334,8 +398,7 @@ class CompileTimeConstantExpr extends Expr { } /** An expression parent is an element that may have an expression as its child. */ -class ExprParent extends @exprparent, Top { -} +class ExprParent extends @exprparent, Top { } /** * An array access. @@ -344,7 +407,7 @@ class ExprParent extends @exprparent, Top { * `a` is the accessed array and `i++` is * the index expression of the array access. */ -class ArrayAccess extends Expr,@arrayaccess { +class ArrayAccess extends Expr, @arrayaccess { /** Gets the array that is accessed in this array access. */ Expr getArray() { result.isNthChildOf(this, 0) } @@ -365,7 +428,7 @@ class ArrayAccess extends Expr,@arrayaccess { * respectively. In the second example, * `{ { "a", "b", "c" } , { "d", "e", "f" } }` is the initializer. */ -class ArrayCreationExpr extends Expr,@arraycreationexpr { +class ArrayCreationExpr extends Expr, @arraycreationexpr { /** Gets a dimension of this array creation expression. */ Expr getADimension() { result.getParent() = this and result.getIndex() >= 0 } @@ -382,10 +445,9 @@ class ArrayCreationExpr extends Expr,@arraycreationexpr { * Gets the size of the first dimension, if it can be statically determined. */ int getFirstDimensionSize() { - if exists(getInit()) then - result = count(getInit().getAnInit()) - else - result = getDimension(0).(CompileTimeConstantExpr).getIntValue() + if exists(getInit()) + then result = count(getInit().getAnInit()) + else result = getDimension(0).(CompileTimeConstantExpr).getIntValue() } /** Gets a printable representation of this expression. */ @@ -393,7 +455,7 @@ class ArrayCreationExpr extends Expr,@arraycreationexpr { } /** An array initializer occurs in an array creation expression. */ -class ArrayInit extends Expr,@arrayinit { +class ArrayInit extends Expr, @arrayinit { /** * An expression occurring in this initializer. * This may either be an initializer itself or an @@ -410,7 +472,7 @@ class ArrayInit extends Expr,@arrayinit { } /** A common super-class that represents all varieties of assignments. */ -class Assignment extends Expr,@assignment { +class Assignment extends Expr, @assignment { /** Gets the destination (left-hand side) of the assignment. */ Expr getDest() { result.isNthChildOf(this, 0) } @@ -434,7 +496,7 @@ class Assignment extends Expr,@assignment { * * For example, `x = 23`. */ -class AssignExpr extends Assignment,@assignexpr { } +class AssignExpr extends Assignment, @assignexpr { } /** * A common super-class to represent compound assignments, which include an implicit operator. @@ -442,7 +504,7 @@ class AssignExpr extends Assignment,@assignexpr { } * For example, the compound assignment `x += 23` * uses `+` as the implicit operator. */ -class AssignOp extends Assignment,@assignop { +class AssignOp extends Assignment, @assignop { /** * Gets a source of the compound assignment, which includes both the right-hand side * and the left-hand side of the assignment. @@ -457,35 +519,51 @@ class AssignOp extends Assignment,@assignop { } /** A compound assignment expression using the `+=` operator. */ -class AssignAddExpr extends AssignOp,@assignaddexpr { override string getOp() { result = "+=" } } +class AssignAddExpr extends AssignOp, @assignaddexpr { override string getOp() { result = "+=" } } + /** A compound assignment expression using the `-=` operator. */ -class AssignSubExpr extends AssignOp,@assignsubexpr { override string getOp() { result = "-=" } } +class AssignSubExpr extends AssignOp, @assignsubexpr { override string getOp() { result = "-=" } } + /** A compound assignment expression using the `*=` operator. */ -class AssignMulExpr extends AssignOp,@assignmulexpr { override string getOp() { result = "*=" } } +class AssignMulExpr extends AssignOp, @assignmulexpr { override string getOp() { result = "*=" } } + /** A compound assignment expression using the `/=` operator. */ -class AssignDivExpr extends AssignOp,@assigndivexpr { override string getOp() { result = "/=" } } +class AssignDivExpr extends AssignOp, @assigndivexpr { override string getOp() { result = "/=" } } + /** A compound assignment expression using the `%=` operator. */ -class AssignRemExpr extends AssignOp,@assignremexpr { override string getOp() { result = "%=" } } +class AssignRemExpr extends AssignOp, @assignremexpr { override string getOp() { result = "%=" } } + /** A compound assignment expression using the `&=` operator. */ -class AssignAndExpr extends AssignOp,@assignandexpr { override string getOp() { result = "&=" } } +class AssignAndExpr extends AssignOp, @assignandexpr { override string getOp() { result = "&=" } } + /** A compound assignment expression using the `|=` operator. */ -class AssignOrExpr extends AssignOp,@assignorexpr { override string getOp() { result = "|=" } } +class AssignOrExpr extends AssignOp, @assignorexpr { override string getOp() { result = "|=" } } + /** A compound assignment expression using the `^=` operator. */ -class AssignXorExpr extends AssignOp,@assignxorexpr { override string getOp() { result = "^=" } } +class AssignXorExpr extends AssignOp, @assignxorexpr { override string getOp() { result = "^=" } } + /** A compound assignment expression using the `<<=` operator. */ -class AssignLShiftExpr extends AssignOp,@assignlshiftexpr { override string getOp() { result = "<<=" } } +class AssignLShiftExpr extends AssignOp, @assignlshiftexpr { + override string getOp() { result = "<<=" } +} + /** A compound assignment expression using the `>>=` operator. */ -class AssignRShiftExpr extends AssignOp,@assignrshiftexpr { override string getOp() { result = ">>=" } } +class AssignRShiftExpr extends AssignOp, @assignrshiftexpr { + override string getOp() { result = ">>=" } +} + /** A compound assignment expression using the `>>>=` operator. */ -class AssignURShiftExpr extends AssignOp,@assignurshiftexpr { override string getOp() { result = ">>>=" } } +class AssignURShiftExpr extends AssignOp, @assignurshiftexpr { + override string getOp() { result = ">>>=" } +} /** A common super-class to represent constant literals. */ -class Literal extends Expr,@literal { +class Literal extends Expr, @literal { /** Gets a string representation of this literal. */ - string getLiteral() { namestrings(result,_,this) } + string getLiteral() { namestrings(result, _, this) } /** Gets a string representation of the value of this literal. */ - string getValue() { namestrings(_,result,this) } + string getValue() { namestrings(_, result, this) } /** Gets a printable representation of this expression. */ override string toString() { result = this.getLiteral() } @@ -498,56 +576,50 @@ class Literal extends Expr,@literal { } /** A boolean literal. Either `true` or `false`. */ -class BooleanLiteral extends Literal,@booleanliteral { - +class BooleanLiteral extends Literal, @booleanliteral { /** Gets the boolean representation of this literal. */ boolean getBooleanValue() { - result = true and getLiteral() = "true" or + result = true and getLiteral() = "true" + or result = false and getLiteral() = "false" } } /** An integer literal. For example, `23`. */ -class IntegerLiteral extends Literal,@integerliteral { - +class IntegerLiteral extends Literal, @integerliteral { /** Gets the int representation of this literal. */ - int getIntValue() { - result = getValue().toInt() - } + int getIntValue() { result = getValue().toInt() } } /** A long literal. For example, `23l`. */ -class LongLiteral extends Literal,@longliteral {} +class LongLiteral extends Literal, @longliteral { } /** A floating point literal. For example, `4.2f`. */ -class FloatingPointLiteral extends Literal,@floatingpointliteral {} +class FloatingPointLiteral extends Literal, @floatingpointliteral { } /** A double literal. For example, `4.2`. */ -class DoubleLiteral extends Literal,@doubleliteral {} +class DoubleLiteral extends Literal, @doubleliteral { } /** A character literal. For example, `'\n'`. */ -class CharacterLiteral extends Literal,@characterliteral {} +class CharacterLiteral extends Literal, @characterliteral { } /** A string literal. For example, `"hello world"`. */ -class StringLiteral extends Literal,@stringliteral { - +class StringLiteral extends Literal, @stringliteral { /** * Gets the literal string without the quotes. */ - string getRepresentedString() { - result = getValue() - } + string getRepresentedString() { result = getValue() } } /** The null literal, written `null`. */ -class NullLiteral extends Literal,@nullliteral { +class NullLiteral extends Literal, @nullliteral { override string getLiteral() { result = "null" } + override string getValue() { result = "null" } } - /** A common super-class to represent binary operator expressions. */ -class BinaryExpr extends Expr,@binaryexpr { +class BinaryExpr extends Expr, @binaryexpr { /** Gets the operand on the left-hand side of this binary expression. */ Expr getLeftOperand() { result.isNthChildOf(this, 0) } @@ -563,9 +635,9 @@ class BinaryExpr extends Expr,@binaryexpr { /** The operands of this binary expression are `e` and `f`, in either order. */ predicate hasOperands(Expr e, Expr f) { - exists(int i | i in [0..1] | + exists(int i | i in [0 .. 1] | e.isNthChildOf(this, i) and - f.isNthChildOf(this, 1-i) + f.isNthChildOf(this, 1 - i) ) } @@ -577,43 +649,65 @@ class BinaryExpr extends Expr,@binaryexpr { } /** A binary expression using the `*` operator. */ -class MulExpr extends BinaryExpr,@mulexpr { override string getOp() { result = " * " } } +class MulExpr extends BinaryExpr, @mulexpr { override string getOp() { result = " * " } } + /** A binary expression using the `/` operator. */ -class DivExpr extends BinaryExpr,@divexpr { override string getOp() { result = " / " } } +class DivExpr extends BinaryExpr, @divexpr { override string getOp() { result = " / " } } + /** A binary expression using the `%` operator. */ -class RemExpr extends BinaryExpr,@remexpr { override string getOp() { result = " % " } } +class RemExpr extends BinaryExpr, @remexpr { override string getOp() { result = " % " } } + /** A binary expression using the `+` operator. */ -class AddExpr extends BinaryExpr,@addexpr { override string getOp() { result = " + " } } +class AddExpr extends BinaryExpr, @addexpr { override string getOp() { result = " + " } } + /** A binary expression using the `-` operator. */ -class SubExpr extends BinaryExpr,@subexpr { override string getOp() { result = " - " } } +class SubExpr extends BinaryExpr, @subexpr { override string getOp() { result = " - " } } + /** A binary expression using the `<<` operator. */ -class LShiftExpr extends BinaryExpr,@lshiftexpr { override string getOp() { result = " << " } } +class LShiftExpr extends BinaryExpr, @lshiftexpr { override string getOp() { result = " << " } } + /** A binary expression using the `>>` operator. */ -class RShiftExpr extends BinaryExpr,@rshiftexpr { override string getOp() { result = " >> " } } +class RShiftExpr extends BinaryExpr, @rshiftexpr { override string getOp() { result = " >> " } } + /** A binary expression using the `>>>` operator. */ -class URShiftExpr extends BinaryExpr,@urshiftexpr { override string getOp() { result = " >>> " } } +class URShiftExpr extends BinaryExpr, @urshiftexpr { override string getOp() { result = " >>> " } } + /** A binary expression using the `&` operator. */ -class AndBitwiseExpr extends BinaryExpr,@andbitexpr { override string getOp() { result = " & " } } +class AndBitwiseExpr extends BinaryExpr, @andbitexpr { override string getOp() { result = " & " } } + /** A binary expression using the `|` operator. */ -class OrBitwiseExpr extends BinaryExpr,@orbitexpr { override string getOp() { result = " | " } } +class OrBitwiseExpr extends BinaryExpr, @orbitexpr { override string getOp() { result = " | " } } + /** A binary expression using the `^` operator. */ -class XorBitwiseExpr extends BinaryExpr,@xorbitexpr { override string getOp() { result = " ^ " } } +class XorBitwiseExpr extends BinaryExpr, @xorbitexpr { override string getOp() { result = " ^ " } } + /** A binary expression using the `&&` operator. */ -class AndLogicalExpr extends BinaryExpr,@andlogicalexpr { override string getOp() { result = " && " } } +class AndLogicalExpr extends BinaryExpr, @andlogicalexpr { + override string getOp() { result = " && " } +} + /** A binary expression using the `||` operator. */ -class OrLogicalExpr extends BinaryExpr,@orlogicalexpr { override string getOp() { result = " || " } } +class OrLogicalExpr extends BinaryExpr, @orlogicalexpr { + override string getOp() { result = " || " } +} + /** A binary expression using the `<` operator. */ -class LTExpr extends BinaryExpr,@ltexpr { override string getOp() { result = " < " } } +class LTExpr extends BinaryExpr, @ltexpr { override string getOp() { result = " < " } } + /** A binary expression using the `>` operator. */ -class GTExpr extends BinaryExpr,@gtexpr { override string getOp() { result = " > " } } +class GTExpr extends BinaryExpr, @gtexpr { override string getOp() { result = " > " } } + /** A binary expression using the `<=` operator. */ -class LEExpr extends BinaryExpr,@leexpr { override string getOp() { result = " <= " } } +class LEExpr extends BinaryExpr, @leexpr { override string getOp() { result = " <= " } } + /** A binary expression using the `>=` operator. */ -class GEExpr extends BinaryExpr,@geexpr { override string getOp() { result = " >= " } } +class GEExpr extends BinaryExpr, @geexpr { override string getOp() { result = " >= " } } + /** A binary expression using the `==` operator. */ -class EQExpr extends BinaryExpr,@eqexpr { override string getOp() { result = " == " } } +class EQExpr extends BinaryExpr, @eqexpr { override string getOp() { result = " == " } } + /** A binary expression using the `!=` operator. */ -class NEExpr extends BinaryExpr,@neexpr { override string getOp() { result = " != " } } +class NEExpr extends BinaryExpr, @neexpr { override string getOp() { result = " != " } } /** * A bitwise expression. @@ -633,7 +727,8 @@ class BitwiseExpr extends Expr { } } -/** A logical expression. +/** + * A logical expression. * * This includes expressions involving the operators * `&&`, `||`, or `!`. @@ -662,18 +757,12 @@ abstract class ComparisonExpr extends BinaryExpr { /** * DEPRECATED: use `getLesserOperand()` instead. */ - deprecated - Expr getLesser() { - result = getLesserOperand() - } + deprecated Expr getLesser() { result = getLesserOperand() } /** * DEPRECATED: use `getGreaterOperand()` instead. */ - deprecated - Expr getGreater() { - result = getGreaterOperand() - } + deprecated Expr getGreater() { result = getGreaterOperand() } /** * Gets the lesser operand of this comparison expression. @@ -694,43 +783,29 @@ abstract class ComparisonExpr extends BinaryExpr { abstract Expr getGreaterOperand(); /** Holds if this comparison is strict, i.e. `<` or `>`. */ - predicate isStrict() { - this instanceof LTExpr or this instanceof GTExpr - } + predicate isStrict() { this instanceof LTExpr or this instanceof GTExpr } } /** A comparison expression using the operator `<` or `<=`. */ class LessThanComparison extends ComparisonExpr { - LessThanComparison() { - this instanceof LTExpr or this instanceof LEExpr - } + LessThanComparison() { this instanceof LTExpr or this instanceof LEExpr } /** Gets the lesser operand of this comparison expression. */ - override Expr getLesserOperand() { - result = this.getLeftOperand() - } + override Expr getLesserOperand() { result = this.getLeftOperand() } /** Gets the greater operand of this comparison expression. */ - override Expr getGreaterOperand() { - result = this.getRightOperand() - } + override Expr getGreaterOperand() { result = this.getRightOperand() } } /** A comparison expression using the operator `>` or `>=`. */ class GreaterThanComparison extends ComparisonExpr { - GreaterThanComparison() { - this instanceof GTExpr or this instanceof GEExpr - } + GreaterThanComparison() { this instanceof GTExpr or this instanceof GEExpr } /** Gets the lesser operand of this comparison expression. */ - override Expr getLesserOperand() { - result = this.getRightOperand() - } + override Expr getLesserOperand() { result = this.getRightOperand() } /** Gets the greater operand of this comparison expression. */ - override Expr getGreaterOperand() { - result = this.getLeftOperand() - } + override Expr getGreaterOperand() { result = this.getLeftOperand() } } /** @@ -751,7 +826,7 @@ class EqualityTest extends BinaryExpr { } /** A common super-class that represents unary operator expressions. */ -class UnaryExpr extends Expr,@unaryexpr { +class UnaryExpr extends Expr, @unaryexpr { /** Gets the operand expression. */ Expr getExpr() { result.getParent() = this } } @@ -760,28 +835,42 @@ class UnaryExpr extends Expr,@unaryexpr { * A unary assignment expression is a unary expression using the * prefix or postfix `++` or `--` operator. */ -class UnaryAssignExpr extends UnaryExpr,@unaryassignment { -} +class UnaryAssignExpr extends UnaryExpr, @unaryassignment { } /** A post-increment expression. For example, `i++`. */ -class PostIncExpr extends UnaryAssignExpr,@postincexpr { override string toString() { result = "...++" } } +class PostIncExpr extends UnaryAssignExpr, @postincexpr { + override string toString() { result = "...++" } +} + /** A post-decrement expression. For example, `i--`. */ -class PostDecExpr extends UnaryAssignExpr,@postdecexpr { override string toString() { result = "...--" } } +class PostDecExpr extends UnaryAssignExpr, @postdecexpr { + override string toString() { result = "...--" } +} + /** A pre-increment expression. For example, `++i`. */ -class PreIncExpr extends UnaryAssignExpr,@preincexpr { override string toString() { result = "++..." } } +class PreIncExpr extends UnaryAssignExpr, @preincexpr { + override string toString() { result = "++..." } +} + /** A pre-decrement expression. For example, `--i`. */ -class PreDecExpr extends UnaryAssignExpr,@predecexpr { override string toString() { result = "--..." } } +class PreDecExpr extends UnaryAssignExpr, @predecexpr { + override string toString() { result = "--..." } +} + /** A unary minus expression. For example, `-i`. */ -class MinusExpr extends UnaryExpr,@minusexpr { override string toString() { result = "-..." } } +class MinusExpr extends UnaryExpr, @minusexpr { override string toString() { result = "-..." } } + /** A unary plus expression. For example, `+i`. */ -class PlusExpr extends UnaryExpr,@plusexpr { override string toString() { result = "+..." } } +class PlusExpr extends UnaryExpr, @plusexpr { override string toString() { result = "+..." } } + /** A bit negation expression. For example, `~x`. */ -class BitNotExpr extends UnaryExpr,@bitnotexpr { override string toString() { result = "~..." } } +class BitNotExpr extends UnaryExpr, @bitnotexpr { override string toString() { result = "~..." } } + /** A logical negation expression. For example, `!b`. */ -class LogNotExpr extends UnaryExpr,@lognotexpr { override string toString() { result = "!..." } } +class LogNotExpr extends UnaryExpr, @lognotexpr { override string toString() { result = "!..." } } /** A cast expression. */ -class CastExpr extends Expr,@castexpr { +class CastExpr extends Expr, @castexpr { /** Gets the target type of this cast expression. */ Expr getTypeExpr() { result.isNthChildOf(this, 0) } @@ -820,7 +909,9 @@ class ClassInstanceExpr extends Expr, ConstructorCall, @classinstancexpr { * Gets the type argument provided to the constructor of this class instance creation expression * at the specified (zero-based) position. */ - Expr getTypeArgument(int index) { result = this.getTypeName().(TypeAccess).getTypeArgument(index) } + Expr getTypeArgument(int index) { + result = this.getTypeName().(TypeAccess).getTypeArgument(index) + } /** Gets the qualifier of this class instance creation expression, if any. */ override Expr getQualifier() { result.isNthChildOf(this, -2) } @@ -832,7 +923,7 @@ class ClassInstanceExpr extends Expr, ConstructorCall, @classinstancexpr { Expr getTypeName() { result.isNthChildOf(this, -3) } /** Gets the constructor invoked by this class instance creation expression. */ - override Constructor getConstructor() { callableBinding(this,result) } + override Constructor getConstructor() { callableBinding(this, result) } /** Gets the anonymous class created by this class instance creation expression, if any. */ AnonymousClass getAnonymousClass() { isAnonymClass(result, this) } @@ -880,12 +971,16 @@ class LambdaExpr extends FunctionalExpr, @lambdaexpr { override Method asMethod() { result = getAnonymousClass().getAMethod() } /** Holds if the body of this lambda is an expression. */ - predicate hasExprBody() { lambdaKind(this,0) } + predicate hasExprBody() { lambdaKind(this, 0) } + /** Holds if the body of this lambda is a statement. */ - predicate hasStmtBody() { lambdaKind(this,1) } + predicate hasStmtBody() { lambdaKind(this, 1) } /** Gets the body of this lambda expression, if it is an expression. */ - Expr getExprBody() { hasExprBody() and result = asMethod().getBody().getAChild().(ReturnStmt).getResult() } + Expr getExprBody() { + hasExprBody() and result = asMethod().getBody().getAChild().(ReturnStmt).getResult() + } + /** Gets the body of this lambda expression, if it is a statement. */ Stmt getStmtBody() { hasStmtBody() and result = asMethod().getBody() } @@ -911,10 +1006,11 @@ class MemberRefExpr extends FunctionalExpr, @memberref { * is to an array constructor). */ override Method asMethod() { result = getAnonymousClass().getAMethod() } + /** * Gets the method or constructor referenced by this member reference expression. */ - Callable getReferencedCallable() { memberRefBinding(this,result) } + Callable getReferencedCallable() { memberRefBinding(this, result) } /** Gets a printable representation of this expression. */ override string toString() { result = "...::..." } @@ -925,7 +1021,7 @@ class MemberRefExpr extends FunctionalExpr, @memberref { * `b` is the expression that is evaluated if the condition evaluates to `true`, * and `c` is the expression that is evaluated if the condition evaluates to `false`. */ -class ConditionalExpr extends Expr,@conditionalexpr { +class ConditionalExpr extends Expr, @conditionalexpr { /** Gets the condition of this conditional expression. */ Expr getCondition() { result.isNthChildOf(this, 0) } @@ -946,7 +1042,7 @@ class ConditionalExpr extends Expr,@conditionalexpr { } /** A parenthesised expression. */ -class ParExpr extends Expr,@parexpr { +class ParExpr extends Expr, @parexpr { /** Gets the expression inside the parentheses. */ Expr getExpr() { result.getParent() = this } @@ -955,7 +1051,7 @@ class ParExpr extends Expr,@parexpr { } /** An `instanceof` expression. */ -class InstanceOfExpr extends Expr,@instanceofexpr { +class InstanceOfExpr extends Expr, @instanceofexpr { /** Gets the expression on the left-hand side of the `instanceof` operator. */ Expr getExpr() { result.isNthChildOf(this, 0) } @@ -972,18 +1068,21 @@ class InstanceOfExpr extends Expr,@instanceofexpr { * Contexts in which such expressions may occur include * local variable declaration statements and `for` loops. */ -class LocalVariableDeclExpr extends Expr,@localvariabledeclexpr { +class LocalVariableDeclExpr extends Expr, @localvariabledeclexpr { /** Gets an access to the variable declared by this local variable declaration expression. */ - VarAccess getAnAccess() { variableBinding(result,this.getVariable()) } + VarAccess getAnAccess() { variableBinding(result, this.getVariable()) } /** Gets the local variable declared by this local variable declaration expression. */ - LocalVariableDecl getVariable() { localvars(result,_,_,this) } + LocalVariableDecl getVariable() { localvars(result, _, _, this) } /** Gets the type access of this local variable declaration expression. */ Expr getTypeAccess() { - exists(LocalVariableDeclStmt lvds | lvds.getAVariable() = this | result.isNthChildOf(lvds, 0)) or - exists(CatchClause cc | cc.getVariable() = this | result.isNthChildOf(cc, -1)) or - exists(ForStmt fs | fs.getAnInit() = this | result.isNthChildOf(fs, 0)) or + exists(LocalVariableDeclStmt lvds | lvds.getAVariable() = this | result.isNthChildOf(lvds, 0)) + or + exists(CatchClause cc | cc.getVariable() = this | result.isNthChildOf(cc, -1)) + or + exists(ForStmt fs | fs.getAnInit() = this | result.isNthChildOf(fs, 0)) + or exists(EnhancedForStmt efs | efs.getVariable() = this | result.isNthChildOf(efs, -1)) } @@ -1041,7 +1140,7 @@ class VariableAssign extends VariableUpdate { } /** A type literal. For example, `String.class`. */ -class TypeLiteral extends Expr,@typeliteral { +class TypeLiteral extends Expr, @typeliteral { /** Gets the access to the type whose class is accessed. */ Expr getTypeName() { result.getParent() = this } @@ -1066,9 +1165,7 @@ abstract class InstanceAccess extends Expr { * This never holds for accesses in lambda expressions as they cannot access * their own instance directly. */ - predicate isOwnInstanceAccess() { - not isEnclosingInstanceAccess(_) - } + predicate isOwnInstanceAccess() { not isEnclosingInstanceAccess(_) } /** Holds if this instance access is to an enclosing instance of type `t`. */ predicate isEnclosingInstanceAccess(RefType t) { @@ -1089,10 +1186,11 @@ abstract class InstanceAccess extends Expr { * For example, `A.this` refers to the enclosing instance * of type `A`. */ -class ThisAccess extends InstanceAccess,@thisaccess { +class ThisAccess extends InstanceAccess, @thisaccess { /** Gets a printable representation of this expression. */ override string toString() { - if exists(this.getQualifier()) then ( + if exists(this.getQualifier()) + then ( result = this.getQualifier() + ".this" ) else ( result = "this" @@ -1106,10 +1204,11 @@ class ThisAccess extends InstanceAccess,@thisaccess { * Such an expression allows access to super-class members of an enclosing instance. * For example, `A.super.x`. */ -class SuperAccess extends InstanceAccess,@superaccess { +class SuperAccess extends InstanceAccess, @superaccess { /** Gets a printable representation of this expression. */ override string toString() { - if exists(this.getQualifier()) then ( + if exists(this.getQualifier()) + then ( result = this.getQualifier() + ".super" ) else ( result = "super" @@ -1121,7 +1220,7 @@ class SuperAccess extends InstanceAccess,@superaccess { * A variable access is a (possibly qualified) reference to * a field, parameter or local variable. */ -class VarAccess extends Expr,@varaccess { +class VarAccess extends Expr, @varaccess { /** Gets the qualifier of this variable access, if any. */ Expr getQualifier() { result.getParent() = this } @@ -1129,7 +1228,7 @@ class VarAccess extends Expr,@varaccess { predicate hasQualifier() { exists(getQualifier()) } /** Gets the variable accessed by this variable access. */ - Variable getVariable() { variableBinding(this,result) } + Variable getVariable() { variableBinding(this, result) } /** * Holds if this variable access is an l-value. @@ -1152,13 +1251,12 @@ class VarAccess extends Expr,@varaccess { * a simple assignment, but it may occur as the destination of a compound assignment * or a unary assignment. */ - predicate isRValue() { - not exists(AssignExpr a | a.getDest() = this) - } + predicate isRValue() { not exists(AssignExpr a | a.getDest() = this) } /** Gets a printable representation of this expression. */ override string toString() { - result = this.getQualifier().toString() + "." + this.getVariable().getName() or + result = this.getQualifier().toString() + "." + this.getVariable().getName() + or (not this.hasQualifier() and result = this.getVariable().getName()) } @@ -1191,9 +1289,7 @@ class LValue extends VarAccess { * (such as (`+=`), both the RHS and the LHS of the compound assignment * are source expressions of the assignment. */ - Expr getRHS() { - exists(Assignment e | e.getDest() = this and e.getSource() = result) - } + Expr getRHS() { exists(Assignment e | e.getDest() = this and e.getSource() = result) } } /** @@ -1203,9 +1299,7 @@ class LValue extends VarAccess { * a simple assignment, but it may occur as the destination of a compound assignment * or a unary assignment. */ -class RValue extends VarAccess { - RValue() { this.isRValue() } -} +class RValue extends VarAccess { RValue() { this.isRValue() } } /** A method access is an invocation of a method with a list of arguments. */ class MethodAccess extends Expr, Call, @methodaccess { @@ -1231,7 +1325,7 @@ class MethodAccess extends Expr, Call, @methodaccess { } /** Gets the method accessed by this method access. */ - Method getMethod() { callableBinding(this,result) } + Method getMethod() { callableBinding(this, result) } /** Gets the immediately enclosing callable that contains this method access. */ override Callable getEnclosingCallable() { result = Expr.super.getEnclosingCallable() } @@ -1243,16 +1337,15 @@ class MethodAccess extends Expr, Call, @methodaccess { override string toString() { result = this.printAccess() } /** Gets a printable representation of this expression. */ - string printAccess() { - result = this.getMethod().getName() + "(...)" - } + string printAccess() { result = this.getMethod().getName() + "(...)" } /** * Gets the type of the qualifier on which this method is invoked, or * the enclosing type if there is no qualifier. */ RefType getReceiverType() { - result = getQualifier().getType() or + result = getQualifier().getType() + or not hasQualifier() and result = getEnclosingCallable().getDeclaringType() } @@ -1260,18 +1353,14 @@ class MethodAccess extends Expr, Call, @methodaccess { * Holds if this is a method access to an instance method of `this`. That is, * the qualifier is either an explicit or implicit unqualified `this` or `super`. */ - predicate isOwnMethodAccess() { - Qualifier::ownMemberAccess(this) - } + predicate isOwnMethodAccess() { Qualifier::ownMemberAccess(this) } /** * Holds if this is a method access to an instance method of the enclosing * class `t`. That is, the qualifier is either an explicit or implicit * `t`-qualified `this` or `super`. */ - predicate isEnclosingMethodAccess(RefType t) { - Qualifier::enclosingMemberAccess(this, t) - } + predicate isEnclosingMethodAccess(RefType t) { Qualifier::enclosingMemberAccess(this, t) } } /** A type access is a (possibly qualified) reference to a type. */ @@ -1299,13 +1388,14 @@ class TypeAccess extends Expr, Annotatable, @typeaccess { /** Gets a printable representation of this expression. */ override string toString() { - result = this.getQualifier().toString() + "." + this.getType().toString() or + result = this.getQualifier().toString() + "." + this.getType().toString() + or (not this.hasQualifier() and result = this.getType().toString()) } } /** An array type access is a type access of the form `String[]`. */ -class ArrayTypeAccess extends Expr,@arraytypeaccess { +class ArrayTypeAccess extends Expr, @arraytypeaccess { /** * Gets the expression representing the component type of this array type access. * @@ -1354,6 +1444,7 @@ class IntersectionTypeAccess extends Expr, @intersectiontypeaccess { * and `Cloneable` are bounds. */ Expr getABound() { result.getParent() = this } + /** * Gets the bound at a specified (zero-based) position in this intersection type access expression. * @@ -1368,13 +1459,13 @@ class IntersectionTypeAccess extends Expr, @intersectiontypeaccess { } /** A package access. */ -class PackageAccess extends Expr,@packageaccess { +class PackageAccess extends Expr, @packageaccess { /** Gets a printable representation of this expression. */ override string toString() { result = "package" } } /** A wildcard type access, which may have either a lower or an upper bound. */ -class WildcardTypeAccess extends Expr,@wildcardtypeaccess { +class WildcardTypeAccess extends Expr, @wildcardtypeaccess { /** Gets the upper bound of this wildcard type access, if any. */ Expr getUpperBound() { result.isNthChildOf(this, 0) } @@ -1397,12 +1488,16 @@ class WildcardTypeAccess extends Expr,@wildcardtypeaccess { class Call extends Top, @caller { /** Gets an argument supplied in this call. */ /*abstract*/ Expr getAnArgument() { none() } + /** Gets the argument specified at the (zero-based) position in this call. */ /*abstract*/ Expr getArgument(int n) { none() } + /** Gets the immediately enclosing callable that contains this call. */ /*abstract*/ Callable getEnclosingCallable() { none() } + /** Gets the qualifying expression of this call, if any. */ /*abstract*/ Expr getQualifier() { none() } + /** Gets the enclosing statement of this call. */ /*abstract*/ Stmt getEnclosingStmt() { none() } @@ -1410,14 +1505,10 @@ class Call extends Top, @caller { int getNumArgument() { count(this.getAnArgument()) = result } /** Gets the target callable of this call. */ - Callable getCallee() { - callableBinding(this,result) - } + Callable getCallee() { callableBinding(this, result) } /** Gets the callable invoking this call. */ - Callable getCaller() { - result = getEnclosingCallable() - } + Callable getCaller() { result = getEnclosingCallable() } } /** A polymorphic call to an instance method. */ @@ -1430,16 +1521,12 @@ class VirtualMethodAccess extends MethodAccess { /** A static method call. */ class StaticMethodAccess extends MethodAccess { - StaticMethodAccess() { - this.getMethod().isStatic() - } + StaticMethodAccess() { this.getMethod().isStatic() } } /** A call to a method in the superclass. */ class SuperMethodAccess extends MethodAccess { - SuperMethodAccess() { - this.getQualifier() instanceof SuperAccess - } + SuperMethodAccess() { this.getQualifier() instanceof SuperAccess } } /** @@ -1447,19 +1534,14 @@ class SuperMethodAccess extends MethodAccess { * constructor, or as part of a class instance expression. */ abstract class ConstructorCall extends Call { - /** Gets the target constructor of the class being instantiated. */ abstract Constructor getConstructor(); /** Holds if this constructor call is an explicit call to `this(...)`. */ - predicate callsThis() { - this instanceof ThisConstructorInvocationStmt - } + predicate callsThis() { this instanceof ThisConstructorInvocationStmt } /** Holds if this constructor call is an explicit call to `super(...)`. */ - predicate callsSuper() { - this instanceof SuperConstructorInvocationStmt - } + predicate callsSuper() { this instanceof SuperConstructorInvocationStmt } /** Gets the type of the object instantiated by this constructor call. */ RefType getConstructedType() { result = this.getConstructor().getDeclaringType() } @@ -1467,41 +1549,33 @@ abstract class ConstructorCall extends Call { /** An expression that accesses a field. */ class FieldAccess extends VarAccess { - FieldAccess() { - this.getVariable() instanceof Field - } + FieldAccess() { this.getVariable() instanceof Field } /** Gets the field accessed by this field access expression. */ - Field getField() { - this.getVariable() = result - } + Field getField() { this.getVariable() = result } /** Gets the immediately enclosing callable that contains this field access expression. */ - Callable getSite() { - this.getEnclosingCallable() = result - } + Callable getSite() { this.getEnclosingCallable() = result } /** * Holds if this is a field access to an instance field of `this`. That is, * the qualifier is either an explicit or implicit unqualified `this` or `super`. */ - predicate isOwnFieldAccess() { - Qualifier::ownMemberAccess(this) - } + predicate isOwnFieldAccess() { Qualifier::ownMemberAccess(this) } /** * Holds if this is a field access to an instance field of the enclosing * class `t`. That is, the qualifier is either an explicit or implicit * `t`-qualified `this` or `super`. */ - predicate isEnclosingFieldAccess(RefType t) { - Qualifier::enclosingMemberAccess(this, t) - } + predicate isEnclosingFieldAccess(RefType t) { Qualifier::enclosingMemberAccess(this, t) } } private module Qualifier { /** A type qualifier for an `InstanceAccess`. */ - private newtype TThisQualifier = TThis() or TEnclosing(RefType t) + private newtype TThisQualifier = + TThis() or + TEnclosing(RefType t) /** An expression that accesses a member. That is, either a `FieldAccess` or a `MethodAccess`. */ class MemberAccess extends Expr { @@ -1509,11 +1583,13 @@ private module Qualifier { this instanceof FieldAccess or this instanceof MethodAccess } + /** Gets the member accessed by this member access. */ Member getMember() { result = this.(FieldAccess).getField() or result = this.(MethodAccess).getMethod() } + /** Gets the qualifier of this member access, if any. */ Expr getQualifier() { result = this.(FieldAccess).getQualifier() or @@ -1527,10 +1603,9 @@ private module Qualifier { */ private RefType getImplicitEnclosingQualifier(InnerClass ic, Member m) { exists(RefType enclosing | enclosing = ic.getEnclosingType() | - if enclosing.inherits(m) then - result = enclosing - else - result = getImplicitEnclosingQualifier(enclosing, m) + if enclosing.inherits(m) + then result = enclosing + else result = getImplicitEnclosingQualifier(enclosing, m) ) } @@ -1542,12 +1617,12 @@ private module Qualifier { not m.isStatic() and not exists(ma.getQualifier()) and exists(RefType t | t = ma.getEnclosingCallable().getDeclaringType() | - not t instanceof InnerClass and result = TThis() or + not t instanceof InnerClass and result = TThis() + or exists(InnerClass ic | ic = t | - if ic.inherits(m) then - result = TThis() - else - result = TEnclosing(getImplicitEnclosingQualifier(ic, m)) + if ic.inherits(m) + then result = TThis() + else result = TEnclosing(getImplicitEnclosingQualifier(ic, m)) ) ) ) @@ -1557,13 +1632,17 @@ private module Qualifier { * Gets the type qualifier of the `InstanceAccess` qualifier of `ma`. */ private TThisQualifier getThisQualifier(MemberAccess ma) { - result = getImplicitQualifier(ma) or + result = getImplicitQualifier(ma) + or exists(Expr q | not ma.getMember().isStatic() and q = ma.getQualifier() - | - exists(InstanceAccess ia | ia = q and ia.isOwnInstanceAccess() and result = TThis()) or - exists(InstanceAccess ia, RefType qt | ia = q and ia.isEnclosingInstanceAccess(qt) and result = TEnclosing(qt)) + | + exists(InstanceAccess ia | ia = q and ia.isOwnInstanceAccess() and result = TThis()) + or + exists(InstanceAccess ia, RefType qt | + ia = q and ia.isEnclosingInstanceAccess(qt) and result = TEnclosing(qt) + ) ) } @@ -1571,9 +1650,7 @@ private module Qualifier { * Holds if `ma` is a member access to an instance field or method of `this`. That is, * the qualifier is either an explicit or implicit unqualified `this` or `super`. */ - predicate ownMemberAccess(MemberAccess ma) { - TThis() = getThisQualifier(ma) - } + predicate ownMemberAccess(MemberAccess ma) { TThis() = getThisQualifier(ma) } /** * Holds if `ma` is a member access to an instance field or method of the enclosing @@ -1587,16 +1664,12 @@ private module Qualifier { /** An expression that assigns a value to a field. */ class FieldWrite extends FieldAccess { - FieldWrite() { - exists(Field f | f = getVariable() and isLValue()) - } + FieldWrite() { exists(Field f | f = getVariable() and isLValue()) } } /** An expression that reads a field. */ class FieldRead extends FieldAccess { - FieldRead() { - exists(Field f | f = getVariable() and isRValue()) - } + FieldRead() { exists(Field f | f = getVariable() and isRValue()) } } private predicate hasInstantiation(RefType t) { @@ -1609,19 +1682,16 @@ private predicate hasInstantiation(RefType t) { /** An argument to a call. */ class Argument extends Expr { Call call; + int pos; - Argument() { - call.getArgument(pos) = this - } + Argument() { call.getArgument(pos) = this } /** Gets the call that has this argument. */ Call getCall() { result = call } /** Gets the position of this argument. */ - int getPosition() { - result = pos - } + int getPosition() { result = pos } /** * Holds if this argument is an array of the appropriate type passed to a @@ -1643,9 +1713,7 @@ class Argument extends Expr { } /** Holds if this argument is part of an implicit varargs array. */ - predicate isVararg() { - isNthVararg(_) - } + predicate isVararg() { isNthVararg(_) } /** * Holds if this argument is part of an implicit varargs array at the diff --git a/java/ql/src/semmle/code/java/GeneratedFiles.qll b/java/ql/src/semmle/code/java/GeneratedFiles.qll index bd49af52c8b..f88d68b74f8 100644 --- a/java/ql/src/semmle/code/java/GeneratedFiles.qll +++ b/java/ql/src/semmle/code/java/GeneratedFiles.qll @@ -6,17 +6,13 @@ import Type private import semmle.code.java.frameworks.JavaxAnnotations /** A Java class that is detected as having been generated. */ -abstract class GeneratedClass extends Class { - -} +abstract class GeneratedClass extends Class { } /** * A Java class annotated with a `@Generated` annotation. */ class AnnotatedGeneratedClass extends GeneratedClass { - AnnotatedGeneratedClass() { - this.getAnAnnotation() instanceof GeneratedAnnotation - } + AnnotatedGeneratedClass() { this.getAnAnnotation() instanceof GeneratedAnnotation } } /** A Java class generated by an ANTLR scanner or parser class. */ @@ -28,38 +24,36 @@ class AntlrGenerated extends GeneratedClass { t.hasQualifiedName("org.antlr.runtime", "Parser") or t.hasQualifiedName("org.antlr.runtime.tree", "TreeParser") or // ANTLR v2 - t.hasQualifiedName("antlr","TreeParser") or - t.hasQualifiedName("antlr","CharScanner") or - t.hasQualifiedName("antlr","LLkParser") + t.hasQualifiedName("antlr", "TreeParser") or + t.hasQualifiedName("antlr", "CharScanner") or + t.hasQualifiedName("antlr", "LLkParser") ) } } /** A generated callable is a callable declared in a generated class. */ class GeneratedCallable extends Callable { - GeneratedCallable() { - this.getDeclaringType() instanceof GeneratedClass - } + GeneratedCallable() { this.getDeclaringType() instanceof GeneratedClass } } /** * A file that is detected as having been generated. */ -abstract class GeneratedFile extends File { -} +abstract class GeneratedFile extends File { } /** * A file detected as generated based on commonly-used marker comments. */ -library -class MarkerCommentGeneratedFile extends GeneratedFile { +library class MarkerCommentGeneratedFile extends GeneratedFile { MarkerCommentGeneratedFile() { exists(JavadocElement t | t.getFile() = this | exists(string msg | msg = t.getText() | msg.regexpMatch("(?i).*\\bGenerated By\\b.*\\bDo not edit\\b.*") or - msg.regexpMatch("(?i).*\\bThis (file|class|interface|art[ei]fact) (was|is|(has been)) (?:auto[ -]?)?gener(e?)ated.*") or + msg + .regexpMatch("(?i).*\\bThis (file|class|interface|art[ei]fact) (was|is|(has been)) (?:auto[ -]?)?gener(e?)ated.*") or msg.regexpMatch("(?i).*\\bAny modifications to this file will be lost\\b.*") or - msg.regexpMatch("(?i).*\\bThis (file|class|interface|art[ei]fact) (was|is) (?:mechanically|automatically) generated\\b.*") or + msg + .regexpMatch("(?i).*\\bThis (file|class|interface|art[ei]fact) (was|is) (?:mechanically|automatically) generated\\b.*") or msg.regexpMatch("(?i).*\\bThe following code was (?:auto[ -]?)?generated (?:by|from)\\b.*") or msg.regexpMatch("(?i).*\\bAutogenerated by Thrift.*") or msg.regexpMatch("(?i).*\\bGenerated By.*JavaCC.*") or diff --git a/java/ql/src/semmle/code/java/Generics.qll b/java/ql/src/semmle/code/java/Generics.qll index 73b08d9de62..dd0737101e6 100755 --- a/java/ql/src/semmle/code/java/Generics.qll +++ b/java/ql/src/semmle/code/java/Generics.qll @@ -39,7 +39,7 @@ import Type * For example, `X` in `class X { }`. */ class GenericType extends RefType { - GenericType() { typeVars(_,_,_,_,this) } + GenericType() { typeVars(_, _, _, _, this) } /** * Gets a parameterization of this generic type, where each use of @@ -78,12 +78,10 @@ class GenericType extends RefType { } /** A generic type that is a class. */ -class GenericClass extends GenericType, Class { -} +class GenericClass extends GenericType, Class { } /** A generic type that is an interface. */ -class GenericInterface extends GenericType, Interface { -} +class GenericInterface extends GenericType, Interface { } /** * A common super-class for Java types that may have a type bound. @@ -113,7 +111,8 @@ abstract class BoundedType extends RefType, @boundedtype { /** Gets a transitive upper bound for this type that is not itself a bounded type. */ RefType getAnUltimateUpperBoundType() { - result = getUpperBoundType() and not result instanceof BoundedType or + result = getUpperBoundType() and not result instanceof BoundedType + or result = getUpperBoundType().(BoundedType).getAnUltimateUpperBoundType() } } @@ -126,10 +125,10 @@ abstract class BoundedType extends RefType, @boundedtype { */ class TypeVariable extends BoundedType, @typevariable { /** Gets the generic type that is parameterized by this type parameter, if any. */ - RefType getGenericType() { typeVars(this,_,_,_,result) } + RefType getGenericType() { typeVars(this, _, _, _, result) } /** Gets the generic callable that is parameterized by this type parameter, if any. */ - GenericCallable getGenericCallable() { typeVars(this,_,_,_,result) } + GenericCallable getGenericCallable() { typeVars(this, _, _, _, result) } /** * Gets an upper bound of this type parameter, or `Object` @@ -137,10 +136,9 @@ class TypeVariable extends BoundedType, @typevariable { */ pragma[nomagic] override RefType getUpperBoundType() { - if this.hasTypeBound() then - result = this.getATypeBound().getType() - else - result instanceof TypeObject + if this.hasTypeBound() + then result = this.getATypeBound().getType() + else result instanceof TypeObject } /** @@ -149,10 +147,9 @@ class TypeVariable extends BoundedType, @typevariable { */ pragma[nomagic] override RefType getFirstUpperBoundType() { - if this.hasTypeBound() then - result = this.getFirstTypeBound().getType() - else - result instanceof TypeObject + if this.hasTypeBound() + then result = this.getFirstTypeBound().getType() + else result instanceof TypeObject } /** Gets the lexically enclosing package of this type parameter, if any. */ @@ -167,19 +164,20 @@ class TypeVariable extends BoundedType, @typevariable { exists(GenericType gen, int pos | this = gen.getTypeParameter(pos) and typearg = gen.getAParameterizedType().getTypeArgument(pos) - ) or + ) + or typearg = any(GenericCall call).getATypeArgument(this) - | - if typearg.(Wildcard).isUnconstrained() and this.hasTypeBound() then - result.(Wildcard).getUpperBound().getType() = this.getUpperBoundType() - else - result = typearg + | + if typearg.(Wildcard).isUnconstrained() and this.hasTypeBound() + then result.(Wildcard).getUpperBound().getType() = this.getUpperBoundType() + else result = typearg ) } /** Finds a non-typevariable type that was transitively supplied for this parameter. */ RefType getAnUltimatelySuppliedType() { - result = getASuppliedType() and not result instanceof TypeVariable or + result = getASuppliedType() and not result instanceof TypeVariable + or result = getASuppliedType().(TypeVariable).getAnUltimatelySuppliedType() } } @@ -197,29 +195,22 @@ class TypeVariable extends BoundedType, @typevariable { */ class Wildcard extends BoundedType, @wildcard { /** Holds if this wildcard has an upper bound. */ - predicate hasUpperBound() { - wildcards(this, _, 1) - } + predicate hasUpperBound() { wildcards(this, _, 1) } /** Holds if this wildcard has a lower bound. */ - predicate hasLowerBound() { - wildcards(this, _, 2) - } + predicate hasLowerBound() { wildcards(this, _, 2) } /** Gets the upper bound for this wildcard, if any. */ - TypeBound getUpperBound() { - this.hasUpperBound() and result = this.getATypeBound() - } + TypeBound getUpperBound() { this.hasUpperBound() and result = this.getATypeBound() } /** * Gets an upper bound type of this wildcard, or `Object` * if no explicit type bound is present. */ override RefType getUpperBoundType() { - if this.hasUpperBound() then - result = this.getUpperBound().getType() - else - result instanceof TypeObject + if this.hasUpperBound() + then result = this.getUpperBound().getType() + else result instanceof TypeObject } /** @@ -227,24 +218,19 @@ class Wildcard extends BoundedType, @wildcard { * if no explicit type bound is present. */ override RefType getFirstUpperBoundType() { - if this.hasUpperBound() then - result = this.getFirstTypeBound().getType() - else - result instanceof TypeObject + if this.hasUpperBound() + then result = this.getFirstTypeBound().getType() + else result instanceof TypeObject } /** Gets the lower bound of this wildcard, if any. */ - TypeBound getLowerBound() { - this.hasLowerBound() and result = this.getATypeBound() - } + TypeBound getLowerBound() { this.hasLowerBound() and result = this.getATypeBound() } /** * Gets the lower bound type for this wildcard, * if an explicit lower bound is present. */ - Type getLowerBoundType() { - result = this.getLowerBound().getType() - } + Type getLowerBoundType() { result = this.getLowerBound().getType() } /** * Holds if this is the unconstrained wildcard `?`. @@ -273,7 +259,7 @@ class TypeBound extends @typebound { * For example, `T` is the type variable bounded by the * type `Number` in `T extends Number`. */ - BoundedType getBoundedType() { typeBounds(this,_,_,result) } + BoundedType getBoundedType() { typeBounds(this, _, _, result) } /** * Gets the type of this bound. @@ -281,7 +267,7 @@ class TypeBound extends @typebound { * For example, `Number` is the type of the bound (of * the type variable `T`) in `T extends Number`. */ - RefType getType() { typeBounds(this,result,_,_) } + RefType getType() { typeBounds(this, result, _, _) } /** * Gets the (zero-indexed) position of this bound. @@ -294,14 +280,13 @@ class TypeBound extends @typebound { * the position of the bound `Runnable` is 0 and * the position of the bound `Cloneable` is 1. */ - int getPosition() { typeBounds(this,_,result,_) } + int getPosition() { typeBounds(this, _, result, _) } /** Gets a textual representation of this type bound. */ string toString() { result = this.getType().getName() } } // -------- Parameterizations of generic types -------- - /** * A parameterized type is an instantiation of a generic type, where * each formal type variable has been replaced with a type argument. @@ -311,8 +296,8 @@ class TypeBound extends @typebound { */ class ParameterizedType extends RefType { ParameterizedType() { - typeArgs(_,_,this) or - typeVars(_,_,_,_,this) + typeArgs(_, _, this) or + typeVars(_, _, _, _, this) } /** @@ -320,7 +305,7 @@ class ParameterizedType extends RefType { * * For example, the erasure of both `X` and `X` is `X`. */ - override RefType getErasure() { erasure(this,result) or this.(GenericType) = result } + override RefType getErasure() { erasure(this, result) or this.(GenericType) = result } /** * Gets the generic type corresponding to this parameterized type. @@ -335,35 +320,33 @@ class ParameterizedType extends RefType { * For example, `Number` in `List`. */ RefType getATypeArgument() { - typeArgs(result,_,this) or - typeVars(result,_,_,_,this) + typeArgs(result, _, this) or + typeVars(result, _, _, _, this) } /** Gets the type argument of this parameterized type at the specified position. */ RefType getTypeArgument(int pos) { - typeArgs(result,pos,this) or - typeVars(result,_,pos,_,this) + typeArgs(result, pos, this) or + typeVars(result, _, pos, _, this) } /** Gets the number of type arguments of this parameterized type. */ int getNumberOfTypeArguments() { result = count(int pos | - typeArgs(_,pos,this) or - typeVars(_,_,pos,_,this) - ) + typeArgs(_, pos, this) or + typeVars(_, _, pos, _, this) + ) } /** Holds if this type originates from source code. */ - override predicate fromSource() { typeVars(_,_,_,_,this) and RefType.super.fromSource() } + override predicate fromSource() { typeVars(_, _, _, _, this) and RefType.super.fromSource() } } /** A parameterized type that is a class. */ -class ParameterizedClass extends Class, ParameterizedType { -} +class ParameterizedClass extends Class, ParameterizedType { } /** A parameterized type that is an interface. */ -class ParameterizedInterface extends Interface, ParameterizedType { -} +class ParameterizedInterface extends Interface, ParameterizedType { } /** * The raw version of a generic type is the type that is formed by @@ -383,31 +366,28 @@ class RawType extends RefType { * * For example, the erasure of `List` is `List`. */ - override RefType getErasure() { erasure(this,result) } + override RefType getErasure() { erasure(this, result) } /** Holds if this type originates from source code. */ override predicate fromSource() { not any() } } /** A raw type that is a class. */ -class RawClass extends Class, RawType { -} +class RawClass extends Class, RawType { } /** A raw type that is an interface. */ -class RawInterface extends Interface, RawType { -} +class RawInterface extends Interface, RawType { } // -------- Generic callables -------- - /** * A generic callable is a callable with a type parameter. */ class GenericCallable extends Callable { GenericCallable() { exists(Callable srcDecl | - methods(this,_,_,_,_,srcDecl) or constrs(this,_,_,_,_,srcDecl) - | - typeVars(_,_,_,_,srcDecl) + methods(this, _, _, _, _, srcDecl) or constrs(this, _, _, _, _, srcDecl) + | + typeVars(_, _, _, _, srcDecl) ) } @@ -431,9 +411,7 @@ class GenericCallable extends Callable { * A call where the callee is a generic callable. */ class GenericCall extends Call { - GenericCall() { - this.getCallee() instanceof GenericCallable - } + GenericCall() { this.getCallee() instanceof GenericCallable } private RefType getAnInferredTypeArgument(TypeVariable v) { typevarArg(this, v, result) @@ -454,7 +432,8 @@ class GenericCall extends Call { /** Gets a type argument of the call for the given `TypeVariable`. */ RefType getATypeArgument(TypeVariable v) { - result = getAnExplicitTypeArgument(v) or + result = getAnExplicitTypeArgument(v) + or not exists(getAnExplicitTypeArgument(v)) and result = getAnInferredTypeArgument(v) } @@ -465,36 +444,38 @@ private predicate typevarArg(Call call, TypeVariable v, RefType typearg) { exists(GenericCallable gen | gen = call.getCallee() and v = gen.getATypeParameter() - | - hasSubstitution(gen.getReturnType(), call.(Expr).getType(), v, typearg) - or - exists(int n | hasSubtypedSubstitution(gen.getParameterType(n), call.getArgument(n).getType(), v, typearg)) + | + hasSubstitution(gen.getReturnType(), call.(Expr).getType(), v, typearg) or + exists(int n | + hasSubtypedSubstitution(gen.getParameterType(n), call.getArgument(n).getType(), v, typearg) + ) ) } /** * The reflexive transitive closure of `RefType.extendsOrImplements` including reflexivity on `Type`s. */ -private Type getShallowSupertype(Type t) { - result = t or t.(RefType).extendsOrImplements+(result) -} +private Type getShallowSupertype(Type t) { result = t or t.(RefType).extendsOrImplements+(result) } /** * Manual magic sets optimization for the "inputs" of `hasSubstitution` and * `hasParameterSubstitution`. */ private predicate unificationTargets(RefType t1, Type t2) { - exists(GenericCallable gen, Call call | - gen = call.getCallee() - | - t1 = gen.getReturnType() and t2 = call.(Expr).getType() or - exists(int n | t1 = gen.getParameterType(n) and t2 = getShallowSupertype(call.getArgument(n).getType())) - ) or + exists(GenericCallable gen, Call call | gen = call.getCallee() | + t1 = gen.getReturnType() and t2 = call.(Expr).getType() + or + exists(int n | + t1 = gen.getParameterType(n) and t2 = getShallowSupertype(call.getArgument(n).getType()) + ) + ) + or exists(Array a1, Array a2 | unificationTargets(a1, a2) and t1 = a1.getComponentType() and t2 = a2.getComponentType() - ) or + ) + or exists(ParameterizedType pt1, ParameterizedType pt2, int pos | unificationTargets(pt1, pt2) and t1 = pt1.getTypeArgument(pos) and @@ -526,17 +507,21 @@ private predicate hasSubtypedSubstitution(RefType t1, Type t2, TypeVariable v, R private predicate hasSubstitution(RefType t1, Type t2, TypeVariable v, RefType subst) { unificationTargets(t1, t2) and ( - t1 = v and (t2 = subst or t2.(PrimitiveType).getBoxedType() = subst) or - hasSubstitution(t1.(Array).getComponentType(), t2.(Array).getComponentType(), v, subst) or + t1 = v and + (t2 = subst or t2.(PrimitiveType).getBoxedType() = subst) + or + hasSubstitution(t1.(Array).getComponentType(), t2.(Array).getComponentType(), v, subst) + or exists(GenericType g | hasParameterSubstitution(g, t1, g, t2, v, subst)) ) } -private predicate hasParameterSubstitution(GenericType g1, ParameterizedType pt1, GenericType g2, ParameterizedType pt2, TypeVariable v, RefType subst) { +private predicate hasParameterSubstitution( + GenericType g1, ParameterizedType pt1, GenericType g2, ParameterizedType pt2, TypeVariable v, + RefType subst +) { unificationTargets(pt1, pt2) and - exists(int pos | - hasSubstitution(pt1.getTypeArgument(pos), pt2.getTypeArgument(pos), v, subst) - ) and + exists(int pos | hasSubstitution(pt1.getTypeArgument(pos), pt2.getTypeArgument(pos), v, subst)) and g1 = pt1.getGenericType() and g2 = pt2.getGenericType() } @@ -547,7 +532,10 @@ private predicate hasParameterSubstitution(GenericType g1, ParameterizedType pt1 * For example, ` C(T t) { }` is a generic constructor for type `C`. */ class GenericConstructor extends Constructor, GenericCallable { - override GenericConstructor getSourceDeclaration() { result = Constructor.super.getSourceDeclaration() } + override GenericConstructor getSourceDeclaration() { + result = Constructor.super.getSourceDeclaration() + } + override ConstructorCall getAReference() { result = Constructor.super.getAReference() } } @@ -561,5 +549,4 @@ class GenericMethod extends Method, GenericCallable { } /** A generic method that is the same as its source declaration. */ -class GenericSrcMethod extends SrcMethod, GenericMethod { -} +class GenericSrcMethod extends SrcMethod, GenericMethod { } diff --git a/java/ql/src/semmle/code/java/Import.qll b/java/ql/src/semmle/code/java/Import.qll index 90a85595a8a..81823e7e2ac 100755 --- a/java/ql/src/semmle/code/java/Import.qll +++ b/java/ql/src/semmle/code/java/Import.qll @@ -22,10 +22,10 @@ class Import extends Element, @import { * For example, `import java.util.Set;`. */ class ImportType extends Import { - ImportType() { imports(this,_,_,1) } + ImportType() { imports(this, _, _, 1) } /** Gets the imported type. */ - RefType getImportedType() { imports(this,result,_,_) } + RefType getImportedType() { imports(this, result, _, _) } override string toString() { result = "import " + this.getImportedType().toString() } } @@ -39,17 +39,15 @@ class ImportType extends Import { * `java.util.Map`. */ class ImportOnDemandFromType extends Import { - ImportOnDemandFromType() { imports(this,_,_,2) } + ImportOnDemandFromType() { imports(this, _, _, 2) } /** Gets the type from which accessible nested types are imported. */ - RefType getTypeHoldingImport() { imports(this,result,_,_) } + RefType getTypeHoldingImport() { imports(this, result, _, _) } /** Gets an imported type. */ NestedType getAnImport() { result.getEnclosingType() = this.getTypeHoldingImport() } - override string toString() { - result = "import " + this.getTypeHoldingImport().toString() + ".*" - } + override string toString() { result = "import " + this.getTypeHoldingImport().toString() + ".*" } } /** @@ -59,10 +57,10 @@ class ImportOnDemandFromType extends Import { * For example, `import java.util.*;`. */ class ImportOnDemandFromPackage extends Import { - ImportOnDemandFromPackage() { imports(this,_,_,3) } + ImportOnDemandFromPackage() { imports(this, _, _, 3) } /** Gets the package from which accessible types are imported. */ - Package getPackageHoldingImport() { imports(this,result,_,_) } + Package getPackageHoldingImport() { imports(this, result, _, _) } /** Gets an imported type. */ RefType getAnImport() { result.getPackage() = this.getPackageHoldingImport() } @@ -80,10 +78,10 @@ class ImportOnDemandFromPackage extends Import { * For example, `import static java.lang.System.*;`. */ class ImportStaticOnDemand extends Import { - ImportStaticOnDemand() { imports(this,_,_,4) } + ImportStaticOnDemand() { imports(this, _, _, 4) } /** Gets the type from which accessible static members are imported. */ - RefType getTypeHoldingImport() { imports(this,result,_,_) } + RefType getTypeHoldingImport() { imports(this, result, _, _) } /** Gets an imported type. */ NestedType getATypeImport() { result.getEnclosingType() = this.getTypeHoldingImport() } @@ -109,18 +107,19 @@ class ImportStaticOnDemand extends Import { * class `java.util.Collections`. */ class ImportStaticTypeMember extends Import { - ImportStaticTypeMember() { imports(this,_,_,5) } + ImportStaticTypeMember() { imports(this, _, _, 5) } /** Gets the type from which static members with a given name are imported. */ - RefType getTypeHoldingImport() { imports(this,result,_,_) } + RefType getTypeHoldingImport() { imports(this, result, _, _) } /** Gets the name of the imported member(s). */ - override string getName() { imports(this,_,result,_) } + override string getName() { imports(this, _, result, _) } /** Gets an imported member. */ Member getAMemberImport() { this.getTypeHoldingImport().getAMember() = result and - result.getName() = this.getName() and result.isStatic() + result.getName() = this.getName() and + result.isStatic() } /** Gets an imported type. */ @@ -134,7 +133,6 @@ class ImportStaticTypeMember extends Import { /** Gets a printable representation of this import declaration. */ override string toString() { - result = "import static " + this.getTypeHoldingImport().toString() - + "." + this.getName() + result = "import static " + this.getTypeHoldingImport().toString() + "." + this.getName() } } diff --git a/java/ql/src/semmle/code/java/J2EE.qll b/java/ql/src/semmle/code/java/J2EE.qll index 783d8e7c66c..5daec35b562 100755 --- a/java/ql/src/semmle/code/java/J2EE.qll +++ b/java/ql/src/semmle/code/java/J2EE.qll @@ -7,61 +7,49 @@ import Type /** An entity bean. */ class EntityBean extends Class { EntityBean() { - exists(Interface i | i.hasQualifiedName("javax.ejb","EntityBean") | - this.hasSupertype+(i) - ) + exists(Interface i | i.hasQualifiedName("javax.ejb", "EntityBean") | this.hasSupertype+(i)) } } /** An enterprise bean. */ class EnterpriseBean extends RefType { EnterpriseBean() { - exists(Interface i | i.hasQualifiedName("javax.ejb","EnterpriseBean") | - this.hasSupertype+(i) - ) + exists(Interface i | i.hasQualifiedName("javax.ejb", "EnterpriseBean") | this.hasSupertype+(i)) } } /** A local EJB home interface. */ class LocalEJBHomeInterface extends Interface { LocalEJBHomeInterface() { - exists(Interface i | i.hasQualifiedName("javax.ejb","EJBLocalHome") | - this.hasSupertype+(i) - ) + exists(Interface i | i.hasQualifiedName("javax.ejb", "EJBLocalHome") | this.hasSupertype+(i)) } } /** A remote EJB home interface. */ class RemoteEJBHomeInterface extends Interface { RemoteEJBHomeInterface() { - exists(Interface i | i.hasQualifiedName("javax.ejb","EJBHome") | - this.hasSupertype+(i) - ) + exists(Interface i | i.hasQualifiedName("javax.ejb", "EJBHome") | this.hasSupertype+(i)) } } /** A local EJB interface. */ class LocalEJBInterface extends Interface { LocalEJBInterface() { - exists(Interface i | i.hasQualifiedName("javax.ejb","EJBLocalObject") | - this.hasSupertype+(i) - ) + exists(Interface i | i.hasQualifiedName("javax.ejb", "EJBLocalObject") | this.hasSupertype+(i)) } } /** A remote EJB interface. */ class RemoteEJBInterface extends Interface { RemoteEJBInterface() { - exists(Interface i | i.hasQualifiedName("javax.ejb","EJBObject") | - this.hasSupertype+(i) - ) + exists(Interface i | i.hasQualifiedName("javax.ejb", "EJBObject") | this.hasSupertype+(i)) } } /** A message bean. */ class MessageBean extends Class { MessageBean() { - exists(Interface i | i.hasQualifiedName("javax.ejb","MessageDrivenBean") | + exists(Interface i | i.hasQualifiedName("javax.ejb", "MessageDrivenBean") | this.hasSupertype+(i) ) } @@ -70,8 +58,6 @@ class MessageBean extends Class { /** A session bean. */ class SessionBean extends Class { SessionBean() { - exists(Interface i | i.hasQualifiedName("javax.ejb","SessionBean") | - this.hasSupertype+(i) - ) + exists(Interface i | i.hasQualifiedName("javax.ejb", "SessionBean") | this.hasSupertype+(i)) } } diff --git a/java/ql/src/semmle/code/java/JDK.qll b/java/ql/src/semmle/code/java/JDK.qll index 73ec22b700e..4d4566a393b 100644 --- a/java/ql/src/semmle/code/java/JDK.qll +++ b/java/ql/src/semmle/code/java/JDK.qll @@ -5,104 +5,67 @@ import Member // --- Standard types --- - /** The class `java.lang.Object`. */ class TypeObject extends Class { pragma[noinline] - TypeObject() { - this.hasQualifiedName("java.lang", "Object") - } + TypeObject() { this.hasQualifiedName("java.lang", "Object") } } /** The interface `java.lang.Cloneable`. */ class TypeCloneable extends Interface { - TypeCloneable() { - this.hasQualifiedName("java.lang", "Cloneable") - } + TypeCloneable() { this.hasQualifiedName("java.lang", "Cloneable") } } /** The class `java.lang.ProcessBuilder`. */ class TypeProcessBuilder extends Class { - TypeProcessBuilder() { - hasQualifiedName("java.lang", "ProcessBuilder") - } + TypeProcessBuilder() { hasQualifiedName("java.lang", "ProcessBuilder") } } /** The class `java.lang.Runtime`. */ -class TypeRuntime extends Class { - TypeRuntime() { - hasQualifiedName("java.lang", "Runtime") - } -} +class TypeRuntime extends Class { TypeRuntime() { hasQualifiedName("java.lang", "Runtime") } } /** The class `java.lang.String`. */ -class TypeString extends Class { - TypeString() { - this.hasQualifiedName("java.lang", "String") - } -} +class TypeString extends Class { TypeString() { this.hasQualifiedName("java.lang", "String") } } /** The `length()` method of the class `java.lang.String`. */ class StringLengthMethod extends Method { - StringLengthMethod() { - this.hasName("length") and this.getDeclaringType() instanceof TypeString - } + StringLengthMethod() { this.hasName("length") and this.getDeclaringType() instanceof TypeString } } /** The class `java.lang.StringBuffer`. */ class TypeStringBuffer extends Class { - TypeStringBuffer() { - this.hasQualifiedName("java.lang", "StringBuffer") - } + TypeStringBuffer() { this.hasQualifiedName("java.lang", "StringBuffer") } } /** The class `java.lang.StringBuilder`. */ class TypeStringBuilder extends Class { - TypeStringBuilder() { - this.hasQualifiedName("java.lang", "StringBuilder") - } + TypeStringBuilder() { this.hasQualifiedName("java.lang", "StringBuilder") } } /** The class `java.lang.System`. */ -class TypeSystem extends Class { - TypeSystem() { - this.hasQualifiedName("java.lang", "System") - } -} +class TypeSystem extends Class { TypeSystem() { this.hasQualifiedName("java.lang", "System") } } /** The class `java.lang.Throwable`. */ class TypeThrowable extends Class { - TypeThrowable() { - this.hasQualifiedName("java.lang", "Throwable") - } + TypeThrowable() { this.hasQualifiedName("java.lang", "Throwable") } } /** The class `java.lang.Exception`. */ class TypeException extends Class { - TypeException() { - this.hasQualifiedName("java.lang", "Exception") - } + TypeException() { this.hasQualifiedName("java.lang", "Exception") } } /** The class `java.lang.Error`. */ -class TypeError extends Class { - TypeError() { - this.hasQualifiedName("java.lang", "Error") - } -} +class TypeError extends Class { TypeError() { this.hasQualifiedName("java.lang", "Error") } } /** The class `java.lang.RuntimeException`. */ class TypeRuntimeException extends Class { - TypeRuntimeException() { - this.hasQualifiedName("java.lang", "RuntimeException") - } + TypeRuntimeException() { this.hasQualifiedName("java.lang", "RuntimeException") } } /** The class `java.lang.ClassCastException`. */ class TypeClassCastException extends Class { - TypeClassCastException() { - this.hasQualifiedName("java.lang", "ClassCastException") - } + TypeClassCastException() { this.hasQualifiedName("java.lang", "ClassCastException") } } /** @@ -111,9 +74,7 @@ class TypeClassCastException extends Class { * This includes the generic source declaration, any parameterized instances and the raw type. */ class TypeClass extends Class { - TypeClass() { - this.getSourceDeclaration().hasQualifiedName("java.lang", "Class") - } + TypeClass() { this.getSourceDeclaration().hasQualifiedName("java.lang", "Class") } } /** @@ -128,11 +89,7 @@ class TypeConstructor extends Class { } /** The class `java.lang.Math`. */ -class TypeMath extends Class { - TypeMath() { - this.hasQualifiedName("java.lang", "Math") - } -} +class TypeMath extends Class { TypeMath() { this.hasQualifiedName("java.lang", "Math") } } /** A numeric type, including both primitive and boxed types. */ class NumericType extends Type { @@ -140,7 +97,7 @@ class NumericType extends Type { exists(string name | name = this.(PrimitiveType).getName() or name = this.(BoxedType).getPrimitiveType().getName() - | + | name.regexpMatch("byte|short|int|long|double|float") ) } @@ -158,58 +115,36 @@ class ImmutableType extends Type { } // --- Java IO --- - /** The interface `java.io.Serializable`. */ class TypeSerializable extends Interface { - TypeSerializable() { - hasQualifiedName("java.io", "Serializable") - } + TypeSerializable() { hasQualifiedName("java.io", "Serializable") } } /** The interface `java.io.ObjectOutput`. */ class TypeObjectOutput extends Interface { - TypeObjectOutput() { - hasQualifiedName("java.io", "ObjectOutput") - } + TypeObjectOutput() { hasQualifiedName("java.io", "ObjectOutput") } } /** The type `java.io.ObjectOutputStream`. */ class TypeObjectOutputStream extends RefType { - TypeObjectOutputStream() { - hasQualifiedName("java.io", "ObjectOutputStream") - } + TypeObjectOutputStream() { hasQualifiedName("java.io", "ObjectOutputStream") } } /** The class `java.nio.file.Paths`. */ -class TypePaths extends Class { - TypePaths() { - this.hasQualifiedName("java.nio.file", "Paths") - } -} +class TypePaths extends Class { TypePaths() { this.hasQualifiedName("java.nio.file", "Paths") } } /** The class `java.nio.file.Path`. */ -class TypePath extends Class { - TypePath() { - this.hasQualifiedName("java.nio.file", "Path") - } -} +class TypePath extends Class { TypePath() { this.hasQualifiedName("java.nio.file", "Path") } } /** The class `java.nio.file.FileSystem`. */ class TypeFileSystem extends Class { - TypeFileSystem() { - this.hasQualifiedName("java.nio.file", "FileSystem") - } + TypeFileSystem() { this.hasQualifiedName("java.nio.file", "FileSystem") } } /** The class `java.io.File`. */ -class TypeFile extends Class { - TypeFile() { - this.hasQualifiedName("java.io", "File") - } -} +class TypeFile extends Class { TypeFile() { this.hasQualifiedName("java.io", "File") } } // --- Standard methods --- - /** * Any of the methods named `command` on class `java.lang.ProcessBuilder`. */ @@ -315,7 +250,6 @@ class MethodAbs extends Method { } // --- Standard fields --- - /** The field `System.in`. */ class SystemIn extends Field { SystemIn() { @@ -341,7 +275,6 @@ class SystemErr extends Field { } // --- User-defined methods with a particular meaning --- - /** A method with the same signature as `java.lang.Object.equals`. */ class EqualsMethod extends Method { EqualsMethod() { @@ -351,9 +284,7 @@ class EqualsMethod extends Method { } /** Gets the single parameter of this method. */ - Parameter getParameter() { - result = this.getAParameter() - } + Parameter getParameter() { result = this.getAParameter() } } /** A method with the same signature as `java.lang.Object.hashCode`. */ @@ -399,8 +330,7 @@ class PreMainMethod extends Method { this.getReturnType().hasName("void") and this.getNumberOfParameters() < 3 and this.getParameter(0).getType() instanceof TypeString and - (exists(this.getParameter(1)) implies - this.getParameter(1).getType().hasName("Instrumentation")) + (exists(this.getParameter(1)) implies this.getParameter(1).getType().hasName("Instrumentation")) } } @@ -414,9 +344,7 @@ class ArrayLengthField extends Field { /** A (reflexive, transitive) subtype of `java.lang.Throwable`. */ class ThrowableType extends RefType { - ThrowableType() { - exists(TypeThrowable throwable | hasSubtype*(throwable, this)) - } + ThrowableType() { exists(TypeThrowable throwable | hasSubtype*(throwable, this)) } } /** An unchecked exception. That is, a (reflexive, transitive) subtype of `java.lang.Error` or `java.lang.RuntimeException`. */ diff --git a/java/ql/src/semmle/code/java/JDKAnnotations.qll b/java/ql/src/semmle/code/java/JDKAnnotations.qll index 12936f9f9ff..e3e1e40d946 100644 --- a/java/ql/src/semmle/code/java/JDKAnnotations.qll +++ b/java/ql/src/semmle/code/java/JDKAnnotations.qll @@ -6,23 +6,17 @@ import java /** A `@Deprecated` annotation. */ class DeprecatedAnnotation extends Annotation { - DeprecatedAnnotation() { - this.getType().hasQualifiedName("java.lang", "Deprecated") - } + DeprecatedAnnotation() { this.getType().hasQualifiedName("java.lang", "Deprecated") } } /** An `@Override` annotation. */ class OverrideAnnotation extends Annotation { - OverrideAnnotation() { - this.getType().hasQualifiedName("java.lang", "Override") - } + OverrideAnnotation() { this.getType().hasQualifiedName("java.lang", "Override") } } /** A `@SuppressWarnings` annotation. */ class SuppressWarningsAnnotation extends Annotation { - SuppressWarningsAnnotation() { - this.getType().hasQualifiedName("java.lang", "SuppressWarnings") - } + SuppressWarningsAnnotation() { this.getType().hasQualifiedName("java.lang", "SuppressWarnings") } /** Gets the name of a warning suppressed by this annotation. */ string getASuppressedWarning() { @@ -33,9 +27,7 @@ class SuppressWarningsAnnotation extends Annotation { /** A `@Target` annotation. */ class TargetAnnotation extends Annotation { - TargetAnnotation() { - this.getType().hasQualifiedName("java.lang.annotation", "Target") - } + TargetAnnotation() { this.getType().hasQualifiedName("java.lang.annotation", "Target") } /** * Gets a target expression within this annotation. @@ -61,16 +53,15 @@ class TargetAnnotation extends Annotation { exists(EnumConstant ec | ec = this.getATargetExpression().(VarAccess).getVariable() and ec.getDeclaringType().hasQualifiedName("java.lang.annotation", "ElementType") - | - result = ec.getName()) + | + result = ec.getName() + ) } } /** A `@Retention` annotation. */ class RetentionAnnotation extends Annotation { - RetentionAnnotation() { - this.getType().hasQualifiedName("java.lang.annotation", "Retention") - } + RetentionAnnotation() { this.getType().hasQualifiedName("java.lang.annotation", "Retention") } /** * Gets the retention policy expression within this annotation. @@ -78,9 +69,7 @@ class RetentionAnnotation extends Annotation { * For example, the field access `RetentionPolicy.RUNTIME` is the * retention policy expression in `@Retention(RetentionPolicy.RUNTIME)`. */ - Expr getRetentionPolicyExpression() { - result = this.getValue("value") - } + Expr getRetentionPolicyExpression() { result = this.getValue("value") } /** * Gets the name of the retention policy of this annotation. @@ -92,8 +81,9 @@ class RetentionAnnotation extends Annotation { exists(EnumConstant ec | ec = this.getRetentionPolicyExpression().(VarAccess).getVariable() and ec.getDeclaringType().hasQualifiedName("java.lang.annotation", "RetentionPolicy") - | - result = ec.getName()) + | + result = ec.getName() + ) } } @@ -122,7 +112,7 @@ class ReflectiveAccessAnnotation extends Annotation { * Any annotation that is not a subclass of `NonReflectiveAnnotation` is assumed to * allow for reflective access. */ -abstract class NonReflectiveAnnotation extends Annotation {} +abstract class NonReflectiveAnnotation extends Annotation { } library class StandardNonReflectiveAnnotation extends NonReflectiveAnnotation { StandardNonReflectiveAnnotation() { diff --git a/java/ql/src/semmle/code/java/JMX.qll b/java/ql/src/semmle/code/java/JMX.qll index d8693eab35b..3bb391eeda3 100644 --- a/java/ql/src/semmle/code/java/JMX.qll +++ b/java/ql/src/semmle/code/java/JMX.qll @@ -5,15 +5,10 @@ import Type /** A managed bean. */ -abstract class ManagedBean extends Interface { -} +abstract class ManagedBean extends Interface { } /** An `MBean`. */ -class MBean extends ManagedBean { - MBean() { - this.getQualifiedName().matches("%MBean%") - } -} +class MBean extends ManagedBean { MBean() { this.getQualifiedName().matches("%MBean%") } } /** An `MXBean`. */ class MXBean extends ManagedBean { @@ -30,26 +25,20 @@ class MXBean extends ManagedBean { class RegisteredManagedBeanImpl extends Class { RegisteredManagedBeanImpl() { getAnAncestor() instanceof ManagedBean and - exists(JMXRegistrationCall registerCall | - registerCall.getObjectArgument().getType() = this - ) + exists(JMXRegistrationCall registerCall | registerCall.getObjectArgument().getType() = this) } /** * Gets a managed bean that this registered bean class implements. */ - ManagedBean getAnImplementedManagedBean() { - result = getAnAncestor() - } + ManagedBean getAnImplementedManagedBean() { result = getAnAncestor() } } /** * A call that registers an object with the `MBeanServer`, directly or indirectly. */ class JMXRegistrationCall extends MethodAccess { - JMXRegistrationCall() { - getCallee() instanceof JMXRegistrationMethod - } + JMXRegistrationCall() { getCallee() instanceof JMXRegistrationMethod } /** * Gets the argument that represents the object in the registration call. @@ -71,16 +60,19 @@ class JMXRegistrationMethod extends Method { // A direct registration with the `MBeanServer`. getDeclaringType().hasQualifiedName("javax.management", "MBeanServer") and getName() = "registerMBean" - ) or + ) + or /* * The `MBeanServer` is often wrapped by an application specific management class, so identify * methods that wrap a call to another `JMXRegistrationMethod`. */ + exists(JMXRegistrationCall c | /* * This must be a call to another JMX registration method, where the object argument is an access * of one of the parameters of this method. */ + c.getObjectArgument().(VarAccess).getVariable() = getAParameter() ) } @@ -94,7 +86,8 @@ class JMXRegistrationMethod extends Method { getDeclaringType().hasQualifiedName("javax.management", "MBeanServer") and getName() = "registerMBean" and result = 0 - ) or + ) + or // Identify the position in this method where the object parameter should be passed. exists(JMXRegistrationCall c | c.getObjectArgument().(VarAccess).getVariable() = getParameter(result) diff --git a/java/ql/src/semmle/code/java/Javadoc.qll b/java/ql/src/semmle/code/java/Javadoc.qll index 8cab8a615d0..26d1bba3f93 100755 --- a/java/ql/src/semmle/code/java/Javadoc.qll +++ b/java/ql/src/semmle/code/java/Javadoc.qll @@ -11,64 +11,43 @@ class JavadocParent extends @javadocParent, Top { JavadocElement getAChild() { result.getParent() = this } /** Gets the child documentation element at the specified (zero-based) position. */ - JavadocElement getChild(int index) { - result = this.getAChild() and result.getIndex() = index - } + JavadocElement getChild(int index) { result = this.getAChild() and result.getIndex() = index } /** Gets the number of documentation elements attached to this parent. */ - int getNumChild() { - result = count(getAChild()) - } + int getNumChild() { result = count(getAChild()) } /** Gets a documentation element with the specified Javadoc tag name. */ - JavadocTag getATag(string name) { - result = this.getAChild() and result.getTagName() = name - } + JavadocTag getATag(string name) { result = this.getAChild() and result.getTagName() = name } /*abstract*/ override string toString() { result = "Javadoc" } } /** A Javadoc comment. */ class Javadoc extends JavadocParent, @javadoc { - /** Gets the number of lines in this Javadoc comment. */ - int getNumberOfLines() { - result = this.getLocation().getNumberOfCommentLines() - } + int getNumberOfLines() { result = this.getLocation().getNumberOfCommentLines() } /** Gets the value of the `@version` tag, if any. */ - string getVersion() { - result = this.getATag("@version").getChild(0).toString() - } + string getVersion() { result = this.getATag("@version").getChild(0).toString() } /** Gets the value of the `@author` tag, if any. */ - string getAuthor() { - result = this.getATag("@author").getChild(0).toString() - } + string getAuthor() { result = this.getATag("@author").getChild(0).toString() } - override string toString() { - result = toStringPrefix() + getChild(0) + toStringPostfix() - } + override string toString() { result = toStringPrefix() + getChild(0) + toStringPostfix() } private string toStringPrefix() { - if isEolComment(this) then - result = "//" + if isEolComment(this) + then result = "//" else ( - if isNormalComment(this) then - result = "/* " - else - result = "/** " + if isNormalComment(this) then result = "/* " else result = "/** " ) } private string toStringPostfix() { - if isEolComment(this) then - result = "" + if isEolComment(this) + then result = "" else ( - if strictcount(getAChild()) = 1 then - result = " */" - else - result = " ... */" + if strictcount(getAChild()) = 1 then result = " */" else result = " ... */" ) } @@ -79,25 +58,19 @@ class Javadoc extends JavadocParent, @javadoc { /** A documentable element that can have an attached Javadoc comment. */ class Documentable extends Element, @member { /** Gets the Javadoc comment attached to this element. */ - Javadoc getJavadoc() { hasJavadoc(this,result) and not isNormalComment(result) } + Javadoc getJavadoc() { hasJavadoc(this, result) and not isNormalComment(result) } /** Gets the name of the author(s) of this element, if any. */ - string getAuthor() { - result = this.getJavadoc().getAuthor() - } + string getAuthor() { result = this.getJavadoc().getAuthor() } } /** A common super-class for Javadoc elements, which may be either tags or text. */ abstract class JavadocElement extends @javadocElement, Top { /** Gets the parent of this Javadoc element. */ - JavadocParent getParent() { - javadocTag(this,_,result,_) or javadocText(this,_,result,_) - } + JavadocParent getParent() { javadocTag(this, _, result, _) or javadocText(this, _, result, _) } /** Gets the index of this child element relative to its parent. */ - int getIndex() { - javadocTag(this,_,_,result) or javadocText(this,_,_,result) - } + int getIndex() { javadocTag(this, _, _, result) or javadocText(this, _, _, result) } /** Gets a printable representation of this Javadoc element. */ /*abstract*/ override string toString() { result = "Javadoc element" } @@ -109,7 +82,7 @@ abstract class JavadocElement extends @javadocElement, Top { /** A Javadoc tag. */ class JavadocTag extends JavadocElement, JavadocParent, @javadocTag { /** Gets the name of this Javadoc tag. */ - string getTagName() { javadocTag(this,result,_,_) } + string getTagName() { javadocTag(this, result, _, _) } /** Gets a printable representation of this Javadoc tag. */ override string toString() { result = this.getTagName() } @@ -158,12 +131,11 @@ class AuthorTag extends JavadocTag { /** A piece of Javadoc text. */ class JavadocText extends JavadocElement, @javadocText { - /** Gets the Javadoc comment that contains this piece of text. */ Javadoc getJavadoc() { result.getAChild+() = this } /** Gets the text itself. */ - override string getText() { javadocText(this,result,_,_) } + override string getText() { javadocText(this, result, _, _) } /** Gets a printable representation of this Javadoc element. */ override string toString() { result = this.getText() } diff --git a/java/ql/src/semmle/code/java/Maps.qll b/java/ql/src/semmle/code/java/Maps.qll index b259637de22..bba4018e5dd 100644 --- a/java/ql/src/semmle/code/java/Maps.qll +++ b/java/ql/src/semmle/code/java/Maps.qll @@ -6,7 +6,7 @@ class MapType extends RefType { MapType() { exists(ParameterizedInterface coll | coll.getSourceDeclaration().hasQualifiedName("java.util", "Map") - | + | this.hasSupertype*(coll) ) } @@ -28,44 +28,30 @@ class MapType extends RefType { /** A method declared in a map type. */ class MapMethod extends Method { - MapMethod() { - this.getDeclaringType() instanceof MapType - } + MapMethod() { this.getDeclaringType() instanceof MapType } /** Gets the type of keys of the map to which this method belongs. */ - RefType getReceiverKeyType() { - result = this.getDeclaringType().(MapType).getKeyType() - } + RefType getReceiverKeyType() { result = this.getDeclaringType().(MapType).getKeyType() } /** Gets the type of values of the map to which this method belongs. */ - RefType getReceiverValueType() { - result = this.getDeclaringType().(MapType).getValueType() - } + RefType getReceiverValueType() { result = this.getDeclaringType().(MapType).getValueType() } } /** A method that mutates the map it belongs to. */ class MapMutator extends MapMethod { - MapMutator() { - this.getName().regexpMatch("(put.*|remove|clear)") - } + MapMutator() { this.getName().regexpMatch("(put.*|remove|clear)") } } /** The `size` method of `java.util.Map`. */ class MapSizeMethod extends MapMethod { - MapSizeMethod() { - this.hasName("size") and this.hasNoParameters() - } + MapSizeMethod() { this.hasName("size") and this.hasNoParameters() } } /** A method call that mutates a map. */ class MapMutation extends MethodAccess { - MapMutation() { - this.getMethod() instanceof MapMutator - } + MapMutation() { this.getMethod() instanceof MapMutator } - predicate resultIsChecked() { - not this.getParent() instanceof ExprStmt - } + predicate resultIsChecked() { not this.getParent() instanceof ExprStmt } } /** A method that queries the contents of the map it belongs to without mutating it. */ @@ -88,15 +74,9 @@ class FreshMap extends ClassInstanceExpr { * A call to `Map.put(key, value)`. */ class MapPutCall extends MethodAccess { - MapPutCall() { - getCallee().(MapMethod).hasName("put") - } + MapPutCall() { getCallee().(MapMethod).hasName("put") } - Expr getKey() { - result = getArgument(0) - } + Expr getKey() { result = getArgument(0) } - Expr getValue() { - result = getArgument(1) - } + Expr getValue() { result = getArgument(1) } } diff --git a/java/ql/src/semmle/code/java/Member.qll b/java/ql/src/semmle/code/java/Member.qll index 829ce4386ef..f4ae47fbc6f 100755 --- a/java/ql/src/semmle/code/java/Member.qll +++ b/java/ql/src/semmle/code/java/Member.qll @@ -14,17 +14,13 @@ import metrics.MetricField * including methods, constructors, fields, and nested types. */ class Member extends Element, Annotatable, Modifiable, @member { - Member() { - declaresMember(_,this) - } + Member() { declaresMember(_, this) } /** Gets the type in which this member is declared. */ RefType getDeclaringType() { declaresMember(result, this) } /** Gets the qualified name of this member. */ - string getQualifiedName() { - result = getDeclaringType().getName() + "." + getName() - } + string getQualifiedName() { result = getDeclaringType().getName() + "." + getName() } /** Holds if this member is package protected, that is, neither public nor private nor protected. */ predicate isPackageProtected() { @@ -78,16 +74,15 @@ class Callable extends StmtParent, Member, @callable { } private string descriptorUpTo(int n) { - (n = 0 and result = "") or - exists(Parameter p | p = this.getParameter(n-1) | - result = descriptorUpTo(n-1) + p.getType().getTypeDescriptor() + (n = 0 and result = "") + or + exists(Parameter p | p = this.getParameter(n - 1) | + result = descriptorUpTo(n - 1) + p.getType().getTypeDescriptor() ) } /** Holds if this callable calls `target`. */ - predicate calls(Callable target) { - exists(getACallSite(target)) - } + predicate calls(Callable target) { exists(getACallSite(target)) } /** * Holds if this callable calls `target` @@ -109,28 +104,23 @@ class Callable extends StmtParent, Member, @callable { * Holds if this callable calls `target` * using a `super` method call. */ - predicate callsSuper(Method target) { - getACallSite(target) instanceof SuperMethodAccess - } + predicate callsSuper(Method target) { getACallSite(target) instanceof SuperMethodAccess } /** * Holds if this callable calls `c` using * either a `super(...)` constructor call * or a `this(...)` constructor call. */ - predicate callsConstructor(Constructor c) { - this.callsSuperConstructor(c) or this.callsThis(c) - } + predicate callsConstructor(Constructor c) { this.callsSuperConstructor(c) or this.callsThis(c) } /** * Holds if this callable may call the specified callable, * taking overriding into account. */ predicate polyCalls(Callable m) { - this.calls(m) or - exists(Method mSuper, VirtualMethodAccess c | - c.getCaller() = this and c.getMethod() = mSuper - | + this.calls(m) + or + exists(Method mSuper, VirtualMethodAccess c | c.getCaller() = this and c.getMethod() = mSuper | m.(Method).overrides(mSuper) ) } @@ -139,17 +129,13 @@ class Callable extends StmtParent, Member, @callable { * Holds if field `f` may be assigned a value * within the body of this callable. */ - predicate writes(Field f) { - f.getAnAccess().(LValue).getEnclosingCallable() = this - } + predicate writes(Field f) { f.getAnAccess().(LValue).getEnclosingCallable() = this } /** * Holds if field `f` may be read * within the body of this callable. */ - predicate reads(Field f) { - f.getAnAccess().(RValue).getEnclosingCallable() = this - } + predicate reads(Field f) { f.getAnAccess().(RValue).getEnclosingCallable() = this } /** * Holds if field `f` may be either read or written @@ -169,9 +155,7 @@ class Callable extends StmtParent, Member, @callable { predicate hasNoParameters() { not exists(getAParameter()) } /** Gets the number of formal parameters of this callable. */ - int getNumberOfParameters() { - result = count(getAParameter()) - } + int getNumberOfParameters() { result = count(getAParameter()) } /** Gets a formal parameter of this callable. */ Parameter getAParameter() { result.getCallable() = this } @@ -188,9 +172,7 @@ class Callable extends StmtParent, Member, @callable { * * Use `getSignature` to obtain a signature including fully qualified type names. */ - string getStringSignature() { - result = this.getName() + this.paramsString() - } + string getStringSignature() { result = this.getName() + this.paramsString() } /** Gets a parenthesized string containing all parameter types of this callable, separated by a comma. */ pragma[nomagic] @@ -198,7 +180,7 @@ class Callable extends StmtParent, Member, @callable { exists(int n | n = getNumberOfParameters() | n = 0 and result = "()" or - n > 0 and result = "(" + this.paramUpTo(n-1) + ")" + n > 0 and result = "(" + this.paramUpTo(n - 1) + ")" ) } @@ -209,24 +191,20 @@ class Callable extends StmtParent, Member, @callable { private string paramUpTo(int n) { n = 0 and result = getParameterType(0).toString() or - n > 0 and result = paramUpTo(n-1) + ", " + getParameterType(n) + n > 0 and result = paramUpTo(n - 1) + ", " + getParameterType(n) } /** Holds if this callable has the specified string signature. */ - predicate hasStringSignature(string sig) { - sig = this.getStringSignature() - } + predicate hasStringSignature(string sig) { sig = this.getStringSignature() } /** Gets an exception that occurs in the `throws` clause of this callable. */ - Exception getAnException() { exceptions(result,_,this) } + Exception getAnException() { exceptions(result, _, this) } /** Gets an exception type that occurs in the `throws` clause of this callable. */ RefType getAThrownExceptionType() { result = getAnException().getType() } /** Gets a call site that references this callable. */ - Call getAReference() { - result.getCallee() = this - } + Call getAReference() { result.getCallee() = this } /** Gets the body of this callable, if any. */ Block getBody() { result.getParent() = this } @@ -266,11 +244,12 @@ class Callable extends StmtParent, Member, @callable { } /** Holds if method `m1` overrides method `m2`. */ -private -predicate overrides(Method m1, Method m2) { +private predicate overrides(Method m1, Method m2) { exists(RefType t1, RefType t2 | overridesIgnoringAccess(m1, t1, m2, t2) | - m2.isPublic() or - m2.isProtected() or + m2.isPublic() + or + m2.isProtected() + or m2.isPackageProtected() and t1.getPackage() = t2.getPackage() ) } @@ -290,7 +269,7 @@ predicate overridesIgnoringAccess(Method m1, RefType t1, Method m2, RefType t2) } private predicate virtualMethodWithSignature(string sig, RefType t, Method m) { - methods(m,_,_,_,t,_) and + methods(m, _, _, _, t, _) and sig = m.getSignature() and m.isVirtual() } @@ -326,21 +305,20 @@ class Method extends Callable, @method { * source declaration of this method (and not equal to it). */ predicate overridesOrInstantiates(Method m) { - this.overrides(m) or + this.overrides(m) + or this.getSourceDeclaration() = m and this != m } /** Gets a method (directly or transitively) overridden by this method. */ - Method getAnOverride() { - this.overrides+(result) - } + Method getAnOverride() { this.overrides+(result) } /** Gets the source declaration of a method overridden by this method. */ SrcMethod getASourceOverriddenMethod() { exists(Method m | this.overrides(m) and result = m.getSourceDeclaration()) } - override string getSignature() { methods(this,_,result,_,_,_) } + override string getSignature() { methods(this, _, result, _, _, _) } /** * Holds if this method and method `m` are declared in the same type @@ -357,7 +335,7 @@ class Method extends Callable, @method { not exists(int n | this.getParameterType(n) != m.getParameterType(n)) } - override SrcMethod getSourceDeclaration() { methods(this,_,_,_,_,result) } + override SrcMethod getSourceDeclaration() { methods(this, _, _, _, _, result) } /** * All the methods that could possibly be called when this method @@ -372,9 +350,7 @@ class Method extends Callable, @method { this.getSourceDeclaration().getAPossibleImplementationOfSrcMethod() = result } - override MethodAccess getAReference() { - result = Callable.super.getAReference() - } + override MethodAccess getAReference() { result = Callable.super.getAReference() } override predicate isPublic() { Callable.super.isPublic() or @@ -413,9 +389,7 @@ class Method extends Callable, @method { * Holds if this method is neither private nor static, and hence * uses dynamic dispatch. */ - predicate isVirtual() { - not isPrivate() and not isStatic() - } + predicate isVirtual() { not isPrivate() and not isStatic() } /** Holds if this method can be overridden. */ predicate isOverridable() { @@ -427,7 +401,7 @@ class Method extends Callable, @method { /** A method that is the same as its source declaration. */ class SrcMethod extends Method { - SrcMethod() { methods(_,_,_,_,_,this) } + SrcMethod() { methods(_, _, _, _, _, this) } /** * All the methods that could possibly be called when this method @@ -440,10 +414,9 @@ class SrcMethod extends Method { */ SrcMethod getAPossibleImplementationOfSrcMethod() { ( - if this.getDeclaringType() instanceof Interface and this.isVirtual() then - implementsInterfaceMethod(result, this) - else - result.getASourceOverriddenMethod*() = this + if this.getDeclaringType() instanceof Interface and this.isVirtual() + then implementsInterfaceMethod(result, this) + else result.getASourceOverriddenMethod*() = this ) and (exists(result.getBody()) or result.hasModifier("native")) } @@ -462,7 +435,7 @@ class SetterMethod extends Method { this.getNumberOfParameters() = 1 and exists(ExprStmt s, Assignment a | s = this.getBody().(SingletonBlock).getStmt() and a = s.getExpr() - | + | exists(Field f | f.getDeclaringType() = this.getDeclaringType() | a.getDest() = f.getAnAccess() and a.getSource() = this.getAParameter().getAnAccess() @@ -472,9 +445,7 @@ class SetterMethod extends Method { /** Gets the field assigned by this setter method. */ Field getField() { - exists(Assignment a | a.getEnclosingCallable() = this | - a.getDest() = result.getAnAccess() - ) + exists(Assignment a | a.getEnclosingCallable() = this | a.getDest() = result.getAnAccess()) } } @@ -495,9 +466,7 @@ class GetterMethod extends Method { /** Gets the field whose value is returned by this getter method. */ Field getField() { - exists(ReturnStmt r | r.getEnclosingCallable() = this | - r.getResult() = result.getAnAccess() - ) + exists(ReturnStmt r | r.getEnclosingCallable() = this | r.getResult() = result.getAnAccess()) } } @@ -518,9 +487,9 @@ class Constructor extends Callable, @constructor { /** Holds if this is a default constructor, not explicitly declared in source code. */ predicate isDefaultConstructor() { isDefConstr(this) } - override Constructor getSourceDeclaration() { constrs(this,_,_,_,_,result) } + override Constructor getSourceDeclaration() { constrs(this, _, _, _, _, result) } - override string getSignature() { constrs(this,_,result,_,_,_) } + override string getSignature() { constrs(this, _, result, _, _, _) } } /** @@ -528,26 +497,20 @@ class Constructor extends Callable, @constructor { * non-static), which is used to hold (static or non-static) field * initializers, as well as explicit initializer blocks. */ -abstract class InitializerMethod extends Method {} +abstract class InitializerMethod extends Method { } /** * A static initializer is a method that contains all static * field initializations and static initializer blocks. */ -class StaticInitializer extends InitializerMethod { - StaticInitializer() { - hasName("") - } -} +class StaticInitializer extends InitializerMethod { StaticInitializer() { hasName("") } } /** * An instance initializer is a method that contains field initializations * and explicit instance initializer blocks. */ class InstanceInitializer extends InitializerMethod { - InstanceInitializer() { - this.hasName("") - } + InstanceInitializer() { this.hasName("") } } /** A field declaration that declares one or more class or instance fields. */ @@ -565,10 +528,9 @@ class FieldDeclaration extends ExprParent, @fielddecl, Annotatable { int getNumField() { result = max(int idx | fieldDeclaredIn(_, this, idx) | idx) + 1 } override string toString() { - if this.getNumField() = 0 then - result = this.getTypeAccess() + " " + this.getField(0) + ";" - else - result = this.getTypeAccess() + " " + this.getField(0) + ", ...;" + if this.getNumField() = 0 + then result = this.getTypeAccess() + " " + this.getField(0) + ";" + else result = this.getTypeAccess() + " " + this.getField(0) + ", ...;" } } @@ -607,7 +569,7 @@ class Field extends Member, ExprParent, @field, Variable { * * For all other fields, the source declaration is the field itself. */ - Field getSourceDeclaration() { fields(this,_,_,_,result) } + Field getSourceDeclaration() { fields(this, _, _, _, result) } /** Holds if this field is the same as its source declaration. */ predicate isSourceDeclaration() { this.getSourceDeclaration() = this } @@ -638,8 +600,4 @@ class Field extends Member, ExprParent, @field, Variable { } /** An instance field. */ -class InstanceField extends Field { - InstanceField() { - not this.isStatic() - } -} +class InstanceField extends Field { InstanceField() { not this.isStatic() } } diff --git a/java/ql/src/semmle/code/java/Modifier.qll b/java/ql/src/semmle/code/java/Modifier.qll index 73463369e6c..8c48ffb117a 100755 --- a/java/ql/src/semmle/code/java/Modifier.qll +++ b/java/ql/src/semmle/code/java/Modifier.qll @@ -7,7 +7,7 @@ import Element /** A modifier such as `private`, `static` or `abstract`. */ class Modifier extends Element, @modifier { /** Gets the element to which this modifier applies. */ - Element getElement() { hasModifier(result,this) } + Element getElement() { hasModifier(result, this) } } /** An element of the Java syntax tree that may have a modifier. */ @@ -21,12 +21,10 @@ abstract class Modifiable extends Element { * abstract, so `isAbstract()` will hold for them even if `hasModifier("abstract")` * does not. */ - predicate hasModifier(string m) { - modifiers(getAModifier(), m) - } + predicate hasModifier(string m) { modifiers(getAModifier(), m) } /** Holds if this element has no modifier. */ - predicate hasNoModifier() { not hasModifier(this,_) } + predicate hasNoModifier() { not hasModifier(this, _) } /** Gets a modifier of this element. */ Modifier getAModifier() { this = result.getElement() } diff --git a/java/ql/src/semmle/code/java/Modules.qll b/java/ql/src/semmle/code/java/Modules.qll index 61973c3a22c..6c7a1a5f5f1 100755 --- a/java/ql/src/semmle/code/java/Modules.qll +++ b/java/ql/src/semmle/code/java/Modules.qll @@ -8,9 +8,7 @@ import CompilationUnit * A module. */ class Module extends @module { - Module() { - modules(this, _) - } + Module() { modules(this, _) } /** * Gets the name of this module. @@ -50,9 +48,7 @@ abstract class Directive extends @directive { * A `requires` directive in a module declaration. */ class RequiresDirective extends Directive, @requires { - RequiresDirective() { - requires(this,_) - } + RequiresDirective() { requires(this, _) } /** * Holds if this `requires` directive is `transitive`, @@ -75,12 +71,11 @@ class RequiresDirective extends Directive, @requires { */ Module getTargetModule() { requires(this, result) } - override - string toString() { + override string toString() { exists(string transitive, string static | (if isTransitive() then transitive = "transitive " else transitive = "") and (if isStatic() then static = "static " else static = "") - | + | result = "requires " + transitive + static + getTargetModule() + ";" ) } @@ -90,9 +85,7 @@ class RequiresDirective extends Directive, @requires { * An `exports` directive in a module declaration. */ class ExportsDirective extends Directive, @exports { - ExportsDirective() { - exports(this,_) - } + ExportsDirective() { exports(this, _) } /** * Gets the package exported by this `exports` directive. @@ -116,11 +109,12 @@ class ExportsDirective extends Directive, @exports { */ Module getATargetModule() { exportsTo(this, result) } - override - string toString() { + override string toString() { exists(string toClause | - if isQualified() then toClause = (" to " + concat(getATargetModule().getName(), ", ")) else toClause = "" - | + if isQualified() + then toClause = (" to " + concat(getATargetModule().getName(), ", ")) + else toClause = "" + | result = "exports " + getExportedPackage() + toClause + ";" ) } @@ -130,9 +124,7 @@ class ExportsDirective extends Directive, @exports { * An `opens` directive in a module declaration. */ class OpensDirective extends Directive, @opens { - OpensDirective() { - opens(this,_) - } + OpensDirective() { opens(this, _) } /** * Gets the package opened by this `opens` directive. @@ -156,11 +148,12 @@ class OpensDirective extends Directive, @opens { */ Module getATargetModule() { opensTo(this, result) } - override - string toString() { + override string toString() { exists(string toClause | - if isQualified() then toClause = (" to " + concat(getATargetModule().getName(), ", ")) else toClause = "" - | + if isQualified() + then toClause = (" to " + concat(getATargetModule().getName(), ", ")) + else toClause = "" + | result = "opens " + getOpenedPackage() + toClause + ";" ) } @@ -170,28 +163,21 @@ class OpensDirective extends Directive, @opens { * A `uses` directive in a module declaration. */ class UsesDirective extends Directive, @uses { - UsesDirective() { - uses(this,_) - } + UsesDirective() { uses(this, _) } /** * Gets the qualified name of the service interface specified in this `uses` directive. */ string getServiceInterfaceName() { uses(this, result) } - override - string toString() { - result = "uses " + getServiceInterfaceName() + ";" - } + override string toString() { result = "uses " + getServiceInterfaceName() + ";" } } /** * A `provides` directive in a module declaration. */ class ProvidesDirective extends Directive, @provides { - ProvidesDirective() { - provides(this,_) - } + ProvidesDirective() { provides(this, _) } /** * Gets the qualified name of the service interface specified in this `provides` directive. @@ -203,9 +189,8 @@ class ProvidesDirective extends Directive, @provides { */ string getServiceImplementationName() { providesWith(this, result) } - override - string toString() { - result = "provides " + getServiceInterfaceName() + " with " + concat(getServiceImplementationName(), ", ") + ";" + override string toString() { + result = "provides " + getServiceInterfaceName() + " with " + + concat(getServiceImplementationName(), ", ") + ";" } } - diff --git a/java/ql/src/semmle/code/java/Package.qll b/java/ql/src/semmle/code/java/Package.qll index ae21a688d3b..6cb41ca559f 100755 --- a/java/ql/src/semmle/code/java/Package.qll +++ b/java/ql/src/semmle/code/java/Package.qll @@ -15,9 +15,7 @@ class Package extends Element, Annotatable, @package { TopLevelType getATopLevelType() { result.getPackage() = this } /** Holds if at least one reference type in this package originates from source code. */ - override predicate fromSource() { - exists(RefType t | t.fromSource() and t.getPackage() = this) - } + override predicate fromSource() { exists(RefType t | t.fromSource() and t.getPackage() = this) } /** Cast this package to a class that provides access to metrics information. */ MetricPackage getMetrics() { result = this } diff --git a/java/ql/src/semmle/code/java/Reflection.qll b/java/ql/src/semmle/code/java/Reflection.qll index 700ca69dd1e..db479119fa1 100644 --- a/java/ql/src/semmle/code/java/Reflection.qll +++ b/java/ql/src/semmle/code/java/Reflection.qll @@ -7,13 +7,13 @@ import JDKAnnotations import Serializability import semmle.code.java.dataflow.DefUse -predicate reflectivelyRead(Field f){ +predicate reflectivelyRead(Field f) { f instanceof SerializableField or f.getAnAnnotation() instanceof ReflectiveAccessAnnotation or referencedInXmlFile(f) } -predicate reflectivelyWritten(Field f){ +predicate reflectivelyWritten(Field f) { f instanceof DeserializableField or f.getAnAnnotation() instanceof ReflectiveAccessAnnotation or referencedInXmlFile(f) @@ -44,7 +44,7 @@ private XMLElement elementReferencingType(RefType rt) { result.getAnAttribute().getValue() = rt.getSourceDeclaration().getQualifiedName() } -private abstract class ReflectiveClassIdentifier extends Expr { +abstract private class ReflectiveClassIdentifier extends Expr { abstract RefType getReflectivelyIdentifiedClass(); } @@ -60,17 +60,17 @@ private class ReflectiveClassIdentifierLiteral extends ReflectiveClassIdentifier library class ReflectiveClassIdentifierMethodAccess extends ReflectiveClassIdentifier, MethodAccess { ReflectiveClassIdentifierMethodAccess() { // A call to `Class.forName(...)`, from which we can infer `T` in the returned type `Class`. - getCallee().getDeclaringType() instanceof TypeClass and getCallee().hasName("forName") or + getCallee().getDeclaringType() instanceof TypeClass and getCallee().hasName("forName") + or // A call to `ClassLoader.loadClass(...)`, from which we can infer `T` in the returned type `Class`. - getCallee().getDeclaringType().hasQualifiedName("java.lang", "ClassLoader") and getCallee().hasName("loadClass") + getCallee().getDeclaringType().hasQualifiedName("java.lang", "ClassLoader") and + getCallee().hasName("loadClass") } /** * If the argument to this call is a `StringLiteral`, then return that string. */ - string getTypeName() { - result = getArgument(0).(StringLiteral).getRepresentedString() - } + string getTypeName() { result = getArgument(0).(StringLiteral).getRepresentedString() } override RefType getReflectivelyIdentifiedClass() { // We only handle cases where the class is specified as a string literal to this call. @@ -82,16 +82,17 @@ library class ReflectiveClassIdentifierMethodAccess extends ReflectiveClassIdent * Gets a `ReflectiveClassIdentifier` that we believe may represent the value of `expr`. */ private ReflectiveClassIdentifier pointsToReflectiveClassIdentifier(Expr expr) { - // If this is an expression creating a `Class`, return the inferred `T` from the creation expression. - result = expr or - // Or if this is an access of a variable which was defined as an expression creating a `Class`, - // return the inferred `T` from the definition expression. - exists(RValue use, VariableAssign assign | - use = expr and - defUsePair(assign, use) and - // The source of the assignment must be a `ReflectiveClassIdentifier`. - result = assign.getSource() - ) + // If this is an expression creating a `Class`, return the inferred `T` from the creation expression. + result = expr + or + // Or if this is an access of a variable which was defined as an expression creating a `Class`, + // return the inferred `T` from the definition expression. + exists(RValue use, VariableAssign assign | + use = expr and + defUsePair(assign, use) and + // The source of the assignment must be a `ReflectiveClassIdentifier`. + result = assign.getSource() + ) } /** @@ -107,11 +108,7 @@ private predicate overlyGenericType(Type type) { * `? extends Object` and `? extends Serializable`. */ private predicate catchallType(BoundedType type) { - exists(Type upperBound | - upperBound = type.getUpperBoundType() - | - overlyGenericType(upperBound) - ) + exists(Type upperBound | upperBound = type.getUpperBoundType() | overlyGenericType(upperBound)) } /** @@ -123,9 +120,7 @@ private predicate catchallType(BoundedType type) { */ pragma[nomagic] private Type parameterForSubTypes(ParameterizedType type) { - ( - type instanceof TypeClass or type instanceof TypeConstructor - ) and + (type instanceof TypeClass or type instanceof TypeConstructor) and // Only report "real" types. not result instanceof TypeVariable and // Identify which types the type argument `arg` could represent. @@ -133,27 +128,31 @@ private Type parameterForSubTypes(ParameterizedType type) { arg = type.getTypeArgument(0) and // 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 - ) or + ) + or exists(RefType upperBound | // Upper bound case upperBound = arg.(BoundedType).getUpperBoundType() - | + | /* * `T extends Foo` implies that `Foo`, or any sub-type of `Foo`, may be represented. */ + result.(RefType).getAnAncestor() = upperBound - ) or + ) + or exists(RefType lowerBound | // Lower bound case lowerBound = arg.(Wildcard).getLowerBoundType() - | + | /* * `T super Foo` implies that `Foo`, or any super-type of `Foo`, may be represented. */ + lowerBound.(RefType).getAnAncestor() = result ) ) @@ -170,21 +169,23 @@ Type inferClassParameterType(Expr expr) { * If this `expr` is a `VarAccess` of a final or effectively final parameter, then look at the * arguments to calls to this method, to see if we can infer anything from that case. */ + exists(Parameter p | p = expr.(VarAccess).getVariable() and p.isEffectivelyFinal() - | + | result = inferClassParameterType(p.getAnArgument()) ) or - if exists(pointsToReflectiveClassIdentifier(expr).getReflectivelyIdentifiedClass()) then + if exists(pointsToReflectiveClassIdentifier(expr).getReflectivelyIdentifiedClass()) + then /* * 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`. @@ -195,6 +196,7 @@ 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()) ) ) @@ -224,7 +226,10 @@ private predicate expectsEnclosingInstance(RefType r) { */ class NewInstance extends MethodAccess { NewInstance() { - (getCallee().getDeclaringType() instanceof TypeClass or getCallee().getDeclaringType() instanceof TypeConstructor) and + ( + getCallee().getDeclaringType() instanceof TypeClass or + getCallee().getDeclaringType() instanceof TypeConstructor + ) and getCallee().hasName("newInstance") } @@ -234,25 +239,31 @@ class NewInstance extends MethodAccess { */ Constructor getInferredConstructor() { result = getInferredConstructedType().getAConstructor() and - if getCallee().getDeclaringType() instanceof TypeClass then - result.getNumberOfParameters() = 0 - else if getNumArgument() = 1 and getArgument(0).getType() instanceof Array then - /* - * This is a var-args array argument. If array argument is initialized inline, then identify - * the number of arguments specified in the array. - */ - if exists(getArgument(0).(ArrayCreationExpr).getInit()) then - // Count the number of elements in the initializer, and find the matching constructors. - matchConstructorArguments(result, count(getArgument(0).(ArrayCreationExpr).getInit().getAnInit())) - else - // Could be any of the constructors on this class. - any() + if getCallee().getDeclaringType() instanceof TypeClass + then result.getNumberOfParameters() = 0 else - /* - * No var-args in play, just use the number of arguments to the `newInstance(..)` to determine - * which constructors may be called. - */ - matchConstructorArguments(result, getNumArgument()) + if getNumArgument() = 1 and getArgument(0).getType() instanceof Array + then + /* + * This is a var-args array argument. If array argument is initialized inline, then identify + * the number of arguments specified in the array. + */ + + if exists(getArgument(0).(ArrayCreationExpr).getInit()) + then + // Count the number of elements in the initializer, and find the matching constructors. + matchConstructorArguments(result, + count(getArgument(0).(ArrayCreationExpr).getInit().getAnInit())) + else + // Could be any of the constructors on this class. + any() + else + /* + * No var-args in play, just use the number of arguments to the `newInstance(..)` to determine + * which constructors may be called. + */ + + matchConstructorArguments(result, getNumArgument()) } /** @@ -263,10 +274,9 @@ class NewInstance extends MethodAccess { * provided for the enclosing instance. */ private predicate matchConstructorArguments(Constructor c, int numArguments) { - if expectsEnclosingInstance(c.getDeclaringType()) then - c.getNumberOfParameters() = numArguments - 1 - else - c.getNumberOfParameters() = numArguments + if expectsEnclosingInstance(c.getDeclaringType()) + then c.getNumberOfParameters() = numArguments - 1 + else c.getNumberOfParameters() = numArguments } /** @@ -296,15 +306,15 @@ class NewInstance extends MethodAccess { * cast. */ private Type getCastInferredConstructedTypes() { - exists(CastExpr cast | - cast.getExpr() = this or cast.getExpr().(ParExpr).getExpr() = this - | - result = cast.getType() or + 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) ) @@ -316,9 +326,7 @@ class NewInstance extends MethodAccess { * A `MethodAccess` on a `Class` element. */ class ClassMethodAccess extends MethodAccess { - ClassMethodAccess() { - this.getCallee().getDeclaringType() instanceof TypeClass - } + ClassMethodAccess() { this.getCallee().getDeclaringType() instanceof TypeClass } /** * Gets an inferred type for the `Class` represented by this expression. @@ -345,14 +353,14 @@ class ReflectiveMethodAccess extends ClassMethodAccess { */ Method inferAccessedMethod() { ( - if this.getCallee().hasName("getDeclaredMethod") then + if this.getCallee().hasName("getDeclaredMethod") + then // The method must be declared on the type itself. result.getDeclaringType() = getInferredClassType() else // The method may be declared on an inferred type or a super-type. getInferredClassType().inherits(result) - ) - and + ) and // Only consider instances where the method name is provided as a `StringLiteral`. result.hasName(getArgument(0).(StringLiteral).getRepresentedString()) } @@ -362,16 +370,12 @@ class ReflectiveMethodAccess extends ClassMethodAccess { * A call to `Class.getAnnotation(..)`. */ class ReflectiveAnnotationAccess extends ClassMethodAccess { - ReflectiveAnnotationAccess() { - this.getCallee().hasName("getAnnotation") - } + ReflectiveAnnotationAccess() { this.getCallee().hasName("getAnnotation") } /** * Gets a possible annotation type for this reflective annotation access. */ - AnnotationType getAPossibleAnnotationType() { - result = inferClassParameterType(getArgument(0)) - } + AnnotationType getAPossibleAnnotationType() { result = inferClassParameterType(getArgument(0)) } } /** @@ -385,15 +389,15 @@ class ReflectiveFieldAccess extends ClassMethodAccess { Field inferAccessedField() { ( - if this.getCallee().hasName("getDeclaredField") then + if this.getCallee().hasName("getDeclaredField") + then // Declared fields must be on the type itself. result.getDeclaringType() = getInferredClassType() - else - ( - // This field must be public, and be inherited by one of the inferred class types. - result.isPublic() and - getInferredClassType().inherits(result) - ) + else ( + // This field must be public, and be inherited by one of the inferred class types. + result.isPublic() and + getInferredClassType().inherits(result) + ) ) and result.hasName(getArgument(0).(StringLiteral).getRepresentedString()) } diff --git a/java/ql/src/semmle/code/java/Serializability.qll b/java/ql/src/semmle/code/java/Serializability.qll index 508ef67bad8..339d6bb3c30 100644 --- a/java/ql/src/semmle/code/java/Serializability.qll +++ b/java/ql/src/semmle/code/java/Serializability.qll @@ -10,16 +10,13 @@ private import frameworks.google.GoogleHttpClientApi * A serializable field may be read without code referencing it, * due to the use of serialization. */ -abstract class SerializableField extends Field { +abstract class SerializableField extends Field { } -} /** * A deserializable field may be written without code referencing it, * due to the use of serialization. */ -abstract class DeserializableField extends Field { - -} +abstract class DeserializableField extends Field { } /** * A non-`transient` field in a type that (directly or indirectly) implements the `Serializable` interface diff --git a/java/ql/src/semmle/code/java/Statement.qll b/java/ql/src/semmle/code/java/Statement.qll index cc17f35e4eb..1b36765b065 100755 --- a/java/ql/src/semmle/code/java/Statement.qll +++ b/java/ql/src/semmle/code/java/Statement.qll @@ -16,13 +16,13 @@ class Stmt extends StmtParent, ExprParent, @stmt { * Gets the immediately enclosing callable (method or constructor) * whose body contains this statement. */ - Callable getEnclosingCallable() { stmts(this,_,_,_,result) } + Callable getEnclosingCallable() { stmts(this, _, _, _, result) } /** Gets the index of this statement as a child of its parent. */ - int getIndex() { stmts(this,_,_,result,_) } + int getIndex() { stmts(this, _, _, result, _) } /** Gets the parent of this statement. */ - StmtParent getParent() { stmts(this,_,result,_,_) } + StmtParent getParent() { stmts(this, _, result, _, _) } /** Holds if this statement is the child of the specified parent at the specified (zero-based) position. */ predicate isNthChildOf(StmtParent parent, int index) { @@ -49,11 +49,10 @@ class Stmt extends StmtParent, ExprParent, @stmt { } /** A statement parent is any element that can have a statement as its child. */ -class StmtParent extends @stmtparent, Top { -} +class StmtParent extends @stmtparent, Top { } /** A block of statements. */ -class Block extends Stmt,@block { +class Block extends Stmt, @block { /** Gets a statement that is an immediate child of this block. */ Stmt getAStmt() { result.getParent() = this } @@ -64,7 +63,7 @@ class Block extends Stmt,@block { int getNumStmt() { result = count(this.getAStmt()) } /** Gets the last statement in this block. */ - Stmt getLastStmt() { result = getStmt(getNumStmt()-1) } + Stmt getLastStmt() { result = getStmt(getNumStmt() - 1) } /** Gets a printable representation of this statement. May include more detail than `toString()`. */ override string pp() { result = "{ ... }" } @@ -95,11 +94,11 @@ abstract class ConditionalStmt extends Stmt { * * DEPRECATED: use `ConditionNode.getATrueSuccessor()` instead. */ - deprecated abstract Stmt getTrueSuccessor(); + abstract deprecated Stmt getTrueSuccessor(); } /** An `if` statement. */ -class IfStmt extends ConditionalStmt,@ifstmt { +class IfStmt extends ConditionalStmt, @ifstmt { /** Gets the boolean condition of this `if` statement. */ override Expr getCondition() { result.isNthChildOf(this, 0) } @@ -127,16 +126,14 @@ class IfStmt extends ConditionalStmt,@ifstmt { } /** A `for` loop. */ -class ForStmt extends ConditionalStmt,@forstmt { +class ForStmt extends ConditionalStmt, @forstmt { /** * Gets an initializer expression of the loop. * * This may be an assignment expression or a * local variable declaration expression. */ - Expr getAnInit() { - exists(int index | result.isNthChildOf(this, index) | index <= -1) - } + Expr getAnInit() { exists(int index | result.isNthChildOf(this, index) | index <= -1) } /** Gets the initializer expression of the loop at the specified (zero-based) position. */ Expr getInit(int index) { @@ -148,9 +145,7 @@ class ForStmt extends ConditionalStmt,@forstmt { override Expr getCondition() { result.isNthChildOf(this, 1) } /** Gets an update expression of this `for` loop. */ - Expr getAnUpdate() { - exists(int index | result.isNthChildOf(this, index) | index >= 3) - } + Expr getAnUpdate() { exists(int index | result.isNthChildOf(this, index) | index >= 3) } /** Gets the update expression of this loop at the specified (zero-based) position. */ Expr getUpdate(int index) { @@ -189,16 +184,14 @@ class ForStmt extends ConditionalStmt,@forstmt { } /** Gets a printable representation of this statement. May include more detail than `toString()`. */ - override string pp() { - result = "for (...;...;...) " + this.getStmt().pp() - } + override string pp() { result = "for (...;...;...) " + this.getStmt().pp() } /** This statement's Halstead ID (used to compute Halstead metrics). */ override string getHalsteadID() { result = "ForStmt" } } /** An enhanced `for` loop. (Introduced in Java 5.) */ -class EnhancedForStmt extends Stmt,@enhancedforstmt { +class EnhancedForStmt extends Stmt, @enhancedforstmt { /** Gets the local variable declaration expression of this enhanced `for` loop. */ LocalVariableDeclExpr getVariable() { result.getParent() = this } @@ -209,16 +202,14 @@ class EnhancedForStmt extends Stmt,@enhancedforstmt { Stmt getStmt() { result.getParent() = this } /** Gets a printable representation of this statement. May include more detail than `toString()`. */ - override string pp() { - result = "for (...) " + this.getStmt().pp() - } + override string pp() { result = "for (...) " + this.getStmt().pp() } /** This statement's Halstead ID (used to compute Halstead metrics). */ override string getHalsteadID() { result = "EnhancedForStmt" } } /** A `while` loop. */ -class WhileStmt extends ConditionalStmt,@whilestmt { +class WhileStmt extends ConditionalStmt, @whilestmt { /** Gets the boolean condition of this `while` loop. */ override Expr getCondition() { result.getParent() = this } @@ -232,16 +223,14 @@ class WhileStmt extends ConditionalStmt,@whilestmt { override Stmt getTrueSuccessor() { result = getStmt() } /** Gets a printable representation of this statement. May include more detail than `toString()`. */ - override string pp() { - result = "while (...) " + this.getStmt().pp() - } + override string pp() { result = "while (...) " + this.getStmt().pp() } /** This statement's Halstead ID (used to compute Halstead metrics). */ override string getHalsteadID() { result = "WhileStmt" } } /** A `do` loop. */ -class DoStmt extends ConditionalStmt,@dostmt { +class DoStmt extends ConditionalStmt, @dostmt { /** Gets the condition of this `do` loop. */ override Expr getCondition() { result.getParent() = this } @@ -255,9 +244,7 @@ class DoStmt extends ConditionalStmt,@dostmt { override Stmt getTrueSuccessor() { result = getStmt() } /** Gets a printable representation of this statement. May include more detail than `toString()`. */ - override string pp() { - result = "do " + this.getStmt().pp() + " while (...)" - } + override string pp() { result = "do " + this.getStmt().pp() + " while (...)" } /** This statement's Halstead ID (used to compute Halstead metrics). */ override string getHalsteadID() { result = "DoStmt" } @@ -292,7 +279,7 @@ class LoopStmt extends Stmt { } /** A `try` statement. */ -class TryStmt extends Stmt,@trystmt { +class TryStmt extends Stmt, @trystmt { /** Gets the block of the `try` statement. */ Stmt getBlock() { result.isNthChildOf(this, -1) } @@ -312,9 +299,7 @@ class TryStmt extends Stmt,@trystmt { Block getFinally() { result.isNthChildOf(this, -2) } /** Gets a resource variable declaration, if any. */ - LocalVariableDeclStmt getAResourceDecl() { - result.getParent() = this and result.getIndex() <= -3 - } + LocalVariableDeclStmt getAResourceDecl() { result.getParent() = this and result.getIndex() <= -3 } /** Gets the resource variable declaration at the specified position in this `try` statement. */ LocalVariableDeclStmt getResourceDecl(int index) { @@ -323,9 +308,7 @@ class TryStmt extends Stmt,@trystmt { } /** Gets a resource expression, if any. */ - VarAccess getAResourceExpr() { - result.getParent() = this and result.getIndex() <= -3 - } + VarAccess getAResourceExpr() { result.getParent() = this and result.getIndex() <= -3 } /** Gets the resource expression at the specified position in this `try` statement. */ VarAccess getResourceExpr(int index) { @@ -334,9 +317,7 @@ class TryStmt extends Stmt,@trystmt { } /** Gets a resource in this `try` statement, if any. */ - ExprParent getAResource() { - result = getAResourceDecl() or result = getAResourceExpr() - } + ExprParent getAResource() { result = getAResourceDecl() or result = getAResourceExpr() } /** Gets the resource at the specified position in this `try` statement. */ ExprParent getResource(int index) { @@ -350,16 +331,14 @@ class TryStmt extends Stmt,@trystmt { } /** Gets a printable representation of this statement. May include more detail than `toString()`. */ - override string pp() { - result = "try " + this.getBlock().pp() + " catch (...)" - } + override string pp() { result = "try " + this.getBlock().pp() + " catch (...)" } /** This statement's Halstead ID (used to compute Halstead metrics). */ override string getHalsteadID() { result = "TryStmt" } } /** A `catch` clause in a `try` statement. */ -class CatchClause extends Stmt,@catchclause { +class CatchClause extends Stmt, @catchclause { /** Gets the block of this `catch` clause. */ Block getBlock() { result.getParent() = this } @@ -370,9 +349,7 @@ class CatchClause extends Stmt,@catchclause { LocalVariableDeclExpr getVariable() { result.getParent() = this } /** Holds if this `catch` clause is a _multi_-`catch` clause. */ - predicate isMultiCatch() { - this.getVariable().getTypeAccess() instanceof UnionTypeAccess - } + predicate isMultiCatch() { this.getVariable().getTypeAccess() instanceof UnionTypeAccess } /** Gets a type caught by this `catch` clause. */ RefType getACaughtType() { @@ -383,16 +360,14 @@ class CatchClause extends Stmt,@catchclause { } /** Gets a printable representation of this statement. May include more detail than `toString()`. */ - override string pp() { - result = "catch (...) " + this.getBlock().pp() - } + override string pp() { result = "catch (...) " + this.getBlock().pp() } /** This statement's Halstead ID (used to compute Halstead metrics). */ override string getHalsteadID() { result = "CatchClause" } } /** A `switch` statement. */ -class SwitchStmt extends Stmt,@switchstmt { +class SwitchStmt extends Stmt, @switchstmt { /** Gets an immediate child statement of this `switch` statement. */ Stmt getAStmt() { result.getParent() = this } @@ -418,9 +393,7 @@ class SwitchStmt extends Stmt,@switchstmt { Expr getExpr() { result.getParent() = this } /** Gets a printable representation of this statement. May include more detail than `toString()`. */ - override string pp() { - result = "switch (...)" - } + override string pp() { result = "switch (...)" } /** This statement's Halstead ID (used to compute Halstead metrics). */ override string getHalsteadID() { result = "SwitchStmt" } @@ -431,9 +404,7 @@ class SwitchStmt extends Stmt,@switchstmt { * * This includes both normal `case`s and the `default` case. */ -class SwitchCase extends Stmt, @case { - SwitchStmt getSwitch() { result.getACase() = this } -} +class SwitchCase extends Stmt, @case { SwitchStmt getSwitch() { result.getACase() = this } } /** A constant `case` of a switch statement. */ class ConstCase extends SwitchCase { @@ -443,9 +414,7 @@ class ConstCase extends SwitchCase { Expr getValue() { result.getParent() = this } /** Gets a printable representation of this statement. May include more detail than `toString()`. */ - override string pp() { - result = "case ...:" - } + override string pp() { result = "case ...:" } /** This statement's Halstead ID (used to compute Halstead metrics). */ override string getHalsteadID() { result = "ConstCase" } @@ -456,16 +425,14 @@ class DefaultCase extends SwitchCase { DefaultCase() { not exists(Expr e | e.getParent() = this) } /** Gets a printable representation of this statement. May include more detail than `toString()`. */ - override string pp() { - result = "default" - } + override string pp() { result = "default" } /** This statement's Halstead ID (used to compute Halstead metrics). */ override string getHalsteadID() { result = "DefaultCase" } } /** A `synchronized` statement. */ -class SynchronizedStmt extends Stmt,@synchronizedstmt { +class SynchronizedStmt extends Stmt, @synchronizedstmt { /** Gets the expression on which this `synchronized` statement synchronizes. */ Expr getExpr() { result.getParent() = this } @@ -473,37 +440,31 @@ class SynchronizedStmt extends Stmt,@synchronizedstmt { Stmt getBlock() { result.getParent() = this } /** Gets a printable representation of this statement. May include more detail than `toString()`. */ - override string pp() { - result = "synchronized (...) " + this.getBlock().pp() - } + override string pp() { result = "synchronized (...) " + this.getBlock().pp() } /** This statement's Halstead ID (used to compute Halstead metrics). */ override string getHalsteadID() { result = "SynchronizedStmt" } } /** A `return` statement. */ -class ReturnStmt extends Stmt,@returnstmt { +class ReturnStmt extends Stmt, @returnstmt { /** Gets the expression returned by this `return` statement, if any. */ Expr getResult() { result.getParent() = this } /** Gets a printable representation of this statement. May include more detail than `toString()`. */ - override string pp() { - result = "return ..." - } + override string pp() { result = "return ..." } /** This statement's Halstead ID (used to compute Halstead metrics). */ override string getHalsteadID() { result = "ReturnStmt" } } /** A `throw` statement. */ -class ThrowStmt extends Stmt,@throwstmt { +class ThrowStmt extends Stmt, @throwstmt { /** Gets the expression thrown by this `throw` statement. */ Expr getExpr() { result.getParent() = this } /** Gets a printable representation of this statement. May include more detail than `toString()`. */ - override string pp() { - result = "throw ..." - } + override string pp() { result = "throw ..." } /** This statement's Halstead ID (used to compute Halstead metrics). */ override string getHalsteadID() { result = "ThrowStmt" } @@ -522,10 +483,11 @@ class ThrowStmt extends Stmt,@throwstmt { } private Stmt findEnclosing() { - result = getParent() or + result = getParent() + or exists(Stmt mid | mid = findEnclosing() and - not exists(this.catchClauseForThis((TryStmt)mid)) and + not exists(this.catchClauseForThis(mid.(TryStmt))) and result = mid.getParent() ) } @@ -533,7 +495,7 @@ class ThrowStmt extends Stmt,@throwstmt { private CatchClause catchClauseForThis(TryStmt try) { result = try.getACatchClause() and result.getEnclosingCallable() = this.getEnclosingCallable() and - ((RefType)getExpr().getType()).hasSupertype*((RefType)result.getVariable().getType()) and + (getExpr().getType().(RefType)).hasSupertype*(result.getVariable().getType().(RefType)) and not this.getParent+() = result } } @@ -554,14 +516,13 @@ class JumpStmt extends Stmt { namestrings(result.getLabel(), _, this) } - private Stmt getLabelTarget() { - result = getTargetLabel().getStmt() - } + private Stmt getLabelTarget() { result = getTargetLabel().getStmt() } private Stmt getAPotentialTarget() { this.getParent+() = result and ( - result instanceof LoopStmt or + result instanceof LoopStmt + or this instanceof BreakStmt and result instanceof SwitchStmt ) } @@ -575,25 +536,23 @@ class JumpStmt extends Stmt { * Gets the statement that this `break` or `continue` jumps to. */ Stmt getTarget() { - result = getLabelTarget() or + result = getLabelTarget() + or (not exists(getLabelTarget()) and result = getEnclosingTarget()) } } /** A `break` statement. */ -class BreakStmt extends Stmt,@breakstmt { +class BreakStmt extends Stmt, @breakstmt { /** Gets the label targeted by this `break` statement, if any. */ - string getLabel() { namestrings(result,_,this) } + string getLabel() { namestrings(result, _, this) } /** Holds if this `break` statement has an explicit label. */ predicate hasLabel() { exists(string s | s = this.getLabel()) } /** Gets a printable representation of this statement. May include more detail than `toString()`. */ override string pp() { - if this.hasLabel() then - result = "break " + this.getLabel() - else - result = "break" + if this.hasLabel() then result = "break " + this.getLabel() else result = "break" } /** This statement's Halstead ID (used to compute Halstead metrics). */ @@ -601,19 +560,16 @@ class BreakStmt extends Stmt,@breakstmt { } /** A `continue` statement. */ -class ContinueStmt extends Stmt,@continuestmt { +class ContinueStmt extends Stmt, @continuestmt { /** Gets the label targeted by this `continue` statement, if any. */ - string getLabel() { namestrings(result,_,this) } + string getLabel() { namestrings(result, _, this) } /** Holds if this `continue` statement has an explicit label. */ predicate hasLabel() { exists(string s | s = this.getLabel()) } /** Gets a printable representation of this statement. May include more detail than `toString()`. */ override string pp() { - if this.hasLabel() then - result = "continue " + this.getLabel() - else - result = "continue" + if this.hasLabel() then result = "continue " + this.getLabel() else result = "continue" } /** This statement's Halstead ID (used to compute Halstead metrics). */ @@ -621,11 +577,9 @@ class ContinueStmt extends Stmt,@continuestmt { } /** The empty statement. */ -class EmptyStmt extends Stmt,@emptystmt { +class EmptyStmt extends Stmt, @emptystmt { /** Gets a printable representation of this statement. May include more detail than `toString()`. */ - override string pp() { - result = ";" - } + override string pp() { result = ";" } /** This statement's Halstead ID (used to compute Halstead metrics). */ override string getHalsteadID() { result = "EmptyStmt" } @@ -636,14 +590,12 @@ class EmptyStmt extends Stmt,@emptystmt { * * Certain kinds of expressions may be used as statements by appending a semicolon. */ -class ExprStmt extends Stmt,@exprstmt { +class ExprStmt extends Stmt, @exprstmt { /** Gets the expression of this expression statement. */ Expr getExpr() { result.getParent() = this } /** Gets a printable representation of this statement. May include more detail than `toString()`. */ - override string pp() { - result = "...;" - } + override string pp() { result = "...;" } /** This statement's Halstead ID (used to compute Halstead metrics). */ override string getHalsteadID() { result = "ExprStmt" } @@ -653,7 +605,7 @@ class ExprStmt extends Stmt,@exprstmt { getEnclosingCallable() instanceof InitializerMethod and exists(FieldDeclaration fd, Location fdl, Location sl | fdl = fd.getLocation() and sl = getLocation() - | + | fdl.getFile() = sl.getFile() and fdl.getStartLine() = sl.getStartLine() and fdl.getStartColumn() = sl.getStartColumn() @@ -662,36 +614,31 @@ class ExprStmt extends Stmt,@exprstmt { } /** A labeled statement. */ -class LabeledStmt extends Stmt,@labeledstmt { +class LabeledStmt extends Stmt, @labeledstmt { /** Gets the statement of this labeled statement. */ Stmt getStmt() { result.getParent() = this } /** Gets the label of this labeled statement. */ - string getLabel() { namestrings(result,_,this) } + string getLabel() { namestrings(result, _, this) } /** Gets a printable representation of this statement. May include more detail than `toString()`. */ - override string pp() { - result = this.getLabel() + ": " + this.getStmt().pp() - } + override string pp() { result = this.getLabel() + ": " + this.getStmt().pp() } /** This statement's Halstead ID (used to compute Halstead metrics). */ override string getHalsteadID() { result = this.getLabel() + ":" } } /** An `assert` statement. */ -class AssertStmt extends Stmt,@assertstmt { +class AssertStmt extends Stmt, @assertstmt { /** Gets the boolean expression of this `assert` statement. */ - Expr getExpr() { exprs(result,_,_,this,_) and result.getIndex() = 0 } + Expr getExpr() { exprs(result, _, _, this, _) and result.getIndex() = 0 } /** Gets the assertion message expression, if any. */ - Expr getMessage() { exprs(result,_,_,this,_) and result.getIndex() = 1 } + Expr getMessage() { exprs(result, _, _, this, _) and result.getIndex() = 1 } /** Gets a printable representation of this statement. May include more detail than `toString()`. */ override string pp() { - if exists(this.getMessage()) then - result = "assert ... : ..." - else - result = "assert ..." + if exists(this.getMessage()) then result = "assert ... : ..." else result = "assert ..." } /** This statement's Halstead ID (used to compute Halstead metrics). */ @@ -699,7 +646,7 @@ class AssertStmt extends Stmt,@assertstmt { } /** A statement that declares one or more local variables. */ -class LocalVariableDeclStmt extends Stmt,@localvariabledeclstmt { +class LocalVariableDeclStmt extends Stmt, @localvariabledeclstmt { /** Gets a declared variable. */ LocalVariableDeclExpr getAVariable() { result.getParent() = this } @@ -710,28 +657,22 @@ class LocalVariableDeclStmt extends Stmt,@localvariabledeclstmt { } /** Gets an index of a variable declared in this local variable declaration statement. */ - int getAVariableIndex() { - exists(getVariable(result)) - } + int getAVariableIndex() { exists(getVariable(result)) } /** Gets a printable representation of this statement. May include more detail than `toString()`. */ - override string pp() { - result = "local variable declaration" - } + override string pp() { result = "local variable declaration" } /** This statement's Halstead ID (used to compute Halstead metrics). */ override string getHalsteadID() { result = "LocalVariableDeclStmt" } } /** A statement that declares a local class. */ -class LocalClassDeclStmt extends Stmt,@localclassdeclstmt { +class LocalClassDeclStmt extends Stmt, @localclassdeclstmt { /** Gets the local class declared by this statement. */ - LocalClass getLocalClass() { isLocalClass(result,this) } + LocalClass getLocalClass() { isLocalClass(result, this) } /** Gets a printable representation of this statement. May include more detail than `toString()`. */ - override string pp() { - result = "local class declaration: " + this.getLocalClass().toString() - } + override string pp() { result = "local class declaration: " + this.getLocalClass().toString() } /** This statement's Halstead ID (used to compute Halstead metrics). */ override string getHalsteadID() { result = "LocalClassDeclStmt" } @@ -758,7 +699,7 @@ class ThisConstructorInvocationStmt extends Stmt, ConstructorCall, @constructori } /** Gets the constructor invoked by this constructor invocation. */ - override Constructor getConstructor() { callableBinding(this,result) } + override Constructor getConstructor() { callableBinding(this, result) } override Expr getQualifier() { none() } @@ -769,9 +710,7 @@ class ThisConstructorInvocationStmt extends Stmt, ConstructorCall, @constructori override Stmt getEnclosingStmt() { result = this } /** Gets a printable representation of this statement. May include more detail than `toString()`. */ - override string pp() { - result = "this(...)" - } + override string pp() { result = "this(...)" } /** Gets a printable representation of this statement. */ override string toString() { result = pp() } @@ -801,7 +740,7 @@ class SuperConstructorInvocationStmt extends Stmt, ConstructorCall, @superconstr } /** Gets the constructor invoked by this constructor invocation. */ - override Constructor getConstructor() { callableBinding(this,result) } + override Constructor getConstructor() { callableBinding(this, result) } /** Gets the qualifier expression of this `super(...)` constructor invocation, if any. */ override Expr getQualifier() { result.isNthChildOf(this, -1) } @@ -813,9 +752,7 @@ class SuperConstructorInvocationStmt extends Stmt, ConstructorCall, @superconstr override Stmt getEnclosingStmt() { result = this } /** Gets a printable representation of this statement. May include more detail than `toString()`. */ - override string pp() { - result = "super(...)" - } + override string pp() { result = "super(...)" } /** Gets a printable representation of this statement. */ override string toString() { result = pp() } diff --git a/java/ql/src/semmle/code/java/Type.qll b/java/ql/src/semmle/code/java/Type.qll index e8eccbb68a3..567c64edc6c 100755 --- a/java/ql/src/semmle/code/java/Type.qll +++ b/java/ql/src/semmle/code/java/Type.qll @@ -20,33 +20,32 @@ import JDK cached predicate hasSubtype(RefType t, Type sub) { // Direct subtype. - (extendsReftype(sub, t) and t != sub) or - implInterface(sub, t) or + (extendsReftype(sub, t) and t != sub) + or + implInterface(sub, t) + or // A parameterized type `T` is a subtype of the corresponding raw type `T<>`. - (parSubtypeRaw(t, sub) and t != sub) or + (parSubtypeRaw(t, sub) and t != sub) + or // Array subtyping is covariant. - (arraySubtype(t, sub) and t != sub) or + (arraySubtype(t, sub) and t != sub) + or // Type parameter containment for parameterized types. - (parContainmentSubtype(t, sub) and t != sub) or + (parContainmentSubtype(t, sub) and t != sub) + or // Type variables are subtypes of their upper bounds. (typeVarSubtypeBound(t, sub) and t != sub) } -private -predicate typeVarSubtypeBound(RefType t, TypeVariable tv) { - if tv.hasTypeBound() then - t = tv.getATypeBound().getType() - else - t instanceof TypeObject +private predicate typeVarSubtypeBound(RefType t, TypeVariable tv) { + if tv.hasTypeBound() then t = tv.getATypeBound().getType() else t instanceof TypeObject } -private -predicate parSubtypeRaw(RefType t, ParameterizedType sub) { +private predicate parSubtypeRaw(RefType t, ParameterizedType sub) { t = sub.getErasure().(GenericType).getRawType() } -private -predicate arraySubtype(Array sup, Array sub) { +private predicate arraySubtype(Array sup, Array sub) { hasSubtype(sup.getComponentType(), sub.getComponentType()) } @@ -67,10 +66,10 @@ predicate arraySubtype(Array sup, Array sub) { * base case for `typeArgumentsContain` is therefore `n=1` and this allows an * improved join order implemented by `contains01`. */ -private -predicate parContainmentSubtype(ParameterizedType pt, ParameterizedType psub) { + +private predicate parContainmentSubtype(ParameterizedType pt, ParameterizedType psub) { pt != psub and - typeArgumentsContain(_, pt, psub, pt.getNumberOfTypeArguments()-1) + typeArgumentsContain(_, pt, psub, pt.getNumberOfTypeArguments() - 1) or typeArgumentsContain0(_, pt, psub) } @@ -78,8 +77,7 @@ predicate parContainmentSubtype(ParameterizedType pt, ParameterizedType psub) { /** * Gets the `index`-th type parameter of `t`, which is a parameterization of `g`. */ -private -RefType parameterisationTypeArgument(GenericType g, ParameterizedType t, int index) { +private RefType parameterisationTypeArgument(GenericType g, ParameterizedType t, int index) { g = t.getGenericType() and result = t.getTypeArgument(index) } @@ -89,7 +87,9 @@ private predicate varianceCandidate(ParameterizedType pt) { } pragma[noinline] -private RefType parameterisationTypeArgumentVarianceCand(GenericType g, ParameterizedType t, int index) { +private RefType parameterisationTypeArgumentVarianceCand( + GenericType g, ParameterizedType t, int index +) { result = parameterisationTypeArgument(g, t, index) and varianceCandidate(t) } @@ -100,15 +100,18 @@ private RefType parameterisationTypeArgumentVarianceCand(GenericType g, Paramete * being parameterizations of `g`. */ pragma[nomagic] -private -predicate typeArgumentsContain(GenericType g, ParameterizedType s, ParameterizedType t, int n) { +private predicate typeArgumentsContain( + GenericType g, ParameterizedType s, ParameterizedType t, int n +) { contains01(g, s, t) and n = 1 or contains(g, s, t, n) and - typeArgumentsContain(g, s, t, n-1) + typeArgumentsContain(g, s, t, n - 1) } -private predicate typeArgumentsContain0(GenericType g, ParameterizedType sParm, ParameterizedType tParm) { +private predicate typeArgumentsContain0( + GenericType g, ParameterizedType sParm, ParameterizedType tParm +) { exists(RefType s, RefType t | containsAux0(g, tParm, s, t) and s = parameterisationTypeArgument(g, sParm, 0) and @@ -136,14 +139,18 @@ private predicate contains01(GenericType g, ParameterizedType sParm, Parameteriz } pragma[nomagic] -private predicate contains01Aux0(GenericType g, ParameterizedType tParm, RefType s0, RefType t0, RefType t1) { +private predicate contains01Aux0( + GenericType g, ParameterizedType tParm, RefType s0, RefType t0, RefType t1 +) { typeArgumentContains(g, s0, t0, 0) and t0 = parameterisationTypeArgument(g, tParm, 0) and t1 = parameterisationTypeArgument(g, tParm, 1) } pragma[nomagic] -private predicate contains01Aux1(GenericType g, ParameterizedType sParm, RefType s0, RefType s1, RefType t1) { +private predicate contains01Aux1( + GenericType g, ParameterizedType sParm, RefType s0, RefType s1, RefType t1 +) { typeArgumentContains(g, s1, t1, 1) and s0 = parameterisationTypeArgumentVarianceCand(g, sParm, 0) and s1 = parameterisationTypeArgumentVarianceCand(g, sParm, 1) @@ -164,8 +171,7 @@ private predicate containsAux0(GenericType g, ParameterizedType tParm, RefType s * * See JLS 4.5.1, Type Arguments of Parameterized Types. */ -private -predicate contains(GenericType g, ParameterizedType sParm, ParameterizedType tParm, int n) { +private predicate contains(GenericType g, ParameterizedType sParm, ParameterizedType tParm, int n) { exists(RefType s, RefType t | containsAux(g, tParm, n, s, t) and s = parameterisationTypeArgumentVarianceCand(g, sParm, n) @@ -201,19 +207,20 @@ private predicate typeArgumentContainsAux2(GenericType g, RefType s, RefType t, * * See JLS 4.5.1, Type Arguments of Parameterized Types. */ -private -predicate typeArgumentContainsAux1(RefType s, RefType t, int n) { +private predicate typeArgumentContainsAux1(RefType s, RefType t, int n) { exists(int i | s = parameterisationTypeArgumentVarianceCand(_, _, i) and t = parameterisationTypeArgument(_, _, n) and - i <= n and n <= i - | + i <= n and + n <= i + | exists(RefType tUpperBound | tUpperBound = t.(Wildcard).getUpperBound().getType() | // ? extends T <= ? extends S if T <: S hasSubtypeStar0(s.(Wildcard).getUpperBound().getType(), tUpperBound) or // ? extends T <= ? s.(Wildcard).isUnconstrained() - ) or + ) + or exists(RefType tLowerBound | tLowerBound = t.(Wildcard).getLowerBound().getType() | // ? super T <= ? super S if s <: T hasSubtypeStar0(tLowerBound, s.(Wildcard).getLowerBound().getType()) or @@ -221,11 +228,14 @@ predicate typeArgumentContainsAux1(RefType s, RefType t, int n) { s.(Wildcard).isUnconstrained() or // ? super T <= ? extends Object wildcardExtendsObject(s) - ) or + ) + or // T <= T - s = t or + s = t + or // T <= ? extends T - hasSubtypeStar0(s.(Wildcard).getUpperBound().getType(), t) or + hasSubtypeStar0(s.(Wildcard).getUpperBound().getType(), t) + or // T <= ? super T hasSubtypeStar0(t, s.(Wildcard).getLowerBound().getType()) ) @@ -239,9 +249,7 @@ private predicate wildcardExtendsObject(Wildcard wc) { /** * DEPRECATED: Use `hasSubtype*` instead. */ -deprecated predicate hasSubtypeStar(RefType t, RefType sub) { - hasSubtype*(t, sub) -} +deprecated predicate hasSubtypeStar(RefType t, RefType sub) { hasSubtype*(t, sub) } private predicate hasSubtypeStar0(RefType t, RefType sub) { sub = t @@ -253,13 +261,13 @@ private predicate hasSubtypeStar0(RefType t, RefType sub) { /** Holds if type `t` declares member `m`. */ predicate declaresMember(Type t, @member m) { - methods(m,_,_,_,t,_) + methods(m, _, _, _, t, _) or - constrs(m,_,_,_,t,_) + constrs(m, _, _, _, t, _) or - fields(m,_,_,t,_) + fields(m, _, _, t, _) or - enclInReftype(m,t) and + enclInReftype(m, t) and // Since the type `@member` in the dbscheme includes all `@reftype`s, // anonymous and local classes need to be excluded here. not m instanceof AnonymousClass and @@ -311,9 +319,7 @@ class Array extends RefType, @array { /** * Gets the JVM descriptor for this type, as used in bytecode. */ - override string getTypeDescriptor() { - result = "[" + this.getComponentType().getTypeDescriptor() - } + override string getTypeDescriptor() { result = "[" + this.getComponentType().getTypeDescriptor() } } /** @@ -323,29 +329,27 @@ class Array extends RefType, @array { class RefType extends Type, Annotatable, Modifiable, @reftype { /** Gets the package in which this type is declared. */ Package getPackage() { - classes(this,_,result,_) or - interfaces(this,_,result,_) + classes(this, _, result, _) or + interfaces(this, _, result, _) } /** Gets the type in which this reference type is enclosed, if any. */ - RefType getEnclosingType() { - enclInReftype(this, result) - } + RefType getEnclosingType() { enclInReftype(this, result) } /** Gets the compilation unit in which this type is declared. */ override CompilationUnit getCompilationUnit() { result = this.getFile() } /** Holds if `t` is an immediate supertype of this type. */ - predicate hasSupertype(RefType t) { hasSubtype(t,this) } + predicate hasSupertype(RefType t) { hasSubtype(t, this) } /** Holds if `t` is an immediate subtype of this type. */ - predicate hasSubtype(RefType t) { hasSubtype(this,t) } + predicate hasSubtype(RefType t) { hasSubtype(this, t) } /** Gets a direct subtype of this type. */ - RefType getASubtype() { hasSubtype(this,result) } + RefType getASubtype() { hasSubtype(this, result) } /** Gets a direct supertype of this type. */ - RefType getASupertype() { hasSubtype(result,this) } + RefType getASupertype() { hasSubtype(result, this) } /** Gets a direct or indirect supertype of this type, including itself. */ RefType getAnAncestor() { hasSubtype*(result, this) } @@ -413,9 +417,7 @@ class RefType extends Type, Annotatable, Modifiable, @reftype { * Holds if this type declares or inherits method `m`, which is declared * in `declaringType`. */ - predicate hasMethod(Method m, RefType declaringType) { - hasMethod(m, declaringType, false) - } + predicate hasMethod(Method m, RefType declaringType) { hasMethod(m, declaringType, false) } /** * Holds if this type declares or inherits method `m`, which is declared @@ -425,13 +427,14 @@ class RefType extends Type, Annotatable, Modifiable, @reftype { */ cached predicate hasMethod(Method m, RefType declaringType, boolean hidden) { - hasNonInterfaceMethod(m, declaringType, hidden) or + hasNonInterfaceMethod(m, declaringType, hidden) + or hasInterfaceMethod(m, declaringType) and hidden = false } private predicate noMethodExtraction() { - not methods(_,_,_,_,this,_) and - exists(Method m | methods(m,_,_,_,getSourceDeclaration(),_) and m.isInheritable()) + not methods(_, _, _, _, this, _) and + exists(Method m | methods(m, _, _, _, getSourceDeclaration(), _) and m.isInheritable()) } private predicate canInheritFromSupertype(RefType sup) { @@ -446,25 +449,42 @@ class RefType extends Type, Annotatable, Modifiable, @reftype { } private predicate hasNonInterfaceMethod(Method m, RefType declaringType, boolean hidden) { - m = getAMethod() and this = declaringType and not declaringType instanceof Interface and hidden = false or + m = getAMethod() and + this = declaringType and + not declaringType instanceof Interface and + hidden = false + or exists(RefType sup, boolean h1, boolean h2 | - (if m.isPackageProtected() and sup.getPackage() != this.getPackage() then h1 = true else h1 = false) and + ( + if m.isPackageProtected() and sup.getPackage() != this.getPackage() + then h1 = true + else h1 = false + ) and (not sup instanceof Interface or this instanceof Interface) and canInheritFromSupertype(sup) and sup.hasNonInterfaceMethod(m, declaringType, h2) and hidden = h1.booleanOr(h2) and - exists(string signature | methods(m,_,signature,_,_,_) and not methods(_,_,signature,_,this,_)) and + exists(string signature | + methods(m, _, signature, _, _, _) and not methods(_, _, signature, _, this, _) + ) and m.isInheritable() ) } private predicate cannotInheritInterfaceMethod(string signature) { - methods(_,_,signature,_,this,_) or - exists(Method m | hasNonInterfaceMethod(m, _, false) and methods(m,_,signature,_,_,_)) + methods(_, _, signature, _, this, _) + or + exists(Method m | hasNonInterfaceMethod(m, _, false) and methods(m, _, signature, _, _, _)) } - private predicate interfaceMethodCandidateWithSignature(Method m, string signature, RefType declaringType) { - m = getAMethod() and this = declaringType and declaringType instanceof Interface and methods(m,_,signature,_,_,_) or + private predicate interfaceMethodCandidateWithSignature( + Method m, string signature, RefType declaringType + ) { + m = getAMethod() and + this = declaringType and + declaringType instanceof Interface and + methods(m, _, signature, _, _, _) + or exists(RefType sup | sup.interfaceMethodCandidateWithSignature(m, signature, declaringType) and not cannotInheritInterfaceMethod(signature) and @@ -500,12 +520,14 @@ class RefType extends Type, Annotatable, Modifiable, @reftype { /** Holds if this type declares or inherits the specified member. */ predicate inherits(Member m) { exists(Field f | f = m | - f = getAField() or - not f.isPrivate() and not declaresField(f.getName()) and getASupertype().inherits(f) or + f = getAField() + or + not f.isPrivate() and not declaresField(f.getName()) and getASupertype().inherits(f) + or getSourceDeclaration().inherits(f) ) or - hasMethod((Method)m, _) + hasMethod(m.(Method), _) } /** Holds if this is a top-level type, which is not nested inside any other types. */ @@ -521,7 +543,7 @@ class RefType extends Type, Annotatable, Modifiable, @reftype { */ override string getTypeDescriptor() { result = "L" + this.getPackage().getName().replaceAll(".", "/") + "/" + - this.getSourceDeclaration().nestedName() + ";" + this.getSourceDeclaration().nestedName() + ";" } /** @@ -529,10 +551,7 @@ class RefType extends Type, Annotatable, Modifiable, @reftype { */ string getQualifiedName() { exists(string pkgName | pkgName = getPackage().getName() | - if pkgName = "" then - result = nestedName() - else - result = pkgName + "." + nestedName() + if pkgName = "" then result = nestedName() else result = pkgName + "." + nestedName() ) } @@ -583,19 +602,17 @@ class RefType extends Type, Annotatable, Modifiable, @reftype { } /** A type that is the same as its source declaration. */ -class SrcRefType extends RefType { - SrcRefType() { this.isSourceDeclaration() } -} +class SrcRefType extends RefType { SrcRefType() { this.isSourceDeclaration() } } /** A class declaration. */ class Class extends RefType, @class { /** Holds if this class is an anonymous class. */ - predicate isAnonymous() { isAnonymClass(this,_) } + predicate isAnonymous() { isAnonymClass(this, _) } /** Holds if this class is a local class. */ - predicate isLocal() { isLocalClass(this,_) } + predicate isLocal() { isLocalClass(this, _) } - override RefType getSourceDeclaration() { classes(this,_,_,result) } + override RefType getSourceDeclaration() { classes(this, _, _, result) } /** * Gets an annotation that applies to this class. @@ -603,7 +620,8 @@ class Class extends RefType, @class { * Note that a class may inherit annotations from super-classes. */ override Annotation getAnAnnotation() { - result = RefType.super.getAnAnnotation() or + result = RefType.super.getAnAnnotation() + or exists(AnnotationType tp | tp = result.getType() | tp.isInherited() and not exists(Annotation ann | ann = RefType.super.getAnAnnotation() | ann.getType() = tp) and @@ -620,14 +638,16 @@ class IntersectionType extends RefType, @class { shortname.matches("% & ...") ) } + private RefType superType() { extendsReftype(this, result) } + private RefType superInterface() { implInterface(this, result) } + string getLongName() { result = superType().toString() + concat(" & " + superInterface().toString()) } - RefType getFirstBound() { - extendsReftype(this, result) - } + + RefType getFirstBound() { extendsReftype(this, result) } } /** An anonymous class. */ @@ -656,7 +676,9 @@ class AnonymousClass extends NestedClass { */ override string getTypeDescriptor() { exists(RefType parent | parent = this.getEnclosingType() | - exists(int num | num = 1 + count(AnonymousClass other | other.rankInParent(parent) < rankInParent(parent)) | + exists(int num | + num = 1 + count(AnonymousClass other | other.rankInParent(parent) < rankInParent(parent)) + | exists(string parentWithSemi | parentWithSemi = parent.getTypeDescriptor() | result = parentWithSemi.prefix(parentWithSemi.length() - 1) + "$" + num + ";" ) @@ -667,7 +689,9 @@ class AnonymousClass extends NestedClass { /** Gets the class instance expression where this anonymous class occurs. */ ClassInstanceExpr getClassInstanceExpr() { isAnonymClass(this, result) } - override string toString() { result = "new " + this.getClassInstanceExpr().getTypeName() + "(...) { ... }" } + override string toString() { + result = "new " + this.getClassInstanceExpr().getTypeName() + "(...) { ... }" + } /** * Gets the qualified name of this type. @@ -689,32 +713,26 @@ class LocalClass extends NestedClass { /** A top-level type. */ class TopLevelType extends RefType { TopLevelType() { - not enclInReftype(this,_) and + not enclInReftype(this, _) and (this instanceof Class or this instanceof Interface) } } /** A top-level class. */ -class TopLevelClass extends TopLevelType, Class { -} +class TopLevelClass extends TopLevelType, Class { } /** A nested type is a type declared within another type. */ class NestedType extends RefType { - NestedType() { - enclInReftype(this,_) - } + NestedType() { enclInReftype(this, _) } /** Gets the type enclosing this nested type. */ - override RefType getEnclosingType() { - enclInReftype(this,result) - } + override RefType getEnclosingType() { enclInReftype(this, result) } /** Gets the nesting depth of this nested type. Top-level types have nesting depth 0. */ int getNestingDepth() { - if getEnclosingType() instanceof NestedType then - result = getEnclosingType().(NestedType).getNestingDepth() + 1 - else - result = 1 + if getEnclosingType() instanceof NestedType + then result = getEnclosingType().(NestedType).getNestingDepth() + 1 + else result = 1 } override predicate isPublic() { @@ -760,17 +778,14 @@ class NestedType extends RefType { * This includes (static and non-static) member classes, * local classes and anonymous classes. */ -class NestedClass extends NestedType, Class { -} +class NestedClass extends NestedType, Class { } /** * An inner class is a nested class that is neither * explicitly nor implicitly declared static. */ class InnerClass extends NestedClass { - InnerClass() { - not this.isStatic() - } + InnerClass() { not this.isStatic() } /** * Holds if an instance of this inner class holds a reference to its @@ -785,7 +800,7 @@ class InnerClass extends NestedClass { /** An interface. */ class Interface extends RefType, @interface { - override RefType getSourceDeclaration() { interfaces(this,_,_,result) } + override RefType getSourceDeclaration() { interfaces(this, _, _, result) } override predicate isAbstract() { // JLS 9.1.1.1: "Every interface is implicitly abstract" @@ -809,26 +824,29 @@ class ClassOrInterface extends RefType { * and `double`. */ class PrimitiveType extends Type, @primitive { - PrimitiveType() { - this.getName().regexpMatch("float|double|int|boolean|short|byte|char|long") - } + PrimitiveType() { this.getName().regexpMatch("float|double|int|boolean|short|byte|char|long") } /** Gets the boxed type corresponding to this primitive type. */ - BoxedType getBoxedType() { - result.getPrimitiveType() = this - } + BoxedType getBoxedType() { result.getPrimitiveType() = this } /** * Gets the JVM descriptor for this type, as used in bytecode. */ override string getTypeDescriptor() { - (this.hasName("float") and result = "F") or - (this.hasName("double") and result = "D") or - (this.hasName("int") and result = "I") or - (this.hasName("boolean") and result = "Z") or - (this.hasName("short") and result = "S") or - (this.hasName("byte") and result = "B") or - (this.hasName("char") and result = "C") or + (this.hasName("float") and result = "F") + or + (this.hasName("double") and result = "D") + or + (this.hasName("int") and result = "I") + or + (this.hasName("boolean") and result = "Z") + or + (this.hasName("short") and result = "S") + or + (this.hasName("byte") and result = "B") + or + (this.hasName("char") and result = "C") + or (this.hasName("long") and result = "J") } @@ -842,16 +860,18 @@ class PrimitiveType extends Type, @primitive { * require an explicit cast. */ Literal getADefaultValue() { - getName() = "boolean" and result.getLiteral() = "false" or - getName() = "char" and (result.getLiteral() = "'\\0'" or result.getLiteral() = "'\\u0000'") or - getName().regexpMatch("(float|double|int|short|byte|long)") and result.getLiteral().regexpMatch("0(\\.0)?+[lLfFdD]?+") + getName() = "boolean" and result.getLiteral() = "false" + or + getName() = "char" and + (result.getLiteral() = "'\\0'" or result.getLiteral() = "'\\u0000'") + or + getName().regexpMatch("(float|double|int|short|byte|long)") and + result.getLiteral().regexpMatch("0(\\.0)?+[lLfFdD]?+") } } /** The type of the `null` literal. */ -class NullType extends Type, @primitive { - NullType() { this.hasName("") } -} +class NullType extends Type, @primitive { NullType() { this.hasName("") } } /** The `void` type. */ class VoidType extends Type, @primitive { @@ -860,9 +880,7 @@ class VoidType extends Type, @primitive { /** * Gets the JVM descriptor for this type, as used in bytecode. */ - override string getTypeDescriptor() { - result = "V" - } + override string getTypeDescriptor() { result = "V" } } /** @@ -886,13 +904,20 @@ class BoxedType extends RefType { /** Gets the primitive type corresponding to this boxed type. */ PrimitiveType getPrimitiveType() { - (this.hasName("Float") and result.hasName("float")) or - (this.hasName("Double") and result.hasName("double")) or - (this.hasName("Integer") and result.hasName("int")) or - (this.hasName("Boolean") and result.hasName("boolean")) or - (this.hasName("Short") and result.hasName("short")) or - (this.hasName("Byte") and result.hasName("byte")) or - (this.hasName("Character") and result.hasName("char")) or + (this.hasName("Float") and result.hasName("float")) + or + (this.hasName("Double") and result.hasName("double")) + or + (this.hasName("Integer") and result.hasName("int")) + or + (this.hasName("Boolean") and result.hasName("boolean")) + or + (this.hasName("Short") and result.hasName("short")) + or + (this.hasName("Byte") and result.hasName("byte")) + or + (this.hasName("Character") and result.hasName("char")) + or (this.hasName("Long") and result.hasName("long")) } } @@ -917,13 +942,11 @@ class EnumType extends Class { /** Gets the enum constant with the specified name. */ EnumConstant getEnumConstant(string name) { - fields(result,_,_,this,_) and result.hasName(name) + fields(result, _, _, this, _) and result.hasName(name) } /** Gets an enum constant declared in this enum type. */ - EnumConstant getAnEnumConstant() { - fields(result,_,_,this,_) - } + EnumConstant getAnEnumConstant() { fields(result, _, _, this, _) } override predicate isFinal() { // JLS 8.9: An enum declaration is implicitly `final` unless it contains @@ -940,7 +963,9 @@ class EnumConstant extends Field { // [enum type] `E`, `E` has an implicitly declared `public static final` // field of type `E` that has the same name as `c`. override predicate isPublic() { any() } + override predicate isStatic() { any() } + override predicate isFinal() { any() } } @@ -949,15 +974,23 @@ class EnumConstant extends Field { * * See JLS v8, section 4.6 (Type Erasure). */ -private cached Type erase(Type t) { - result = t.(Class).getSourceDeclaration() and not t instanceof IntersectionType or - result = erase(t.(IntersectionType).getFirstBound()) or - result = t.(Interface).getSourceDeclaration() or - result.(Array).getComponentType() = erase(t.(Array).getComponentType()) or - result = erase(t.(BoundedType).getFirstUpperBoundType()) or - result = (NullType)t or - result = (VoidType)t or - result = (PrimitiveType)t +cached +private Type erase(Type t) { + result = t.(Class).getSourceDeclaration() and not t instanceof IntersectionType + or + result = erase(t.(IntersectionType).getFirstBound()) + or + result = t.(Interface).getSourceDeclaration() + or + result.(Array).getComponentType() = erase(t.(Array).getComponentType()) + or + result = erase(t.(BoundedType).getFirstUpperBoundType()) + or + result = t.(NullType) + or + result = t.(VoidType) + or + result = t.(PrimitiveType) } /** @@ -984,7 +1017,9 @@ predicate haveIntersection(RefType t1, RefType t2) { * types `t1` and `t2`. */ predicate erasedHaveIntersection(RefType t1, RefType t2) { - exists(SrcRefType commonSub | commonSub.getASourceSupertype*() = t1 and commonSub.getASourceSupertype*() = t2) and + exists(SrcRefType commonSub | + commonSub.getASourceSupertype*() = t1 and commonSub.getASourceSupertype*() = t2 + ) and t1 = erase(_) and t2 = erase(_) } @@ -994,7 +1029,7 @@ class IntegralType extends Type { IntegralType() { exists(string name | name = this.(PrimitiveType).getName() or name = this.(BoxedType).getPrimitiveType().getName() - | + | name.regexpMatch("byte|char|short|int|long") ) } @@ -1005,7 +1040,7 @@ class BooleanType extends Type { BooleanType() { exists(string name | name = this.(PrimitiveType).getName() or name = this.(BoxedType).getPrimitiveType().getName() - | + | name = "boolean" ) } @@ -1016,7 +1051,7 @@ class CharacterType extends Type { CharacterType() { exists(string name | name = this.(PrimitiveType).getName() or name = this.(BoxedType).getPrimitiveType().getName() - | + | name = "char" ) } @@ -1027,7 +1062,7 @@ class NumericOrCharType extends Type { NumericOrCharType() { exists(string name | name = this.(PrimitiveType).getName() or name = this.(BoxedType).getPrimitiveType().getName() - | + | name.regexpMatch("byte|char|short|int|long|double|float") ) } @@ -1038,7 +1073,7 @@ class FloatingPointType extends Type { FloatingPointType() { exists(string name | name = this.(PrimitiveType).getName() or name = this.(BoxedType).getPrimitiveType().getName() - | + | name.regexpMatch("float|double") ) } diff --git a/java/ql/src/semmle/code/java/UnitTests.qll b/java/ql/src/semmle/code/java/UnitTests.qll index b058c1f1789..5f221ec7b53 100644 --- a/java/ql/src/semmle/code/java/UnitTests.qll +++ b/java/ql/src/semmle/code/java/UnitTests.qll @@ -8,30 +8,22 @@ import semmle.code.java.frameworks.JUnitAnnotations /** The Java class `junit.framework.TestCase`. */ class TypeJUnitTestCase extends RefType { - TypeJUnitTestCase() { - this.hasQualifiedName("junit.framework", "TestCase") - } + TypeJUnitTestCase() { this.hasQualifiedName("junit.framework", "TestCase") } } /** The Java interface `junit.framework.Test`. */ class TypeJUnitTest extends RefType { - TypeJUnitTest() { - this.hasQualifiedName("junit.framework", "Test") - } + TypeJUnitTest() { this.hasQualifiedName("junit.framework", "Test") } } /** The Java class `junit.framework.TestSuite`. */ class TypeJUnitTestSuite extends RefType { - TypeJUnitTestSuite() { - this.hasQualifiedName("junit.framework", "TestSuite") - } + TypeJUnitTestSuite() { this.hasQualifiedName("junit.framework", "TestSuite") } } /** A JUnit 3.8 test class. */ class JUnit38TestClass extends Class { - JUnit38TestClass() { - exists(TypeJUnitTestCase tc | this.hasSupertype+(tc)) - } + JUnit38TestClass() { exists(TypeJUnitTestCase tc | this.hasSupertype+(tc)) } } /** A JUnit 3.8 `tearDown` method. */ @@ -40,9 +32,7 @@ class TearDownMethod extends Method { this.hasName("tearDown") and this.hasNoParameters() and this.getReturnType().hasName("void") and - exists(Method m | m.getDeclaringType() instanceof TypeJUnitTestCase | - this.overrides*(m) - ) + exists(Method m | m.getDeclaringType() instanceof TypeJUnitTestCase | this.overrides*(m)) } } @@ -87,14 +77,11 @@ class JUnit3TestSuite extends Method { } } - /** * A JUnit test method that is annotated with the `org.junit.Test` annotation. */ class JUnit4TestMethod extends Method { - JUnit4TestMethod() { - this.getAnAnnotation().getType().hasQualifiedName("org.junit", "Test") - } + JUnit4TestMethod() { this.getAnAnnotation().getType().hasQualifiedName("org.junit", "Test") } } /** @@ -110,9 +97,7 @@ class JUnitJupiterTestMethod extends Method { * A JUnit `@Ignore` annotation. */ class JUnitIgnoreAnnotation extends Annotation { - JUnitIgnoreAnnotation() { - getType().hasQualifiedName("org.junit", "Ignore") - } + JUnitIgnoreAnnotation() { getType().hasQualifiedName("org.junit", "Ignore") } } /** @@ -121,10 +106,9 @@ class JUnitIgnoreAnnotation extends Annotation { */ class JUnitIgnoredMethod extends Method { JUnitIgnoredMethod() { - getAnAnnotation() instanceof JUnitIgnoreAnnotation or - exists(Class c | - c = this.getDeclaringType() - | + getAnAnnotation() instanceof JUnitIgnoreAnnotation + or + exists(Class c | c = this.getDeclaringType() | c.getAnAnnotation() instanceof JUnitIgnoreAnnotation ) } @@ -134,27 +118,21 @@ class JUnitIgnoredMethod extends Method { * An annotation in TestNG. */ class TestNGAnnotation extends Annotation { - TestNGAnnotation() { - getType().getPackage().hasName("org.testng.annotations") - } + TestNGAnnotation() { getType().getPackage().hasName("org.testng.annotations") } } /** * An annotation of type `org.test.ng.annotations.Test`. */ class TestNGTestAnnotation extends TestNGAnnotation { - TestNGTestAnnotation() { - getType().hasName("Test") - } + TestNGTestAnnotation() { getType().hasName("Test") } } /** * A TestNG test method, annotated with the `org.testng.annotations.Test` annotation. */ class TestNGTestMethod extends Method { - TestNGTestMethod() { - this.getAnAnnotation() instanceof TestNGTestAnnotation - } + TestNGTestMethod() { this.getAnAnnotation() instanceof TestNGTestAnnotation } /** * Identify a possible `DataProvider` for this method, if the annotation includes a `dataProvider` @@ -164,12 +142,19 @@ class TestNGTestMethod extends Method { exists(TestNGTestAnnotation testAnnotation | testAnnotation = getAnAnnotation() and // The data provider must have the same name as the referenced data provider - result.getDataProviderName() = testAnnotation.getValue("dataProvider").(StringLiteral).getRepresentedString() - | + result.getDataProviderName() = testAnnotation + .getValue("dataProvider") + .(StringLiteral) + .getRepresentedString() + | // Either the data provider should be on the current class, or a supertype getDeclaringType().getAnAncestor() = result.getDeclaringType() or // Or the data provider class should be declared - result.getDeclaringType() = testAnnotation.getValue("dataProviderClass").(TypeLiteral).getTypeName().getType() + result.getDeclaringType() = testAnnotation + .getValue("dataProviderClass") + .(TypeLiteral) + .getTypeName() + .getType() ) } } @@ -191,18 +176,14 @@ class TestMethod extends Method { * A TestNG annotation used to mark a method that runs "before". */ class TestNGBeforeAnnotation extends TestNGAnnotation { - TestNGBeforeAnnotation() { - getType().getName().matches("Before%") - } + TestNGBeforeAnnotation() { getType().getName().matches("Before%") } } /** * A TestNG annotation used to mark a method that runs "after". */ class TestNGAfterAnnotation extends TestNGAnnotation { - TestNGAfterAnnotation() { - getType().getName().matches("After%") - } + TestNGAfterAnnotation() { getType().getName().matches("After%") } } /** @@ -210,9 +191,7 @@ class TestNGAfterAnnotation extends TestNGAnnotation { * them as data provider methods for TestNG. */ class TestNGDataProviderAnnotation extends TestNGAnnotation { - TestNGDataProviderAnnotation() { - getType().hasName("DataProvider") - } + TestNGDataProviderAnnotation() { getType().hasName("DataProvider") } } /** @@ -220,9 +199,7 @@ class TestNGDataProviderAnnotation extends TestNGAnnotation { * them as factory methods for TestNG. */ class TestNGFactoryAnnotation extends TestNGAnnotation { - TestNGFactoryAnnotation() { - getType().hasName("Factory") - } + TestNGFactoryAnnotation() { getType().hasName("Factory") } } /** @@ -230,9 +207,7 @@ class TestNGFactoryAnnotation extends TestNGAnnotation { * which listeners apply to them. */ class TestNGListenersAnnotation extends TestNGAnnotation { - TestNGListenersAnnotation() { - getType().hasName("Listeners") - } + TestNGListenersAnnotation() { getType().hasName("Listeners") } /** * Gets a listener defined in this annotation. @@ -246,9 +221,7 @@ class TestNGListenersAnnotation extends TestNGAnnotation { * A concrete implementation class of one or more of the TestNG listener interfaces. */ class TestNGListenerImpl extends Class { - TestNGListenerImpl() { - getAnAncestor().hasQualifiedName("org.testng", "ITestNGListener") - } + TestNGListenerImpl() { getAnAncestor().hasQualifiedName("org.testng", "ITestNGListener") } } /** @@ -259,15 +232,17 @@ class TestNGListenerImpl extends Class { * an instance of a particular value when running a test method. */ class TestNGDataProviderMethod extends Method { - TestNGDataProviderMethod() { - getAnAnnotation() instanceof TestNGDataProviderAnnotation - } + TestNGDataProviderMethod() { getAnAnnotation() instanceof TestNGDataProviderAnnotation } /** * Gets the name associated with this data provider. */ string getDataProviderName() { - result = getAnAnnotation().(TestNGDataProviderAnnotation).getValue("name").(StringLiteral).getRepresentedString() + result = getAnAnnotation() + .(TestNGDataProviderAnnotation) + .getValue("name") + .(StringLiteral) + .getRepresentedString() } } @@ -278,9 +253,7 @@ class TestNGDataProviderMethod extends Method { * This factory callable is used to generate instances of parameterized test classes. */ class TestNGFactoryCallable extends Callable { - TestNGFactoryCallable() { - getAnAnnotation() instanceof TestNGFactoryAnnotation - } + TestNGFactoryCallable() { getAnAnnotation() instanceof TestNGFactoryAnnotation } } /** @@ -288,7 +261,11 @@ class TestNGFactoryCallable extends Callable { */ class ParameterizedJUnitTest extends Class { ParameterizedJUnitTest() { - getAnAnnotation().(RunWithAnnotation).getRunner().(Class).hasQualifiedName("org.junit.runners", "Parameterized") + getAnAnnotation() + .(RunWithAnnotation) + .getRunner() + .(Class) + .hasQualifiedName("org.junit.runners", "Parameterized") } } @@ -309,7 +286,8 @@ class JUnitCategoryAnnotation extends Annotation { ( literal = value or literal = value.(ArrayCreationExpr).getInit().getAnInit() - ) | + ) + | result = literal.getTypeName().getType() ) } @@ -320,6 +298,10 @@ class JUnitCategoryAnnotation extends Annotation { */ class JUnitTheoryTest extends Class { JUnitTheoryTest() { - getAnAnnotation().(RunWithAnnotation).getRunner().(Class).hasQualifiedName("org.junit.experimental.theories", "Theories") + getAnAnnotation() + .(RunWithAnnotation) + .getRunner() + .(Class) + .hasQualifiedName("org.junit.experimental.theories", "Theories") } } diff --git a/java/ql/src/semmle/code/java/Variable.qll b/java/ql/src/semmle/code/java/Variable.qll index 0147c19121b..9a281786ac4 100755 --- a/java/ql/src/semmle/code/java/Variable.qll +++ b/java/ql/src/semmle/code/java/Variable.qll @@ -10,24 +10,22 @@ class Variable extends @variable, Annotatable, Element, Modifiable { /*abstract*/ Type getType() { none() } /** Gets an access to this variable. */ - VarAccess getAnAccess() { variableBinding(result,this) } + VarAccess getAnAccess() { variableBinding(result, this) } /** Gets an expression on the right-hand side of an assignment to this variable. */ Expr getAnAssignedValue() { exists(LocalVariableDeclExpr e | e.getVariable() = this and result = e.getInit()) or - exists(AssignExpr e | e.getDest().getProperExpr() = this.getAnAccess() and result = e.getSource()) + exists(AssignExpr e | + e.getDest().getProperExpr() = this.getAnAccess() and result = e.getSource() + ) } /** Gets the initializer expression of this variable. */ - Expr getInitializer() { - none() - } + Expr getInitializer() { none() } /** Gets a printable representation of this variable together with its type. */ - string pp() { - result = this.getType().getName() + " " + this.getName() - } + string pp() { result = this.getType().getName() + " " + this.getName() } } /** A locally scoped variable, that is, either a local variable or a parameter. */ @@ -39,13 +37,13 @@ class LocalScopeVariable extends Variable, @localscopevariable { /** A local variable declaration */ class LocalVariableDecl extends @localvar, LocalScopeVariable { /** Gets the type of this local variable. */ - override Type getType() { localvars(this,_,result,_) } + override Type getType() { localvars(this, _, result, _) } /** Gets the expression declaring this variable. */ LocalVariableDeclExpr getDeclExpr() { localvars(this, _, _, result) } /** Gets the parent of this declaration. */ - Expr getParent() { localvars(this,_,_,result) } + Expr getParent() { localvars(this, _, _, result) } /** Gets the callable in which this declaration occurs. */ override Callable getCallable() { result = this.getParent().getEnclosingCallable() } @@ -56,35 +54,31 @@ class LocalVariableDecl extends @localvar, LocalScopeVariable { override string toString() { result = this.getType().getName() + " " + this.getName() } /** Gets the initializer expression of this local variable declaration. */ - override Expr getInitializer() { - result = getDeclExpr().getInit() - } + override Expr getInitializer() { result = getDeclExpr().getInit() } } /** A formal parameter of a callable. */ class Parameter extends Element, @param, LocalScopeVariable { /** Gets the type of this formal parameter. */ - override Type getType() { params(this,result,_,_,_) } + override Type getType() { params(this, result, _, _, _) } /** Holds if the parameter is never assigned a value in the body of the callable. */ predicate isEffectivelyFinal() { not exists(getAnAssignedValue()) } /** Gets the (zero-based) index of this formal parameter. */ - int getPosition() { params(this,_,result,_,_) } + int getPosition() { params(this, _, result, _, _) } /** Gets the callable that declares this formal parameter. */ - override Callable getCallable() { params(this,_,_,result,_) } + override Callable getCallable() { params(this, _, _, result, _) } /** Gets the source declaration of this formal parameter. */ - Parameter getSourceDeclaration() { params(this,_,_,_,result) } + Parameter getSourceDeclaration() { params(this, _, _, _, result) } /** Holds if this formal parameter is the same as its source declaration. */ predicate isSourceDeclaration() { this.getSourceDeclaration() = this } /** Holds if this formal parameter is a variable arity parameter. */ - predicate isVarargs() { - isVarargsParam(this) - } + predicate isVarargs() { isVarargsParam(this) } /** * Gets an argument for this parameter in any call to the callable that declares this formal @@ -97,7 +91,8 @@ class Parameter extends Element, @param, LocalScopeVariable { result = getACallArgument(getPosition()) } - private pragma[noinline] Expr getACallArgument(int i) { + pragma[noinline] + private Expr getACallArgument(int i) { exists(Call call | result = call.getArgument(i) and call.getCallee().getSourceDeclaration().getAParameter() = this diff --git a/java/ql/src/semmle/code/java/comparison/Comparison.qll b/java/ql/src/semmle/code/java/comparison/Comparison.qll index c6546fd715c..8a869d8a2e4 100644 --- a/java/ql/src/semmle/code/java/comparison/Comparison.qll +++ b/java/ql/src/semmle/code/java/comparison/Comparison.qll @@ -6,9 +6,13 @@ import java * Used as basis for the transitive closure in `exprImplies`. */ private predicate exprImpliesStep(Expr e1, boolean b1, Expr e2, boolean b2) { - e1.(ParExpr).getProperExpr() = e2 and b2 = b1 and (b1 = true or b1 = false) + e1.(ParExpr).getProperExpr() = e2 and + b2 = b1 and + (b1 = true or b1 = false) or - e1.(LogNotExpr).getExpr() = e2 and b2 = b1.booleanNot() and (b1 = true or b1 = false) + e1.(LogNotExpr).getExpr() = e2 and + b2 = b1.booleanNot() and + (b1 = true or b1 = false) or b1 = true and e1.(AndLogicalExpr).getAnOperand() = e2 and b2 = true or @@ -17,7 +21,11 @@ private predicate exprImpliesStep(Expr e1, boolean b1, Expr e2, boolean b2) { /** If `e1` evaluates to `b1` then the subexpression `e2` evaluates to `b2`. */ predicate exprImplies(Expr e1, boolean b1, Expr e2, boolean b2) { - e1 = e2 and b1 = b2 and (b1 = true or b1 = false) + e1 = e2 and + b1 = b2 and + (b1 = true or b1 = false) or - exists(Expr emid, boolean bmid | exprImplies(e1, b1, emid, bmid) and exprImpliesStep(emid, bmid, e2, b2)) + exists(Expr emid, boolean bmid | + exprImplies(e1, b1, emid, bmid) and exprImpliesStep(emid, bmid, e2, b2) + ) }