Java: Autoformat libs outside semmle.code.java.

This commit is contained in:
Anders Schack-Mulligen 2018-10-11 12:52:13 +02:00
Родитель 16b29b2d08
Коммит 67d1c72e64
41 изменённых файлов: 1305 добавлений и 1183 удалений

Просмотреть файл

@ -1,25 +1,23 @@
import java
/** Holds if the given `Javadoc` contains a minimum of a few characters of text. */
private
predicate acceptableDocText(Javadoc j) {
private predicate acceptableDocText(Javadoc j) {
// Require minimum combined length of all non-tag elements.
sum(JavadocElement e, int toSum |
e = j.getAChild() and
not e = j.getATag(_) and
toSum = e.toString().length()
|
|
toSum
) >= 5
}
/** Holds if the given `JavadocTag` contains a minimum of a few characters of text. */
private
predicate acceptableTag(JavadocTag t) {
private predicate acceptableTag(JavadocTag t) {
sum(JavadocElement e, int toSum |
e = t.getAChild() and
toSum = e.toString().length()
|
|
toSum
) >= 5
}
@ -31,9 +29,7 @@ class DocuRefType extends RefType {
this.isPublic()
}
predicate hasAcceptableDocText() {
acceptableDocText(this.getDoc().getJavadoc())
}
predicate hasAcceptableDocText() { acceptableDocText(this.getDoc().getJavadoc()) }
}
/** A public (non-getter, non-setter) `Callable` that does not override another method. */
@ -50,12 +46,11 @@ class DocuCallable extends Callable {
not this.getLocation() = this.getDeclaringType().getLocation()
}
predicate hasAcceptableDocText() {
acceptableDocText(this.getDoc().getJavadoc())
}
predicate hasAcceptableDocText() { acceptableDocText(this.getDoc().getJavadoc()) }
string toMethodOrConstructorString() {
(this instanceof Method and result = "method") or
(this instanceof Method and result = "method")
or
(this instanceof Constructor and result = "constructor")
}
}

Просмотреть файл

@ -6,11 +6,11 @@ import semmle.code.xml.MavenPom
* within the given container (folder, jar file etc.).
*/
predicate pomDependsOnContainer(Pom f, Container g) {
exists(RefType source, RefType target |
source.getFile().getParentContainer*() = f.getFile().getParentContainer() and
target.getFile().getParentContainer*() = g and
depends(source, target)
)
exists(RefType source, RefType target |
source.getFile().getParentContainer*() = f.getFile().getParentContainer() and
target.getFile().getParentContainer*() = g and
depends(source, target)
)
}
/**
@ -18,9 +18,9 @@ predicate pomDependsOnContainer(Pom f, Container g) {
* within the project represented by the targetPom.
*/
predicate pomDependsOnPom(Pom sourcePom, Pom targetPom) {
exists(RefType source, RefType target |
source.getFile().getParentContainer*() = sourcePom.getFile().getParentContainer() and
target.getFile().getParentContainer*() = targetPom.getFile().getParentContainer() and
depends(source, target)
)
exists(RefType source, RefType target |
source.getFile().getParentContainer*() = sourcePom.getFile().getParentContainer() and
target.getFile().getParentContainer*() = targetPom.getFile().getParentContainer() and
depends(source, target)
)
}

Просмотреть файл

@ -3,7 +3,6 @@
*
* http://hg.openjdk.java.net/jdk9/jdk9/langtools/file/6ba2130e87bd/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/resources/jdk8_internals.txt
*/
predicate jdkInternalApi(string p) {
p = "apple.applescript" or
p = "apple.laf" or

Просмотреть файл

@ -3,16 +3,14 @@
*
* http://hg.openjdk.java.net/jdk9/jdk9/langtools/file/6ba2130e87bd/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/resources/jdkinternals.properties
*/
predicate jdkInternalReplacement(string old, string new) {
exists(string r, int eqIdx | jdkInternalReplacement(r) and eqIdx = r.indexOf("=") |
old = r.prefix(eqIdx) and
new = r.suffix(eqIdx+1)
new = r.suffix(eqIdx + 1)
)
}
private
predicate jdkInternalReplacement(string r) {
private predicate jdkInternalReplacement(string r) {
r = "com.sun.crypto.provider.SunJCE=Use java.security.Security.getProvider(provider-name) @since 1.3" or
r = "com.sun.org.apache.xml.internal.security=Use java.xml.crypto @since 1.6" or
r = "com.sun.org.apache.xml.internal.security.utils.Base64=Use java.util.Base64 @since 1.8" or

Просмотреть файл

@ -15,7 +15,8 @@ class RefiningEquals extends EqualsMethod {
// ... there is a `super` access that ...
exists(MethodAccess sup, SuperAccess qual |
// ... is of the form `super.something`, but not `A.super.something` ...
qual = sup.getQualifier() and not exists(qual.getQualifier()) and
qual = sup.getQualifier() and
not exists(qual.getQualifier()) and
// ... calls `super.equals` ...
sup.getCallee() instanceof EqualsMethod and
// ... on the (only) parameter of this method ...

Просмотреть файл

@ -14,40 +14,33 @@ library class BoundKind extends string {
this = "<="
}
predicate isEqual() {
this = "="
}
predicate isEqual() { this = "=" }
predicate isNotEqual() {
this = "!="
}
predicate isNotEqual() { this = "!=" }
predicate isLower() {
this = ">="
}
predicate isLower() { this = ">=" }
predicate isUpper() {
this = "<="
}
predicate isUpper() { this = "<=" }
predicate providesLowerBound() {
isEqual() or isLower()
}
predicate providesLowerBound() { isEqual() or isLower() }
predicate providesUpperBound() {
isEqual() or isUpper()
}
predicate providesUpperBound() { isEqual() or isUpper() }
}
/**
* The information from `s1` implies that `test` always has the value `testIsTrue`.
*/
predicate uselessTest(ConditionNode s1, BinaryExpr test, boolean testIsTrue) {
exists(ConditionBlock cb, SsaVariable v, BinaryExpr cond, boolean condIsTrue, int k1, int k2, CompileTimeConstantExpr c1, CompileTimeConstantExpr c2 |
exists(
ConditionBlock cb, SsaVariable v, BinaryExpr cond, boolean condIsTrue, int k1, int k2,
CompileTimeConstantExpr c1, CompileTimeConstantExpr c2
|
s1 = cond and
cb.getCondition() = cond and
cond.hasOperands(v.getAUse(), c1) and c1.getIntValue() = k1 and
test.hasOperands(v.getAUse(), c2) and c2.getIntValue() = k2 and
cond.hasOperands(v.getAUse(), c1) and
c1.getIntValue() = k1 and
test.hasOperands(v.getAUse(), c2) and
c2.getIntValue() = k2 and
v.getSourceVariable().getVariable() instanceof LocalScopeVariable and
cb.controls(test.getBasicBlock(), condIsTrue) and
v.getSourceVariable().getType() instanceof IntegralType and
@ -62,22 +55,36 @@ predicate uselessTest(ConditionNode s1, BinaryExpr test, boolean testIsTrue) {
or
exists(ComparisonExpr comp | comp = cond |
comp.getLesserOperand() = v.getAUse() and
(condIsTrue = true and boundKind.isUpper() and (if comp.isStrict() then bound = k1-1 else bound = k1)
(
condIsTrue = true and
boundKind.isUpper() and
(if comp.isStrict() then bound = k1 - 1 else bound = k1)
or
condIsTrue = false and boundKind.isLower() and (if comp.isStrict() then bound = k1 else bound = k1+1))
condIsTrue = false and
boundKind.isLower() and
(if comp.isStrict() then bound = k1 else bound = k1 + 1)
)
or
comp.getGreaterOperand() = v.getAUse() and
(condIsTrue = true and boundKind.isLower() and (if comp.isStrict() then bound = k1+1 else bound = k1)
(
condIsTrue = true and
boundKind.isLower() and
(if comp.isStrict() then bound = k1 + 1 else bound = k1)
or
condIsTrue = false and boundKind.isUpper() and (if comp.isStrict() then bound = k1 else bound = k1-1))
condIsTrue = false and
boundKind.isUpper() and
(if comp.isStrict() then bound = k1 else bound = k1 - 1)
)
)
|
// Given the bound we check if the `test` is either
// always true (`testIsTrue = true`) or always false (`testIsTrue = false`).
exists(EqualityTest testeq, boolean pol | testeq = test and pol = testeq.polarity() |
(
boundKind.providesLowerBound() and k2 < bound or
boundKind.providesUpperBound() and bound < k2 or
boundKind.providesLowerBound() and k2 < bound
or
boundKind.providesUpperBound() and bound < k2
or
boundKind.isNotEqual() and k2 = bound
) and
testIsTrue = pol.booleanNot()
@ -87,14 +94,42 @@ predicate uselessTest(ConditionNode s1, BinaryExpr test, boolean testIsTrue) {
or
exists(ComparisonExpr comp | comp = test |
comp.getLesserOperand() = v.getAUse() and
(boundKind.providesLowerBound() and testIsTrue = false and (k2 < bound or k2 = bound and comp.isStrict())
(
boundKind.providesLowerBound() and
testIsTrue = false and
(
k2 < bound
or
k2 = bound and comp.isStrict()
)
or
boundKind.providesUpperBound() and testIsTrue = true and (bound < k2 or bound = k2 and not comp.isStrict()))
boundKind.providesUpperBound() and
testIsTrue = true and
(
bound < k2
or
bound = k2 and not comp.isStrict()
)
)
or
comp.getGreaterOperand() = v.getAUse() and
(boundKind.providesLowerBound() and testIsTrue = true and (k2 < bound or k2 = bound and not comp.isStrict())
(
boundKind.providesLowerBound() and
testIsTrue = true and
(
k2 < bound
or
k2 = bound and not comp.isStrict()
)
or
boundKind.providesUpperBound() and testIsTrue = false and (bound < k2 or bound = k2 and comp.isStrict()))
boundKind.providesUpperBound() and
testIsTrue = false and
(
bound < k2
or
bound = k2 and comp.isStrict()
)
)
)
)
)

Просмотреть файл

@ -6,11 +6,13 @@ import semmle.code.java.frameworks.Mockito
/**
* Expression `e` is assigned to variable `v`.
*/
private
predicate flowsInto(Expr e, Variable v) {
e = v.getAnAssignedValue() or
exists(ParExpr p | flowsInto(p, v) | e = p.getExpr()) or
exists(CastExpr c | flowsInto(c, v) | e = c.getExpr()) or
private predicate flowsInto(Expr e, Variable v) {
e = v.getAnAssignedValue()
or
exists(ParExpr p | flowsInto(p, v) | e = p.getExpr())
or
exists(CastExpr c | flowsInto(c, v) | e = c.getExpr())
or
exists(ConditionalExpr c | flowsInto(c, v) | e = c.getTrueExpr() or e = c.getFalseExpr())
}
@ -30,8 +32,7 @@ predicate sqlType(RefType t) {
* A (reflexive, transitive) subtype of `Closeable` or `AutoCloseable`,
* or a closeable type in the `java.sql` package.
*/
private
predicate closeableType(RefType t) {
private predicate closeableType(RefType t) {
exists(RefType supertype | supertype = t.getASupertype*() |
supertype.hasName("Closeable") or
supertype.hasName("AutoCloseable") or
@ -73,14 +74,14 @@ class CloseableInitExpr extends Expr {
*
* The expression `parent` is the "closeable init" from which `e` is derived, if any, or `e` itself.
*/
private
predicate closeableInit(Expr e, Expr parent) {
private predicate closeableInit(Expr e, Expr parent) {
exists(ClassInstanceExpr cie | cie = e |
closeableType(cie.getType()) and
(
exists(Expr arg | arg = cie.getAnArgument() |
closeableType(arg.getType()) and
parent = arg)
parent = arg
)
or
(
not exists(Expr arg | arg = cie.getAnArgument() | closeableType(arg.getType())) and
@ -91,9 +92,7 @@ predicate closeableInit(Expr e, Expr parent) {
or
exists(SqlResourceOpeningMethodAccess ma | ma = e and parent = e)
or
exists(LocalVariableDecl v, Expr f |
e = v.getAnAccess() and flowsInto(f, v)
|
exists(LocalVariableDecl v, Expr f | e = v.getAnAccess() and flowsInto(f, v) |
closeableInit(f, parent)
)
}
@ -101,20 +100,16 @@ predicate closeableInit(Expr e, Expr parent) {
/**
* The transitive closure of `closeableInit`.
*/
private
predicate transitiveCloseableInit(Expr init, Expr transParent) {
private predicate transitiveCloseableInit(Expr init, Expr transParent) {
closeableInit+(init, transParent)
}
/**
* The expression `root` is the innermost "closeable init" expression of `cie` (possibly itself).
*/
private
predicate closeableInitRootCause(Expr cie, Expr root) {
private predicate closeableInitRootCause(Expr cie, Expr root) {
transitiveCloseableInit(cie, root) and
not exists(Expr other |
transitiveCloseableInit(root, other) and other != root
)
not exists(Expr other | transitiveCloseableInit(root, other) and other != root)
}
/**
@ -122,7 +117,8 @@ predicate closeableInitRootCause(Expr cie, Expr root) {
* the type of any of the "closeable init" expressions that it is derived from.
*/
RefType typeInDerivation(ClassInstanceExpr cie) {
result = cie.getType() or
result = cie.getType()
or
exists(Expr transParent | transitiveCloseableInit(cie, transParent) |
result = transParent.getType()
)
@ -131,20 +127,19 @@ RefType typeInDerivation(ClassInstanceExpr cie) {
/**
* A "closeable init" whose root cause is not a field or parameter.
*/
private
predicate locallyInitializedCloseable(Expr cie) {
private predicate locallyInitializedCloseable(Expr cie) {
exists(Expr root | closeableInitRootCause(cie, root) |
not exists(VarAccess va | va = root |
va.getVariable() instanceof Parameter or
va.getVariable() instanceof Field)
va.getVariable() instanceof Field
)
)
}
/**
* A locally initialized "closeable init" whose constructor does not have a throws clause.
*/
private
predicate safeCloseableInit(ClassInstanceExpr cie) {
private predicate safeCloseableInit(ClassInstanceExpr cie) {
locallyInitializedCloseable(cie) and
not exists(cie.getConstructor().getAnException())
}
@ -152,8 +147,7 @@ predicate safeCloseableInit(ClassInstanceExpr cie) {
/**
* A locally initialized "closeable init" that is neither assigned to a variable nor passed to a safe outer "closeable init".
*/
private
predicate unassignedCloseableInit(CloseableInitExpr cie) {
private predicate unassignedCloseableInit(CloseableInitExpr cie) {
locallyInitializedCloseable(cie) and
not flowsInto(cie, _) and
not exists(ClassInstanceExpr outer | safeCloseableInit(outer) | cie = outer.getAnArgument())
@ -162,23 +156,25 @@ predicate unassignedCloseableInit(CloseableInitExpr cie) {
/**
* A locally initialized "closeable init" that flows into a field or return statement.
*/
private
predicate escapingCloseableInit(CloseableInitExpr cie) {
private predicate escapingCloseableInit(CloseableInitExpr cie) {
exists(Expr wrappingResource |
locallyInitializedCloseable(cie) and (transitiveCloseableInit(wrappingResource, cie) or wrappingResource = cie)
|
exists(Field f | flowsInto(wrappingResource, f)) or
locallyInitializedCloseable(cie) and
(transitiveCloseableInit(wrappingResource, cie) or wrappingResource = cie)
|
exists(Field f | flowsInto(wrappingResource, f))
or
exists(ConstructorCall call | call.callsThis() or call.callsSuper() |
closeableType(call.getConstructedType()) and
call.getAnArgument() = wrappingResource
) or
wrappingResource.getEnclosingStmt() instanceof ReturnStmt or
)
or
wrappingResource.getEnclosingStmt() instanceof ReturnStmt
or
getCloseableVariable(wrappingResource).getAnAccess().getEnclosingStmt() instanceof ReturnStmt
or
exists(Parameter p0 |
escapingMethodParameterClosable(p0)
|
p0.getAnArgument() = wrappingResource or
exists(Parameter p0 | escapingMethodParameterClosable(p0) |
p0.getAnArgument() = wrappingResource
or
exists(LocalVariableDecl v |
p0.getAnArgument() = v.getAnAccess() and flowsInto(wrappingResource, v)
)
@ -189,17 +185,20 @@ predicate escapingCloseableInit(CloseableInitExpr cie) {
/**
* Holds if `p` is a closable that escapes by an assignment to a field.
*/
private
predicate escapingMethodParameterClosable(Parameter p) {
private predicate escapingMethodParameterClosable(Parameter p) {
p.getCallable() instanceof Method and
exists(Expr wrappingResource |
closeableType(p.getType()) and (transitiveCloseableInit(wrappingResource, p.getAnAccess()) or wrappingResource = p.getAnAccess())
|
exists(Field f | flowsInto(wrappingResource, f)) or
exists(Parameter p0 |
escapingMethodParameterClosable(p0)
|
p0.getAnArgument() = wrappingResource or
closeableType(p.getType()) and
(
transitiveCloseableInit(wrappingResource, p.getAnAccess()) or
wrappingResource = p.getAnAccess()
)
|
exists(Field f | flowsInto(wrappingResource, f))
or
exists(Parameter p0 | escapingMethodParameterClosable(p0) |
p0.getAnArgument() = wrappingResource
or
exists(LocalVariableDecl v |
p0.getAnArgument() = v.getAnAccess() and flowsInto(wrappingResource, v)
)
@ -210,16 +209,14 @@ predicate escapingMethodParameterClosable(Parameter p) {
/**
* A local variable into which the specified (locally initialized) "closeable init" flows.
*/
private
LocalVariableDecl getCloseableVariable(CloseableInitExpr cie) {
private LocalVariableDecl getCloseableVariable(CloseableInitExpr cie) {
locallyInitializedCloseable(cie) and flowsInto(cie, result)
}
/**
* A variable on which a "close" method is called, implicitly or explicitly, directly or indirectly.
*/
private
predicate closeCalled(Variable v) {
private predicate closeCalled(Variable v) {
// `close()` is implicitly called on variables declared or referenced
// in the resources clause of try-with-resource statements.
exists(TryStmt try | try.getAResourceVariable() = v)
@ -227,7 +224,7 @@ predicate closeCalled(Variable v) {
// Otherwise, there should be an explicit call to a method whose name contains "close".
exists(MethodAccess e |
v = getCloseableVariable(_) or v instanceof Parameter or v instanceof LocalVariableDecl
|
|
(
e.getMethod().getName().toLowerCase().matches("%close%") and
exists(VarAccess va | va = v.getAnAccess() |
@ -239,10 +236,14 @@ predicate closeCalled(Variable v) {
// The "close" call could happen indirectly inside a helper method of unknown name.
exists(int i | exprs(v.getAnAccess(), _, _, e, i) |
exists(Parameter p, int j | params(p, _, j, e.getMethod(), _) |
(closeCalled(p) and i = j) or
(closeCalled(p) and i = j)
or
// The helper method could be iterating over a varargs parameter.
exists(EnhancedForStmt for | for.getExpr() = p.getAnAccess() |
closeCalled(for.getVariable().getVariable())) and p.isVarargs() and j<=i
closeCalled(for.getVariable().getVariable())
) and
p.isVarargs() and
j <= i
)
)
)
@ -252,17 +253,17 @@ predicate closeCalled(Variable v) {
* A locally initialized "closeable init" that flows into a variable on which a "close" method is called
* or is immediately closed after creation.
*/
private
predicate closedResource(CloseableInitExpr cie) {
private predicate closedResource(CloseableInitExpr cie) {
locallyInitializedCloseable(cie) and
(
exists(LocalVariableDecl v | closeCalled(v) |
exists(Expr wrappingResource |
wrappingResource = cie or transitiveCloseableInit(wrappingResource, cie)
|
|
flowsInto(wrappingResource, v)
)
) or
)
or
immediatelyClosed(cie)
)
}
@ -274,9 +275,9 @@ private predicate immediatelyClosed(ClassInstanceExpr cie) {
/**
* A unassigned or locally-assigned "closeable init" that does not escape and is not closed.
*/
private
predicate badCloseableInitImpl(CloseableInitExpr cie) {
(unassignedCloseableInit(cie) and not immediatelyClosed(cie) and not escapingCloseableInit(cie)) or
private predicate badCloseableInitImpl(CloseableInitExpr cie) {
(unassignedCloseableInit(cie) and not immediatelyClosed(cie) and not escapingCloseableInit(cie))
or
(locallyInitializedCloseable(cie) and not closedResource(cie) and not escapingCloseableInit(cie))
}
@ -285,7 +286,9 @@ predicate badCloseableInitImpl(CloseableInitExpr cie) {
*/
predicate badCloseableInit(CloseableInitExpr cie) {
badCloseableInitImpl(cie) and
not exists(CloseableInitExpr cie2 | transitiveCloseableInit(cie, cie2) and cie2 != cie and badCloseableInitImpl(cie2))
not exists(CloseableInitExpr cie2 |
transitiveCloseableInit(cie, cie2) and cie2 != cie and badCloseableInitImpl(cie2)
)
}
/**
@ -294,12 +297,14 @@ predicate badCloseableInit(CloseableInitExpr cie) {
predicate noNeedToClose(CloseableInitExpr cie) {
locallyInitializedCloseable(cie) and
(
(cie instanceof ClassInstanceExpr and not exists(cie.(ClassInstanceExpr).getAnArgument())) or
(cie instanceof ClassInstanceExpr and not exists(cie.(ClassInstanceExpr).getAnArgument()))
or
exists(RefType t | t = cie.getType() and t.fromSource() |
exists(Method close | close.getDeclaringType() = t and close.getName() = "close" |
not exists(close.getBody().getAChild())
)
) or
)
or
exists(CloseableInitExpr sqlStmt, LocalVariableDecl v |
// If a `java.sql.Statement` is closed, an associated `java.sql.ResultSet` is implicitly closed.
sqlStmt.getType().(RefType).getASupertype*() instanceof TypeStatement and
@ -307,7 +312,8 @@ predicate noNeedToClose(CloseableInitExpr cie) {
closedResource(sqlStmt) and
cie.getType() instanceof TypeResultSet and
cie.(SqlResourceOpeningMethodAccess).getQualifier() = v.getAnAccess()
) or
)
or
exists(MethodAccess ma | cie.(ClassInstanceExpr).getAnArgument() = ma |
ma.getMethod() instanceof ServletResponseGetOutputStreamMethod or
ma.getMethod() instanceof ServletResponseGetWriterMethod or
@ -317,5 +323,7 @@ predicate noNeedToClose(CloseableInitExpr cie) {
or
exists(CloseableInitExpr inner | transitiveCloseableInit(cie, inner) | noNeedToClose(inner))
or
exists(CloseableInitExpr inner | transitiveCloseableInit(cie, inner) | closeCalled(getCloseableVariable(inner)))
exists(CloseableInitExpr inner | transitiveCloseableInit(cie, inner) |
closeCalled(getCloseableVariable(inner))
)
}

Просмотреть файл

@ -9,9 +9,7 @@ import java
* declared in an immutable type, and that every method overriding it is also
* designed for chaining.
*/
predicate designedForChaining(Method m) {
not nonChaining(m)
}
predicate designedForChaining(Method m) { not nonChaining(m) }
private predicate nonChaining(Method m) {
// The method has a body, and at least one of the return values is not suitable for chaining.
@ -22,9 +20,11 @@ private predicate nonChaining(Method m) {
not exists(m.getBody()) and
(
// ... it has the wrong return type, ...
not hasSubtype*(m.getReturnType(), m.getDeclaringType()) or
not hasSubtype*(m.getReturnType(), m.getDeclaringType())
or
// ... it is defined on an immutable type, or ...
m.getDeclaringType() instanceof ImmutableType or
m.getDeclaringType() instanceof ImmutableType
or
// ... it has an override that is non-chaining.
exists(Method override | override.overrides(m) | nonChaining(override))
)
@ -36,25 +36,31 @@ private predicate nonChainingReturn(Method m, ReturnStmt ret) {
(
ret.getResult() instanceof ThisAccess and
ret.getResult().getType() != m.getDeclaringType()
) or
)
or
// A method call to the wrong method is returned.
(
ret.getResult() instanceof MethodAccess and
exists(MethodAccess delegateCall, Method delegate |
delegateCall = ret.getResult() and
delegate = delegateCall.getMethod()
|
delegate.getDeclaringType() != m.getDeclaringType() or
delegate.isStatic() or
not hasSubtype*(m.getReturnType(), delegate.getReturnType()) or
|
delegate.getDeclaringType() != m.getDeclaringType()
or
delegate.isStatic()
or
not hasSubtype*(m.getReturnType(), delegate.getReturnType())
or
// A method on the wrong object is called.
not (
delegateCall.getQualifier().getProperExpr() instanceof ThisAccess or
not exists(delegateCall.getQualifier())
) or
)
or
nonChaining(delegate)
)
) or
)
or
// Something else is returned.
not (
ret.getResult() instanceof ThisAccess or

Просмотреть файл

@ -17,10 +17,16 @@ import java
class RangeCallable extends Callable {
predicate hasLocationInfo(string path, int sl, int sc, int el, int ec) {
exists(int elSuper, int ecSuper | super.hasLocationInfo(path, sl, sc, elSuper, ecSuper) |
this.getBody().hasLocationInfo(path, _, _, el, ec) or
(not exists(this.getBody()) and
(lastParameter().hasLocationInfo(path, _, _, el, ec) or
(not exists(this.getAParameter()) and el = elSuper and ec = ecSuper)))
this.getBody().hasLocationInfo(path, _, _, el, ec)
or
(
not exists(this.getBody()) and
(
lastParameter().hasLocationInfo(path, _, _, el, ec)
or
(not exists(this.getAParameter()) and el = elSuper and ec = ecSuper)
)
)
)
}
@ -37,7 +43,8 @@ class RangeCallable extends Callable {
class RangeRefType extends RefType {
predicate hasLocationInfo(string path, int sl, int sc, int el, int ec) {
exists(int elSuper, int ecSuper | super.hasLocationInfo(path, sl, sc, elSuper, ecSuper) |
lastMember().hasLocationInfo(path, _, _, el, ec) or
lastMember().hasLocationInfo(path, _, _, el, ec)
or
(not exists(this.getAMember()) and el = elSuper and ec = ecSuper)
)
}

Просмотреть файл

@ -1,9 +1,7 @@
import java
import semmle.code.java.controlflow.Guards
abstract class PathCreation extends Expr {
abstract Expr getInput();
}
abstract class PathCreation extends Expr { abstract Expr getInput(); }
class PathsGet extends PathCreation, MethodAccess {
PathsGet() {
@ -28,9 +26,7 @@ class FileSystemGetPath extends PathCreation, MethodAccess {
}
class FileCreation extends PathCreation, ClassInstanceExpr {
FileCreation() {
this.getConstructedType() instanceof TypeFile
}
FileCreation() { this.getConstructedType() instanceof TypeFile }
override Expr getInput() {
result = this.getAnArgument() and
@ -40,9 +36,7 @@ class FileCreation extends PathCreation, ClassInstanceExpr {
}
class FileWriterCreation extends PathCreation, ClassInstanceExpr {
FileWriterCreation() {
this.getConstructedType().getQualifiedName() = "java.io.FileWriter"
}
FileWriterCreation() { this.getConstructedType().getQualifiedName() = "java.io.FileWriter" }
override Expr getInput() {
result = this.getAnArgument() and
@ -58,11 +52,10 @@ predicate inWeakCheck(Expr e) {
def.getName() = "endsWith" or
def.getName() = "isEmpty" or
def.getName() = "equals"
) or
// Checking against `null` has no bearing on path traversal.
exists(EqualityTest b | b.getAnOperand() = e |
b.getAnOperand() instanceof NullLiteral
)
or
// Checking against `null` has no bearing on path traversal.
exists(EqualityTest b | b.getAnOperand() = e | b.getAnOperand() instanceof NullLiteral)
}
// Ignore cases where the variable has been checked somehow,

Просмотреть файл

@ -2,10 +2,17 @@ import semmle.code.java.dataflow.FlowSources
import semmle.code.java.security.ExternalProcess
private class RemoteUserInputToArgumentToExecFlowConfig extends TaintTracking::Configuration {
RemoteUserInputToArgumentToExecFlowConfig() { this = "ExecCommon::RemoteUserInputToArgumentToExecFlowConfig" }
RemoteUserInputToArgumentToExecFlowConfig() {
this = "ExecCommon::RemoteUserInputToArgumentToExecFlowConfig"
}
override predicate isSource(DataFlow::Node src) { src instanceof RemoteUserInput }
override predicate isSink(DataFlow::Node sink) { sink.asExpr() instanceof ArgumentToExec }
override predicate isSanitizer(DataFlow::Node node) { node.getType() instanceof PrimitiveType or node.getType() instanceof BoxedType }
override predicate isSanitizer(DataFlow::Node node) {
node.getType() instanceof PrimitiveType or node.getType() instanceof BoxedType
}
}
/**

Просмотреть файл

@ -6,12 +6,13 @@ import semmle.code.java.frameworks.android.SQLite
import semmle.code.java.frameworks.javaee.Persistence
/** A sink for database query language injection vulnerabilities. */
abstract class QueryInjectionSink extends DataFlow::ExprNode {}
abstract class QueryInjectionSink extends DataFlow::ExprNode { }
/** A sink for SQL injection vulnerabilities. */
class SqlInjectionSink extends QueryInjectionSink {
SqlInjectionSink() {
this.getExpr() instanceof SqlExpr or
this.getExpr() instanceof SqlExpr
or
exists(SQLiteRunner s, MethodAccess m | m.getMethod() = s |
m.getArgument(s.sqlIndex()) = this.getExpr()
)
@ -33,9 +34,14 @@ class PersistenceQueryInjectionSink extends QueryInjectionSink {
private class QueryInjectionFlowConfig extends TaintTracking::Configuration {
QueryInjectionFlowConfig() { this = "SqlInjectionLib::QueryInjectionFlowConfig" }
override predicate isSource(DataFlow::Node src) { src instanceof RemoteUserInput }
override predicate isSink(DataFlow::Node sink) { sink instanceof QueryInjectionSink }
override predicate isSanitizer(DataFlow::Node node) { node.getType() instanceof PrimitiveType or node.getType() instanceof BoxedType }
override predicate isSanitizer(DataFlow::Node node) {
node.getType() instanceof PrimitiveType or node.getType() instanceof BoxedType
}
}
/**
@ -43,7 +49,5 @@ private class QueryInjectionFlowConfig extends TaintTracking::Configuration {
* can be excluded from `SqlUnescaped.ql` to avoid overlapping results.
*/
predicate queryTaintedBy(QueryInjectionSink query, RemoteUserInput source) {
exists(QueryInjectionFlowConfig conf |
conf.hasFlow(source, query)
)
exists(QueryInjectionFlowConfig conf | conf.hasFlow(source, query))
}

Просмотреть файл

@ -10,18 +10,21 @@ class HeaderSplittingSink extends DataFlow::ExprNode {
exists(ResponseAddCookieMethod m, MethodAccess ma |
ma.getMethod() = m and
this.getExpr() = ma.getArgument(0)
) or
)
or
exists(ResponseAddHeaderMethod m, MethodAccess ma |
ma.getMethod() = m and
this.getExpr() = ma.getAnArgument()
) or
)
or
exists(ResponseSetHeaderMethod m, MethodAccess ma |
ma.getMethod() = m and
this.getExpr() = ma.getAnArgument()
) or
)
or
exists(JaxRsResponseBuilder builder, Method m |
m = builder.getAMethod() and m.getName() = "header"
|
|
this.getExpr() = m.getAReference().getArgument(1)
)
}

Просмотреть файл

@ -7,8 +7,13 @@ private import BoundingChecks
* If the `Array` accessed by the `ArrayAccess` is a fixed size, return the array size.
*/
int fixedArraySize(ArrayAccess arrayAccess) {
result = arrayAccess.getArray().(VarAccess).getVariable().getAnAssignedValue()
.(ArrayCreationExpr).getFirstDimensionSize()
result = arrayAccess
.getArray()
.(VarAccess)
.getVariable()
.getAnAssignedValue()
.(ArrayCreationExpr)
.getFirstDimensionSize()
}
/**
@ -22,8 +27,12 @@ private predicate arrayIndexOutOfBoundExceptionCaught(ArrayAccess arrayAccess) {
ts.getAResourceExpr().getAChildExpr*() = arrayAccess
) and
cc = ts.getACatchClause()
|
cc.getVariable().getType().(RefType).hasQualifiedName("java.lang", "ArrayIndexOutOfBoundsException")
|
cc
.getVariable()
.getType()
.(RefType)
.hasQualifiedName("java.lang", "ArrayIndexOutOfBoundsException")
)
}
@ -41,15 +50,11 @@ class PointlessLoop extends WhileStmt {
PointlessLoop() {
getCondition().(BooleanLiteral).getBooleanValue() = true and
// The only `break` must be the last statement.
forall(BreakStmt break |
break.(JumpStmt).getTarget() = this
|
forall(BreakStmt break | break.(JumpStmt).getTarget() = this |
this.getStmt().(Block).getLastStmt() = break
) and
// No `continue` statements.
not exists(ContinueStmt continue |
continue.(JumpStmt).getTarget() = this
)
not exists(ContinueStmt continue | continue.(JumpStmt).getTarget() = this)
}
}
@ -64,11 +69,13 @@ class CheckableArrayAccess extends ArrayAccess {
/*
* We are not interested in array accesses that don't access the first dimension.
*/
not this.getArray() instanceof ArrayAccess and
/*
* Array accesses within loops can make it difficult to verify whether the index is checked
* prior to access. Ignore "pointless" loops of the sort found in Juliet test cases.
*/
not exists(LoopStmt loop |
loop.getBody().getAChild*() = getEnclosingStmt() and
not loop instanceof PointlessLoop
@ -84,8 +91,7 @@ class CheckableArrayAccess extends ArrayAccess {
index = getIndexExpr() and
not (
// There is a condition dominating this expression ensuring that the index is >= 0.
lowerBound(index) >= 0
and
lowerBound(index) >= 0 and
// There is a condition dominating this expression that ensures the index is less than the length.
lessthanLength(this)
)
@ -99,6 +105,7 @@ class CheckableArrayAccess extends ArrayAccess {
/*
* Find an `ArrayCreationExpr` for the array used in this indexing operation.
*/
exists(VariableAssign assign |
assign.getSource() = arrayCreation and
defUsePair(assign, this.getArray())
@ -107,10 +114,12 @@ class CheckableArrayAccess extends ArrayAccess {
* If the array access is protected by a conditional that verifies the index is less than the array
* length, then the array will never be accessed if the size is zero.
*/
not lessthanLength(this) and
/*
* Verify that the size expression is never checked to be greater than 0.
*/
sizeExpr = arrayCreation.getDimension(0) and
not lowerBound(sizeExpr) > 0
}
@ -120,7 +129,6 @@ class CheckableArrayAccess extends ArrayAccess {
* A source of "flow" which has an upper or lower bound.
*/
abstract class BoundedFlowSource extends DataFlow::Node {
/**
* Return a lower bound for the input, if possible.
*/
@ -144,7 +152,7 @@ class RandomValueFlowSource extends BoundedFlowSource {
RandomValueFlowSource() {
exists(RefType random, MethodAccess nextAccess |
random.hasQualifiedName("java.util", "Random")
|
|
nextAccess.getCallee().getDeclaringType().getAnAncestor() = random and
nextAccess.getCallee().getName().matches("next%") and
nextAccess = this.asExpr()
@ -163,31 +171,24 @@ class RandomValueFlowSource extends BoundedFlowSource {
* If this call specified an argument to `nextInt()`, and that argument is a compile time constant,
* it forms the upper bound.
*/
this.asExpr().(MethodAccess).getCallee().hasName("nextInt") and
this.asExpr().(MethodAccess).getNumArgument() = 1 and
result = this.asExpr().(MethodAccess).getArgument(0).(CompileTimeConstantExpr).getIntValue()
}
string getDescription() {
result = "Random value"
}
string getDescription() { result = "Random value" }
}
/**
* A compile time constant expression that evaluates to a numeric type.
*/
class NumericLiteralFlowSource extends BoundedFlowSource {
NumericLiteralFlowSource() {
exists(this.asExpr().(CompileTimeConstantExpr).getIntValue())
}
NumericLiteralFlowSource() { exists(this.asExpr().(CompileTimeConstantExpr).getIntValue()) }
int lowerBound() {
result = this.asExpr().(CompileTimeConstantExpr).getIntValue()
}
int lowerBound() { result = this.asExpr().(CompileTimeConstantExpr).getIntValue() }
int upperBound() {
result = this.asExpr().(CompileTimeConstantExpr).getIntValue()
}
int upperBound() { result = this.asExpr().(CompileTimeConstantExpr).getIntValue() }
string getDescription() {
result = "Literal value " + this.asExpr().(CompileTimeConstantExpr).getIntValue()

Просмотреть файл

@ -24,9 +24,10 @@ int lowerBound(VarAccess va) {
exists(ComparisonExpr greaterThanValue |
// This condition should hold when the variable is later accessed.
conditionHolds(greaterThanValue, va)
|
|
greaterThanValue.getGreaterOperand() = va.getVariable().getAnAccess() and
if greaterThanValue.isStrict() then
if greaterThanValue.isStrict()
then
// value > i, so value has a lower bound of i + 1
result = greaterThanValue.getLesserOperand().(CompileTimeConstantExpr).getIntValue() + 1
else
@ -43,7 +44,7 @@ predicate lessthanLength(ArrayAccess a) {
exists(ComparisonExpr lessThanLength, VarAccess va |
va = a.getIndexExpr() and
conditionHolds(lessThanLength, va)
|
|
lessThanLength.getGreaterOperand().(FieldAccess).getQualifier() = arrayReference(a) and
lessThanLength.getGreaterOperand().(FieldAccess).getField().hasName("length") and
lessThanLength.getLesserOperand() = va.getVariable().getAnAccess() and
@ -54,7 +55,8 @@ predicate lessthanLength(ArrayAccess a) {
/**
* Return all other references to the array accessed in the `ArrayAccess`.
*/
private pragma[nomagic] Expr arrayReference(ArrayAccess arrayAccess) {
pragma[nomagic]
private Expr arrayReference(ArrayAccess arrayAccess) {
// Array is stored in a variable.
result = arrayAccess.getArray().(VarAccess).getVariable().getAnAccess() or
// Array is returned from a method.

Просмотреть файл

@ -7,19 +7,18 @@ import semmle.code.java.controlflow.Guards
* The type of `exp` is narrower than or equal to `numType`,
* or there is an enclosing cast to a type at least as narrow as 'numType'.
*/
predicate narrowerThanOrEqualTo(ArithExpr exp, NumType numType) {
exp.getType().(NumType).widerThan(numType)
implies
exists(CastExpr cast | cast.getAChildExpr().getProperExpr() = exp |
numType.widerThanOrEqualTo((NumType)cast.getType())
numType.widerThanOrEqualTo(cast.getType().(NumType))
)
}
/** Holds if the size of this use is guarded using `Math.abs`. */
predicate guardedAbs(ArithExpr e, Expr use) {
exists(MethodAccess m |
m.getMethod() instanceof MethodAbs
|
exists(MethodAccess m | m.getMethod() instanceof MethodAbs |
m.getArgument(0) = use and
guardedLesser(e, m)
)
@ -31,7 +30,8 @@ predicate guardedLesser(ArithExpr e, Expr use) {
use = guard.getLesserOperand() and
guard = c.getCondition() and
c.controls(e.getBasicBlock(), true)
) or
)
or
guardedAbs(e, use)
}
@ -41,7 +41,8 @@ predicate guardedGreater(ArithExpr e, Expr use) {
use = guard.getGreaterOperand() and
guard = c.getCondition() and
c.controls(e.getBasicBlock(), true)
) or
)
or
guardedAbs(e, use)
}
@ -55,25 +56,31 @@ predicate guarded(ArithExpr e, Expr use) {
}
/** A prior use of the same variable that could see the same value. */
VarAccess priorAccess(VarAccess access) {
useUsePair(result, access)
}
VarAccess priorAccess(VarAccess access) { useUsePair(result, access) }
/** Holds if `e` is guarded against overflow by `use`. */
predicate guardedAgainstOverflow(ArithExpr e, VarAccess use) {
use = e.getAnOperand() and
(
// overflow possible if large
e instanceof AddExpr and guardedLesser(e, priorAccess(use)) or
e instanceof PreIncExpr and guardedLesser(e, priorAccess(use)) or
e instanceof PostIncExpr and guardedLesser(e, priorAccess(use)) or
e instanceof AddExpr and guardedLesser(e, priorAccess(use))
or
e instanceof PreIncExpr and guardedLesser(e, priorAccess(use))
or
e instanceof PostIncExpr and guardedLesser(e, priorAccess(use))
or
// overflow unlikely with subtraction
e instanceof SubExpr or
e instanceof PreDecExpr or
e instanceof PostDecExpr or
e instanceof SubExpr
or
e instanceof PreDecExpr
or
e instanceof PostDecExpr
or
// overflow possible if large or small
e instanceof MulExpr and guardedLesser(e, priorAccess(use)) and
guardedGreater(e, priorAccess(use)) or
e instanceof MulExpr and
guardedLesser(e, priorAccess(use)) and
guardedGreater(e, priorAccess(use))
or
// overflow possible if MIN_VALUE
e instanceof DivExpr and guardedGreater(e, priorAccess(use))
)
@ -84,16 +91,25 @@ predicate guardedAgainstUnderflow(ArithExpr e, VarAccess use) {
use = e.getAnOperand() and
(
// underflow unlikely for addition
e instanceof AddExpr or
e instanceof PreIncExpr or
e instanceof PostIncExpr or
e instanceof AddExpr
or
e instanceof PreIncExpr
or
e instanceof PostIncExpr
or
// underflow possible if use is left operand and small
e instanceof SubExpr and (use = e.getRightOperand() or guardedGreater(e, priorAccess(use))) or
e instanceof PreDecExpr and guardedGreater(e, priorAccess(use)) or
e instanceof PostDecExpr and guardedGreater(e, priorAccess(use)) or
e instanceof SubExpr and
(use = e.getRightOperand() or guardedGreater(e, priorAccess(use)))
or
e instanceof PreDecExpr and guardedGreater(e, priorAccess(use))
or
e instanceof PostDecExpr and guardedGreater(e, priorAccess(use))
or
// underflow possible if large or small
e instanceof MulExpr and guardedLesser(e, priorAccess(use)) and
guardedGreater(e, priorAccess(use)) or
e instanceof MulExpr and
guardedLesser(e, priorAccess(use)) and
guardedGreater(e, priorAccess(use))
or
// underflow possible if MAX_VALUE
e instanceof DivExpr and guardedLesser(e, priorAccess(use))
)

Просмотреть файл

@ -9,8 +9,7 @@ import semmle.code.java.security.SensitiveActions
/** Test code filter. */
predicate testMethod(Method m) {
(
m instanceof TestMethod
or
m instanceof TestMethod or
m.getDeclaringType() instanceof TestClass
) and
// Do report results in the Juliet tests.
@ -19,14 +18,19 @@ predicate testMethod(Method m) {
private class SensitiveSourceFlowConfig extends TaintTracking::Configuration {
SensitiveSourceFlowConfig() { this = "SensitiveStorage::SensitiveSourceFlowConfig" }
override predicate isSource(DataFlow::Node src) { src.asExpr() instanceof SensitiveExpr }
override predicate isSink(DataFlow::Node sink) {
sink.asExpr() = cookieInput(_) or
sink.asExpr() = cookieInput(_)
or
exists(MethodAccess m |
m.getMethod() instanceof PropertiesSetPropertyMethod and sink.asExpr() = m.getArgument(1)
) or
)
or
sink.asExpr() = getInstanceInput(_, _)
}
override predicate isSanitizer(DataFlow::Node n) {
n.getType() instanceof NumericType or n.getType() instanceof BooleanType
}
@ -74,13 +78,13 @@ private predicate cookieStore(DataFlow::Node cookie, Expr store) {
private class CookieToStoreFlowConfig extends DataFlow2::Configuration {
CookieToStoreFlowConfig() { this = "SensitiveStorage::CookieToStoreFlowConfig" }
override predicate isSource(DataFlow::Node src) { src.asExpr() instanceof Cookie }
override predicate isSink(DataFlow::Node sink) { cookieStore(sink, _) }
}
private Expr cookieInput(Cookie c) {
result = c.getArgument(1)
}
private Expr cookieInput(Cookie c) { result = c.getArgument(1) }
/** The instantiation of a cookie, which can act as storage. */
class Cookie extends Storable {
@ -89,9 +93,7 @@ class Cookie extends Storable {
}
/** Gets an input, for example `input` in `new Cookie("...", input);`. */
override Expr getAnInput() {
result = cookieInput(this)
}
override Expr getAnInput() { result = cookieInput(this) }
/** Gets a store, for example `response.addCookie(cookie);`. */
override Expr getAStore() {
@ -120,7 +122,9 @@ private predicate propertiesStore(DataFlow::Node prop, Expr store) {
private class PropertiesFlowConfig extends DataFlow3::Configuration {
PropertiesFlowConfig() { this = "SensitiveStorage::PropertiesFlowConfig" }
override predicate isSource(DataFlow::Node src) { src.asExpr() instanceof Properties }
override predicate isSink(DataFlow::Node sink) {
propertiesInput(sink, _) or
propertiesStore(sink, _)
@ -129,9 +133,7 @@ private class PropertiesFlowConfig extends DataFlow3::Configuration {
/** The instantiation of a `Properties` object, which can be stored to disk. */
class Properties extends Storable {
Properties() {
this.getConstructor().getDeclaringType() instanceof TypeProperty
}
Properties() { this.getConstructor().getDeclaringType() instanceof TypeProperty }
/** Gets an input, for example `input` in `props.setProperty("password", input);`. */
override Expr getAnInput() {
@ -167,7 +169,7 @@ private Expr getInstanceInput(DataFlow::Node instance, RefType t) {
a.getDest() = fa and
a.getSource() = result and
fa.getField().getDeclaringType() = t
|
|
t.getASourceSupertype*() instanceof TypeSerializable or
t instanceof JAXBElement
)
@ -175,12 +177,15 @@ private Expr getInstanceInput(DataFlow::Node instance, RefType t) {
private class ClassStoreFlowConfig extends DataFlow4::Configuration {
ClassStoreFlowConfig() { this = "SensitiveStorage::ClassStoreFlowConfig" }
override predicate isSource(DataFlow::Node src) { src.asExpr() instanceof ClassStore }
override predicate isSink(DataFlow::Node sink) {
exists(getInstanceInput(sink, _)) or
serializableStore(sink, _) or
marshallableStore(sink, _)
}
override int fieldFlowBranchLimit() { result = 1 }
}
@ -212,7 +217,9 @@ class Serializable extends ClassStore {
// `Properties` are `Serializable`, but handled elsewhere.
not this instanceof Properties and
// restrict attention to tainted instances
exists(SensitiveSource data | data.flowsToCached(getInstanceInput(_, this.getConstructor().getDeclaringType())))
exists(SensitiveSource data |
data.flowsToCached(getInstanceInput(_, this.getConstructor().getDeclaringType()))
)
}
/** Gets a store, for example `outputStream.writeObject(instance)`. */
@ -226,9 +233,7 @@ class Serializable extends ClassStore {
/** The instantiation of a marshallable class, which can be stored to disk as XML. */
class Marshallable extends ClassStore {
Marshallable() {
this.getConstructor().getDeclaringType() instanceof JAXBElement
}
Marshallable() { this.getConstructor().getDeclaringType() instanceof JAXBElement }
/** Gets a store, for example `marshaller.marshal(instance)`. */
override Expr getAStore() {

Просмотреть файл

@ -18,9 +18,12 @@ class XMLDecoderReadObjectMethod extends Method {
class SafeXStream extends DataFlow2::Configuration {
SafeXStream() { this = "UnsafeDeserialization::SafeXStream" }
override predicate isSource(DataFlow::Node src) {
any(XStreamEnableWhiteListing ma).getQualifier().(VarAccess).getVariable().getAnAccess() = src.asExpr()
any(XStreamEnableWhiteListing ma).getQualifier().(VarAccess).getVariable().getAnAccess() = src
.asExpr()
}
override predicate isSink(DataFlow::Node sink) {
exists(MethodAccess ma |
sink.asExpr() = ma.getQualifier() and
@ -31,9 +34,12 @@ class SafeXStream extends DataFlow2::Configuration {
class SafeKryo extends DataFlow2::Configuration {
SafeKryo() { this = "UnsafeDeserialization::SafeKryo" }
override predicate isSource(DataFlow::Node src) {
any(KryoEnableWhiteListing ma).getQualifier().(VarAccess).getVariable().getAnAccess() = src.asExpr()
any(KryoEnableWhiteListing ma).getQualifier().(VarAccess).getVariable().getAnAccess() = src
.asExpr()
}
override predicate isSink(DataFlow::Node sink) {
exists(MethodAccess ma |
sink.asExpr() = ma.getQualifier() and
@ -64,8 +70,7 @@ predicate unsafeDeserialization(MethodAccess ma, Expr sink) {
}
class UnsafeDeserializationSink extends DataFlow::ExprNode {
UnsafeDeserializationSink() {
unsafeDeserialization(_, this.getExpr())
}
UnsafeDeserializationSink() { unsafeDeserialization(_, this.getExpr()) }
MethodAccess getMethodAccess() { unsafeDeserialization(result, this.getExpr()) }
}

Просмотреть файл

@ -15,7 +15,7 @@ class UrlRedirectSink extends DataFlow::ExprNode {
exists(MethodAccess ma |
ma.getMethod() instanceof ResponseSetHeaderMethod or
ma.getMethod() instanceof ResponseAddHeaderMethod
|
|
ma.getArgument(0).(CompileTimeConstantExpr).getStringValue() = "Location" and
this.asExpr() = ma.getArgument(1)
)

Просмотреть файл

@ -20,6 +20,7 @@ abstract class XmlParserCall extends MethodAccess {
* Gets the argument representing the XML content to be parsed.
*/
abstract Expr getSink();
/**
* Holds if the call is safe.
*/
@ -30,7 +31,6 @@ abstract class XmlParserCall extends MethodAccess {
* An access to a method use for configuring the parser.
*/
abstract class ParserConfig extends MethodAccess {
/**
* Holds if the method disables a property.
*/
@ -54,16 +54,12 @@ abstract class ParserConfig extends MethodAccess {
/** The class `javax.xml.parsers.DocumentBuilderFactory`. */
class DocumentBuilderFactory extends RefType {
DocumentBuilderFactory() {
this.hasQualifiedName("javax.xml.parsers", "DocumentBuilderFactory")
}
DocumentBuilderFactory() { this.hasQualifiedName("javax.xml.parsers", "DocumentBuilderFactory") }
}
/** The class `javax.xml.parsers.DocumentBuilder`. */
class DocumentBuilder extends RefType {
DocumentBuilder() {
this.hasQualifiedName("javax.xml.parsers", "DocumentBuilder")
}
DocumentBuilder() { this.hasQualifiedName("javax.xml.parsers", "DocumentBuilder") }
}
/** A call to `DocumentBuilder.parse`. */
@ -76,19 +72,26 @@ class DocumentBuilderParse extends XmlParserCall {
)
}
override Expr getSink() {
result = this.getArgument(0)
}
override Expr getSink() { result = this.getArgument(0) }
override predicate isSafe() {
exists(SafeDocumentBuilderToDocumentBuilderParseFlowConfig conf | conf.hasFlowToExpr(this.getQualifier()))
exists(SafeDocumentBuilderToDocumentBuilderParseFlowConfig conf |
conf.hasFlowToExpr(this.getQualifier())
)
}
}
private class SafeDocumentBuilderToDocumentBuilderParseFlowConfig extends DataFlow2::Configuration {
SafeDocumentBuilderToDocumentBuilderParseFlowConfig() { this = "XmlParsers::SafeDocumentBuilderToDocumentBuilderParseFlowConfig" }
SafeDocumentBuilderToDocumentBuilderParseFlowConfig() {
this = "XmlParsers::SafeDocumentBuilderToDocumentBuilderParseFlowConfig"
}
override predicate isSource(DataFlow::Node src) { src.asExpr() instanceof SafeDocumentBuilder }
override predicate isSink(DataFlow::Node sink) { sink.asExpr() = any(DocumentBuilderParse dbp).getQualifier() }
override predicate isSink(DataFlow::Node sink) {
sink.asExpr() = any(DocumentBuilderParse dbp).getQualifier()
}
override predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
exists(RefType t, ReturnStmt ret, Method m |
node2.asExpr().(ClassInstanceExpr).getConstructedType().getSourceDeclaration() = t and
@ -97,7 +100,8 @@ private class SafeDocumentBuilderToDocumentBuilderParseFlowConfig extends DataFl
ret.getEnclosingCallable() = m and
m.hasName("initialValue") and
m.getDeclaringType() = t
) or
)
or
exists(MethodAccess ma, Method m |
ma = node2.asExpr() and
ma.getQualifier() = node1.asExpr() and
@ -106,6 +110,7 @@ private class SafeDocumentBuilderToDocumentBuilderParseFlowConfig extends DataFl
m.getDeclaringType().getSourceDeclaration().hasQualifiedName("java.lang", "ThreadLocal")
)
}
override int fieldFlowBranchLimit() { result = 0 }
}
@ -123,7 +128,8 @@ class DocumentBuilderFactoryConfig extends ParserConfig {
}
private predicate constantStringExpr(Expr e, string val) {
e.(CompileTimeConstantExpr).getStringValue() = val or
e.(CompileTimeConstantExpr).getStringValue() = val
or
exists(SsaExplicitUpdate v, Expr src |
e = v.getAUse() and
src = v.getDefiningExpr().(VariableAssign).getSource() and
@ -134,22 +140,21 @@ private predicate constantStringExpr(Expr e, string val) {
/** An expression that always has the same string value. */
private class ConstantStringExpr extends Expr {
string value;
ConstantStringExpr() {
constantStringExpr(this, value)
}
ConstantStringExpr() { constantStringExpr(this, value) }
/** Get the string value of this expression. */
string getStringValue() {
result = value
}
string getStringValue() { result = value }
}
/**
* A general configuration that is safe when enabled.
*/
Expr singleSafeConfig() {
result.(ConstantStringExpr).getStringValue() = "http://apache.org/xml/features/disallow-doctype-decl" or
result.(ConstantStringExpr).getStringValue() = "http://javax.xml.XMLConstants/feature/secure-processing" or
result.(ConstantStringExpr).getStringValue() = "http://apache.org/xml/features/disallow-doctype-decl"
or
result.(ConstantStringExpr).getStringValue() = "http://javax.xml.XMLConstants/feature/secure-processing"
or
exists(Field f |
result = f.getAnAccess() and
f.hasName("FEATURE_SECURE_PROCESSING") and
@ -170,10 +175,16 @@ class SafeDocumentBuilderFactory extends VarAccess {
(
//These two need to be set together to work
exists(DocumentBuilderFactoryConfig config | config.getQualifier() = v.getAnAccess() |
config.disables(any(ConstantStringExpr s | s.getStringValue() = "http://xml.org/sax/features/external-general-entities"))
config
.disables(any(ConstantStringExpr s |
s.getStringValue() = "http://xml.org/sax/features/external-general-entities"
))
) and
exists(DocumentBuilderFactoryConfig config | config.getQualifier() = v.getAnAccess() |
config.disables(any(ConstantStringExpr s | s.getStringValue() = "http://xml.org/sax/features/external-parameter-entities"))
config
.disables(any(ConstantStringExpr s |
s.getStringValue() = "http://xml.org/sax/features/external-parameter-entities"
))
)
)
)
@ -191,9 +202,18 @@ private class DocumentBuilderConstruction extends MethodAccess {
}
private class SafeDocumentBuilderFactoryToDocumentBuilderConstructionFlowConfig extends DataFlow3::Configuration {
SafeDocumentBuilderFactoryToDocumentBuilderConstructionFlowConfig() { this = "XmlParsers::SafeDocumentBuilderFactoryToDocumentBuilderConstructionFlowConfig" }
override predicate isSource(DataFlow::Node src) { src.asExpr() instanceof SafeDocumentBuilderFactory }
override predicate isSink(DataFlow::Node sink) { sink.asExpr() = any(DocumentBuilderConstruction dbc).getQualifier() }
SafeDocumentBuilderFactoryToDocumentBuilderConstructionFlowConfig() {
this = "XmlParsers::SafeDocumentBuilderFactoryToDocumentBuilderConstructionFlowConfig"
}
override predicate isSource(DataFlow::Node src) {
src.asExpr() instanceof SafeDocumentBuilderFactory
}
override predicate isSink(DataFlow::Node sink) {
sink.asExpr() = any(DocumentBuilderConstruction dbc).getQualifier()
}
override int fieldFlowBranchLimit() { result = 0 }
}
@ -214,9 +234,7 @@ class SafeDocumentBuilder extends DocumentBuilderConstruction {
/** The class `javax.xml.stream.XMLInputFactory`. */
class XmlInputFactory extends RefType {
XmlInputFactory() {
this.hasQualifiedName("javax.xml.stream", "XMLInputFactory")
}
XmlInputFactory() { this.hasQualifiedName("javax.xml.stream", "XMLInputFactory") }
}
/** A call to `XMLInputFactory.createXMLStreamReader`. */
@ -231,24 +249,29 @@ class XmlInputFactoryStreamReader extends XmlParserCall {
override Expr getSink() {
if this.getMethod().getParameterType(0) instanceof TypeString
then
result = this.getArgument(1)
else
result = this.getArgument(0)
then result = this.getArgument(1)
else result = this.getArgument(0)
}
override predicate isSafe() {
exists(SafeXmlInputFactoryToXmlInputFactoryReaderFlowConfig conf | conf.hasFlowToExpr(this.getQualifier()))
exists(SafeXmlInputFactoryToXmlInputFactoryReaderFlowConfig conf |
conf.hasFlowToExpr(this.getQualifier())
)
}
}
private class SafeXmlInputFactoryToXmlInputFactoryReaderFlowConfig extends DataFlow2::Configuration {
SafeXmlInputFactoryToXmlInputFactoryReaderFlowConfig() { this = "XmlParsers::SafeXmlInputFactoryToXmlInputFactoryReaderFlowConfig" }
SafeXmlInputFactoryToXmlInputFactoryReaderFlowConfig() {
this = "XmlParsers::SafeXmlInputFactoryToXmlInputFactoryReaderFlowConfig"
}
override predicate isSource(DataFlow::Node src) { src.asExpr() instanceof SafeXmlInputFactory }
override predicate isSink(DataFlow::Node sink) {
sink.asExpr() = any(XmlInputFactoryStreamReader xifsr).getQualifier() or
sink.asExpr() = any(XmlInputFactoryEventReader xifer).getQualifier()
}
override int fieldFlowBranchLimit() { result = 0 }
}
@ -264,14 +287,14 @@ class XmlInputFactoryEventReader extends XmlParserCall {
override Expr getSink() {
if this.getMethod().getParameterType(0) instanceof TypeString
then
result = this.getArgument(1)
else
result = this.getArgument(0)
then result = this.getArgument(1)
else result = this.getArgument(0)
}
override predicate isSafe() {
exists(SafeXmlInputFactoryToXmlInputFactoryReaderFlowConfig conf | conf.hasFlowToExpr(this.getQualifier()))
exists(SafeXmlInputFactoryToXmlInputFactoryReaderFlowConfig conf |
conf.hasFlowToExpr(this.getQualifier())
)
}
}
@ -292,7 +315,8 @@ class XmlInputFactoryConfig extends ParserConfig {
* An `XmlInputFactory` specific expression that indicates whether parsing external entities is supported.
*/
Expr configOptionIsSupportingExternalEntities() {
result.(ConstantStringExpr).getStringValue() = "javax.xml.stream.isSupportingExternalEntities" or
result.(ConstantStringExpr).getStringValue() = "javax.xml.stream.isSupportingExternalEntities"
or
exists(Field f |
result = f.getAnAccess() and
f.hasName("IS_SUPPORTING_EXTERNAL_ENTITIES") and
@ -304,7 +328,8 @@ Expr configOptionIsSupportingExternalEntities() {
* An `XmlInputFactory` specific expression that indicates whether DTD is supported.
*/
Expr configOptionSupportDTD() {
result.(ConstantStringExpr).getStringValue() = "javax.xml.stream.supportDTD" or
result.(ConstantStringExpr).getStringValue() = "javax.xml.stream.supportDTD"
or
exists(Field f |
result = f.getAnAccess() and
f.hasName("SUPPORT_DTD") and
@ -329,7 +354,6 @@ class SafeXmlInputFactory extends VarAccess {
}
}
/*
* https://www.owasp.org/index.php/XML_External_Entity_(XXE)_Prevention_Cheat_Sheet#SAXBuilder
*/
@ -356,9 +380,7 @@ class SAXBuilderParse extends XmlParserCall {
)
}
override Expr getSink() {
result = this.getArgument(0)
}
override Expr getSink() { result = this.getArgument(0) }
override predicate isSafe() {
exists(SafeSAXBuilderToSAXBuilderParseFlowConfig conf | conf.hasFlowToExpr(this.getQualifier()))
@ -366,9 +388,16 @@ class SAXBuilderParse extends XmlParserCall {
}
private class SafeSAXBuilderToSAXBuilderParseFlowConfig extends DataFlow2::Configuration {
SafeSAXBuilderToSAXBuilderParseFlowConfig() { this = "XmlParsers::SafeSAXBuilderToSAXBuilderParseFlowConfig" }
SafeSAXBuilderToSAXBuilderParseFlowConfig() {
this = "XmlParsers::SafeSAXBuilderToSAXBuilderParseFlowConfig"
}
override predicate isSource(DataFlow::Node src) { src.asExpr() instanceof SafeSAXBuilder }
override predicate isSink(DataFlow::Node sink) { sink.asExpr() = any(SAXBuilderParse sax).getQualifier() }
override predicate isSink(DataFlow::Node sink) {
sink.asExpr() = any(SAXBuilderParse sax).getQualifier()
}
override int fieldFlowBranchLimit() { result = 0 }
}
@ -391,7 +420,10 @@ class SafeSAXBuilder extends VarAccess {
exists(Variable v |
v = this.getVariable() and
exists(SAXBuilderConfig config | config.getQualifier() = v.getAnAccess() |
config.enables(any(ConstantStringExpr s | s.getStringValue() = "http://apache.org/xml/features/disallow-doctype-decl"))
config
.enables(any(ConstantStringExpr s |
s.getStringValue() = "http://apache.org/xml/features/disallow-doctype-decl"
))
)
)
}
@ -407,16 +439,12 @@ class SafeSAXBuilder extends VarAccess {
* The class `javax.xml.parsers.SAXParser`.
*/
class SAXParser extends RefType {
SAXParser() {
this.hasQualifiedName("javax.xml.parsers", "SAXParser")
}
SAXParser() { this.hasQualifiedName("javax.xml.parsers", "SAXParser") }
}
/** The class `javax.xml.parsers.SAXParserFactory`. */
class SAXParserFactory extends RefType {
SAXParserFactory() {
this.hasQualifiedName("javax.xml.parsers", "SAXParserFactory")
}
SAXParserFactory() { this.hasQualifiedName("javax.xml.parsers", "SAXParserFactory") }
}
/** A call to `SAXParser.parse`. */
@ -429,9 +457,7 @@ class SAXParserParse extends XmlParserCall {
)
}
override Expr getSink() {
result = this.getArgument(0)
}
override Expr getSink() { result = this.getArgument(0) }
override predicate isSafe() {
exists(SafeSAXParserFlowConfig sp | sp.hasFlowToExpr(this.getQualifier()))
@ -449,7 +475,6 @@ class SAXParserFactoryConfig extends ParserConfig {
}
}
/**
* A safely configured `SAXParserFactory`.
*/
@ -457,21 +482,34 @@ class SafeSAXParserFactory extends VarAccess {
SafeSAXParserFactory() {
exists(Variable v | v = this.getVariable() |
exists(SAXParserFactoryConfig config | config.getQualifier() = v.getAnAccess() |
config.disables(any(ConstantStringExpr s | s.getStringValue() = "http://xml.org/sax/features/external-general-entities"))
config
.disables(any(ConstantStringExpr s |
s.getStringValue() = "http://xml.org/sax/features/external-general-entities"
))
) and
exists(SAXParserFactoryConfig config | config.getQualifier() = v.getAnAccess() |
config.disables(any(ConstantStringExpr s | s.getStringValue() = "http://xml.org/sax/features/external-parameter-entities"))
config
.disables(any(ConstantStringExpr s |
s.getStringValue() = "http://xml.org/sax/features/external-parameter-entities"
))
) and
exists(SAXParserFactoryConfig config | config.getQualifier() = v.getAnAccess() |
config.disables(any(ConstantStringExpr s | s.getStringValue() = "http://apache.org/xml/features/nonvalidating/load-external-dtd"))
config
.disables(any(ConstantStringExpr s |
s.getStringValue() = "http://apache.org/xml/features/nonvalidating/load-external-dtd"
))
)
)
}
}
private class SafeSAXParserFactoryToNewSAXParserFlowConfig extends DataFlow5::Configuration {
SafeSAXParserFactoryToNewSAXParserFlowConfig() { this = "XmlParsers::SafeSAXParserFactoryToNewSAXParserFlowConfig" }
SafeSAXParserFactoryToNewSAXParserFlowConfig() {
this = "XmlParsers::SafeSAXParserFactoryToNewSAXParserFlowConfig"
}
override predicate isSource(DataFlow::Node src) { src.asExpr() instanceof SafeSAXParserFactory }
override predicate isSink(DataFlow::Node sink) {
exists(MethodAccess ma, Method m |
sink.asExpr() = ma.getQualifier() and
@ -480,15 +518,21 @@ private class SafeSAXParserFactoryToNewSAXParserFlowConfig extends DataFlow5::Co
m.hasName("newSAXParser")
)
}
override int fieldFlowBranchLimit() { result = 0 }
}
private class SafeSAXParserFlowConfig extends DataFlow4::Configuration {
SafeSAXParserFlowConfig() { this = "XmlParsers::SafeSAXParserFlowConfig" }
override predicate isSource(DataFlow::Node src) { src.asExpr() instanceof SafeSAXParser }
override predicate isSink(DataFlow::Node sink) {
exists(MethodAccess ma | sink.asExpr() = ma.getQualifier() and ma.getMethod().getDeclaringType() instanceof SAXParser)
exists(MethodAccess ma |
sink.asExpr() = ma.getQualifier() and ma.getMethod().getDeclaringType() instanceof SAXParser
)
}
override int fieldFlowBranchLimit() { result = 0 }
}
@ -504,14 +548,11 @@ class SafeSAXParser extends MethodAccess {
}
/* SAXReader: https://www.owasp.org/index.php/XML_External_Entity_(XXE)_Prevention_Cheat_Sheet#SAXReader */
/**
* The class `org.dom4j.io.SAXReader`.
*/
class SAXReader extends RefType {
SAXReader() {
this.hasQualifiedName("org.dom4j.io", "SAXReader")
}
SAXReader() { this.hasQualifiedName("org.dom4j.io", "SAXReader") }
}
/** A call to `SAXReader.read`. */
@ -524,9 +565,7 @@ class SAXReaderRead extends XmlParserCall {
)
}
override Expr getSink() {
result = this.getArgument(0)
}
override Expr getSink() { result = this.getArgument(0) }
override predicate isSafe() {
exists(SafeSAXReaderFlowConfig sr | sr.hasFlowToExpr(this.getQualifier()))
@ -546,10 +585,15 @@ class SAXReaderConfig extends ParserConfig {
private class SafeSAXReaderFlowConfig extends DataFlow4::Configuration {
SafeSAXReaderFlowConfig() { this = "XmlParsers::SafeSAXReaderFlowConfig" }
override predicate isSource(DataFlow::Node src) { src.asExpr() instanceof SafeSAXReader }
override predicate isSink(DataFlow::Node sink) {
exists(MethodAccess ma | sink.asExpr() = ma.getQualifier() and ma.getMethod().getDeclaringType() instanceof SAXReader)
exists(MethodAccess ma |
sink.asExpr() = ma.getQualifier() and ma.getMethod().getDeclaringType() instanceof SAXReader
)
}
override int fieldFlowBranchLimit() { result = 0 }
}
@ -558,25 +602,31 @@ class SafeSAXReader extends VarAccess {
SafeSAXReader() {
exists(Variable v | v = this.getVariable() |
exists(SAXReaderConfig config | config.getQualifier() = v.getAnAccess() |
config.disables(any(ConstantStringExpr s | s.getStringValue() = "http://xml.org/sax/features/external-general-entities"))
config
.disables(any(ConstantStringExpr s |
s.getStringValue() = "http://xml.org/sax/features/external-general-entities"
))
) and
exists(SAXReaderConfig config | config.getQualifier() = v.getAnAccess() |
config.disables(any(ConstantStringExpr s | s.getStringValue() = "http://xml.org/sax/features/external-parameter-entities"))
config
.disables(any(ConstantStringExpr s |
s.getStringValue() = "http://xml.org/sax/features/external-parameter-entities"
))
) and
exists(SAXReaderConfig config | config.getQualifier() = v.getAnAccess() |
config.enables(any(ConstantStringExpr s | s.getStringValue() = "http://apache.org/xml/features/disallow-doctype-decl"))
config
.enables(any(ConstantStringExpr s |
s.getStringValue() = "http://apache.org/xml/features/disallow-doctype-decl"
))
)
)
}
}
/* https://www.owasp.org/index.php/XML_External_Entity_(XXE)_Prevention_Cheat_Sheet#XMLReader */
/** The class `org.xml.sax.XMLReader`. */
class XMLReader extends RefType {
XMLReader() {
this.hasQualifiedName("org.xml.sax", "XMLReader")
}
XMLReader() { this.hasQualifiedName("org.xml.sax", "XMLReader") }
}
/** A call to `XMLReader.read`. */
@ -589,9 +639,7 @@ class XMLReaderParse extends XmlParserCall {
)
}
override Expr getSink() {
result = this.getArgument(0)
}
override Expr getSink() { result = this.getArgument(0) }
override predicate isSafe() {
exists(ExplicitlySafeXMLReader sr | sr.flowsTo(this.getQualifier())) or
@ -601,7 +649,7 @@ class XMLReaderParse extends XmlParserCall {
/** A `ParserConfig` specific to the `XMLReader`. */
class XMLReaderConfig extends ParserConfig {
XMLReaderConfig() {
XMLReaderConfig() {
exists(Method m |
m = this.getMethod() and
m.getDeclaringType() instanceof XMLReader and
@ -612,8 +660,13 @@ class XMLReaderConfig extends ParserConfig {
private class ExplicitlySafeXMLReaderFlowConfig extends DataFlow3::Configuration {
ExplicitlySafeXMLReaderFlowConfig() { this = "XmlParsers::ExplicitlySafeXMLReaderFlowConfig" }
override predicate isSource(DataFlow::Node src) { src.asExpr() instanceof ExplicitlySafeXMLReader }
override predicate isSource(DataFlow::Node src) {
src.asExpr() instanceof ExplicitlySafeXMLReader
}
override predicate isSink(DataFlow::Node sink) { sink.asExpr() instanceof SafeXMLReaderFlowSink }
override int fieldFlowBranchLimit() { result = 0 }
}
@ -631,28 +684,47 @@ class ExplicitlySafeXMLReader extends VarAccess {
exists(Variable v | v = this.getVariable() |
(
exists(XMLReaderConfig config | config.getQualifier() = v.getAnAccess() |
config.disables(any(ConstantStringExpr s | s.getStringValue() = "http://xml.org/sax/features/external-general-entities"))
config
.disables(any(ConstantStringExpr s |
s.getStringValue() = "http://xml.org/sax/features/external-general-entities"
))
) and
exists(XMLReaderConfig config | config.getQualifier() = v.getAnAccess() |
config.disables(any(ConstantStringExpr s | s.getStringValue() = "http://xml.org/sax/features/external-parameter-entities"))
config
.disables(any(ConstantStringExpr s |
s.getStringValue() = "http://xml.org/sax/features/external-parameter-entities"
))
) and
exists(XMLReaderConfig config | config.getQualifier() = v.getAnAccess() |
config.disables(any(ConstantStringExpr s | s.getStringValue() = "http://apache.org/xml/features/nonvalidating/load-external-dtd"))
config
.disables(any(ConstantStringExpr s |
s.getStringValue() = "http://apache.org/xml/features/nonvalidating/load-external-dtd"
))
)
) or
)
or
exists(XMLReaderConfig config | config.getQualifier() = v.getAnAccess() |
config.enables(any(ConstantStringExpr s | s.getStringValue() = "http://apache.org/xml/features/disallow-doctype-decl")))
config
.enables(any(ConstantStringExpr s |
s.getStringValue() = "http://apache.org/xml/features/disallow-doctype-decl"
))
)
)
}
predicate flowsTo(SafeXMLReaderFlowSink sink) {
any(ExplicitlySafeXMLReaderFlowConfig conf).hasFlow(DataFlow::exprNode(this), DataFlow::exprNode(sink))
any(ExplicitlySafeXMLReaderFlowConfig conf)
.hasFlow(DataFlow::exprNode(this), DataFlow::exprNode(sink))
}
}
private class CreatedSafeXMLReaderFlowConfig extends DataFlow3::Configuration {
CreatedSafeXMLReaderFlowConfig() { this = "XmlParsers::CreatedSafeXMLReaderFlowConfig" }
override predicate isSource(DataFlow::Node src) { src.asExpr() instanceof CreatedSafeXMLReader }
override predicate isSink(DataFlow::Node sink) { sink.asExpr() instanceof SafeXMLReaderFlowSink }
override int fieldFlowBranchLimit() { result = 0 }
}
@ -664,7 +736,8 @@ class CreatedSafeXMLReader extends MethodAccess {
this.getMethod().getDeclaringType() instanceof SAXParser and
this.getMethod().hasName("getXMLReader") and
safeParser.hasFlowToExpr(this.getQualifier())
) or
)
or
//Obtained from SAXReader
exists(SafeSAXReaderFlowConfig safeReader |
this.getMethod().getDeclaringType() instanceof SAXReader and
@ -672,8 +745,10 @@ class CreatedSafeXMLReader extends MethodAccess {
safeReader.hasFlowToExpr(this.getQualifier())
)
}
predicate flowsTo(SafeXMLReaderFlowSink sink) {
any(CreatedSafeXMLReaderFlowConfig conf).hasFlow(DataFlow::exprNode(this), DataFlow::exprNode(sink))
any(CreatedSafeXMLReaderFlowConfig conf)
.hasFlow(DataFlow::exprNode(this), DataFlow::exprNode(sink))
}
}
@ -684,9 +759,7 @@ class CreatedSafeXMLReader extends MethodAccess {
/** The class `javax.xml.transform.sax.SAXSource` */
class SAXSource extends RefType {
SAXSource() {
this.hasQualifiedName("javax.xml.transform.sax", "SAXSource")
}
SAXSource() { this.hasQualifiedName("javax.xml.transform.sax", "SAXSource") }
}
/** A call to the constructor of `SAXSource` with `XMLReader` and `InputSource`. */
@ -696,12 +769,12 @@ class ConstructedSAXSource extends ClassInstanceExpr {
this.getNumArgument() = 2 and
this.getArgument(0).getType() instanceof XMLReader
}
/**
* Gets the argument representing the XML content to be parsed.
*/
Expr getSink() {
result = this.getArgument(1)
}
Expr getSink() { result = this.getArgument(1) }
/** Holds if the resulting `SAXSource` is safe. */
predicate isSafe() {
exists(CreatedSafeXMLReader safeReader | safeReader.flowsTo(this.getArgument(0))) or
@ -730,13 +803,13 @@ class SafeSAXSource extends Expr {
exists(ExplicitlySafeXMLReader safeReader | safeReader.flowsTo(s.getArgument(0)))
)
)
) or
)
or
this.(ConstructedSAXSource).isSafe()
}
}
/* Transformer: https://www.owasp.org/index.php/XML_External_Entity_(XXE)_Prevention_Cheat_Sheet#TransformerFactory */
/** An access to a method use for configuring a transformer or schema. */
abstract class TransformerConfig extends MethodAccess {
/** Holds if the configuration is disabled */
@ -748,14 +821,13 @@ abstract class TransformerConfig extends MethodAccess {
/** The class `javax.xml.XMLConstants`. */
class XmlConstants extends RefType {
XmlConstants() {
this.hasQualifiedName("javax.xml", "XMLConstants")
}
XmlConstants() { this.hasQualifiedName("javax.xml", "XMLConstants") }
}
/** A configuration specific for transformers and schema. */
Expr configAccessExternalDTD() {
result.(ConstantStringExpr).getStringValue() = "http://javax.xml.XMLConstants/property/accessExternalDTD" or
result.(ConstantStringExpr).getStringValue() = "http://javax.xml.XMLConstants/property/accessExternalDTD"
or
exists(Field f |
result = f.getAnAccess() and
f.hasName("ACCESS_EXTERNAL_DTD") and
@ -765,7 +837,8 @@ Expr configAccessExternalDTD() {
/** A configuration specific for transformers. */
Expr configAccessExternalStyleSheet() {
result.(ConstantStringExpr).getStringValue() = "http://javax.xml.XMLConstants/property/accessExternalStylesheet" or
result.(ConstantStringExpr).getStringValue() = "http://javax.xml.XMLConstants/property/accessExternalStylesheet"
or
exists(Field f |
result = f.getAnAccess() and
f.hasName("ACCESS_EXTERNAL_STYLESHEET") and
@ -775,7 +848,8 @@ Expr configAccessExternalStyleSheet() {
/** A configuration specific for schema. */
Expr configAccessExternalSchema() {
result.(ConstantStringExpr).getStringValue() = "http://javax.xml.XMLConstants/property/accessExternalSchema" or
result.(ConstantStringExpr).getStringValue() = "http://javax.xml.XMLConstants/property/accessExternalSchema"
or
exists(Field f |
result = f.getAnAccess() and
f.hasName("ACCESS_EXTERNAL_SCHEMA") and
@ -786,17 +860,14 @@ Expr configAccessExternalSchema() {
/** The class `javax.xml.transform.TransformerFactory` or `javax.xml.transform.sax.SAXTransformerFactory`. */
class TransformerFactory extends RefType {
TransformerFactory() {
this.hasQualifiedName("javax.xml.transform", "TransformerFactory")
or
this.hasQualifiedName("javax.xml.transform", "TransformerFactory") or
this.hasQualifiedName("javax.xml.transform.sax", "SAXTransformerFactory")
}
}
/** The class `javax.xml.transform.Transformer`. */
class Transformer extends RefType {
Transformer() {
this.hasQualifiedName("javax.xml.transform", "Transformer")
}
Transformer() { this.hasQualifiedName("javax.xml.transform", "Transformer") }
}
/** A call to `Transformer.transform`. */
@ -809,19 +880,26 @@ class TransformerTransform extends XmlParserCall {
)
}
override Expr getSink() {
result = this.getArgument(0)
}
override Expr getSink() { result = this.getArgument(0) }
override predicate isSafe() {
exists(SafeTransformerToTransformerTransformFlowConfig st | st.hasFlowToExpr(this.getQualifier()))
exists(SafeTransformerToTransformerTransformFlowConfig st |
st.hasFlowToExpr(this.getQualifier())
)
}
}
private class SafeTransformerToTransformerTransformFlowConfig extends DataFlow2::Configuration {
SafeTransformerToTransformerTransformFlowConfig() { this = "XmlParsers::SafeTransformerToTransformerTransformFlowConfig" }
SafeTransformerToTransformerTransformFlowConfig() {
this = "XmlParsers::SafeTransformerToTransformerTransformFlowConfig"
}
override predicate isSource(DataFlow::Node src) { src.asExpr() instanceof SafeTransformer }
override predicate isSink(DataFlow::Node sink) { sink.asExpr() = any(TransformerTransform tt).getQualifier() }
override predicate isSink(DataFlow::Node sink) {
sink.asExpr() = any(TransformerTransform tt).getQualifier()
}
override int fieldFlowBranchLimit() { result = 0 }
}
@ -835,9 +913,7 @@ class TransformerFactorySource extends XmlParserCall {
)
}
override Expr getSink() {
result = this.getArgument(0)
}
override Expr getSink() { result = this.getArgument(0) }
override predicate isSafe() {
exists(SafeTransformerFactoryFlowConfig stf | stf.hasFlowToExpr(this.getQualifier()))
@ -857,10 +933,16 @@ class TransformerFactoryConfig extends TransformerConfig {
private class SafeTransformerFactoryFlowConfig extends DataFlow3::Configuration {
SafeTransformerFactoryFlowConfig() { this = "XmlParsers::SafeTransformerFactoryFlowConfig" }
override predicate isSource(DataFlow::Node src) { src.asExpr() instanceof SafeTransformerFactory }
override predicate isSink(DataFlow::Node sink) {
exists(MethodAccess ma | sink.asExpr() = ma.getQualifier() and ma.getMethod().getDeclaringType() instanceof TransformerFactory)
exists(MethodAccess ma |
sink.asExpr() = ma.getQualifier() and
ma.getMethod().getDeclaringType() instanceof TransformerFactory
)
}
override int fieldFlowBranchLimit() { result = 0 }
}
@ -890,7 +972,8 @@ class SafeTransformer extends MethodAccess {
}
}
/* SAXTransformer: https://www.owasp.org/index.php/XML_External_Entity_(XXE)_Prevention_Cheat_Sheet#SAXTransformerFactory
/*
* SAXTransformer: https://www.owasp.org/index.php/XML_External_Entity_(XXE)_Prevention_Cheat_Sheet#SAXTransformerFactory
* Has an extra method called newFilter.
*/
@ -904,9 +987,7 @@ class SAXTransformerFactoryNewXMLFilter extends XmlParserCall {
)
}
override Expr getSink() {
result = this.getArgument(0)
}
override Expr getSink() { result = this.getArgument(0) }
override predicate isSafe() {
exists(SafeTransformerFactoryFlowConfig stf | stf.hasFlowToExpr(this.getQualifier()))
@ -916,9 +997,7 @@ class SAXTransformerFactoryNewXMLFilter extends XmlParserCall {
/* Schema: https://www.owasp.org/index.php/XML_External_Entity_(XXE)_Prevention_Cheat_Sheet#SchemaFactory */
/** The class `javax.xml.validation.SchemaFactory`. */
class SchemaFactory extends RefType {
SchemaFactory() {
this.hasQualifiedName("javax.xml.validation", "SchemaFactory")
}
SchemaFactory() { this.hasQualifiedName("javax.xml.validation", "SchemaFactory") }
}
/** A `ParserConfig` specific to `SchemaFactory`. */
@ -942,19 +1021,26 @@ class SchemaFactoryNewSchema extends XmlParserCall {
)
}
override Expr getSink() {
result = this.getArgument(0)
}
override Expr getSink() { result = this.getArgument(0) }
override predicate isSafe() {
exists(SafeSchemaFactoryToSchemaFactoryNewSchemaFlowConfig ssf | ssf.hasFlowToExpr(this.getQualifier()))
exists(SafeSchemaFactoryToSchemaFactoryNewSchemaFlowConfig ssf |
ssf.hasFlowToExpr(this.getQualifier())
)
}
}
private class SafeSchemaFactoryToSchemaFactoryNewSchemaFlowConfig extends DataFlow2::Configuration {
SafeSchemaFactoryToSchemaFactoryNewSchemaFlowConfig() { this = "XmlParsers::SafeSchemaFactoryToSchemaFactoryNewSchemaFlowConfig" }
SafeSchemaFactoryToSchemaFactoryNewSchemaFlowConfig() {
this = "XmlParsers::SafeSchemaFactoryToSchemaFactoryNewSchemaFlowConfig"
}
override predicate isSource(DataFlow::Node src) { src.asExpr() instanceof SafeSchemaFactory }
override predicate isSink(DataFlow::Node sink) { sink.asExpr() = any(SchemaFactoryNewSchema sfns).getQualifier() }
override predicate isSink(DataFlow::Node sink) {
sink.asExpr() = any(SchemaFactoryNewSchema sfns).getQualifier()
}
override int fieldFlowBranchLimit() { result = 0 }
}
@ -963,20 +1049,19 @@ class SafeSchemaFactory extends VarAccess {
SafeSchemaFactory() {
exists(Variable v | v = this.getVariable() |
exists(SchemaFactoryConfig config | config.getQualifier() = v.getAnAccess() |
config.disables(configAccessExternalDTD())) and
config.disables(configAccessExternalDTD())
) and
exists(SchemaFactoryConfig config | config.getQualifier() = v.getAnAccess() |
config.disables(configAccessExternalSchema()))
config.disables(configAccessExternalSchema())
)
)
}
}
/* Unmarshaller: https://www.owasp.org/index.php/XML_External_Entity_(XXE)_Prevention_Cheat_Sheet#Unmarshaller */
/** The class `javax.xml.bind.Unmarshaller`. */
class XmlUnmarshaller extends RefType {
XmlUnmarshaller() {
this.hasQualifiedName("javax.xml.bind", "Unmarshaller")
}
XmlUnmarshaller() { this.hasQualifiedName("javax.xml.bind", "Unmarshaller") }
}
/** A call to `Unmarshaller.unmarshal`. */
@ -989,22 +1074,15 @@ class XmlUnmarshal extends XmlParserCall {
)
}
override Expr getSink() {
result = this.getArgument(0)
}
override Expr getSink() { result = this.getArgument(0) }
override predicate isSafe() {
none()
}
override predicate isSafe() { none() }
}
/* XPathExpression: https://www.owasp.org/index.php/XML_External_Entity_(XXE)_Prevention_Cheat_Sheet#XPathExpression */
/** The class `javax.xml.xpath.XPathExpression`. */
class XPathExpression extends RefType {
XPathExpression() {
this.hasQualifiedName("javax.xml.xpath", "XPathExpression")
}
XPathExpression() { this.hasQualifiedName("javax.xml.xpath", "XPathExpression") }
}
/** A call to `XPathExpression.evaluate`. */
@ -1017,17 +1095,12 @@ class XPathEvaluate extends XmlParserCall {
)
}
override Expr getSink() {
result = this.getArgument(0)
}
override Expr getSink() { result = this.getArgument(0) }
override predicate isSafe() {
none()
}
override predicate isSafe() { none() }
}
// Sink methods in simplexml http://simple.sourceforge.net/home.php
/** A call to `read` or `validate` in `Persister`. */
class SimpleXMLPersisterCall extends XmlParserCall {
SimpleXMLPersisterCall() {
@ -1038,13 +1111,9 @@ class SimpleXMLPersisterCall extends XmlParserCall {
)
}
override Expr getSink() {
result = this.getArgument(1)
}
override Expr getSink() { result = this.getArgument(1) }
override predicate isSafe() {
none()
}
override predicate isSafe() { none() }
}
/** A call to `provide` in `Provider`. */
@ -1060,13 +1129,9 @@ class SimpleXMLProviderCall extends XmlParserCall {
)
}
override Expr getSink() {
result = this.getArgument(0)
}
override Expr getSink() { result = this.getArgument(0) }
override predicate isSafe() {
none()
}
override predicate isSafe() { none() }
}
/** A call to `read` in `NodeBuilder`. */
@ -1079,13 +1144,9 @@ class SimpleXMLNodeBuilderCall extends XmlParserCall {
)
}
override Expr getSink() {
result = this.getArgument(0)
}
override Expr getSink() { result = this.getArgument(0) }
override predicate isSafe() {
none()
}
override predicate isSafe() { none() }
}
/** A call to the `format` method of the `Formatter`. */
@ -1098,11 +1159,7 @@ class SimpleXMLFormatterCall extends XmlParserCall {
)
}
override Expr getSink() {
result = this.getArgument(0)
}
override Expr getSink() { result = this.getArgument(0) }
override predicate isSafe() {
none()
}
override predicate isSafe() { none() }
}

Просмотреть файл

@ -8,7 +8,7 @@ class NumericNarrowingCastExpr extends CastExpr {
NumericNarrowingCastExpr() {
exists(NumericType sourceType, NumericType targetType |
sourceType = getExpr().getType() and targetType = getType()
|
|
not targetType.(NumType).widerThanOrEqualTo(sourceType.(NumType))
)
}
@ -38,8 +38,9 @@ predicate boundedRead(RValue read) {
read = v.getAUse() and
cb.controls(read.getBasicBlock(), testIsTrue) and
cb.getCondition() = comp
|
comp.getLesserOperand() = v.getAUse() and testIsTrue = true or
|
comp.getLesserOperand() = v.getAUse() and testIsTrue = true
or
comp.getGreaterOperand() = v.getAUse() and testIsTrue = false
)
}

Просмотреть файл

@ -9,9 +9,7 @@ import SensitiveApi
private class HardcodedByteArray extends ArrayCreationExpr {
HardcodedByteArray() {
getType().(Array).getElementType().(PrimitiveType).getName() = "byte" and
forex(Expr elem | elem = getInit().getAChildExpr() |
elem instanceof CompileTimeConstantExpr
)
forex(Expr elem | elem = getInit().getAChildExpr() | elem instanceof CompileTimeConstantExpr)
}
}
@ -23,9 +21,7 @@ private class HardcodedByteArray extends ArrayCreationExpr {
private class HardcodedCharArray extends ArrayCreationExpr {
HardcodedCharArray() {
getType().(Array).getElementType().(PrimitiveType).getName() = "char" and
forex(Expr elem | elem = getInit().getAChildExpr() |
elem instanceof CompileTimeConstantExpr
)
forex(Expr elem | elem = getInit().getAChildExpr() | elem instanceof CompileTimeConstantExpr)
}
}
@ -45,9 +41,7 @@ class HardcodedExpr extends Expr {
* An argument to a sensitive call, expected to contain credentials.
*/
abstract class CredentialsSink extends Expr {
Call getSurroundingCall() {
this = result.getAnArgument()
}
Call getSurroundingCall() { this = result.getAnArgument() }
}
/**
@ -82,9 +76,7 @@ class PasswordVariable extends Variable {
* A variable whose name indicates that it may hold a user name.
*/
class UsernameVariable extends Variable {
UsernameVariable() {
getName().regexpMatch("(?i)(user|username)")
}
UsernameVariable() { getName().regexpMatch("(?i)(user|username)") }
}
/**

Просмотреть файл

@ -5,7 +5,8 @@ import java
*/
predicate javaApiCallablePasswordParam(Callable c, int i) {
exists(c.getParameter(i)) and
javaApiCallablePasswordParam(c.getDeclaringType().getQualifiedName() + ";" + c.getStringSignature() + ";" + i)
javaApiCallablePasswordParam(c.getDeclaringType().getQualifiedName() + ";" +
c.getStringSignature() + ";" + i)
}
private predicate javaApiCallablePasswordParam(string s) {
@ -128,7 +129,8 @@ private predicate javaApiCallablePasswordParam(string s) {
*/
predicate javaApiCallableUsernameParam(Callable c, int i) {
exists(c.getParameter(i)) and
javaApiCallableUsernameParam(c.getDeclaringType().getQualifiedName() + ";" + c.getStringSignature() + ";" + i)
javaApiCallableUsernameParam(c.getDeclaringType().getQualifiedName() + ";" +
c.getStringSignature() + ";" + i)
}
private predicate javaApiCallableUsernameParam(string s) {
@ -189,7 +191,8 @@ private predicate javaApiCallableUsernameParam(string s) {
*/
predicate javaApiCallableCryptoKeyParam(Callable c, int i) {
exists(c.getParameter(i)) and
javaApiCallableCryptoKeyParam(c.getDeclaringType().getQualifiedName() + ";" + c.getStringSignature() + ";" + i)
javaApiCallableCryptoKeyParam(c.getDeclaringType().getQualifiedName() + ";" +
c.getStringSignature() + ";" + i)
}
private predicate javaApiCallableCryptoKeyParam(string s) {
@ -413,7 +416,8 @@ private predicate javaApiCallableCryptoKeyParam(string s) {
*/
predicate otherApiCallableCredentialParam(Callable c, int i) {
exists(c.getParameter(i)) and
otherApiCallableCredentialParam(c.getDeclaringType().getQualifiedName() + ";" + c.getStringSignature() + ";" + i)
otherApiCallableCredentialParam(c.getDeclaringType().getQualifiedName() + ";" +
c.getStringSignature() + ";" + i)
}
private predicate otherApiCallableCredentialParam(string s) {

Просмотреть файл

@ -14,9 +14,7 @@ import semmle.code.java.frameworks.j2objc.J2ObjC
* - HTML entities in hexadecimal notation (e.g. `&#x705F;`)
*/
private predicate looksLikeCode(JavadocText line) {
exists(string trimmed |
trimmed = trimmedCommentText(line)
|
exists(string trimmed | trimmed = trimmedCommentText(line) |
(
trimmed.matches("%;") or
trimmed.matches("%{") or
@ -37,10 +35,12 @@ private predicate looksLikeCode(JavadocText line) {
* - HTML entities in hexadecimal notation (e.g. `&#x705F;`)
*/
private string trimmedCommentText(JavadocText line) {
result = line.getText().trim()
.regexpReplaceAll("\\s*//.*$", "")
.regexpReplaceAll("\\{@[^}]+\\}", "")
.regexpReplaceAll("(?i)&#?[a-z0-9]{1,31};", "")
result = line
.getText()
.trim()
.regexpReplaceAll("\\s*//.*$", "")
.regexpReplaceAll("\\{@[^}]+\\}", "")
.regexpReplaceAll("(?i)&#?[a-z0-9]{1,31};", "")
}
/**
@ -49,7 +49,7 @@ private string trimmedCommentText(JavadocText line) {
private predicate hasCodeTags(Javadoc j) {
exists(string tag | tag = "pre" or tag = "code" |
j.getAChild().(JavadocText).getText().matches("%<" + tag + ">%") and
j.getAChild().(JavadocText).getText().matches("%</"+ tag + ">%")
j.getAChild().(JavadocText).getText().matches("%</" + tag + ">%")
)
}
@ -57,9 +57,7 @@ private predicate hasCodeTags(Javadoc j) {
* The comment immediately following `c`.
*/
private Javadoc getNextComment(Javadoc c) {
exists(int n, File f | javadocLines(c, f, _, n) |
javadocLines(result, f, n+1, _)
)
exists(int n, File f | javadocLines(c, f, _, n) | javadocLines(result, f, n + 1, _))
}
private predicate javadocLines(Javadoc j, File f, int start, int end) {
@ -69,9 +67,7 @@ private predicate javadocLines(Javadoc j, File f, int start, int end) {
}
private class JavadocFirst extends Javadoc {
JavadocFirst() {
not exists(Javadoc prev | this = getNextComment(prev))
}
JavadocFirst() { not exists(Javadoc prev | this = getNextComment(prev)) }
}
/**
@ -79,10 +75,10 @@ private class JavadocFirst extends Javadoc {
*/
private int codeCount(JavadocFirst first) {
result = sum(Javadoc following |
following = getNextComment*(first) and not hasCodeTags(following)
following = getNextComment*(first) and not hasCodeTags(following)
|
count(JavadocText line | line = following.getAChild() and looksLikeCode(line))
)
count(JavadocText line | line = following.getAChild() and looksLikeCode(line))
)
}
/**
@ -90,15 +86,16 @@ private int codeCount(JavadocFirst first) {
*/
private int anyCount(JavadocFirst first) {
result = sum(Javadoc following |
following = getNextComment*(first) and not hasCodeTags(following)
following = getNextComment*(first) and not hasCodeTags(following)
|
count(JavadocText line | line = following.getAChild() and
not exists(string trimmed | trimmed = line.getText().trim() |
trimmed.regexpMatch("(|/\\*|/\\*\\*|\\*|\\*/)") or
trimmed.matches("@%")
)
count(JavadocText line |
line = following.getAChild() and
not exists(string trimmed | trimmed = line.getText().trim() |
trimmed.regexpMatch("(|/\\*|/\\*\\*|\\*|\\*/)") or
trimmed.matches("@%")
)
)
)
)
}
/**
@ -107,7 +104,7 @@ private int anyCount(JavadocFirst first) {
class CommentedOutCode extends JavadocFirst {
CommentedOutCode() {
anyCount(this) > 0 and
((float)codeCount(this))/((float)anyCount(this)) > 0.5 and
(codeCount(this).(float)) / (anyCount(this).(float)) > 0.5 and
not this instanceof JSNIComment and
not this instanceof OCNIComment
}
@ -115,9 +112,7 @@ class CommentedOutCode extends JavadocFirst {
/**
* The number of lines that appear to be commented-out code.
*/
int getCodeLines(){
result = codeCount(this)
}
int getCodeLines() { result = codeCount(this) }
private Javadoc getLastSuccessor() {
result = getNextComment*(this) and

Просмотреть файл

@ -19,7 +19,9 @@ private predicate emptyDecl(SsaExplicitUpdate ssa) {
*/
predicate deadLocal(SsaExplicitUpdate ssa) {
ssa.getSourceVariable().getVariable() instanceof LocalScopeVariable and
not exists(ssa.getAUse()) and not exists(SsaPhiNode phi | phi.getAPhiInput() = ssa) and not exists(SsaImplicitInit init | init.captures(ssa)) and
not exists(ssa.getAUse()) and
not exists(SsaPhiNode phi | phi.getAPhiInput() = ssa) and
not exists(SsaImplicitInit init | init.captures(ssa)) and
not emptyDecl(ssa) and
not readImplicitly(ssa, _)
}
@ -44,8 +46,9 @@ predicate overwritten(SsaExplicitUpdate ssa) {
exists(BasicBlock bb1, BasicBlock bb2, int i, int j |
bb1.getNode(i) = ssa.getCFGNode() and
bb2.getNode(j) = overwrite.getCFGNode()
|
bb1.getABBSuccessor+() = bb2 or
|
bb1.getABBSuccessor+() = bb2
or
bb1 = bb2 and i < j
)
)
@ -55,7 +58,8 @@ predicate overwritten(SsaExplicitUpdate ssa) {
* A local variable with a read access.
*/
predicate read(LocalScopeVariable v) {
exists(VarAccess va | va = v.getAnAccess() | va.isRValue()) or
exists(VarAccess va | va = v.getAnAccess() | va.isRValue())
or
readImplicitly(_, v)
}
@ -77,16 +81,19 @@ predicate assigned(LocalScopeVariable v) {
predicate exprHasNoEffect(Expr e) {
inInitializer(e) and
not exists(Expr bad | bad = e.getAChildExpr*() |
bad instanceof Assignment or
bad instanceof UnaryAssignExpr or
bad instanceof Assignment
or
bad instanceof UnaryAssignExpr
or
exists(ClassInstanceExpr cie, Constructor c |
bad = cie and c = cie.getConstructor().getSourceDeclaration()
|
|
constructorHasEffect(c)
) or
)
or
exists(MethodAccess ma, Method m |
bad = ma and m = ma.getMethod().getAPossibleImplementation()
|
|
methodHasEffect(m) or not m.fromSource()
)
)
@ -97,15 +104,17 @@ private predicate inInitializer(Expr e) {
}
// The next two predicates are somewhat conservative.
private predicate constructorHasEffect(Constructor c) {
// Only assign fields of the class - do not call methods,
// create new objects or assign any other variables.
exists(MethodAccess ma | ma.getEnclosingCallable() = c) or
exists(ClassInstanceExpr cie | cie.getEnclosingCallable() = c) or
exists(MethodAccess ma | ma.getEnclosingCallable() = c)
or
exists(ClassInstanceExpr cie | cie.getEnclosingCallable() = c)
or
exists(Assignment a | a.getEnclosingCallable() = c |
not exists(VarAccess va | va = a.getDest() |
va.getVariable() instanceof LocalVariableDecl or
va.getVariable() instanceof LocalVariableDecl
or
exists(Field f | f = va.getVariable() |
va.getQualifier() instanceof ThisAccess or
not exists(va.getQualifier())

Просмотреть файл

@ -1,8 +1,11 @@
import java
private Stmt getASwitchChild(SwitchStmt s) {
result = s.getAChild() or
exists(Stmt mid | mid = getASwitchChild(s) and not mid instanceof SwitchStmt and result = mid.getAChild())
result = s.getAChild()
or
exists(Stmt mid |
mid = getASwitchChild(s) and not mid instanceof SwitchStmt and result = mid.getAChild()
)
}
private predicate blockInSwitch(SwitchStmt s, BasicBlock b) {
@ -16,7 +19,8 @@ private predicate switchCaseControlFlow(SwitchStmt switch, BasicBlock b1, BasicB
}
predicate switchCaseControlFlowPlus(SwitchStmt switch, BasicBlock b1, BasicBlock b2) {
switchCaseControlFlow(switch, b1, b2) or
switchCaseControlFlow(switch, b1, b2)
or
exists(BasicBlock mid |
switchCaseControlFlowPlus(switch, mid, b2) and
switchCaseControlFlow(switch, b1, mid) and
@ -35,22 +39,22 @@ predicate mayDropThroughWithoutComment(SwitchStmt switch, Stmt switchCase) {
)
}
private
predicate fallThroughCommented(Stmt case) {
private predicate fallThroughCommented(Stmt case) {
exists(Location loc |
loc = case.getLocation() and
loc.getStartLine() = fallThroughCommentedLine(loc.getFile())
)
}
private
int fallThroughCommentedLine(File f) {
private int fallThroughCommentedLine(File f) {
exists(Location loc, JavadocText text |
loc.getFile() = f and
text.getLocation() = loc and
text.getText().toLowerCase().regexpMatch(".*falls?[ -]?(through|thru).*") and
result = loc.getStartLine() + 1
) or exists(int mid |
)
or
exists(int mid |
mid = fallThroughCommentedLine(f) and
not stmtLine(f) = mid and
mid < max(stmtLine(f)) and
@ -58,8 +62,7 @@ int fallThroughCommentedLine(File f) {
)
}
private
int stmtLine(File f) {
private int stmtLine(File f) {
exists(Stmt s, Location loc |
s.getLocation() = loc and
loc.getFile() = f and

Просмотреть файл

@ -1,93 +1,212 @@
import java
/*
*
* Counting nontrivial literal occurrences
*
*/
private
predicate trivialPositiveIntValue(string s) {
s="0" or s="1" or s="2" or s="3" or s="4" or s="5" or s="6" or s="7" or s="8" or
s="9" or s="10" or s="11" or s="12" or s="13" or s="14" or s="15" or s="16" or s="17" or
s="18" or s="19" or s="20"
or
s="16" or s="32" or s="64" or s="128" or s="256" or s="512" or s="1024" or
s="2048" or s="4096" or s="16384" or s="32768" or s="65536" or
s="1048576" or s="2147483648" or s="4294967296"
or
s="15" or s="31" or s="63" or s="127" or s="255" or s="511" or s="1023" or
s="2047" or s="4095" or s="16383" or s="32767" or s="65535" or
s="1048577" or s="2147483647" or s="4294967295"
or
s = "0x00000001" or s = "0x00000002" or s = "0x00000004" or s = "0x00000008" or
s = "0x00000010" or s = "0x00000020" or s = "0x00000040" or s = "0x00000080" or
s = "0x00000100" or s = "0x00000200" or s = "0x00000400" or s = "0x00000800" or
s = "0x00001000" or s = "0x00002000" or s = "0x00004000" or s = "0x00008000" or
s = "0x00010000" or s = "0x00020000" or s = "0x00040000" or s = "0x00080000" or
s = "0x00100000" or s = "0x00200000" or s = "0x00400000" or s = "0x00800000" or
s = "0x01000000" or s = "0x02000000" or s = "0x04000000" or s = "0x08000000" or
s = "0x10000000" or s = "0x20000000" or s = "0x40000000" or s = "0x80000000" or
s = "0x00000001" or s = "0x00000003" or s = "0x00000007" or s = "0x0000000f" or
s = "0x0000001f" or s = "0x0000003f" or s = "0x0000007f" or s = "0x000000ff" or
s = "0x000001ff" or s = "0x000003ff" or s = "0x000007ff" or s = "0x00000fff" or
s = "0x00001fff" or s = "0x00003fff" or s = "0x00007fff" or s = "0x0000ffff" or
s = "0x0001ffff" or s = "0x0003ffff" or s = "0x0007ffff" or s = "0x000fffff" or
s = "0x001fffff" or s = "0x003fffff" or s = "0x007fffff" or s = "0x00ffffff" or
s = "0x01ffffff" or s = "0x03ffffff" or s = "0x07ffffff" or s = "0x0fffffff" or
s = "0x1fffffff" or s = "0x3fffffff" or s = "0x7fffffff" or s = "0xffffffff" or
s = "0x0001" or s = "0x0002" or s = "0x0004" or s = "0x0008" or
s = "0x0010" or s = "0x0020" or s = "0x0040" or s = "0x0080" or
s = "0x0100" or s = "0x0200" or s = "0x0400" or s = "0x0800" or
s = "0x1000" or s = "0x2000" or s = "0x4000" or s = "0x8000" or
s = "0x0001" or s = "0x0003" or s = "0x0007" or s = "0x000f" or
s = "0x001f" or s = "0x003f" or s = "0x007f" or s = "0x00ff" or
s = "0x01ff" or s = "0x03ff" or s = "0x07ff" or s = "0x0fff" or
s = "0x1fff" or s = "0x3fff" or s = "0x7fff" or s = "0xffff" or
s = "0x01" or s = "0x02" or s = "0x04" or s = "0x08" or
s = "0x10" or s = "0x20" or s = "0x40" or s = "0x80" or
s = "0x01" or s = "0x03" or s = "0x07" or s = "0x0f" or
s = "0x1f" or s = "0x3f" or s = "0x7f" or s = "0xff" or
s = "0x00"
or
s = "10" or s = "100" or s = "1000" or
s = "10000" or s = "100000" or s = "1000000" or
s = "10000000" or s = "100000000" or s = "1000000000"
private predicate trivialPositiveIntValue(string s) {
s = "0" or
s = "1" or
s = "2" or
s = "3" or
s = "4" or
s = "5" or
s = "6" or
s = "7" or
s = "8" or
s = "9" or
s = "10" or
s = "11" or
s = "12" or
s = "13" or
s = "14" or
s = "15" or
s = "16" or
s = "17" or
s = "18" or
s = "19" or
s = "20" or
s = "16" or
s = "32" or
s = "64" or
s = "128" or
s = "256" or
s = "512" or
s = "1024" or
s = "2048" or
s = "4096" or
s = "16384" or
s = "32768" or
s = "65536" or
s = "1048576" or
s = "2147483648" or
s = "4294967296" or
s = "15" or
s = "31" or
s = "63" or
s = "127" or
s = "255" or
s = "511" or
s = "1023" or
s = "2047" or
s = "4095" or
s = "16383" or
s = "32767" or
s = "65535" or
s = "1048577" or
s = "2147483647" or
s = "4294967295" or
s = "0x00000001" or
s = "0x00000002" or
s = "0x00000004" or
s = "0x00000008" or
s = "0x00000010" or
s = "0x00000020" or
s = "0x00000040" or
s = "0x00000080" or
s = "0x00000100" or
s = "0x00000200" or
s = "0x00000400" or
s = "0x00000800" or
s = "0x00001000" or
s = "0x00002000" or
s = "0x00004000" or
s = "0x00008000" or
s = "0x00010000" or
s = "0x00020000" or
s = "0x00040000" or
s = "0x00080000" or
s = "0x00100000" or
s = "0x00200000" or
s = "0x00400000" or
s = "0x00800000" or
s = "0x01000000" or
s = "0x02000000" or
s = "0x04000000" or
s = "0x08000000" or
s = "0x10000000" or
s = "0x20000000" or
s = "0x40000000" or
s = "0x80000000" or
s = "0x00000001" or
s = "0x00000003" or
s = "0x00000007" or
s = "0x0000000f" or
s = "0x0000001f" or
s = "0x0000003f" or
s = "0x0000007f" or
s = "0x000000ff" or
s = "0x000001ff" or
s = "0x000003ff" or
s = "0x000007ff" or
s = "0x00000fff" or
s = "0x00001fff" or
s = "0x00003fff" or
s = "0x00007fff" or
s = "0x0000ffff" or
s = "0x0001ffff" or
s = "0x0003ffff" or
s = "0x0007ffff" or
s = "0x000fffff" or
s = "0x001fffff" or
s = "0x003fffff" or
s = "0x007fffff" or
s = "0x00ffffff" or
s = "0x01ffffff" or
s = "0x03ffffff" or
s = "0x07ffffff" or
s = "0x0fffffff" or
s = "0x1fffffff" or
s = "0x3fffffff" or
s = "0x7fffffff" or
s = "0xffffffff" or
s = "0x0001" or
s = "0x0002" or
s = "0x0004" or
s = "0x0008" or
s = "0x0010" or
s = "0x0020" or
s = "0x0040" or
s = "0x0080" or
s = "0x0100" or
s = "0x0200" or
s = "0x0400" or
s = "0x0800" or
s = "0x1000" or
s = "0x2000" or
s = "0x4000" or
s = "0x8000" or
s = "0x0001" or
s = "0x0003" or
s = "0x0007" or
s = "0x000f" or
s = "0x001f" or
s = "0x003f" or
s = "0x007f" or
s = "0x00ff" or
s = "0x01ff" or
s = "0x03ff" or
s = "0x07ff" or
s = "0x0fff" or
s = "0x1fff" or
s = "0x3fff" or
s = "0x7fff" or
s = "0xffff" or
s = "0x01" or
s = "0x02" or
s = "0x04" or
s = "0x08" or
s = "0x10" or
s = "0x20" or
s = "0x40" or
s = "0x80" or
s = "0x01" or
s = "0x03" or
s = "0x07" or
s = "0x0f" or
s = "0x1f" or
s = "0x3f" or
s = "0x7f" or
s = "0xff" or
s = "0x00" or
s = "10" or
s = "100" or
s = "1000" or
s = "10000" or
s = "100000" or
s = "1000000" or
s = "10000000" or
s = "100000000" or
s = "1000000000"
}
private
predicate trivialIntValue(string s) {
trivialPositiveIntValue(s) or
private predicate trivialIntValue(string s) {
trivialPositiveIntValue(s)
or
exists(string pos | trivialPositiveIntValue(pos) and s = "-" + pos)
}
private
predicate intTrivial(Literal lit) {
private predicate intTrivial(Literal lit) {
exists(string v | trivialIntValue(v) and v = lit.getLiteral())
}
private
predicate longTrivial(Literal lit) {
private predicate longTrivial(Literal lit) {
exists(string v | trivialIntValue(v) and v + "L" = lit.getLiteral())
}
private
predicate powerOfTen(float f) {
f = 10 or f = 100 or f = 1000 or
f = 10000 or f = 100000 or f = 1000000 or
f = 10000000 or f = 100000000 or f = 1000000000
private predicate powerOfTen(float f) {
f = 10 or
f = 100 or
f = 1000 or
f = 10000 or
f = 100000 or
f = 1000000 or
f = 10000000 or
f = 100000000 or
f = 1000000000
}
private
predicate floatTrivial(Literal lit) {
private predicate floatTrivial(Literal lit) {
(lit instanceof FloatingPointLiteral or lit instanceof DoubleLiteral) and
exists(float f |
f = lit.getValue().toFloat() and
@ -95,18 +214,11 @@ predicate floatTrivial(Literal lit) {
)
}
private
predicate stringTrivial(StringLiteral lit) {
lit.getLiteral().length() < 8
}
private predicate stringTrivial(StringLiteral lit) { lit.getLiteral().length() < 8 }
private
predicate small(Literal lit) {
lit.getLiteral().length() <= 1
}
private predicate small(Literal lit) { lit.getLiteral().length() <= 1 }
private
predicate trivial(Literal lit) {
private predicate trivial(Literal lit) {
lit instanceof CharacterLiteral or
lit instanceof BooleanLiteral or
lit instanceof NullLiteral or
@ -118,8 +230,7 @@ predicate trivial(Literal lit) {
excludedLiteral(lit)
}
private
predicate literalIsConstantInitializer(Literal literal, Field f) {
private predicate literalIsConstantInitializer(Literal literal, Field f) {
exists(AssignExpr e, VarAccess access |
access = e.getAChildExpr() and
f = access.getVariable() and
@ -127,12 +238,12 @@ predicate literalIsConstantInitializer(Literal literal, Field f) {
f.isFinal() and
f.isStatic() and
literal = e.getAChildExpr() and
literal.getIndex() = 1) and
not trivial(literal)
literal.getIndex() = 1
) and
not trivial(literal)
}
private
predicate nonTrivialValue(string value, Literal literal, string context) {
private predicate nonTrivialValue(string value, Literal literal, string context) {
value = literal.getLiteral() and
not trivial(literal) and
not literalIsConstantInitializer(literal, _) and
@ -141,43 +252,37 @@ predicate nonTrivialValue(string value, Literal literal, string context) {
exists(MethodAccess ma | literal = ma.getAnArgument() and ma.getMethod().getName() = context)
}
private
predicate valueOccurrenceCount(string value, int n, string context) {
private predicate valueOccurrenceCount(string value, int n, string context) {
n = strictcount(Literal lit | nonTrivialValue(value, lit, context)) and
n > 20
}
private
predicate occurenceCount(Literal lit, string value, int n, string context) {
private predicate occurenceCount(Literal lit, string value, int n, string context) {
valueOccurrenceCount(value, n, context) and
value = lit.getLiteral() and
nonTrivialValue(_, lit, context)
}
/*
*
* Literals repeated frequently
*
*/
private
predicate check(Literal lit, string value, int n, string context, CompilationUnit f) {
private predicate check(Literal lit, string value, int n, string context, CompilationUnit f) {
// Check that the literal is nontrivial
not trivial(lit) and
// Check that it is repeated a number of times
occurenceCount(lit, value, n, context) and n > 20 and
occurenceCount(lit, value, n, context) and
n > 20 and
f = lit.getCompilationUnit()
}
private
predicate checkWithFileCount(string value, int overallCount, int fileCount, string context, CompilationUnit f) {
private predicate checkWithFileCount(
string value, int overallCount, int fileCount, string context, CompilationUnit f
) {
fileCount = strictcount(Literal lit | check(lit, value, overallCount, context, f))
}
private
predicate firstOccurrence(Literal lit, string value, string context, int n) {
private predicate firstOccurrence(Literal lit, string value, string context, int n) {
exists(CompilationUnit f, int fileCount |
checkWithFileCount(value, n, fileCount, context, f) and
fileCount < 100 and
@ -186,7 +291,8 @@ predicate firstOccurrence(Literal lit, string value, string context, int n) {
check(lit2, value, n, context, f) and
lit.getLocation().getStartLine() = start1 and
lit2.getLocation().getStartLine() = start2 and
start2 < start1)
start2 < start1
)
)
}
@ -202,38 +308,38 @@ predicate isNumber(Literal lit) {
predicate magicConstant(Literal e, string msg) {
exists(string value, int n, string context |
firstOccurrence(e, value, context, n) and
msg = "Magic constant: literal '" + value + "' is used " + n.toString() + " times in calls to " + context
msg = "Magic constant: literal '" + value + "' is used " + n.toString() + " times in calls to " +
context
)
}
/*
*
* Literals where there is a defined constant with the same value
*
*/
private
predicate relevantField(Field f, string value) {
exists(Literal lit | not trivial(lit) and value = lit.getLiteral() and literalIsConstantInitializer(lit, f))
private predicate relevantField(Field f, string value) {
exists(Literal lit |
not trivial(lit) and value = lit.getLiteral() and literalIsConstantInitializer(lit, f)
)
}
private
predicate relevantType(RefType t, string value, Package p) {
private predicate relevantType(RefType t, string value, Package p) {
exists(Literal lit | nonTrivialValue(value, lit, _) |
lit.getEnclosingCallable().getDeclaringType() = t and p = t.getPackage()
)
}
private
predicate fieldUsedInContext(Field constField, string context) {
private predicate fieldUsedInContext(Field constField, string context) {
literalIsConstantInitializer(_, constField) and
exists(MethodAccess ma |
constField.getAnAccess() = ma.getAnArgument() and
ma.getMethod().getName() = context)
ma.getMethod().getName() = context
)
}
private
predicate candidateConstantForLiteral(Field constField, RefType literalType, Literal magicLiteral, string context) {
private predicate candidateConstantForLiteral(
Field constField, RefType literalType, Literal magicLiteral, string context
) {
exists(Literal initLiteral |
literalIsConstantInitializer(initLiteral, constField) and
exists(string value |
@ -245,14 +351,15 @@ predicate candidateConstantForLiteral(Field constField, RefType literalType, Lit
)
}
private
RefType inheritsProtected(Field f) {
(f.isProtected() and result.getASupertype() = f.getDeclaringType()) or
private RefType inheritsProtected(Field f) {
(f.isProtected() and result.getASupertype() = f.getDeclaringType())
or
exists(RefType mid | mid = inheritsProtected(f) and result.getASupertype() = mid)
}
private
predicate constantForLiteral(Field field, string value, RefType fromType, Literal magicLiteral, string context) {
private predicate constantForLiteral(
Field field, string value, RefType fromType, Literal magicLiteral, string context
) {
//public fields in public classes
(
candidateConstantForLiteral(field, fromType, magicLiteral, context) and
@ -291,24 +398,22 @@ predicate constantForLiteral(Field field, string value, RefType fromType, Litera
)
}
private
predicate canUseFieldInsteadOfLiteral(Field constField, Literal magicLiteral, string context) {
private predicate canUseFieldInsteadOfLiteral(Field constField, Literal magicLiteral, string context) {
constantForLiteral(constField, _, _, magicLiteral, context)
}
predicate literalInsteadOfConstant(Literal magicLiteral, string message, Field constField, string linkText) {
predicate literalInsteadOfConstant(
Literal magicLiteral, string message, Field constField, string linkText
) {
exists(string context |
canUseFieldInsteadOfLiteral(constField, magicLiteral, context) and
message =
"Literal value '" + magicLiteral.getLiteral() + "' used " +
" in a call to " + context +
"; consider using the defined constant $@." and linkText = constField.getName()
and
message = "Literal value '" + magicLiteral.getLiteral() + "' used " + " in a call to " + context
+ "; consider using the defined constant $@." and
linkText = constField.getName() and
(
constField.getCompilationUnit() = magicLiteral.getCompilationUnit() or
not almostPrivate(constField)
)
and
) and
(
constField.getCompilationUnit().getPackage() = magicLiteral.getCompilationUnit().getPackage() or
not almostPackageProtected(constField)
@ -317,7 +422,9 @@ predicate literalInsteadOfConstant(Literal magicLiteral, string message, Field c
}
private predicate almostPrivate(Field f) {
not exists(VarAccess va | va.getVariable() = f and va.getCompilationUnit() != f.getCompilationUnit())
not exists(VarAccess va |
va.getVariable() = f and va.getCompilationUnit() != f.getCompilationUnit()
)
or
exists(Interface i | i = f.getDeclaringType() |
forall(VarAccess va | va.getVariable() = f |
@ -333,13 +440,10 @@ private predicate almostPackageProtected(Field f) {
}
/*
*
* Removing literals from uninteresting contexts
*
*/
private
predicate excludedLiteral(Literal lit) {
private predicate excludedLiteral(Literal lit) {
// Remove test cases
lit.getEnclosingCallable().getDeclaringType() instanceof TestClass
or

Просмотреть файл

@ -47,11 +47,12 @@ predicate assignmentToShadowingLocal(LocalVariableDecl d, Field f) {
shadows(d, _, _, _) and
exists(Expr assignedValue, Expr use |
d.getAnAssignedValue() = assignedValue and getARelevantChild(assignedValue) = use
|
|
exists(FieldAccess access, Field ff | access = assignedValue |
ff = access.getField() and
ff.getSourceDeclaration() = f
) or
)
or
exists(MethodAccess get, Method getter | get = assignedValue and getter = get.getMethod() |
getterFor(getter, f)
)
@ -66,7 +67,8 @@ predicate assignmentFromShadowingLocal(LocalVariableDecl d, Field f) {
arg = set.getAnArgument() and
setter = set.getMethod() and
setterFor(setter, f)
) or
)
or
exists(Field instance, Expr assignedValue |
access = getARelevantChild(assignedValue) and
assignedValue = instance.getAnAssignedValue() and
@ -75,9 +77,10 @@ predicate assignmentFromShadowingLocal(LocalVariableDecl d, Field f) {
)
}
private
Expr getARelevantChild(Expr parent) {
exists(MethodAccess ma | parent = ma.getAnArgument() and result = parent) or
exists(Variable v | parent = v.getAnAccess() and result = parent) or
private Expr getARelevantChild(Expr parent) {
exists(MethodAccess ma | parent = ma.getAnArgument() and result = parent)
or
exists(Variable v | parent = v.getAnAccess() and result = parent)
or
exists(Expr mid | mid = getARelevantChild(parent) and result = mid.getAChildExpr())
}

58
java/ql/src/external/Clover.qll поставляемый
Просмотреть файл

@ -5,11 +5,7 @@ import java
* top-level children (usually, in fact, there is only one) is
* a tag with the name "coverage".
*/
class CloverReport extends XMLFile {
CloverReport() {
this.getAChild().getName() = "coverage"
}
}
class CloverReport extends XMLFile { CloverReport() { this.getAChild().getName() = "coverage" } }
/**
* The Clover "coverage" tag contains one or more "projects".
@ -20,9 +16,7 @@ class CloverCoverage extends XMLElement {
this.getName() = "coverage"
}
CloverProject getAProject() {
result = this.getAChild()
}
CloverProject getAProject() { result = this.getAChild() }
}
/**
@ -31,9 +25,7 @@ class CloverCoverage extends XMLElement {
* all subclasses of this class, to share code.
*/
abstract class CloverMetricsContainer extends XMLElement {
CloverMetrics getMetrics() {
result = this.getAChild()
}
CloverMetrics getMetrics() { result = this.getAChild() }
}
/**
@ -46,33 +38,47 @@ class CloverMetrics extends XMLElement {
this.getName() = "metrics"
}
private
int attr(string name) { result = this.getAttribute(name).getValue().toInt() }
private int attr(string name) { result = this.getAttribute(name).getValue().toInt() }
private
float ratio(string name) { result = attr("covered" + name)/(float)attr(name) }
private float ratio(string name) { result = attr("covered" + name) / attr(name).(float) }
int getNumConditionals() { result = attr("conditionals") }
int getNumCoveredConditionals() { result = attr("coveredconditionals") }
int getNumStatements() { result = attr("statements") }
int getNumCoveredStatements() { result = attr("coveredstatements") }
int getNumElements() { result = attr("elements") }
int getNumCoveredElements() { result = attr("coveredelements") }
int getNumMethods() { result = attr("methods") }
int getNumCoveredMethods() { result = attr("coveredmethods") }
int getNumLoC() { result = attr("loc") }
int getNumNonCommentedLoC() { result = attr("ncloc") }
int getNumPackages() { result = attr("packages") }
int getNumFiles() { result = attr("files") }
int getNumClasses() { result = attr("classes") }
int getCloverComplexity() { result = attr("complexity") }
float getConditionalCoverage() { result = ratio("conditionals") }
float getStatementCoverage() { result = ratio("statements") }
float getElementCoverage() { result = ratio("elements") }
float getMethodCoverage() { result = ratio("methods") }
float getNonCommentedLoCRatio() { result = attr("ncloc")/attr("loc")}
float getNonCommentedLoCRatio() { result = attr("ncloc") / attr("loc") }
}
/**
@ -80,9 +86,7 @@ class CloverMetrics extends XMLElement {
* groups together several "package" (or "testpackage") elements.
*/
class CloverProject extends CloverMetricsContainer {
CloverProject() {
this.getParent() instanceof CloverCoverage
}
CloverProject() { this.getParent() instanceof CloverCoverage }
}
/**
@ -94,9 +98,7 @@ class CloverPackage extends CloverMetricsContainer {
this.getName() = "package"
}
Package getRealPackage() {
result.hasName(getAttribute("name").getValue())
}
Package getRealPackage() { result.hasName(getAttribute("name").getValue()) }
}
/**
@ -118,12 +120,12 @@ class CloverClass extends CloverMetricsContainer {
this.getName() = "class"
}
CloverPackage getPackage() {
result = ((CloverFile)getParent()).getParent()
}
CloverPackage getPackage() { result = (getParent().(CloverFile)).getParent() }
RefType getRealClass() {
result.hasQualifiedName(getPackage().getAttribute("name").getValue(), getAttribute("name").getValue())
result
.hasQualifiedName(getPackage().getAttribute("name").getValue(),
getAttribute("name").getValue())
}
}
@ -131,7 +133,5 @@ class CloverClass extends CloverMetricsContainer {
* Get the clover metrics associated with the given class, if any.
*/
CloverMetrics cloverInfo(RefType t) {
exists(CloverClass c | c.getRealClass() = t |
result = c.getMetrics()
)
exists(CloverClass c | c.getRealClass() = t | result = c.getMetrics())
}

180
java/ql/src/external/CodeDuplication.qll поставляемый
Просмотреть файл

@ -1,22 +1,15 @@
import java
private
string relativePath(File file) {
result = file.getRelativePath().replaceAll("\\", "/")
}
private string relativePath(File file) { result = file.getRelativePath().replaceAll("\\", "/") }
private cached
predicate tokenLocation(File file, int sl, int sc, int ec, int el, Copy copy, int index) {
cached
private predicate tokenLocation(File file, int sl, int sc, int ec, int el, Copy copy, int index) {
file = copy.sourceFile() and
tokens(copy, index, sl, sc, ec, el)
}
class Copy extends @duplication_or_similarity
{
private
int lastToken() {
result = max(int i | tokens(this, i, _, _, _, _) | i)
}
class Copy extends @duplication_or_similarity {
private int lastToken() { result = max(int i | tokens(this, i, _, _, _, _) | i) }
int tokenStartingAt(Location loc) {
tokenLocation(loc.getFile(), loc.getStartLine(), loc.getStartColumn(), _, _, this, result)
@ -26,29 +19,17 @@ class Copy extends @duplication_or_similarity
tokenLocation(loc.getFile(), _, _, loc.getEndLine(), loc.getEndColumn(), this, result)
}
int sourceStartLine() {
tokens(this, 0, result, _, _, _)
}
int sourceStartLine() { tokens(this, 0, result, _, _, _) }
int sourceStartColumn() {
tokens(this, 0, _, result, _, _)
}
int sourceStartColumn() { tokens(this, 0, _, result, _, _) }
int sourceEndLine() {
tokens(this, lastToken(), _, _, result, _)
}
int sourceEndLine() { tokens(this, lastToken(), _, _, result, _) }
int sourceEndColumn() {
tokens(this, lastToken(), _, _, _, result)
}
int sourceEndColumn() { tokens(this, lastToken(), _, _, _, result) }
int sourceLines() {
result = this.sourceEndLine() + 1 - this.sourceStartLine()
}
int sourceLines() { result = this.sourceEndLine() + 1 - this.sourceStartLine() }
int getEquivalenceClass() {
duplicateCode(this, _, result) or similarCode(this, _, result)
}
int getEquivalenceClass() { duplicateCode(this, _, result) or similarCode(this, _, result) }
File sourceFile() {
exists(string name | duplicateCode(this, name, _) or similarCode(this, name, _) |
@ -56,7 +37,9 @@ class Copy extends @duplication_or_similarity
)
}
predicate hasLocationInfo(string filepath, int startline, int startcolumn, int endline, int endcolumn) {
predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
sourceFile().getAbsolutePath() = filepath and
startline = sourceStartLine() and
startcolumn = sourceStartColumn() and
@ -67,30 +50,21 @@ class Copy extends @duplication_or_similarity
string toString() { none() }
}
class DuplicateBlock extends Copy, @duplication
{
string toString() {
result = "Duplicate code: " + sourceLines() + " duplicated lines."
}
class DuplicateBlock extends Copy, @duplication {
string toString() { result = "Duplicate code: " + sourceLines() + " duplicated lines." }
}
class SimilarBlock extends Copy, @similarity
{
string toString() {
result = "Similar code: " + sourceLines() + " almost duplicated lines."
}
class SimilarBlock extends Copy, @similarity {
string toString() { result = "Similar code: " + sourceLines() + " almost duplicated lines." }
}
Method sourceMethod() {
hasLocation(result, _) and numlines(result, _, _, _)
}
Method sourceMethod() { hasLocation(result, _) and numlines(result, _, _, _) }
int numberOfSourceMethods(Class c) {
result = count(Method m | m = sourceMethod() and m.getDeclaringType() = c)
}
private
predicate blockCoversStatement(int equivClass, int first, int last, Stmt stmt) {
private predicate blockCoversStatement(int equivClass, int first, int last, Stmt stmt) {
exists(DuplicateBlock b, Location loc |
stmt.getLocation() = loc and
first = b.tokenStartingAt(loc) and
@ -99,20 +73,19 @@ predicate blockCoversStatement(int equivClass, int first, int last, Stmt stmt) {
)
}
private
Stmt statementInMethod(Method m) {
private Stmt statementInMethod(Method m) {
result.getEnclosingCallable() = m and
not result instanceof Block
}
private
predicate duplicateStatement(Method m1, Method m2, Stmt s1, Stmt s2) {
private predicate duplicateStatement(Method m1, Method m2, Stmt s1, Stmt s2) {
exists(int equivClass, int first, int last |
s1 = statementInMethod(m1) and
s2 = statementInMethod(m2) and
blockCoversStatement(equivClass, first, last, s1) and
blockCoversStatement(equivClass, first, last, s2) and
s1 != s2 and m1 != m2
s1 != s2 and
m1 != m2
)
}
@ -129,34 +102,30 @@ predicate duplicateMethod(Method m, Method other) {
}
predicate similarLines(File f, int line) {
exists(SimilarBlock b |
b.sourceFile() = f and line in [b.sourceStartLine() .. b.sourceEndLine()]
)
exists(SimilarBlock b | b.sourceFile() = f and line in [b.sourceStartLine() .. b.sourceEndLine()])
}
private
predicate similarLinesPerEquivalenceClass(int equivClass, int lines, File f)
{
private predicate similarLinesPerEquivalenceClass(int equivClass, int lines, File f) {
lines = strictsum(SimilarBlock b, int toSum |
(b.sourceFile() = f and b.getEquivalenceClass() = equivClass) and (toSum = b.sourceLines()) | toSum)
(b.sourceFile() = f and b.getEquivalenceClass() = equivClass) and
(toSum = b.sourceLines())
|
toSum
)
}
private pragma[noopt]
predicate similarLinesCovered(File f, int coveredLines, File otherFile) {
pragma[noopt]
private predicate similarLinesCovered(File f, int coveredLines, File otherFile) {
exists(int numLines | numLines = f.getTotalNumberOfLines() |
exists(int coveredApprox |
coveredApprox = strictsum(int num |
exists(int equivClass |
similarLinesPerEquivalenceClass(equivClass, num, f) and
similarLinesPerEquivalenceClass(equivClass, num, otherFile) and
f != otherFile
)
) and
exists(int n, int product |
product = coveredApprox * 100 and n = product / numLines
|
n > 75
)
exists(int equivClass |
similarLinesPerEquivalenceClass(equivClass, num, f) and
similarLinesPerEquivalenceClass(equivClass, num, otherFile) and
f != otherFile
)
) and
exists(int n, int product | product = coveredApprox * 100 and n = product / numLines | n > 75)
) and
exists(int notCovered |
notCovered = count(int j | j in [1 .. numLines] and not similarLines(f, j)) and
@ -171,24 +140,26 @@ predicate duplicateLines(File f, int line) {
)
}
private
predicate duplicateLinesPerEquivalenceClass(int equivClass, int lines, File f)
{
private predicate duplicateLinesPerEquivalenceClass(int equivClass, int lines, File f) {
lines = strictsum(DuplicateBlock b, int toSum |
(b.sourceFile() = f and b.getEquivalenceClass() = equivClass) and (toSum = b.sourceLines()) | toSum)
(b.sourceFile() = f and b.getEquivalenceClass() = equivClass) and
(toSum = b.sourceLines())
|
toSum
)
}
private pragma[noopt]
predicate duplicateLinesCovered(File f, int coveredLines, File otherFile) {
pragma[noopt]
private predicate duplicateLinesCovered(File f, int coveredLines, File otherFile) {
exists(int numLines | numLines = f.getTotalNumberOfLines() |
exists(int coveredApprox |
coveredApprox = strictsum(int num |
exists(int equivClass |
duplicateLinesPerEquivalenceClass(equivClass, num, f) and
duplicateLinesPerEquivalenceClass(equivClass, num, otherFile) and
f != otherFile
)
) and
exists(int equivClass |
duplicateLinesPerEquivalenceClass(equivClass, num, f) and
duplicateLinesPerEquivalenceClass(equivClass, num, otherFile) and
f != otherFile
)
) and
exists(int n, int product | product = coveredApprox * 100 and n = product / numLines | n > 75)
) and
exists(int notCovered |
@ -220,14 +191,14 @@ predicate duplicateFiles(File f, File other, int percent) {
predicate duplicateAnonymousClass(AnonymousClass c, AnonymousClass other) {
exists(int numDup |
numDup = strictcount(Method m1 |
exists(Method m2 |
duplicateMethod(m1, m2) and
m1 = sourceMethod() and
m1.getDeclaringType() = c and
m2.getDeclaringType() = other and
c != other
)
) and
exists(Method m2 |
duplicateMethod(m1, m2) and
m1 = sourceMethod() and
m1.getDeclaringType() = c and
m2.getDeclaringType() = other and
c != other
)
) and
numDup = numberOfSourceMethods(c) and
numDup = numberOfSourceMethods(other) and
forall(Type t | c.getASupertype() = t | t = other.getASupertype())
@ -237,15 +208,15 @@ predicate duplicateAnonymousClass(AnonymousClass c, AnonymousClass other) {
pragma[noopt]
predicate mostlyDuplicateClassBase(Class c, Class other, int numDup, int total) {
numDup = strictcount(Method m1 |
exists(Method m2 |
duplicateMethod(m1, m2) and
m1 = sourceMethod() and
m1.getDeclaringType() = c and
m2.getDeclaringType() = other and
other instanceof Class and
c != other
)
) and
exists(Method m2 |
duplicateMethod(m1, m2) and
m1 = sourceMethod() and
m1.getDeclaringType() = c and
m2.getDeclaringType() = other and
other instanceof Class and
c != other
)
) and
total = numberOfSourceMethods(c) and
exists(int n, int product | product = 100 * numDup and n = product / total | n > 80)
}
@ -259,8 +230,11 @@ predicate mostlyDuplicateClass(Class c, Class other, string message) {
(
total != numDup and
exists(string s1, string s2, string s3, string name |
s1 = " out of " and s2 = " methods in " and s3 = " are duplicated in $@." and name = c.getName()
|
s1 = " out of " and
s2 = " methods in " and
s3 = " are duplicated in $@." and
name = c.getName()
|
message = numDup + s1 + total + s2 + name + s3
)
)
@ -269,7 +243,7 @@ predicate mostlyDuplicateClass(Class c, Class other, string message) {
total = numDup and
exists(string s1, string s2, string name |
s1 = "All methods in " and s2 = " are identical in $@." and name = c.getName()
|
|
message = s1 + name + s2
)
)

15
java/ql/src/external/DefectFilter.qll поставляемый
Просмотреть файл

@ -10,9 +10,10 @@ import java
*
* For more information, see [LGTM locations](https://lgtm.com/help/ql/locations).
*/
external predicate defectResults(int id, string queryPath,
string file, int startline, int startcol, int endline, int endcol,
string message);
external predicate defectResults(
int id, string queryPath, string file, int startline, int startcol, int endline, int endcol,
string message
);
/**
* A defect query result stored in a dashboard database.
@ -25,7 +26,9 @@ class DefectResult extends int {
/** Gets the file in which this query result was reported. */
File getFile() {
exists(string path | defectResults(this, _, path, _, _, _, _, _) | result.getAbsolutePath() = path)
exists(string path | defectResults(this, _, path, _, _, _, _, _) |
result.getAbsolutePath() = path
)
}
/** Gets the line on which the location of this query result starts. */
@ -45,7 +48,7 @@ class DefectResult extends int {
/** Gets the URL corresponding to the location of this query result. */
string getURL() {
result = "file://" + getFile().getAbsolutePath() + ":" +
getStartLine() + ":" + getStartColumn() + ":" + getEndLine() + ":" + getEndColumn()
result = "file://" + getFile().getAbsolutePath() + ":" + getStartLine() + ":" + getStartColumn()
+ ":" + getEndLine() + ":" + getEndColumn()
}
}

9
java/ql/src/external/ExternalArtifact.qll поставляемый
Просмотреть файл

@ -1,7 +1,6 @@
import java
class ExternalData extends @externalDataElement {
string getDataPath() { externalData(this, result, _, _) }
string getQueryPath() { result = getDataPath().regexpReplaceAll("\\.[^.]*$", ".ql") }
@ -16,16 +15,13 @@ class ExternalData extends @externalDataElement {
date getFieldAsDate(int index) { result = getField(index).toDate() }
string toString() {
result = getQueryPath() + ": " + buildTupleString(0)
}
string toString() { result = getQueryPath() + ": " + buildTupleString(0) }
private string buildTupleString(int start) {
(start = getNumFields() - 1 and result = getField(start))
or
(start < getNumFields() - 1 and result = getField(start) + "," + buildTupleString(start+1))
(start < getNumFields() - 1 and result = getField(start) + "," + buildTupleString(start + 1))
}
}
/**
@ -41,4 +37,3 @@ class DefectExternalData extends ExternalData {
string getMessage() { result = getField(1) }
}

16
java/ql/src/external/MetricFilter.qll поставляемый
Просмотреть файл

@ -1,14 +1,20 @@
import java
external predicate metricResults(int id, string queryPath, string file, int startline, int startcol, int endline, int endcol, float value);
external predicate metricResults(
int id, string queryPath, string file, int startline, int startcol, int endline, int endcol,
float value
);
class MetricResult extends int {
MetricResult() { metricResults(this, _, _, _, _, _, _, _) }
string getQueryPath() { metricResults(this, result, _, _, _, _, _, _) }
File getFile() { exists(string path | metricResults(this, _, path, _, _, _, _, _) and result.getAbsolutePath() = path) }
File getFile() {
exists(string path |
metricResults(this, _, path, _, _, _, _, _) and result.getAbsolutePath() = path
)
}
int getStartLine() { metricResults(this, _, _, result, _, _, _, _) }
@ -31,7 +37,7 @@ class MetricResult extends int {
float getValue() { metricResults(this, _, _, _, _, _, _, result) }
string getURL() {
result = "file://" + getFile().getAbsolutePath() + ":" + getStartLine() + ":" + getStartColumn() + ":" + getEndLine() + ":" + getEndColumn()
result = "file://" + getFile().getAbsolutePath() + ":" + getStartLine() + ":" + getStartColumn()
+ ":" + getEndLine() + ":" + getEndColumn()
}
}

30
java/ql/src/external/VCS.qll поставляемый
Просмотреть файл

@ -1,7 +1,6 @@
import java
class Commit extends @svnentry {
Commit() {
svnaffectedfiles(this, _, _) and
exists(date svnDate, date snapshotDate |
@ -31,30 +30,22 @@ class Commit extends @svnentry {
string getAnAffectedFilePath() { result = getAnAffectedFilePath(_) }
File getAnAffectedFile(string action) {
svnaffectedfiles(this,result,action)
}
File getAnAffectedFile(string action) { svnaffectedfiles(this, result, action) }
File getAnAffectedFile() { exists(string action | result = this.getAnAffectedFile(action)) }
predicate isRecent() { recentCommit(this) }
int daysToNow() {
exists(date now | snapshotDate(now) |
result = getDate().daysTo(now) and result >= 0
)
exists(date now | snapshotDate(now) | result = getDate().daysTo(now) and result >= 0)
}
int getRecentAdditionsForFile(File f) {
svnchurn(this, f, result, _)
}
int getRecentAdditionsForFile(File f) { svnchurn(this, f, result, _) }
int getRecentDeletionsForFile(File f) {
svnchurn(this, f, _, result)
}
int getRecentDeletionsForFile(File f) { svnchurn(this, f, _, result) }
int getRecentChurnForFile(File f) {
exists(int added, int deleted | svnchurn(this, f, added, deleted) and result = added+deleted)
exists(int added, int deleted | svnchurn(this, f, added, deleted) and result = added + deleted)
}
}
@ -71,7 +62,8 @@ predicate recentCommit(Commit e) {
snapshotDate(snapshotDate) and
e.getDate() = commitDate and
days = commitDate.daysTo(snapshotDate) and
days >= 0 and days <= 60
days >= 0 and
days <= 60
)
}
@ -80,11 +72,7 @@ date firstChange(File f) {
}
predicate firstCommit(Commit e) {
not exists(File f | f = e.getAnAffectedFile() |
firstChange(f) < e.getDate()
)
not exists(File f | f = e.getAnAffectedFile() | firstChange(f) < e.getDate())
}
predicate artificialChange(Commit e) {
firstCommit(e) or e.getChangeSize() >= 50000
}
predicate artificialChange(Commit e) { firstCommit(e) or e.getChangeSize() >= 50000 }

Просмотреть файл

@ -2,7 +2,6 @@
import semmle.code.FileSystem
import semmle.code.Location
import semmle.code.java.Annotation
import semmle.code.java.CompilationUnit
import semmle.code.java.ControlFlowGraph
@ -26,15 +25,12 @@ import semmle.code.java.Statement
import semmle.code.java.Type
import semmle.code.java.UnitTests
import semmle.code.java.Variable
import semmle.code.java.controlflow.BasicBlocks
import semmle.code.java.metrics.MetricCallable
import semmle.code.java.metrics.MetricElement
import semmle.code.java.metrics.MetricField
import semmle.code.java.metrics.MetricPackage
import semmle.code.java.metrics.MetricRefType
import semmle.code.java.metrics.MetricStmt
import semmle.code.xml.Ant
import semmle.code.xml.XML

Просмотреть файл

@ -48,7 +48,7 @@ class Container extends @container, Top {
string getRelativePath() {
exists(string absPath, string pref |
absPath = getAbsolutePath() and sourceLocationPrefix(pref)
|
|
absPath = pref and result = ""
or
absPath = pref.regexpReplaceAll("/$", "") + "/" + result and
@ -100,9 +100,7 @@ class Container extends @container, Top {
* <tr><td>"/tmp/x.tar.gz"</td><td>"gz"</td></tr>
* </table>
*/
string getExtension() {
result = getAbsolutePath().regexpCapture(".*/([^/]*?)(\\.([^.]*))?", 3)
}
string getExtension() { result = getAbsolutePath().regexpCapture(".*/([^/]*?)(\\.([^.]*))?", 3) }
/**
* Gets the stem of this container, that is, the prefix of its base name up to
@ -121,24 +119,16 @@ class Container extends @container, Top {
* <tr><td>"/tmp/x.tar.gz"</td><td>"x.tar"</td></tr>
* </table>
*/
string getStem() {
result = getAbsolutePath().regexpCapture(".*/([^/]*?)(?:\\.([^.]*))?", 1)
}
string getStem() { result = getAbsolutePath().regexpCapture(".*/([^/]*?)(?:\\.([^.]*))?", 1) }
/** Gets the parent container of this file or folder, if any. */
Container getParentContainer() {
containerparent(result, this)
}
Container getParentContainer() { containerparent(result, this) }
/** Gets a file or sub-folder in this container. */
Container getAChildContainer() {
this = result.getParentContainer()
}
Container getAChildContainer() { this = result.getParentContainer() }
/** Gets a file in this container. */
File getAFile() {
result = getAChildContainer()
}
File getAFile() { result = getAChildContainer() }
/** Gets the file in this container that has the given `baseName`, if any. */
File getFile(string baseName) {
@ -147,9 +137,7 @@ class Container extends @container, Top {
}
/** Gets a sub-folder in this container. */
Folder getAFolder() {
result = getAChildContainer()
}
Folder getAFolder() { result = getAChildContainer() }
/** Gets the sub-folder in this container that has the given `baseName`, if any. */
Folder getFolder(string baseName) {
@ -162,19 +150,14 @@ class Container extends @container, Top {
*
* This is the absolute path of the container.
*/
override string toString() {
result = getAbsolutePath()
}
override string toString() { result = getAbsolutePath() }
/**
* DEPRECATED: use `getAbsolutePath()`, `getBaseName()` or `getStem()` instead.
*
* Gets the name of this container.
*/
deprecated
string getName() {
result = getAbsolutePath()
}
deprecated string getName() { result = getAbsolutePath() }
/**
* DEPRECATED: use `getBaseName()` or `getStem()` instead.
@ -184,10 +167,9 @@ class Container extends @container, Top {
* For folders, the short name includes the extension (if any), so the short name
* of the folder with absolute path `/home/user/.m2` is `.m2`.
*/
deprecated
string getShortName() {
folders(this,_,result) or
files(this,_,result,_,_)
deprecated string getShortName() {
folders(this, _, result) or
files(this, _, result, _, _)
}
/**
@ -195,22 +177,15 @@ class Container extends @container, Top {
*
* Gets the full name of this container, including its path and extension (if any).
*/
deprecated
string getFullName() {
result = getAbsolutePath()
}
deprecated string getFullName() { result = getAbsolutePath() }
}
/** A folder. */
class Folder extends Container, @folder {
override string getAbsolutePath() {
folders(this, result, _)
}
override string getAbsolutePath() { folders(this, result, _) }
/** Gets the URL of this folder. */
override string getURL() {
result = "folder://" + getAbsolutePath()
}
override string getURL() { result = "folder://" + getAbsolutePath() }
}
/**
@ -219,55 +194,42 @@ class Folder extends Container, @folder {
* Note that `File` extends `Container` as it may be a `jar` file.
*/
class File extends Container, @file {
override string getAbsolutePath() {
files(this, result, _, _, _)
}
override string getAbsolutePath() { files(this, result, _, _, _) }
/** Gets the URL of this file. */
override string getURL() {
result = "file://" + this.getAbsolutePath() + ":0:0:0:0"
}
override string getURL() { result = "file://" + this.getAbsolutePath() + ":0:0:0:0" }
/**
* DEPRECATED: use `getAbsolutePath()`, `getBaseName()` or `getStem()` instead.
*
* Holds if this file has the specified `name`.
*/
deprecated
predicate hasName(string name) { name = this.getAbsolutePath() }
deprecated predicate hasName(string name) { name = this.getAbsolutePath() }
}
/**
* A Java archive file with a ".jar" extension.
*/
class JarFile extends File {
JarFile() {
getExtension() = "jar"
}
JarFile() { getExtension() = "jar" }
/**
* Gets the main attribute with the specified `key`
* from this JAR file's manifest.
*/
string getManifestMainAttribute(string key) {
jarManifestMain(this, key, result)
}
string getManifestMainAttribute(string key) { jarManifestMain(this, key, result) }
/**
* Gets the "Specification-Version" main attribute
* from this JAR file's manifest.
*/
string getSpecificationVersion() {
result = getManifestMainAttribute("Specification-Version")
}
string getSpecificationVersion() { result = getManifestMainAttribute("Specification-Version") }
/**
* Gets the "Implementation-Version" main attribute
* from this JAR file's manifest.
*/
string getImplementationVersion() {
result = getManifestMainAttribute("Implementation-Version")
}
string getImplementationVersion() { result = getManifestMainAttribute("Implementation-Version") }
/**
* Gets the per-entry attribute for the specified `entry` and `key`

Просмотреть файл

@ -9,25 +9,39 @@ import semmle.code.java.Element
/** Holds if element `e` has name `name`. */
predicate hasName(Element e, string name) {
classes(e,name,_,_) or
interfaces(e,name,_,_) or
primitives(e,name) or
constrs(e,name,_,_,_,_) or
methods(e,name,_,_,_,_) or
fields(e,name,_,_,_) or
packages(e,name) or
files(e,_,name,_,_) or
paramName(e,name) or
classes(e, name, _, _)
or
interfaces(e, name, _, _)
or
primitives(e, name)
or
constrs(e, name, _, _, _, _)
or
methods(e, name, _, _, _, _)
or
fields(e, name, _, _, _)
or
packages(e, name)
or
files(e, _, name, _, _)
or
paramName(e, name)
or
exists(int pos |
params(e,_,pos,_,_) and
not paramName(e,_) and
name = "p"+pos
) or
localvars(e,name,_,_) or
typeVars(e,name,_,_,_) or
wildcards(e,name,_) or
arrays(e,name,_,_,_) or
modifiers(e,name)
params(e, _, pos, _, _) and
not paramName(e, _) and
name = "p" + pos
)
or
localvars(e, name, _, _)
or
typeVars(e, name, _, _, _)
or
wildcards(e, name, _)
or
arrays(e, name, _, _, _)
or
modifiers(e, name)
}
/**
@ -45,35 +59,29 @@ class Top extends @top {
* For more information, see
* [LGTM locations](https://lgtm.com/help/ql/locations).
*/
predicate hasLocationInfo(string filepath, int startline, int startcolumn, int endline, int endcolumn) {
predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
exists(File f, Location l | fixedHasLocation(this, l, f) |
locations_default(l,f,startline,startcolumn,endline,endcolumn) and
locations_default(l, f, startline, startcolumn, endline, endcolumn) and
filepath = f.getAbsolutePath()
)
}
/** Gets the file associated with this element. */
File getFile() {
fixedHasLocation(this, _, result)
}
File getFile() { fixedHasLocation(this, _, result) }
/**
* Gets the total number of lines that this element ranges over,
* including lines of code, comment and whitespace-only lines.
*/
int getTotalNumberOfLines() {
numlines(this, result, _, _)
}
int getTotalNumberOfLines() { numlines(this, result, _, _) }
/** Gets the number of lines of code that this element ranges over. */
int getNumberOfLinesOfCode() {
numlines(this, _, result, _)
}
int getNumberOfLinesOfCode() { numlines(this, _, result, _) }
/** Gets the number of comment lines that this element ranges over. */
int getNumberOfCommentLines() {
numlines(this, _, _, result)
}
int getNumberOfCommentLines() { numlines(this, _, _, result) }
/** Gets a textual representation of this element. */
string toString() { hasName(this, result) }
@ -82,16 +90,16 @@ class Top extends @top {
/** A location maps language elements to positions in source files. */
class Location extends @location {
/** Gets the line number where this location starts. */
int getStartLine() { locations_default(this,_,result,_,_,_) }
int getStartLine() { locations_default(this, _, result, _, _, _) }
/** Gets the column number where this location starts. */
int getStartColumn() { locations_default(this,_,_,result,_,_) }
int getStartColumn() { locations_default(this, _, _, result, _, _) }
/** Gets the line number where this location ends. */
int getEndLine() { locations_default(this,_,_,_,result,_) }
int getEndLine() { locations_default(this, _, _, _, result, _) }
/** Gets the column number where this location ends. */
int getEndColumn() { locations_default(this,_,_,_,_,result) }
int getEndColumn() { locations_default(this, _, _, _, _, result) }
/**
* Gets the total number of lines that this location ranges over,
@ -99,37 +107,41 @@ class Location extends @location {
*/
int getNumberOfLines() {
exists(@sourceline s | hasLocation(s, this) |
numlines(s,result,_,_) or
(not numlines(s,_,_,_) and result = 0)
numlines(s, result, _, _)
or
(not numlines(s, _, _, _) and result = 0)
)
}
/** Gets the number of lines of code that this location ranges over. */
int getNumberOfLinesOfCode() {
exists(@sourceline s | hasLocation(s, this) |
numlines(s,_,result,_) or
(not numlines(s,_,_,_) and result = 0)
numlines(s, _, result, _)
or
(not numlines(s, _, _, _) and result = 0)
)
}
/** Gets the number of comment lines that this location ranges over. */
int getNumberOfCommentLines() {
exists(@sourceline s | hasLocation(s, this) |
numlines(s,_,_,result) or
(not numlines(s,_,_,_) and result = 0)
numlines(s, _, _, result)
or
(not numlines(s, _, _, _) and result = 0)
)
}
/** Gets the file containing this location. */
File getFile() { locations_default(this,result,_,_,_,_) }
File getFile() { locations_default(this, result, _, _, _, _) }
/** Gets a string representation containing the file and range for this location. */
string toString() {
exists(File f, int startLine, int endLine | locations_default(this,f,startLine,_,endLine,_) |
if endLine = startLine then
result = f.toString() + ":" + startLine.toString()
else
result = f.toString() + ":" + startLine.toString() + "-" + endLine.toString()
exists(File f, int startLine, int endLine |
locations_default(this, f, startLine, _, endLine, _)
|
if endLine = startLine
then result = f.toString() + ":" + startLine.toString()
else result = f.toString() + ":" + startLine.toString() + "-" + endLine.toString()
)
}
@ -140,8 +152,10 @@ class Location extends @location {
* For more information, see
* [LGTM locations](https://lgtm.com/help/ql/locations).
*/
predicate hasLocationInfo(string filepath, int startline, int startcolumn, int endline, int endcolumn) {
exists(File f | locations_default(this,f,startline,startcolumn,endline,endcolumn) |
predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
exists(File f | locations_default(this, f, startline, startcolumn, endline, endcolumn) |
filepath = f.getAbsolutePath()
)
}
@ -153,6 +167,7 @@ private predicate hasSourceLocation(Top l, Location loc, File f) {
cached
private predicate fixedHasLocation(Top l, Location loc, File f) {
hasSourceLocation(l, loc, f) or
hasSourceLocation(l, loc, f)
or
(hasLocation(l, loc) and not hasSourceLocation(l, _, _) and locations_default(loc, f, _, _, _, _))
}

Просмотреть файл

@ -19,20 +19,22 @@ class AntTarget extends XMLElement {
*/
string getDependsString() {
result = "," +
this.getAttributeValue("depends").replaceAll(" ", "")
.replaceAll("\r","").replaceAll("\n","").replaceAll("\t","") + ","
this
.getAttributeValue("depends")
.replaceAll(" ", "")
.replaceAll("\r", "")
.replaceAll("\n", "")
.replaceAll("\t", "") + ","
}
/** Holds if this Ant target depends on the specified target. */
predicate dependsOn(AntTarget that) {
this.getFile() = that.getFile() and
this.getDependsString().matches("%,"+that.getName()+",%")
this.getDependsString().matches("%," + that.getName() + ",%")
}
/** Gets an Ant target on which this Ant target depends. */
AntTarget getADependency() {
this.dependsOn(result)
}
AntTarget getADependency() { this.dependsOn(result) }
}
/** An Ant target that occurs in an Ant build file with the default name `build.xml`. */

Просмотреть файл

@ -20,24 +20,24 @@ private string normalize(string path) {
class ProtoPom extends XMLElement {
/** Gets a child XML element named "groupId". */
Group getGroup() { result = this.getAChild() }
/** Gets a child XML element named "artifactId". */
Artifact getArtifact() { result = this.getAChild() }
/** Gets a child XML element named "version". */
Version getVersion() { result=this.getAChild() }
Version getVersion() { result = this.getAChild() }
/**
* Gets a string representing the version, or an empty string if no version
* tag was provided.
*/
string getVersionString() {
if exists(getVersion().getValue()) then
result = getVersion().getValue()
else
result = ""
if exists(getVersion().getValue()) then result = getVersion().getValue() else result = ""
}
/** Gets a Maven coordinate of the form `groupId:artifactId`. */
string getShortCoordinate() {
result = this.getGroup().getValue() + ":" + this.getArtifact().getValue()
result = this.getGroup().getValue() + ":" + this.getArtifact().getValue()
}
}
@ -51,34 +51,33 @@ class ProtoPom extends XMLElement {
*/
class Pom extends ProtoPom {
Pom() {
this.getName()="project" and
this.getName() = "project" and
/*
* Ignore "dependency-reduced-pom" files - these are generated by the
* shading plugin, and duplicate existing pom files.
*/
this.getFile().getStem() != "dependency-reduced-pom"
}
override Group getGroup() {
// For a project element, the group may be defined in the parent tags instead
if not(exists(super.getGroup())) then
exists(Parent p | p = this.getAChild() and result = p.getAChild())
else
result = super.getGroup()
if not (exists(super.getGroup()))
then exists(Parent p | p = this.getAChild() and result = p.getAChild())
else result = super.getGroup()
}
/** Gets a Maven coordinate of the form `groupId:artifactId:version`. */
string getCoordinate() {
result = this.getGroup().getValue() + ":" +
this.getArtifact().getValue() + ":" +
this.getVersion().getValue()
result = this.getGroup().getValue() + ":" + this.getArtifact().getValue() + ":" +
this.getVersion().getValue()
}
/** Gets a child XML element named "name". */
Named getNamed() { result= this.getAChild() }
Named getNamed() { result = this.getAChild() }
/** Gets a child XML element named "dependencies". */
Dependencies getDependencies() { result=this.getAChild() }
Dependencies getDependencies() { result = this.getAChild() }
/** Gets a child XML element named `dependencyManagement`. */
DependencyManagement getDependencyManagement() { result = getAChild() }
@ -89,16 +88,15 @@ class Pom extends ProtoPom {
/**
* Gets a property defined in the `<properties>` section of this POM.
*/
PomProperty getALocalProperty() {
result = getAChild().(PomProperties).getAProperty()
}
PomProperty getALocalProperty() { result = getAChild().(PomProperties).getAProperty() }
/**
* Gets a property value defined for this project, either in a local `<properties>` section, or
* in the `<properties>` section of an ancestor POM.
*/
PomProperty getAProperty() {
result = getALocalProperty() or
result = getALocalProperty()
or
(
result = getParentPom().getAProperty() and
not getALocalProperty().getName() = result.getName()
@ -119,7 +117,8 @@ class Pom extends ProtoPom {
PomElement getProjectProperty() {
(
// It must either be a child of the pom, or a child of the parent node of the pom
result = getAChild() or
result = getAChild()
or
(
result = getParentPom().getAChild() and
// The parent project property is not shadowed by a local project property
@ -135,14 +134,17 @@ class Pom extends ProtoPom {
* occurs by considering the properties defined by this project.
*/
string resolvePlaceholder(string name) {
if name.prefix(8) = "project." then
if name.prefix(8) = "project."
then
exists(PomElement p |
p = getProjectProperty() and
"project." + p.getName() = name and
result = p.getValue()
)
else
exists(PomProperty prop | prop = getAProperty() and prop.getName() = name and result = prop.getValue())
exists(PomProperty prop |
prop = getAProperty() and prop.getName() = name and result = prop.getValue()
)
}
/**
@ -157,35 +159,29 @@ class Pom extends ProtoPom {
* Gets a pom dependency that is exported by this pom. An exported dependency is one that
* is transitively available, i.e. one with scope compile.
*/
Pom getAnExportedPom() {
result = getAnExportedDependency().getPom()
}
Pom getAnExportedPom() { result = getAnExportedDependency().getPom() }
/**
* Gets the `<parent>` element of this pom, if any.
*/
Parent getParentElement() {
result = getAChild()
}
Parent getParentElement() { result = getAChild() }
/**
* Gets the pom referred to by the `<parent>` element of this pom, if any.
*/
Pom getParentPom() {
result = getParentElement().getPom()
}
Pom getParentPom() { result = getParentElement().getPom() }
/**
* Gets the version specified for dependency `dep` in a `dependencyManagement`
* section if this pom or one of its ancestors.
*/
string getVersionStringForDependency(Dependency dep) {
if exists(getDependencyManagement().getDependency(dep)) then
result = getDependencyManagement().getDependency(dep).getVersionString()
else if exists(getParentPom()) then
result = getParentPom().getVersionStringForDependency(dep)
if exists(getDependencyManagement().getDependency(dep))
then result = getDependencyManagement().getDependency(dep).getVersionString()
else
result = ""
if exists(getParentPom())
then result = getParentPom().getVersionStringForDependency(dep)
else result = ""
}
/**
@ -197,24 +193,24 @@ class Pom extends ProtoPom {
*/
Folder getSourceDirectory() {
exists(string relativePath |
if exists(getProperty("sourceDirectory")) then
if exists(getProperty("sourceDirectory"))
then
// A custom source directory has been specified.
relativePath = getProperty("sourceDirectory").getValue()
else
// The Maven default source directory.
relativePath = "src"
|
|
// Resolve the relative path against the base directory for this POM
result.getAbsolutePath() = normalize(getFile().getParentContainer().getAbsolutePath() + "/" + relativePath)
result.getAbsolutePath() = normalize(getFile().getParentContainer().getAbsolutePath() + "/" +
relativePath)
)
}
/**
* Gets a `RefType` contained in the source directory.
*/
RefType getASourceRefType() {
result.getFile().getParentContainer*() = getSourceDirectory()
}
RefType getASourceRefType() { result.getFile().getParentContainer*() = getSourceDirectory() }
}
/**
@ -224,45 +220,37 @@ class Pom extends ProtoPom {
* via inherited methods from the super-class.
*/
class Dependency extends ProtoPom {
Dependency() {this.getName()="dependency" }
Dependency() { this.getName() = "dependency" }
/**
* Gets an XML element with the same Maven short coordinate
* (of the form `groupId:artifactId`) as this element.
*/
Pom getPom() {
result.getShortCoordinate() = this.getShortCoordinate()
}
Pom getPom() { result.getShortCoordinate() = this.getShortCoordinate() }
/**
* Gets the jar file that we think maven resolved this dependency to (if any).
*/
File getJar() {
exists(MavenRepo mr |
result = mr.getAnArtifact(this)
)
}
File getJar() { exists(MavenRepo mr | result = mr.getAnArtifact(this)) }
/**
* Gets the scope of this dependency. If the scope tag is present, this will
* be the string contents of that tag, otherwise it defaults to "compile".
*/
string getScope() {
if exists(getAChild().(Scope)) then
exists(Scope s | s = getAChild() and result = s.getValue())
else
result = "compile"
if exists(getAChild().(Scope))
then exists(Scope s | s = getAChild() and result = s.getValue())
else result = "compile"
}
override string getVersionString() {
if exists(getVersion()) then
result = super.getVersionString()
else if exists(Pom p | this = p.getADependency()) then
exists(Pom p | this = p.getADependency() |
result = p.getVersionStringForDependency(this)
)
if exists(getVersion())
then result = super.getVersionString()
else
result = ""
if exists(Pom p | this = p.getADependency())
then
exists(Pom p | this = p.getADependency() | result = p.getVersionStringForDependency(this))
else result = ""
}
}
@ -277,16 +265,19 @@ class PomDependency extends Dependency {
* management section, where they do not directly contribute to the dependencies of the containing
* pom.
*/
source.getADependency() = this and
/*
* Consider dependencies that can be used at compile time.
*/
(
getScope() = "compile" or
/*
* Provided dependencies are like compile time dependencies except (a) they are not packaged
* when creating the jar and (b) they are not transitive.
*/
getScope() = "provided"
// We ignore "test" dependencies because they can be runtime or compile time dependencies
)
@ -305,59 +296,50 @@ class PomElement extends XMLElement {
string getValue() {
exists(string s |
s = allCharactersString() and
if s.matches("${%") then
if s.matches("${%")
then
// Resolve the placeholder in the parent pom
result = getParent*().(Pom).resolvePlaceholder(s.substring(2, s.length() - 1))
else
result = s
else result = s
)
}
}
/** An XML element named "groupId", as found in Maven POM XML files. */
class Group extends PomElement {
Group() {this.getName()="groupId"}
}
class Group extends PomElement { Group() { this.getName() = "groupId" } }
/** An XML element named "artifactId", as found in Maven POM XML files. */
class Artifact extends PomElement {
Artifact() {this.getName()="artifactId"}
}
class Artifact extends PomElement { Artifact() { this.getName() = "artifactId" } }
/** An XML element named "parent", as found in Maven POM XML files. */
class Parent extends ProtoPom {
Parent() {this.getName()="parent"}
Parent() { this.getName() = "parent" }
Pom getPom() {
result.getShortCoordinate() = this.getShortCoordinate()
}
Pom getPom() { result.getShortCoordinate() = this.getShortCoordinate() }
}
/** An XML element named "version", as found in Maven POM XML files. */
class Version extends PomElement {
Version() {this.getName()="version"}
}
class Version extends PomElement { Version() { this.getName() = "version" } }
/** An XML element named "name", as found in Maven POM XML files. */
class Named extends PomElement {
Named() {this.getName()="name"}
}
class Named extends PomElement { Named() { this.getName() = "name" } }
/** An XML element named "scope", as found in Maven POM XML files. */
class Scope extends PomElement {
Scope() {this.getName()="scope"}
}
class Scope extends PomElement { Scope() { this.getName() = "scope" } }
/** An XML element named "dependencies", as found in Maven POM XML files. */
class Dependencies extends PomElement {
Dependencies() {this.getName()="dependencies"}
Dependency getADependency() {result=this.getAChild()}
Dependencies() { this.getName() = "dependencies" }
Dependency getADependency() { result = this.getAChild() }
}
/** An XML element named `dependencyManagement`, as found in Maven POM XML files. */
class DependencyManagement extends PomElement {
DependencyManagement() { getName() = "dependencyManagement" }
Dependencies getDependencies() { result = getAChild() }
Dependency getADependency() { result = getDependencies().getADependency() }
/**
@ -374,35 +356,28 @@ class DependencyManagement extends PomElement {
* An XML element name "properties", as found in Maven POM XML files.
*/
class PomProperties extends PomElement {
PomProperties() {this.getName()="properties"}
PomProperty getAProperty() {result=this.getAChild()}
PomProperties() { this.getName() = "properties" }
PomProperty getAProperty() { result = this.getAChild() }
}
/**
* An XML element that is the child of a PomProperties element, as found in Maven POM XML files.
* Represents a single property.
*/
class PomProperty extends PomElement {
PomProperty() {
getParent() instanceof PomProperties
}
}
class PomProperty extends PomElement { PomProperty() { getParent() instanceof PomProperties } }
/**
* A folder that represents a maven local repository using the standard layout. Any folder called
* "repository" with a parent name ".m2" is considered to be a maven repository.
*/
class MavenRepo extends Folder {
MavenRepo() {
getBaseName() = "repository" and getParentContainer().getBaseName() = ".m2"
}
MavenRepo() { getBaseName() = "repository" and getParentContainer().getBaseName() = ".m2" }
/**
* Gets a Jar file contained within this repository.
*/
File getAJarFile() {
result = getAChildContainer*().(File) and result.getExtension() = "jar"
}
File getAJarFile() { result = getAChildContainer*().(File) and result.getExtension() = "jar" }
/**
* Gets any jar artifacts in this repository that match the pom project definition. This is an
@ -412,11 +387,11 @@ class MavenRepo extends Folder {
*/
MavenRepoJar getAnArtifact(ProtoPom pom) {
result = getAJarFile() and
if exists(MavenRepoJar mrj | mrj.preciseMatch(pom)) or versionHardMatch(pom) then
if exists(MavenRepoJar mrj | mrj.preciseMatch(pom)) or versionHardMatch(pom)
then
// Either a hard match qualifier, or soft and there is at least one precise match
result.preciseMatch(pom)
else
result.artefactMatches(pom)
else result.artefactMatches(pom)
}
}
@ -433,29 +408,27 @@ private predicate versionHardMatch(ProtoPom pom) {
* See: https://cwiki.apache.org/confluence/display/MAVENOLD/Repository+Layout+-+Final
*/
class MavenRepoJar extends File {
MavenRepoJar() {
exists(MavenRepo mr | mr.getAJarFile() = this)
}
MavenRepoJar() { exists(MavenRepo mr | mr.getAJarFile() = this) }
string getGroupID() {
exists(MavenRepo mr |
mr.getAJarFile() = this
|
exists(MavenRepo mr | mr.getAJarFile() = this |
/*
* Assuming the standard layout, the first part of the directory structure from the maven
* repository will be the groupId converted to a path by replacing "." with "/".
*/
result = getParentContainer().getParentContainer().getParentContainer().getAbsolutePath().suffix(mr.getAbsolutePath().length() + 1).replaceAll("/", ".")
result = getParentContainer()
.getParentContainer()
.getParentContainer()
.getAbsolutePath()
.suffix(mr.getAbsolutePath().length() + 1)
.replaceAll("/", ".")
)
}
string getArtefactID() {
result = getParentContainer().getParentContainer().getBaseName()
}
string getArtefactID() { result = getParentContainer().getParentContainer().getBaseName() }
string getVersion() {
result = getParentContainer().getBaseName()
}
string getVersion() { result = getParentContainer().getBaseName() }
/**
* Holds if this jar is an artefact for the given pom or dependency, regardless of which version it is.
@ -471,9 +444,8 @@ class MavenRepoJar extends File {
*/
predicate preciseMatch(ProtoPom pom) {
artefactMatches(pom) and
if versionHardMatch(pom) then
("[" + getVersion() + "]").matches(pom.getVersionString() + "%")
else
getVersion().matches(pom.getVersionString() + "%")
if versionHardMatch(pom)
then ("[" + getVersion() + "]").matches(pom.getVersionString() + "%")
else getVersion().matches(pom.getVersionString() + "%")
}
}

Просмотреть файл

@ -3,9 +3,7 @@ import java
/**
* Holds if any `web.xml` files are included in this snapshot.
*/
predicate isWebXMLIncluded() {
exists(WebXMLFile webXML)
}
predicate isWebXMLIncluded() { exists(WebXMLFile webXML) }
/**
* A deployment descriptor file, typically called `web.xml`.
@ -34,67 +32,49 @@ class WebXMLFile extends XMLFile {
* An XML element in a `WebXMLFile`.
*/
class WebXMLElement extends XMLElement {
WebXMLElement() {
this.getFile() instanceof WebXMLFile
}
WebXMLElement() { this.getFile() instanceof WebXMLFile }
/**
* Gets the value for this element, with leading and trailing whitespace trimmed.
*/
string getValue() {
result = allCharactersString().trim()
}
string getValue() { result = allCharactersString().trim() }
}
/**
* A `<context-param>` element in a `web.xml` file.
*/
class WebContextParameter extends WebXMLElement {
WebContextParameter() {
this.getName() = "context-param"
}
WebContextParameter() { this.getName() = "context-param" }
/**
* Gets the `<param-name>` element of this `<context-param>`.
*/
WebContextParamName getParamName() {
result = getAChild()
}
WebContextParamName getParamName() { result = getAChild() }
/**
* Gets the `<param-value>` element of this `<context-param>`.
*/
WebContextParamValue getParamValue() {
result = getAChild()
}
WebContextParamValue getParamValue() { result = getAChild() }
}
/**
* A `<param-name>` element in a `web.xml` file.
*/
class WebContextParamName extends WebXMLElement {
WebContextParamName() {
getName() = "param-name"
}
WebContextParamName() { getName() = "param-name" }
}
/**
* A `<param-value>` element in a `web.xml` file.
*/
class WebContextParamValue extends WebXMLElement {
WebContextParamValue() {
getName() = "param-value"
}
WebContextParamValue() { getName() = "param-value" }
}
/**
* A `<filter>` element in a `web.xml` file.
*/
class WebFilter extends WebXMLElement {
WebFilter() {
getName() = "filter"
}
}
class WebFilter extends WebXMLElement { WebFilter() { getName() = "filter" } }
/**
* A `<filter-class>` element in a `web.xml` file, nested under a `<filter>` element.
@ -105,19 +85,13 @@ class WebFilterClass extends WebXMLElement {
getParent() instanceof WebFilter
}
Class getClass() {
result.getQualifiedName() = getValue()
}
Class getClass() { result.getQualifiedName() = getValue() }
}
/**
* A `<servlet>` element in a `web.xml` file.
*/
class WebServlet extends WebXMLElement {
WebServlet() {
getName() = "servlet"
}
}
class WebServlet extends WebXMLElement { WebServlet() { getName() = "servlet" } }
/**
* A `<servlet-class>` element in a `web.xml` file, nested under a `<servlet>` element.
@ -128,19 +102,13 @@ class WebServletClass extends WebXMLElement {
getParent() instanceof WebServlet
}
Class getClass() {
result.getQualifiedName() = getValue()
}
Class getClass() { result.getQualifiedName() = getValue() }
}
/**
* A `<listener>` element in a `web.xml` file.
*/
class WebListener extends WebXMLElement {
WebListener() {
getName() = "listener"
}
}
class WebListener extends WebXMLElement { WebListener() { getName() = "listener" } }
/**
* A `<listener-class>` element in a `web.xml` file, nested under a `<listener>` element.
@ -154,7 +122,5 @@ class WebListenerClass extends WebXMLElement {
/**
* Gets the `Class` instance associated with this element.
*/
Class getClass() {
result.getQualifiedName() = getValue()
}
Class getClass() { result.getQualifiedName() = getValue() }
}

Просмотреть файл

@ -7,7 +7,7 @@ import semmle.code.Location
/** An XML element that has a location. */
abstract class XMLLocatable extends @xmllocatable {
/** Gets the source location for this element. */
Location getLocation() { xmllocations(this,result) }
Location getLocation() { xmllocations(this, result) }
/**
* Holds if this element is at the specified location.
@ -16,9 +16,11 @@ abstract class XMLLocatable extends @xmllocatable {
* For more information, see
* [LGTM locations](https://lgtm.com/help/ql/locations).
*/
predicate hasLocationInfo(string filepath, int startline, int startcolumn, int endline, int endcolumn) {
predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
exists(File f, Location l | l = this.getLocation() |
locations_default(l,f,startline,startcolumn,endline,endcolumn) and
locations_default(l, f, startline, startcolumn, endline, endcolumn) and
filepath = f.getAbsolutePath()
)
}
@ -39,35 +41,31 @@ class XMLParent extends @xmlparent {
abstract string getName();
/** Gets the file to which this XML parent belongs. */
XMLFile getFile() { result = this or xmlElements(this,_,_,_,result) }
XMLFile getFile() { result = this or xmlElements(this, _, _, _, result) }
/** Gets the child element at a specified index of this XML parent. */
XMLElement getChild(int index) { xmlElements(result, _, this, index, _) }
/** Gets a child element of this XML parent. */
XMLElement getAChild() { xmlElements(result,_,this,_,_) }
XMLElement getAChild() { xmlElements(result, _, this, _, _) }
/** Gets a child element of this XML parent with the given `name`. */
XMLElement getAChild(string name) { xmlElements(result,_,this,_,_) and result.hasName(name) }
XMLElement getAChild(string name) { xmlElements(result, _, this, _, _) and result.hasName(name) }
/** Gets a comment that is a child of this XML parent. */
XMLComment getAComment() { xmlComments(result,_,this,_) }
XMLComment getAComment() { xmlComments(result, _, this, _) }
/** Gets a character sequence that is a child of this XML parent. */
XMLCharacters getACharactersSet() { xmlChars(result,_,this,_,_,_) }
XMLCharacters getACharactersSet() { xmlChars(result, _, this, _, _, _) }
/** Gets the depth in the tree. (Overridden in XMLElement.) */
int getDepth() { result = 0 }
/** Gets the number of child XML elements of this XML parent. */
int getNumberOfChildren() {
result = count(XMLElement e | xmlElements(e,_,this,_,_))
}
int getNumberOfChildren() { result = count(XMLElement e | xmlElements(e, _, this, _, _)) }
/** Gets the number of places in the body of this XML parent where text occurs. */
int getNumberOfCharacterSets() {
result = count(int pos | xmlChars(_,_,this,pos,_,_))
}
int getNumberOfCharacterSets() { result = count(int pos | xmlChars(_, _, this, pos, _, _)) }
/**
* DEPRECATED: Internal.
@ -75,25 +73,28 @@ class XMLParent extends @xmlparent {
* Append the character sequences of this XML parent from left to right, separated by a space,
* up to a specified (zero-based) index.
*/
deprecated
string charsSetUpTo(int n) {
n = 0 and xmlChars(_,result,this,0,_,_)
deprecated string charsSetUpTo(int n) {
n = 0 and xmlChars(_, result, this, 0, _, _)
or
n > 0 and
exists(string chars | xmlChars(_,chars,this,n,_,_) |
result = this.charsSetUpTo(n-1) + " " + chars
exists(string chars | xmlChars(_, chars, this, n, _, _) |
result = this.charsSetUpTo(n - 1) + " " + chars
)
}
/** Append all the character sequences of this XML parent from left to right, separated by a space. */
string allCharactersString() {
result = concat(string chars, int pos | xmlChars(_, chars, this, pos, _, _) | chars, " " order by pos)
result = concat(string chars, int pos |
xmlChars(_, chars, this, pos, _, _)
|
chars, " "
order by
pos
)
}
/** Gets the text value contained in this XML parent. */
string getTextValue() {
result = allCharactersString()
}
string getTextValue() { result = allCharactersString() }
/** Gets a printable representation of this XML parent. */
string toString() { result = this.getName() }
@ -101,57 +102,55 @@ class XMLParent extends @xmlparent {
/** An XML file. */
class XMLFile extends XMLParent, File {
XMLFile() {
xmlEncoding(this,_)
}
XMLFile() { xmlEncoding(this, _) }
/** Gets a printable representation of this XML file. */
override
string toString() { result = XMLParent.super.toString() }
override string toString() { result = XMLParent.super.toString() }
/** Gets the name of this XML file. */
override
string getName() { result = File.super.getAbsolutePath() }
override string getName() { result = File.super.getAbsolutePath() }
/** Gets the encoding of this XML file. */
string getEncoding() { xmlEncoding(this,result) }
string getEncoding() { xmlEncoding(this, result) }
/** Gets the XML file itself. */
override
XMLFile getFile() { result = this }
override XMLFile getFile() { result = this }
/** Gets a top-most element in an XML file. */
XMLElement getARootElement() { result = this.getAChild() }
/** Gets a DTD associated with this XML file. */
XMLDTD getADTD() { xmlDTDs(result,_,_,_,this) }
XMLDTD getADTD() { xmlDTDs(result, _, _, _, this) }
}
/** A "Document Type Definition" of an XML file. */
class XMLDTD extends @xmldtd {
/** Gets the name of the root element of this DTD. */
string getRoot() { xmlDTDs(this,result,_,_,_) }
string getRoot() { xmlDTDs(this, result, _, _, _) }
/** Gets the public ID of this DTD. */
string getPublicId() { xmlDTDs(this,_,result,_,_) }
string getPublicId() { xmlDTDs(this, _, result, _, _) }
/** Gets the system ID of this DTD. */
string getSystemId() { xmlDTDs(this,_,_,result,_) }
string getSystemId() { xmlDTDs(this, _, _, result, _) }
/** Holds if this DTD is public. */
predicate isPublic() { not xmlDTDs(this,_,"",_,_) }
predicate isPublic() { not xmlDTDs(this, _, "", _, _) }
/** Gets the parent of this DTD. */
XMLParent getParent() { xmlDTDs(this,_,_,_,result) }
XMLParent getParent() { xmlDTDs(this, _, _, _, result) }
/** Gets a printable representation of this DTD. */
string toString() {
(this.isPublic() and result = this.getRoot() + " PUBLIC '" +
this.getPublicId() + "' '" +
this.getSystemId() + "'") or
(not this.isPublic() and result = this.getRoot() +
" SYSTEM '" +
this.getSystemId() + "'")
(
this.isPublic() and
result = this.getRoot() + " PUBLIC '" + this.getPublicId() + "' '" + this.getSystemId() + "'"
)
or
(
not this.isPublic() and
result = this.getRoot() + " SYSTEM '" + this.getSystemId() + "'"
)
}
}
@ -161,71 +160,61 @@ class XMLElement extends @xmlelement, XMLParent, XMLLocatable {
predicate hasName(string name) { name = getName() }
/** Gets the name of this XML element. */
override
string getName() { xmlElements(this,result,_,_,_) }
override string getName() { xmlElements(this, result, _, _, _) }
/** Gets the XML file in which this XML element occurs. */
override
XMLFile getFile() { xmlElements(this,_,_,_,result) }
override XMLFile getFile() { xmlElements(this, _, _, _, result) }
/** Gets the parent of this XML element. */
XMLParent getParent() { xmlElements(this,_,result,_,_) }
XMLParent getParent() { xmlElements(this, _, result, _, _) }
/** Gets the index of this XML element among its parent's children. */
int getIndex() { xmlElements(this, _, _, result, _) }
/** Holds if this XML element has a namespace. */
predicate hasNamespace() { xmlHasNs(this,_,_) }
predicate hasNamespace() { xmlHasNs(this, _, _) }
/** Gets the namespace of this XML element, if any. */
XMLNamespace getNamespace() { xmlHasNs(this,result,_) }
XMLNamespace getNamespace() { xmlHasNs(this, result, _) }
/** Gets the index of this XML element among its parent's children. */
int getElementPositionIndex() { xmlElements(this,_,_,result,_) }
int getElementPositionIndex() { xmlElements(this, _, _, result, _) }
/** Gets the depth of this element within the XML file tree structure. */
override
int getDepth() { result = this.getParent().getDepth() + 1 }
override int getDepth() { result = this.getParent().getDepth() + 1 }
/** Gets an XML attribute of this XML element. */
XMLAttribute getAnAttribute() { result.getElement() = this }
/** Gets the attribute with the specified `name`, if any. */
XMLAttribute getAttribute(string name) {
result.getElement() = this and result.getName() = name
}
XMLAttribute getAttribute(string name) { result.getElement() = this and result.getName() = name }
/** Holds if this XML element has an attribute with the specified `name`. */
predicate hasAttribute(string name) {
exists(XMLAttribute a| a = this.getAttribute(name))
}
predicate hasAttribute(string name) { exists(XMLAttribute a | a = this.getAttribute(name)) }
/** Gets the value of the attribute with the specified `name`, if any. */
string getAttributeValue(string name) {
result = this.getAttribute(name).getValue()
}
string getAttributeValue(string name) { result = this.getAttribute(name).getValue() }
/** Gets a printable representation of this XML element. */
override
string toString() { result = XMLParent.super.toString() }
override string toString() { result = XMLParent.super.toString() }
}
/** An attribute that occurs inside an XML element. */
class XMLAttribute extends @xmlattribute, XMLLocatable {
/** Gets the name of this attribute. */
string getName() { xmlAttrs(this,_,result,_,_,_) }
string getName() { xmlAttrs(this, _, result, _, _, _) }
/** Gets the XML element to which this attribute belongs. */
XMLElement getElement() { xmlAttrs(this,result,_,_,_,_) }
XMLElement getElement() { xmlAttrs(this, result, _, _, _, _) }
/** Holds if this attribute has a namespace. */
predicate hasNamespace() { xmlHasNs(this,_,_) }
predicate hasNamespace() { xmlHasNs(this, _, _) }
/** Gets the namespace of this attribute, if any. */
XMLNamespace getNamespace() { xmlHasNs(this,result,_) }
XMLNamespace getNamespace() { xmlHasNs(this, result, _) }
/** Gets the value of this attribute. */
string getValue() { xmlAttrs(this,_,_,result,_,_) }
string getValue() { xmlAttrs(this, _, _, result, _, _) }
/** Gets a printable representation of this XML attribute. */
override string toString() { result = this.getName() + "=" + this.getValue() }
@ -234,17 +223,18 @@ class XMLAttribute extends @xmlattribute, XMLLocatable {
/** A namespace used in an XML file */
class XMLNamespace extends @xmlnamespace {
/** Gets the prefix of this namespace. */
string getPrefix() { xmlNs(this,result,_,_) }
string getPrefix() { xmlNs(this, result, _, _) }
/** Gets the URI of this namespace. */
string getURI() { xmlNs(this,_,result,_) }
string getURI() { xmlNs(this, _, result, _) }
/** Holds if this namespace has no prefix. */
predicate isDefault() { this.getPrefix() = "" }
/** Gets a printable representation of this XML namespace. */
string toString() {
(this.isDefault() and result = this.getURI()) or
(this.isDefault() and result = this.getURI())
or
(not this.isDefault() and result = this.getPrefix() + ":" + this.getURI())
}
}
@ -252,10 +242,10 @@ class XMLNamespace extends @xmlnamespace {
/** A comment of the form `<!-- ... -->` is an XML comment. */
class XMLComment extends @xmlcomment, XMLLocatable {
/** Gets the text content of this XML comment. */
string getText() { xmlComments(this,result,_,_) }
string getText() { xmlComments(this, result, _, _) }
/** Gets the parent of this XML comment. */
XMLParent getParent() { xmlComments(this,_,result,_) }
XMLParent getParent() { xmlComments(this, _, result, _) }
/** Gets a printable representation of this XML comment. */
override string toString() { result = this.getText() }
@ -267,13 +257,13 @@ class XMLComment extends @xmlcomment, XMLLocatable {
*/
class XMLCharacters extends @xmlcharacters, XMLLocatable {
/** Gets the content of this character sequence. */
string getCharacters() { xmlChars(this,result,_,_,_,_) }
string getCharacters() { xmlChars(this, result, _, _, _, _) }
/** Gets the parent of this character sequence. */
XMLParent getParent() { xmlChars(this,_,result,_,_,_) }
XMLParent getParent() { xmlChars(this, _, result, _, _, _) }
/** Holds if this character sequence is CDATA. */
predicate isCDATA() { xmlChars(this,_,_,_,1,_) }
predicate isCDATA() { xmlChars(this, _, _, _, 1, _) }
/** Gets a printable representation of this XML character sequence. */
override string toString() { result = this.getCharacters() }