Packaging: Java refactoring

Split java pack into `codeql/java-all` and `codeql/java-queries`.
This commit is contained in:
Andrew Eisenberg
2021-08-18 13:43:21 -07:00
parent 39533317ff
commit 8e750f18ad
326 changed files with 41 additions and 12 deletions

View File

@@ -0,0 +1,317 @@
import java
import semmle.code.java.deadcode.DeadEnumConstant
import semmle.code.java.deadcode.DeadCodeCustomizations
import semmle.code.java.deadcode.DeadField
import semmle.code.java.deadcode.EntryPoints
/**
* Holds if the given callable has any liveness causes.
*/
predicate isLive(Callable c) {
exists(EntryPoint e | c = e.getALiveCallable())
or
exists(Callable live | isLive(live) | live = possibleLivenessCause(c))
}
/**
* Compute a list of callables such that the liveness of any result
* would imply the liveness of `c`.
*/
Callable possibleLivenessCause(Callable c, string reason) {
c.(Method).overridesOrInstantiates(result.(Method)) and
reason = "is overridden or instantiated by"
or
result.calls(c) and reason = "calls"
or
result.callsConstructor(c.(Constructor)) and reason = "calls constructor"
or
exists(ClassInstanceExpr e | e.getEnclosingCallable() = result |
e.getConstructor() = c and reason = "constructs"
)
or
c = result.getSourceDeclaration() and c != result and reason = "instantiates"
or
c.hasName("<clinit>") and
reason = "class initialization" and
exists(RefType clintedType | c = clintedType.getASupertype*().getACallable() |
result.getDeclaringType() = clintedType or
result.getAnAccessedField().getDeclaringType() = clintedType
)
or
c.hasName("<obinit>") and
reason = "object initialization" and
result = c.getDeclaringType().getAConstructor()
}
Callable possibleLivenessCause(Callable c) { result = possibleLivenessCause(c, _) }
/**
* A dead root is not live, and has no liveness causes.
*
* Dead roots are reported for dead classes and dead methods to help verify that classes and
* methods with dependencies are actually dead. A dead class or method may have no dead roots, if
* it is involved in a dead code cycle.
*/
class DeadRoot extends Callable {
DeadRoot() {
not isLive(this) and
// Not a dead root if there exists at least one liveness cause that is not this method.
not exists(Callable c | c = possibleLivenessCause(this) and c != this)
}
}
/**
* For a dead callable, we identify all the possible dead roots.
*
* For dead callables which are either part of dead code cycles, or are only depended upon by
* callables in dead cycles, there will be no dead roots.
*/
DeadRoot getADeadRoot(Callable c) {
not isLive(c) and
(
result = c or
result = getADeadRoot(possibleLivenessCause(c))
)
}
/**
* A constructor that is only declared to override the public accessibility of
* the default constructor generated by the compiler.
*/
class SuppressedConstructor extends Constructor {
SuppressedConstructor() {
// Must be private or protected to suppress it.
(
isPrivate()
or
// A protected, suppressed constructor only makes sense in a non-abstract class.
isProtected() and not getDeclaringType().isAbstract()
) and
// Must be no-arg in order to replace the compiler generated default constructor.
getNumberOfParameters() = 0 and
// Not the compiler-generated constructor itself.
not isDefaultConstructor() and
// Verify that there is only one statement, which is the `super()` call. This exists
// even for empty constructors.
getBody().(BlockStmt).getNumStmt() = 1 and
getBody().(BlockStmt).getAStmt().(SuperConstructorInvocationStmt).getNumArgument() = 0 and
// A constructor that is called is not acting to suppress the default constructor. We permit
// calls from suppressed and default constructors - in both cases, they can only come from
// sub-class constructors.
not exists(Call c |
c.getCallee().getSourceDeclaration() = this and
not c.getCaller() instanceof SuppressedConstructor and
not c.getCaller().(Constructor).isDefaultConstructor()
) and
// If other constructors are declared, then no compiler-generated constructor is added, so
// this constructor is not acting to suppress the default compiler-generated constructor.
not exists(Constructor other | other = getDeclaringType().getAConstructor() and other != this)
}
}
/**
* A namespace class is one that is used purely as a container for static classes, methods and fields.
*/
class NamespaceClass extends RefType {
NamespaceClass() {
fromSource() and
// All members, apart from the default constructor and, if present, a "suppressed" constructor
// must be static. There must be at least one member apart from the permitted constructors.
forex(Member m |
m.getDeclaringType() = this and
not m.(Constructor).isDefaultConstructor() and
not m instanceof SuppressedConstructor
|
m.isStatic()
) and
// Must only extend other namespace classes, or `Object`.
forall(RefType r | r = getASupertype() | r instanceof TypeObject or r instanceof NamespaceClass)
}
}
/**
* A `ClassOrInterface` type that is from source.
*
* This represents the set of classes and interfaces for which we will determine liveness. Each
* `SourceClassOrInterfacce` will either be a `LiveClass` or `DeadClass`.
*/
library class SourceClassOrInterface extends ClassOrInterface {
SourceClassOrInterface() { this.fromSource() }
}
/**
* A source class or interface is live if it fulfills one of the following criteria:
*
* - It, or a sub-class, contains a live callable.
* - It contains a live field.
* - It is a namespace class and it contains a live nested class.
* - It is a whitelisted class.
* - It is an annotation class - these are assumed to be always live.
* - It is an anonymous class - these classes are dead if and only if the outer method is dead.
*/
class LiveClass extends SourceClassOrInterface {
LiveClass() {
exists(Callable c | c.getDeclaringType().getASupertype*().getSourceDeclaration() = this |
isLive(c)
)
or
exists(LiveField f | f.getDeclaringType() = this |
// A `serialVersionUID` field is considered to be a live field, but is
// not be enough to be make this class live.
not f instanceof SerialVersionUIDField
)
or
// If this is a namespace class, it is live if there is at least one live nested class.
// The definition of `NamespaceClass` is such, that the nested classes must all be static.
// Static methods are handled above.
this instanceof NamespaceClass and
exists(NestedType r | r.getEnclosingType() = this | r instanceof LiveClass)
or
// An annotation on the class is reflectively accessed.
exists(ReflectiveAnnotationAccess reflectiveAnnotationAccess |
this = reflectiveAnnotationAccess.getInferredClassType() and
isLive(reflectiveAnnotationAccess.getEnclosingCallable())
)
or
this instanceof AnonymousClass
or
this instanceof WhitelistedLiveClass
or
this instanceof AnnotationType
}
}
/**
* A class is dead if it is from source, and contains no live callables and no live fields. Nested
* classes make the outer class live if and only if the outer class is considered to be present for
* namespace purposes only, and the nested class is static.
*
* Nested instance classes require no special handling. If the nested instance class accesses fields
* or methods on the outer class, then these will already be marked as live fields and methods. If
* it accesses no methods or fields from the outer, then the nested class can be made static, and
* moved into another file.
*/
class DeadClass extends SourceClassOrInterface {
DeadClass() { not this instanceof LiveClass }
/**
* Identify all the "dead" roots of this dead class.
*/
DeadRoot getADeadRoot() { result = getADeadRoot(getACallable()) }
/**
* Holds if this dead class is only used within the class itself.
*/
predicate isUnusedOutsideClass() {
// Accessed externally if any callable in the class has a possible liveness cause outside the
// class. Only one step is required.
not exists(Callable c |
c = possibleLivenessCause(getACallable()) and
not c = getACallable()
)
}
}
/**
* A class which is dead, but should be considered as live.
*
* This should be used for cases where the class is dead, but should not be removed - for example,
* because it may be useful in the future. If a class is marked as dead when it is live, the
* callable or field that makes the class live should be marked as an entry point by either
* extending `CallableEntryPoint` or `ReflectivelyReadField`, instead of whitelisting the class.
*/
abstract class WhitelistedLiveClass extends RefType { }
/**
* A method is dead if it is from source, has no liveness causes, is not a compiler generated
* method and is not a dead method with a purpose, such as a constructor designed to suppress the
* default constructor.
*/
class DeadMethod extends Callable {
DeadMethod() {
fromSource() and
not isLive(this) and
not this.(Constructor).isDefaultConstructor() and
// Ignore `SuppressedConstructor`s in `NamespaceClass`es. There is no reason to use a suppressed
// constructor in other cases.
not (
this instanceof SuppressedConstructor and this.getDeclaringType() instanceof NamespaceClass
) and
not (
this.(Method).isAbstract() and
exists(Method m | m.overridesOrInstantiates+(this.(Method)) | isLive(m))
) and
// A getter or setter associated with a live JPA field.
//
// These getters and setters are often generated in an ad-hoc way by the developer, which leads to
// methods that are theoretically dead, but uninteresting. We therefore ignore them, so long as
// they are "simple".
not exists(JPAReadField readField | this.getDeclaringType() = readField.getDeclaringType() |
this.(GetterMethod).getField() = readField or
this.(SetterMethod).getField() = readField
)
}
/**
* Holds if this dead method is already within the scope of a dead class.
*/
predicate isInDeadScope() {
// We do not need to consider whitelisting because whitelisted classes should not have dead
// methods reported.
this.getDeclaringType() instanceof DeadClass
}
/**
* Identify all the "dead" roots of this dead callable.
*/
DeadRoot getADeadRoot() { result = getADeadRoot(this) }
}
class RootdefCallable extends Callable {
RootdefCallable() {
this.fromSource() and
not this.(Method).overridesOrInstantiates(_)
}
Parameter unusedParameter() {
exists(int i | result = this.getParameter(i) |
not exists(result.getAnAccess()) and
not overrideAccess(this, i)
)
}
predicate whitelisted() {
// Main methods must have a `String[]` argument.
this instanceof MainMethod
or
// Premain methods must have certain arguments.
this instanceof PreMainMethod
or
// Abstract, native and interface methods obviously won't access their own
// parameters, so don't flag unless we can see an overriding method with
// a body that also doesn't.
not hasUsefulBody(this) and
not exists(Method m | hasUsefulBody(m) | m.overridesOrInstantiates+(this))
or
// Methods that are the target of a member reference need to implement
// the exact signature of the resulting functional interface.
exists(MemberRefExpr mre | mre.getReferencedCallable() = this)
or
this.getAnAnnotation() instanceof OverrideAnnotation
}
}
pragma[nomagic]
private predicate overrideAccess(Callable c, int i) {
exists(Method m | m.overridesOrInstantiates+(c) | exists(m.getParameter(i).getAnAccess()))
}
/**
* A predicate to find non-trivial method implementations.
* (A trivial implementation is either abstract, or it just
* throws `UnsupportedOperationException` or similar.)
*/
predicate hasUsefulBody(Callable c) {
exists(c.getBody()) and
not c.getBody().getAChild() instanceof ThrowStmt
}

View File

@@ -0,0 +1,78 @@
import java
import semmle.code.java.JDKAnnotations
/**
* Direct flow of values (i.e. object references) through expressions.
*/
Expr valueFlow(Expr src) {
result = src
or
result.(ConditionalExpr).getABranchExpr() = src
}
/**
* Gets an access to an enum constant, where the reference to the constant may
* be stored and used by the enclosing program rather than just being
* compared and discarded.
*/
VarAccess valueAccess(EnumConstant e) {
result = e.getAnAccess() and
(
exists(Call c |
c.getAnArgument() = valueFlow+(result) or
c.(MethodAccess).getQualifier() = valueFlow+(result)
)
or
exists(Assignment a | a.getSource() = valueFlow+(result))
or
exists(ReturnStmt r | r.getResult() = valueFlow+(result))
or
exists(LocalVariableDeclExpr v | v.getInit() = valueFlow+(result))
or
exists(AddExpr a | a.getAnOperand() = valueFlow+(result))
)
}
/**
* Exceptions to the "must have its value used" rule.
*/
predicate exception(EnumConstant e) {
exists(EnumType t | t = e.getDeclaringType() |
// It looks like a method is trying to return the right constant for a string.
exists(Method fromString | fromString = t.getAMethod() |
fromString.isStatic() and
fromString.getReturnType() = t and
exists(EnhancedForStmt s | s.getEnclosingCallable() = fromString |
s.getVariable().getType() = t
)
)
or
// A method iterates over the values of an enum.
exists(MethodAccess values | values.getMethod().getDeclaringType() = t |
values.getParent() instanceof EnhancedForStmt or
values.getParent().(MethodAccess).getMethod().hasName("findThisIn")
)
or
// The `valueOf` method is called, meaning that depending on the string any constant
// could be retrieved.
exists(MethodAccess valueOf | valueOf.getMethod().getDeclaringType() = t |
valueOf.getMethod().hasName("valueOf")
)
or
// Entire `Enum` annotated with reflective annotation.
exists(ReflectiveAccessAnnotation ann | ann = t.getAnAnnotation())
)
or
// Enum field annotated with reflective annotation.
e.getAnAnnotation() instanceof ReflectiveAccessAnnotation
}
class UnusedEnumConstant extends EnumConstant {
UnusedEnumConstant() {
not exists(valueAccess(this)) and
this.fromSource() and
not exception(this)
}
predicate whitelisted() { none() }
}

View File

@@ -0,0 +1,171 @@
import java
import semmle.code.java.deadcode.DeadCode
import semmle.code.java.frameworks.javaee.Persistence
import semmle.code.java.frameworks.JAXB
import semmle.code.java.frameworks.jackson.JacksonSerializability
/**
* A field that is from a source file.
*
* This defines the set of fields for which we will determine liveness.
*/
library class SourceField extends Field {
SourceField() { fromSource() }
}
/**
* A field is dead if it is never read by a live callable and it is neither reflectively accessed,
* nor whitelisted.
*/
class DeadField extends SourceField {
DeadField() { not this instanceof LiveField }
/**
* Holds if this dead field is already within the scope of a dead class, or reported by a dead
* enum constant.
*/
predicate isInDeadScope() {
// `EnumConstant`s, and fields in dead classes, are reported in other queries.
getDeclaringType() instanceof DeadClass or
this instanceof EnumConstant
}
}
/**
* A field is live if it is read by a live callable, accessed by an annotation on a live element,
* reflectively read, or whitelisted as read.
*/
class LiveField extends SourceField {
LiveField() {
exists(FieldRead access | access = getAnAccess() |
isLive(access.getEnclosingCallable())
or
exists(Annotation a |
// This is an access used in an annotation, either directly, or within the expression.
a.getValue(_) = access.getParent*()
|
// The annotated element is a live callable.
isLive(a.getAnnotatedElement())
or
// The annotated element is in a live callable.
isLive(a.getAnnotatedElement().(LocalVariableDecl).getEnclosingCallable())
or
// The annotated element is a live field.
a.getAnnotatedElement() instanceof LiveField
or
// The annotated element is a live source class or interface.
// Note: We ignore annotation values on library classes, because they should only refer to
// fields in library classes, not `fromSource()` fields.
a.getAnnotatedElement() instanceof LiveClass
)
)
or
this instanceof ReflectivelyReadField
or
this instanceof WhitelistedLiveField
}
}
/**
* A field that may be read reflectively.
*/
abstract class ReflectivelyReadField extends Field { }
/**
* A field which is dead, but should be considered as live.
*
* This should be used for cases where the field is dead, but should not be removed - for example,
* because it may be useful in the future. If the field is live, but is not marked as a such, then
* either a new `EntryPoint` should be added, or, if the field is accessed reflectively, this should
* be identified by extending `ReflectivelyReadField` instead.
*
* Whitelisting a field will automatically cause the containing class to be considered as live.
*/
abstract class WhitelistedLiveField extends Field { }
/**
* A static, final, long field named `serialVersionUID` in a class that extends `Serializable` acts as
* a version number for the serialization framework.
*/
class SerialVersionUIDField extends ReflectivelyReadField {
SerialVersionUIDField() {
hasName("serialVersionUID") and
isStatic() and
isFinal() and
getType().hasName("long") and
getDeclaringType().getASupertype*() instanceof TypeSerializable
}
}
/**
* A field is read by the JAXB during serialization if it is a JAXB bound field, and if the
* containing class is considered "live".
*/
class LiveJaxbBoundField extends ReflectivelyReadField, JaxbBoundField {
LiveJaxbBoundField() {
// If the class is considered live, it must have at least one live constructor.
exists(Constructor c | c = getDeclaringType().getAConstructor() | isLive(c))
}
}
/**
* A field with an annotation which implies that it will be read by `JUnit` when running tests
* within this class.
*/
class JUnitAnnotatedField extends ReflectivelyReadField {
JUnitAnnotatedField() {
hasAnnotation("org.junit.experimental.theories", "DataPoint") or
hasAnnotation("org.junit.experimental.theories", "DataPoints") or
hasAnnotation("org.junit.runners", "Parameterized$Parameter") or
hasAnnotation("org.junit", "Rule") or
hasAnnotation("org.junit", "ClassRule")
}
}
/**
* A field that is reflectively read via a call to `Class.getField(...)`.
*/
class ClassReflectivelyReadField extends ReflectivelyReadField {
ClassReflectivelyReadField() {
exists(ReflectiveFieldAccess fieldAccess | this = fieldAccess.inferAccessedField())
}
}
/**
* Consider all `JacksonSerializableField`s as reflectively read.
*/
class JacksonSerializableReflectivelyReadField extends ReflectivelyReadField,
JacksonSerializableField { }
/**
* A field that is used when applying Jackson mixins.
*/
class JacksonMixinReflextivelyReadField extends ReflectivelyReadField {
JacksonMixinReflextivelyReadField() {
exists(JacksonMixinType mixinType, JacksonAddMixinCall mixinCall |
this = mixinType.getAMixedInField() and
mixinType = mixinCall.getAMixedInType()
|
isLive(mixinCall.getEnclosingCallable())
)
}
}
/**
* A field which is read by a JPA compatible Java persistence framework.
*/
class JPAReadField extends ReflectivelyReadField {
JPAReadField() {
exists(PersistentEntity entity |
this = entity.getAField() and
(
entity.getAccessType() = "field" or
this.hasAnnotation("javax.persistence", "Access")
)
|
not this.hasAnnotation("javax.persistence", "Transient") and
not isStatic() and
not isFinal()
)
}
}

View File

@@ -0,0 +1,452 @@
import java
import semmle.code.java.deadcode.DeadCode
import semmle.code.java.deadcode.frameworks.CamelEntryPoints
import semmle.code.java.deadcode.frameworks.GigaSpacesXAPEntryPoints
import semmle.code.java.deadcode.SpringEntryPoints
import semmle.code.java.deadcode.StrutsEntryPoints
import semmle.code.java.deadcode.TestEntryPoints
import semmle.code.java.deadcode.WebEntryPoints
import semmle.code.java.frameworks.javaee.JavaServerFaces
import semmle.code.java.frameworks.JAXB
import semmle.code.java.frameworks.JaxWS
import semmle.code.java.JMX
import semmle.code.java.Reflection
import semmle.code.java.frameworks.JavaxAnnotations
import semmle.code.java.frameworks.Selenium
/**
* An entry point into our system, marking some number of `Callable`s
* as live.
*/
abstract class EntryPoint extends Top {
/**
* One of the `Callable`s associated with this entry point.
*/
abstract Callable getALiveCallable();
}
/**
* An entry point corresponding to a single method or constructor.
*/
abstract class CallableEntryPoint extends EntryPoint, Callable {
override Callable getALiveCallable() { result = this }
}
/**
* An entry point that is a single method, that is only live if there is a live constructor on the
* class.
*/
abstract class CallableEntryPointOnConstructedClass extends EntryPoint {
CallableEntryPointOnConstructedClass() {
exists(Constructor c | c = this.(Callable).getDeclaringType().getAConstructor() and isLive(c))
}
override Callable getALiveCallable() { result = this }
}
/**
* A callable which is dead, but should be considered as live.
*
* This should be used for cases where the callable is dead, but should not be removed - for
* example, because it may be useful in the future. If the callable is live, but is not marked as a
* such, then a new `CallableEntryPoint` should be added instead.
*
* Whitelisting a callable will automatically cause the containing class to be considered as live.
*/
abstract class WhitelistedLiveCallable extends CallableEntryPoint { }
/**
* A `public static void main(String[] args)` method.
*/
class MainMethodEntry extends CallableEntryPoint {
MainMethodEntry() { this instanceof MainMethod }
}
/**
* A method that overrides a library method -- the result is
* that when the library calls the overridden method, it may
* instead call this method, which makes it live even if we
* don't directly see the call.
*/
class LibOverrideMethodEntry extends CallableEntryPoint {
LibOverrideMethodEntry() {
this.fromSource() and
exists(Method libraryMethod | this.(Method).overrides*(libraryMethod) |
// The library method must not come from source, either directly, or added automatically.
// For example, `values()` and `valueOf(...)` methods are not `fromSource()`, but are added
// automatically to source types.
not libraryMethod.getDeclaringType().getSourceDeclaration().fromSource()
)
}
}
/**
* A class that may be constructed reflectively, making its default constructor live.
*/
abstract class ReflectivelyConstructedClass extends EntryPoint, Class {
/**
* Reflectively constructed classes have a live default constructor.
*/
override Callable getALiveCallable() {
result = this.getAConstructor() and
result.getNumberOfParameters() = 0
}
}
/**
* Classes that are deserialized by Jackson are reflectively constructed.
*/
library class JacksonReflectivelyConstructedClass extends ReflectivelyConstructedClass {
JacksonReflectivelyConstructedClass() { this instanceof JacksonDeserializableType }
override Callable getALiveCallable() {
// Constructors may be called by Jackson, if they are a no-arg, they have a suitable annotation,
// or inherit a suitable annotation through a mixin.
result = getAConstructor() and
(
result.getNumberOfParameters() = 0 or
result.getAnAnnotation() instanceof JacksonAnnotation or
result.getAParameter().getAnAnnotation() instanceof JacksonAnnotation or
exists(JacksonMixedInCallable mixinCallable | result = mixinCallable.getATargetCallable())
)
}
}
/**
* A callable that is used when applying Jackson mixins.
*/
class JacksonMixinCallableEntryPoint extends EntryPoint {
JacksonMixinCallableEntryPoint() {
exists(JacksonMixinType mixinType, JacksonAddMixinCall mixinCall |
this = mixinType.getAMixedInCallable() and
mixinType = mixinCall.getAMixedInType()
|
isLive(mixinCall.getEnclosingCallable())
)
}
override Callable getALiveCallable() { result = this }
}
class JAXAnnotationReflectivelyConstructedClass extends ReflectivelyConstructedClass {
JAXAnnotationReflectivelyConstructedClass() {
this instanceof JaxWsEndpoint or
this instanceof JaxbXmlRegistry or
this instanceof JaxRsResourceClass or
this instanceof JaxbXmlEnum
}
}
class DeserializedClass extends ReflectivelyConstructedClass {
DeserializedClass() {
exists(CastExpr cast, ReadObjectMethod readObject |
cast.getExpr().(MethodAccess).getMethod() = readObject
|
hasSubtype*(cast.getType(), this)
)
}
}
/**
* A call to `Class.newInstance()` or `Constructor.newInstance()` which may imply that a number of
* constructors are live.
*/
class NewInstanceCall extends EntryPoint, NewInstance {
override Constructor getALiveCallable() {
result = getInferredConstructor() and
// The `newInstance(...)` call must be used in a live context.
isLive(this.getEnclosingCallable())
}
}
/**
* A call to either `Class.getMethod(...)` or `Class.getDeclaredMethod(...)`.
*/
class ReflectiveMethodAccessEntryPoint extends EntryPoint, ReflectiveMethodAccess {
override Method getALiveCallable() {
result = inferAccessedMethod() and
// The `getMethod(...)` call must be used in a live context.
isLive(this.getEnclosingCallable())
}
}
/**
* Classes that are entry points recognised by annotations.
*/
abstract class AnnotationEntryPoint extends EntryPoint, Class {
/**
* By default assume all public methods might be called, but not
* constructors -- be sure to register any further subtypes with
* `ReflectivelyConstructedClass`.
*/
override Callable getALiveCallable() {
result = this.getAMethod() and
result.isPublic()
}
}
/**
* A JAXB XML registry, used reflectively to construct objects based on
* the contents of XML files.
*/
class JaxbXmlRegistry extends AnnotationEntryPoint {
JaxbXmlRegistry() { this.(JaxbAnnotated).hasJaxbAnnotation("XmlRegistry") }
}
/**
* An enum annotated with `@XmlEnum` can be used by JAXB when constructing objects reflectively based
* on the contents of XML files. Unlike classes, these are never referred to from the `@XmlRegistry`
* class, because they do not need to be instantiated, just used. We therefore need to special case
* them.
*/
class JaxbXmlEnum extends AnnotationEntryPoint {
JaxbXmlEnum() { this.(JaxbAnnotated).hasJaxbAnnotation("XmlEnum") }
}
/**
* A type annotated with `@XmlType`, indicating that this class is used when marshalling or
* unmarshalling XML documents.
*/
class JaxbXmlType extends AnnotationEntryPoint, JaxbType {
override Callable getALiveCallable() {
// Must have a live no-arg constructor for JAXB to perform marshal/unmarshal.
exists(Constructor c | c = getAConstructor() and c.getNumberOfParameters() = 0 | isLive(c)) and
result = getACallable() and
(
// A bound getter or setter.
result instanceof JaxbBoundGetterSetter
or
// Methods called by reflection when unmarshalling or marshalling.
result.hasName("afterUnmarshal") and result.paramsString() = "(Unmarshaller, Object)"
or
result.hasName("beforeUnmarshal") and result.paramsString() = "(Unmarshaller, Object)"
or
result.hasName("afterMarshal") and result.paramsString() = "(Marshaller, Object)"
or
result.hasName("beforeMarshal") and result.paramsString() = "(Marshaller, Object)"
)
}
}
/**
* A JAX WS endpoint is constructed by the container, and its methods
* are -- where annotated -- called remotely.
*/
class JaxWsEndpointEntry extends JaxWsEndpoint, AnnotationEntryPoint {
override Callable getALiveCallable() { result = this.getARemoteMethod() }
}
/**
* A JAX RS resource class. `@GET` and `@POST` annotated methods are reflectively called by the container. The
* class itself may be reflectively constructed by the container.
*/
class JaxRsResourceClassEntry extends JaxRsResourceClass, AnnotationEntryPoint {
override Callable getALiveCallable() { result = this.getAnInjectableCallable() }
}
/**
* A constructor that may be called when injecting values into a JaxRS resource class constructor or method.
*/
class JaxRsBeanParamConstructorEntryPoint extends JaxRsBeanParamConstructor, CallableEntryPoint { }
/**
* Entry point for methods that can be accessed through JMX.
*
* The instance here is a `ManagedBean` (`MBean` or `MXBean`) implementation class, that is seen to be
* registered with the `MBeanServer`, directly or indirectly. The live callables are all the
* methods in this class that override something declared in one or more of the managed beans
* that this class implements.
*/
class ManagedBeanImplEntryPoint extends EntryPoint, RegisteredManagedBeanImpl {
override Method getALiveCallable() {
// Find the method that will be called for each method on each managed bean that this class
// implements.
this.inherits(result) and
result.(Method).overrides(getAnImplementedManagedBean().getAMethod())
}
}
/**
* Entry point for bean classes. Should be extended to define any
* project specific types of bean.
*/
abstract class BeanClass extends EntryPoint, Class {
override Callable getALiveCallable() {
result = this.getACallable() and
(result.(Method).isPublic() or result.(Constructor).getNumberOfParameters() = 0)
}
}
/**
* Entry point for J2EE beans (`EnterpriseBean`, `EntityBean`, `MessageBean`, `SessionBean`).
*/
class J2EEBean extends BeanClass {
J2EEBean() {
this instanceof EnterpriseBean or
this instanceof EntityBean or
this instanceof MessageBean or
this instanceof SessionBean
}
}
/**
* Entry point for Java Server Faces `ManagedBean`s.
*/
class FacesManagedBeanEntryPoint extends BeanClass, FacesManagedBean { }
/**
* Entry point for methods that may be called by Java Server Faces.
*/
class FacesAccessibleMethodEntryPoint extends CallableEntryPoint {
FacesAccessibleMethodEntryPoint() {
exists(FacesAccessibleType accessibleType | this = accessibleType.getAnAccessibleMethod())
}
}
/**
* A Java Server Faces custom component, that is reflectively constructed by the framework when
* used in a view (JSP or facelet).
*/
class FacesComponentReflectivelyConstructedClass extends ReflectivelyConstructedClass {
FacesComponentReflectivelyConstructedClass() { this instanceof FacesComponent }
}
/**
* Entry point for EJB home interfaces.
*/
class EJBHome extends Interface, EntryPoint {
EJBHome() { this.getASupertype*().hasQualifiedName("javax.ejb", "EJBHome") }
override Callable getALiveCallable() { result = this.getACallable() }
}
/**
* Entry point for EJB object interfaces.
*/
class EJBObject extends Interface, EntryPoint {
EJBObject() { this.getASupertype*().hasQualifiedName("javax.ejb", "EJBObject") }
override Callable getALiveCallable() { result = this.getACallable() }
}
class GsonDeserializationEntryPoint extends ReflectivelyConstructedClass {
GsonDeserializationEntryPoint() {
// Assume any class with a gson annotated field can be deserialized.
this.getAField().getAnAnnotation().getType().hasQualifiedName("com.google.gson.annotations", _)
}
}
class JAXBDeserializationEntryPoint extends ReflectivelyConstructedClass {
JAXBDeserializationEntryPoint() {
// A class can be deserialized by JAXB if it's an `XmlRootElement`...
this.getAnAnnotation().getType().hasQualifiedName("javax.xml.bind.annotation", "XmlRootElement")
or
// ... or the type of an `XmlElement` field.
exists(Field elementField |
elementField.getAnAnnotation().getType() instanceof JaxbMemberAnnotation
|
usesType(elementField.getType(), this)
)
}
}
/**
* A `javax.annotation` for a method that is called after or before dependency injection on a type.
*
* Consider this to be live if and only if there is a live constructor.
*/
class PreOrPostDIMethod extends CallableEntryPointOnConstructedClass {
PreOrPostDIMethod() {
this.(Method).getAnAnnotation() instanceof PostConstructAnnotation or
this.(Method).getAnAnnotation() instanceof PreDestroyAnnotation
}
}
/**
* A `javax.annotation` for a method that is called to inject a resource into the class.
*
* Consider this to be live if and only if there is a live constructor.
*/
class JavaxResourceAnnotatedMethod extends CallableEntryPointOnConstructedClass {
JavaxResourceAnnotatedMethod() { this.(Method).getAnAnnotation() instanceof ResourceAnnotation }
}
/**
* A `javax.annotation.ManagedBean` annotated class, which may be constructed by a container of some
* description.
*/
class JavaxManagedBeanReflectivelyConstructed extends ReflectivelyConstructedClass {
JavaxManagedBeanReflectivelyConstructed() {
getAnAnnotation() instanceof JavaxManagedBeanAnnotation
}
}
/**
* Classes marked as Java persistence entities can be reflectively constructed when the data is
* loaded.
*/
class PersistentEntityEntryPoint extends ReflectivelyConstructedClass {
PersistentEntityEntryPoint() { this instanceof PersistentEntity }
}
/**
* A method (getter or setter) called on a persistent entity class by the persistence framework.
*/
class PersistencePropertyMethod extends CallableEntryPoint {
PersistencePropertyMethod() {
exists(PersistentEntity e |
this = e.getACallable() and
(
e.getAccessType() = "property" or
this.hasAnnotation("javax.persistence", "Access")
) and
(
this.getName().matches("get%") or
this.getName().matches("set%")
)
)
}
}
/**
* Methods that are registered by annotations as callbacks for certain Java persistence events.
*/
class PersistenceCallbackMethod extends CallableEntryPoint {
PersistenceCallbackMethod() {
getAnAnnotation() instanceof PrePersistAnnotation or
getAnAnnotation() instanceof PreRemoveAnnotation or
getAnAnnotation() instanceof PreUpdateAnnotation or
getAnAnnotation() instanceof PostPersistAnnotation or
getAnAnnotation() instanceof PostRemoveAnnotation or
getAnAnnotation() instanceof PostUpdateAnnotation or
getAnAnnotation() instanceof PostLoadAnnotation
}
}
/**
* A source class which is referred to by fully qualified name in the value of an arbitrary XML
* attribute which has a name containing "className" or "ClassName".
*/
class ArbitraryXMLEntryPoint extends ReflectivelyConstructedClass {
ArbitraryXMLEntryPoint() {
fromSource() and
exists(XMLAttribute attribute |
attribute.getName() = "className" or
attribute.getName().matches("%ClassName") or
attribute.getName() = "class" or
attribute.getName().matches("%Class")
|
attribute.getValue() = getQualifiedName()
)
}
override Callable getALiveCallable() {
// Any constructor on these classes, as we don't know which may be called.
result = getAConstructor()
}
}
/** A Selenium PageObject, created by a call to PageFactory.initElements(..). */
class SeleniumPageObjectEntryPoint extends ReflectivelyConstructedClass {
SeleniumPageObjectEntryPoint() { this instanceof SeleniumPageObject }
}

View File

@@ -0,0 +1,128 @@
import java
import semmle.code.java.deadcode.DeadCode
import semmle.code.java.frameworks.spring.Spring
/**
* A method called by Spring to construct a Spring class, or inject a parameter into a Spring class.
*/
class SpringInjectionCallableEntryPoint extends CallableEntryPoint {
SpringInjectionCallableEntryPoint() {
// The constructor of a Spring component, constructed by the container in response to context scanning.
this instanceof SpringComponentConstructor or
// The constructor of a Spring bean, constructed by the container.
this instanceof SpringBeanReflectivelyConstructed or
// A setter method specified in the context.
this instanceof SpringBeanPropertySetterMethod or
exists(this.(SpringBeanXMLAutowiredSetterMethod).getInjectedBean()) or
this instanceof SpringBeanAutowiredCallable
}
}
/**
* A method called by Spring when a bean is initialized or destroyed.
*/
class SpringBeanInitDestroyMethod extends CallableEntryPoint {
SpringBeanInitDestroyMethod() {
exists(SpringBean bean |
this = bean.getInitMethod() or
this = bean.getDestroyMethod()
)
}
}
/**
* A factory method called to construct an instance of a bean.
*/
class SpringFactoryMethod extends CallableEntryPoint {
SpringFactoryMethod() { exists(SpringBean bean | this = bean.getFactoryMethod()) }
}
/**
* A method that creates a Spring bean.
*/
class SpringBeanAnnotatedMethod extends CallableEntryPoint {
SpringBeanAnnotatedMethod() {
hasAnnotation("org.springframework.context.annotation", "Bean") and
getDeclaringType().(SpringComponent).isLive()
}
}
/**
* A live entry point within a Spring controller.
*/
class SpringControllerEntryPoint extends CallableEntryPoint {
SpringControllerEntryPoint() { this instanceof SpringControllerMethod }
}
/**
* A method that is accessible in a response, because it is part of the returned model,
* for example when rendering a JSP page.
*/
class SpringResponseAccessibleMethod extends CallableEntryPoint {
SpringResponseAccessibleMethod() {
// Must be on a type used in a Model response.
getDeclaringType() instanceof SpringModelResponseType and
// Must be public.
isPublic()
}
}
/**
* A Spring "managed resource" is a JMX bean, where only methods annotated with `@ManagedAttribute`
* or `@ManagedOperation` are exposed.
*/
class SpringManagedResource extends CallableEntryPoint {
SpringManagedResource() {
(
hasAnnotation("org.springframework.jmx.export.annotation", "ManagedAttribute") or
hasAnnotation("org.springframework.jmx.export.annotation", "ManagedOperation")
) and
getDeclaringType().hasAnnotation("org.springframework.jmx.export.annotation", "ManagedResource")
}
}
/**
* Spring allows persistence entities to have constructors other than the default constructor.
*/
class SpringPersistenceConstructor extends CallableEntryPoint {
SpringPersistenceConstructor() {
hasAnnotation("org.springframework.data.annotation", "PersistenceConstructor") and
getDeclaringType() instanceof PersistentEntity
}
}
class SpringAspect extends CallableEntryPoint {
SpringAspect() {
(
hasAnnotation("org.aspectj.lang.annotation", "Around") or
hasAnnotation("org.aspectj.lang.annotation", "Before")
) and
getDeclaringType().hasAnnotation("org.aspectj.lang.annotation", "Aspect")
}
}
/**
* Spring Shell provides annotations for identifying methods that contribute CLI commands.
*/
class SpringCLI extends CallableEntryPoint {
SpringCLI() {
(
hasAnnotation("org.springframework.shell.core.annotation", "CliCommand") or
hasAnnotation("org.springframework.shell.core.annotation", "CliAvailabilityIndicator")
) and
getDeclaringType()
.getAnAncestor()
.hasQualifiedName("org.springframework.shell.core", "CommandMarker")
}
}
/**
* An entry point which acts as a remote API for a Flex application to access a Spring application.
*/
class SpringFlexEntryPoint extends CallableEntryPoint {
SpringFlexEntryPoint() {
exists(SpringRemotingDestinationClass remotingDestination |
this = remotingDestination.getARemotingMethod()
)
}
}

View File

@@ -0,0 +1,90 @@
import java
import semmle.code.java.deadcode.DeadCode
import semmle.code.java.frameworks.struts.StrutsActions
/**
* Entry point for apache struts 1.x actions. All methods declared in
* `org.apache.struts.action.Action` + the default constructor are assumed
* to be live. If this is a `DispatchAction` then all public methods are
* live.
*/
class Struts1ActionEntryPoint extends EntryPoint, Class {
Struts1ActionEntryPoint() {
this.getASupertype*().hasQualifiedName("org.apache.struts.action", "Action")
}
override Callable getALiveCallable() {
result = this.getACallable() and
(
exists(Method methodFromAction |
methodFromAction.getDeclaringType().hasQualifiedName("org.apache.struts.action", "Action")
|
result.(Method).overrides(methodFromAction)
)
or
this.getASupertype*().hasQualifiedName("org.apache.struts.actions", "DispatchAction") and
result.(Method).isPublic()
or
result.(Constructor).getNumberOfParameters() = 0
)
}
}
/**
* A struts 2 action class that is reflectively constructed.
*/
class Struts2ReflectivelyConstructedAction extends ReflectivelyConstructedClass {
Struts2ReflectivelyConstructedAction() { this instanceof Struts2ActionClass }
}
/**
* A method called on a struts 2 action class when the action is activated.
*/
class Struts2ActionMethodEntryPoint extends CallableEntryPoint {
Struts2ActionMethodEntryPoint() { this instanceof Struts2ActionMethod }
}
/**
* A method called on a struts 2 action class before an action is activated.
*/
class Struts2PrepareMethodEntryPoint extends CallableEntryPoint {
Struts2PrepareMethodEntryPoint() { this instanceof Struts2PrepareMethod }
}
/**
* A class which is accessible - directly or indirectly - from a struts action.
*/
class ActionAccessibleClass extends Class {
ActionAccessibleClass() {
// A struts action class is directly accessible.
this instanceof Struts2ActionClass or
this instanceof Struts1ActionEntryPoint or
// Any class returned by a struts action is accessible within the JSP.
exists(ActionAccessibleClass actionAccessibleClass |
usesType(actionAccessibleClass.getAGetter().getReturnType(), this)
)
}
Method getAGetter() {
result = this.getAMethod() and
result.getName().matches("get%")
}
Method getASetter() {
result = this.getAMethod() and
result.getName().matches("set%")
}
}
/**
* A Struts getter or setter method is considered to be live, because it can be accessed within
* JSP files, for which we have no information.
*/
class StrutsGetterSetter extends CallableEntryPoint {
StrutsGetterSetter() {
exists(ActionAccessibleClass actionAccessibleClass |
this = actionAccessibleClass.getAGetter() or
this = actionAccessibleClass.getASetter()
)
}
}

View File

@@ -0,0 +1,164 @@
import java
import semmle.code.java.deadcode.DeadCode
import semmle.code.java.frameworks.Cucumber
import semmle.code.java.deadcode.frameworks.FitNesseEntryPoints
import semmle.code.java.frameworks.Mockito
import semmle.code.java.UnitTests
/**
* A test method, suite, or an associated setup/teardown method.
*/
class TestMethodEntry extends CallableEntryPoint {
TestMethodEntry() {
this instanceof TestMethod and
// Ignored tests are not run
not this instanceof JUnitIgnoredMethod
or
this instanceof JUnit3TestSuite
or
exists(AnnotationType a | a = this.getAnAnnotation().getType() |
a.hasQualifiedName("org.junit.runners", "Parameterized$Parameters") and
getDeclaringType() instanceof ParameterizedJUnitTest
)
}
}
/**
* Methods that are called before or after tests.
*/
class BeforeOrAfterEntry extends CallableEntryPoint {
BeforeOrAfterEntry() {
getAnAnnotation() instanceof TestNGBeforeAnnotation or
getAnAnnotation() instanceof TestNGAfterAnnotation or
getAnAnnotation() instanceof BeforeAnnotation or
getAnAnnotation() instanceof BeforeClassAnnotation or
getAnAnnotation() instanceof AfterAnnotation or
getAnAnnotation() instanceof AfterClassAnnotation
}
}
/**
* A method in a test class that is either a JUnit theory, or a method providing data points for a theory.
*/
class JUnitTheories extends CallableEntryPoint {
JUnitTheories() {
exists(AnnotationType a |
a = this.getAnAnnotation().getType() and
getDeclaringType() instanceof JUnitTheoryTest
|
a.hasQualifiedName("org.junit.experimental.theories", "Theory") or
a.hasQualifiedName("org.junit.experimental.theories", "DataPoint") or
a.hasQualifiedName("org.junit.experimental.theories", "DataPoints")
)
}
}
/**
* A field which provides a JUnit `DataPoint` for a theory.
*/
class JUnitDataPointField extends ReflectivelyReadField {
JUnitDataPointField() {
exists(AnnotationType a | a = this.getAnAnnotation().getType() |
(
a.hasQualifiedName("org.junit.experimental.theories", "DataPoint") or
a.hasQualifiedName("org.junit.experimental.theories", "DataPoints")
) and
getDeclaringType() instanceof JUnitTheoryTest
)
}
}
/**
* Any types used as a category in a JUnit `@Category` annotation should be considered live.
*/
class JUnitCategory extends WhitelistedLiveClass {
JUnitCategory() { exists(JUnitCategoryAnnotation ca | ca.getACategory() = this) }
}
/**
* A listener that will be reflectively constructed by TestNG.
*/
class TestNGReflectivelyConstructedListener extends ReflectivelyConstructedClass {
TestNGReflectivelyConstructedListener() {
// Consider any class that implements a TestNG listener interface to be live. Listeners can be
// specified on the command line, in `testng.xml` files and in Ant build files, so it is safest
// to assume that all such listeners are live.
this instanceof TestNGListenerImpl
}
}
/**
* A `@DataProvider` TestNG method which is live because it is accessed by at least one test.
*/
class TestNGDataProvidersEntryPoint extends CallableEntryPoint {
TestNGDataProvidersEntryPoint() {
exists(TestNGTestMethod method | this = method.getADataProvider())
}
}
/**
* A `@Factory` TestNG method or constructor which is live.
*/
class TestNGFactoryEntryPoint extends CallableEntryPoint {
TestNGFactoryEntryPoint() { this instanceof TestNGFactoryCallable }
}
class TestRefectivelyConstructedClass extends ReflectivelyConstructedClass {
TestRefectivelyConstructedClass() {
this.getAnAncestor().getACallable() instanceof TestMethodEntry
}
}
class RunWithReflectivelyConstructedClass extends ReflectivelyConstructedClass {
RunWithReflectivelyConstructedClass() {
exists(AnnotationType a | a = this.getAnAnnotation().getType() |
a.hasQualifiedName("org.junit.runner", "RunWith")
)
}
}
/**
* Callables called by Mockito when performing injection.
*/
class MockitoCalledByInjection extends CallableEntryPoint {
MockitoCalledByInjection() {
exists(MockitoInjectedField field | this = field.getAnInvokedCallable())
or
exists(MockitoSpiedField spyField |
spyField.isConstructed() and
this = spyField.getType().(RefType).getAConstructor() and
this.getNumberOfParameters() = 0
)
}
}
/**
* Mock fields that are read by Mockito when performing injection.
*/
class MockitoReadField extends ReflectivelyReadField {
MockitoReadField() { this.(MockitoMockedField).isReferencedByInjection() }
}
/**
* A class constructed by Cucumber.
*/
class CucumberConstructedClass extends ReflectivelyConstructedClass {
CucumberConstructedClass() {
this instanceof CucumberStepDefinitionClass or
this.getAnAncestor() instanceof CucumberJava8Language
}
override Callable getALiveCallable() {
// Consider any constructor to be live - Cucumber calls a runtime-specified dependency
// injection framework (possibly an in-built one) to construct these instances, so any
// constructor could be called.
result = getAConstructor()
}
}
/**
* A "step definition" that may be called by Cucumber when executing an acceptance test.
*/
class CucumberStepDefinitionEntryPoint extends CallableEntryPoint {
CucumberStepDefinitionEntryPoint() { this instanceof CucumberStepDefinition }
}

View File

@@ -0,0 +1,111 @@
import java
import semmle.code.java.deadcode.DeadCode
import semmle.code.java.frameworks.gwt.GWT
import semmle.code.java.frameworks.Servlets
/**
* Any class which extends the `Servlet` interface is intended to be constructed reflectively by a
* servlet container.
*/
class ServletConstructedClass extends ReflectivelyConstructedClass {
ServletConstructedClass() {
this instanceof ServletClass and
// If we have seen any `web.xml` files, this servlet will be considered to be live only if it is
// referred to as a servlet-class in at least one. If no `web.xml` files are found, we assume
// that XML extraction was not enabled, and therefore consider all `Servlet` classes as live.
(
isWebXMLIncluded()
implies
exists(WebServletClass servletClass | this = servletClass.getClass())
)
}
}
/**
* A "Servlet listener" is a class that is intended to be constructed reflectively by a servlet
* container based upon a `<listener>` tag in the `web.xml` file.
*
* Servlet listeners extend one of a number of listener classes.
*/
class ServletListenerClass extends ReflectivelyConstructedClass {
ServletListenerClass() {
getAnAncestor() instanceof ServletWebXMLListenerType and
// If we have seen any `web.xml` files, this listener will be considered to be live only if it is
// referred to as a listener-class in at least one. If no `web.xml` files are found, we assume
// that XML extraction was not enabled, and therefore consider all listener classes as live.
(
isWebXMLIncluded()
implies
exists(WebListenerClass listenerClass | this = listenerClass.getClass())
)
}
}
/**
* Any class which extends the `Filter` interface is intended to be constructed reflectively by a
* servlet container.
*/
class ServletFilterClass extends ReflectivelyConstructedClass {
ServletFilterClass() {
getASupertype*().hasQualifiedName("javax.servlet", "Filter") and
// If we have seen any `web.xml` files, this filter will be considered to be live only if it is
// referred to as a filter-class in at least one. If no `web.xml` files are found, we assume
// that XML extraction was not enabled, and therefore consider all filter classes as live.
(isWebXMLIncluded() implies exists(WebFilterClass filterClass | this = filterClass.getClass()))
}
}
/**
* An entry point into a GWT application.
*/
class GWTEntryPointConstructedClass extends ReflectivelyConstructedClass {
GWTEntryPointConstructedClass() { this.(GwtEntryPointClass).isLive() }
}
/**
* Servlets referred to from a GWT module config file.
*/
class GWTServletClass extends ReflectivelyConstructedClass {
GWTServletClass() {
this instanceof ServletClass and
// There must be evidence that GWT is being used, otherwise missing `*.gwt.xml` files could cause
// all `Servlet`s to be live.
exists(Package p | p.getName().matches("com.google.gwt%")) and
(
isGwtXmlIncluded()
implies
exists(GwtServletElement servletElement |
this.getQualifiedName() = servletElement.getClassName()
)
)
}
}
/**
* Methods that may be called reflectively by the UiHandler framework.
*/
class GwtUiBinderEntryPoint extends CallableEntryPoint {
GwtUiBinderEntryPoint() {
this instanceof GwtUiFactory
or
this instanceof GwtUiHandler
or
// The UiBinder framework constructs instances of classes specified in the template files. If a
// no-arg constructor is present, that may be called automatically. Or, if there is a
// constructor marked as a `UiConstructor`, then that may be called instead.
this instanceof GwtUiConstructor
or
exists(GwtComponentTemplateElement componentElement |
this.getDeclaringType() = componentElement.getClass() and
this instanceof Constructor and
this.getNumberOfParameters() = 0
)
}
}
/**
* Fields that may be reflectively read or written to by the UiBinder framework.
*/
class GwtUiBinderReflectivelyReadField extends ReflectivelyReadField {
GwtUiBinderReflectivelyReadField() { this instanceof GwtUiField }
}

View File

@@ -0,0 +1,17 @@
/**
* Apache Camel is a messaging framework, which can integrate with Spring.
*/
import java
import semmle.code.java.deadcode.DeadCode
import semmle.code.java.frameworks.Camel
/**
* A method that may be called by Apache Camel to process a message.
*/
class CamelMessageCallableEntryPoint extends CallableEntryPoint {
CamelMessageCallableEntryPoint() {
exists(CamelTargetClass camelTargetClass | this = camelTargetClass.getACamelCalledMethod()) or
exists(CamelConsumeMethod consumeMethod | this = consumeMethod)
}
}

View File

@@ -0,0 +1,69 @@
import default
import semmle.code.java.deadcode.DeadCode
import external.ExternalArtifact
/**
* A method in a FIT fixture class, typically used in the fitnesse framework.
*/
class FitFixtureEntryPoint extends CallableEntryPoint {
FitFixtureEntryPoint() { getDeclaringType().getAnAncestor().hasQualifiedName("fit", "Fixture") }
}
/**
* FitNesse entry points externally defined.
*/
class FitNesseSlimEntryPointData extends ExternalData {
FitNesseSlimEntryPointData() { getDataPath().matches("fitnesse.csv") }
/**
* Gets the class name.
*
* This may be a fully qualified name, or just the name of the class. It may also be, or
* include, a FitNesse symbol, in which case it can be ignored.
*/
string getClassName() { result = getField(0) }
/**
* Gets a Class that either has `getClassName()` as the fully qualified name, or as the class name.
*/
Class getACandidateClass() {
result.getQualifiedName().matches(getClassName()) or
result.getName() = getClassName()
}
/**
* Gets the name of the callable that will be called.
*/
string getCallableName() { result = getField(1) }
/**
* Gets the number of parameters for the callable that will be called.
*/
int getNumParameters() { result = getField(2).toInt() }
/**
* Gets a callable on one of the candidate classes that matches the criteria for the method name
* and number of arguments.
*/
Callable getACandidateCallable() {
result.getDeclaringType() = getACandidateClass() and
result.getName() = getCallableName() and
result.getNumberOfParameters() = getNumParameters()
}
}
/**
* A callable that is a candidate for being called by a processed Slim FitNesse test. This entry
* point requires that the FitNesse tests are processed by the fitnesse-liveness-processor, and
* the resulting CSV file is included in the snapshots external data.
*/
class FitNesseSlimEntryPoint extends EntryPoint {
FitNesseSlimEntryPoint() {
exists(FitNesseSlimEntryPointData entryPointData |
this = entryPointData.getACandidateCallable() and
this.(Callable).fromSource()
)
}
override Callable getALiveCallable() { result = this }
}

View File

@@ -0,0 +1,38 @@
/**
* GigaSpaces XAP (eXtreme Application Platform) is a distributed in-memory "datagrid".
*/
import java
import semmle.code.java.deadcode.DeadCode
import semmle.code.java.frameworks.gigaspaces.GigaSpaces
/**
* A method that is called during event processing by GigaSpaces, on an event listener class.
*
* Note: We do not track registrations of the classes containing these methods. Instead, the method
* is considered live if the listener is at some point constructed.
*/
class GigaSpacesEventCallableEntryPoint extends CallableEntryPointOnConstructedClass {
GigaSpacesEventCallableEntryPoint() { isGigaSpacesEventMethod(this) }
}
/**
* An event listener class that is reflectively constructed by GigaSpaces to handle event processing.
*/
class GigaSpacesEventDrivenReflectivelyConstructed extends ReflectivelyConstructedClass {
GigaSpacesEventDrivenReflectivelyConstructed() { isGigaSpacesEventDrivenClass(this) }
}
/**
* A method that is called when a GigaSpaces "SpaceClass" is written to, or read from, a space.
*
* Note: We do not track whether the space class is written to or read from a space. Instead, the
* methods are considered live if the space class is at some point constructed.
*/
class GigaSpacesSpaceClassMethodEntryPoint extends CallableEntryPointOnConstructedClass {
GigaSpacesSpaceClassMethodEntryPoint() {
this instanceof GigaSpacesSpaceIdGetterMethod or
this instanceof GigaSpacesSpaceIdSetterMethod or
this instanceof GigaSpacesSpaceRoutingMethod
}
}