Java: Consider classes that has a method that returns an iterator as container like types.

This commit is contained in:
Michael Nebel
2022-10-06 11:11:47 +02:00
parent 309b6e0810
commit 8bc92320d4

View File

@@ -1,14 +1,38 @@
private import java
private import semmle.code.java.Collections
private import semmle.code.java.dataflow.internal.ContainerFlow
private import CaptureModelsSpecific as Specific
private import CaptureModels
/**
* TODO: We might just inline this instead.
* Holds if `t` is a collection of type `tv` (eg. `List<T>`)
* A type representing classes that has a method which returns an iterator.
*/
private predicate genericCollectionType(CollectionType t, TypeVariable tv) {
t.getElementType() = tv
private class IterableType extends Class {
private Type elementType;
IterableType() {
exists(Method m, Type return | m.getDeclaringType() = this |
return = m.getReturnType() and
return.getName().matches("Iterator%") and
elementType = return.(ParameterizedType).getTypeArgument(0)
)
}
/**
* Returns the iterator element type of `this`.
*/
Type getElementType() { result = elementType }
}
/**
* Holds if `t` is a container like type of `tv` (eg. `List<T>`).
*/
private predicate genericContainerType(RefType t, TypeVariable tv) {
(
t.(ContainerType).getElementType() = tv
or
t.(IterableType).getElementType() = tv
)
}
/**
@@ -27,8 +51,7 @@ private predicate localTypeParameter(Callable callable, TypeVariable tv) {
}
/**
* Holds if `callable` has a type parameter `tv`
* or collection parameterized over type `tv`.
* Holds if `callable` has a type parameter `tv` or container parameterized over type `tv`.
*/
private predicate parameter(Callable callable, string input, TypeVariable tv) {
exists(Parameter p |
@@ -38,8 +61,8 @@ private predicate parameter(Callable callable, string input, TypeVariable tv) {
// Parameter of type tv
p.getType() = tv
or
// Parameter is a collection of type tv
genericCollectionType(p.getType(), tv)
// Parameter is a container of type tv
genericContainerType(p.getType(), tv)
)
)
}
@@ -58,7 +81,7 @@ private string getSyntheticField(TypeVariable tv) {
private string implicit(Callable callable, TypeVariable tv) {
classTypeParameter(callable, tv) and
exists(string access |
if genericCollectionType(callable.getDeclaringType(), tv)
if genericContainerType(callable.getDeclaringType(), tv)
then access = ".Element"
else access = getSyntheticField(tv)
|
@@ -83,13 +106,13 @@ private class Function extends ParameterizedType {
Type getParameterType() { result = this.getTypeArgument(0) }
/**
* Get the return type of `this` function.
* Gets the return type of `this` function.
*/
Type getReturnType() { result = this.getTypeArgument(1) }
}
/**
* Holds if `callable` has a functional interface parameter `fi` at parameter position `position`.
* Holds if `callable` has a function parameter `f` at parameter position `position`.
*/
private predicate functional(Callable callable, Function f, int position) {
exists(Parameter p |
@@ -110,9 +133,9 @@ bindingset[callable]
private string getAccess(Callable callable, Type return, TypeVariable tv) {
return = tv and result = ""
or
genericCollectionType(return, tv) and result = ".Element"
genericContainerType(return, tv) and result = ".Element"
or
not genericCollectionType(return, tv) and
not genericContainerType(return, tv) and
(
return.(ParameterizedType).getATypeArgument() = tv
or
@@ -123,7 +146,7 @@ private string getAccess(Callable callable, Type return, TypeVariable tv) {
/**
* Holds if `input` is a models as data string representation of, how a value of type `tv`
* (or a generic parameterized over `tv`) can be generated by a functionalinterface parameter of `callable`.
* (or a generic parameterized over `tv`) can be generated by a function parameter of `callable`.
*/
private predicate functionalSource(Callable callable, string input, TypeVariable tv) {
exists(Function f, int position, Type return, string access |
@@ -141,7 +164,7 @@ private predicate functionalSource(Callable callable, string input, TypeVariable
* This includes
* (1) The implicit synthetic field(s) of the declaring type of `callable`.
* (2) The parameters of `callable`.
* (3) Any delegate parameters of `callable`.
* (3) Any function parameters of `callable`.
*/
private predicate input(Callable callable, string input, TypeVariable tv) {
input = implicit(callable, tv)
@@ -163,9 +186,9 @@ private predicate returns(Callable callable, TypeVariable tv, string output) {
}
/**
* Holds if `callable` has a functional interface parameter that accepts a value of type `tv`
* Holds if `callable` has a function parameter that accepts a value of type `tv`
* and `output` is the models as data string representation of, how data is routed to
* the delegate parameter.
* the function parameter.
*/
private predicate functionalSink(Callable callable, TypeVariable tv, string output) {
exists(Function f, int position |
@@ -181,7 +204,7 @@ private predicate functionalSink(Callable callable, TypeVariable tv, string outp
* This includes
* (1) The implicit synthetic field(s) of the declaring type of `callable`.
* (2) The return of `callable`.
* (3) Any delegate parameters of `callable`.
* (3) Any function parameters of `callable`.
*/
private predicate output(Callable callable, TypeVariable tv, string output) {
output = implicit(callable, tv)
@@ -199,7 +222,6 @@ class TypeBasedFlowTargetApi extends Specific::TargetApiSpecific {
TypeBasedFlowTargetApi() { Specific::isRelevantForTypeBasedFlowModels(this) }
/**
* TODO: Update with Java examples instead.
* Gets the string representation of all type based summaries for `this`
* inspired by the Theorems for Free approach.
*
@@ -212,12 +234,12 @@ class TypeBasedFlowTargetApi extends Specific::TargetApiSpecific {
* a (synthetic) field and return the result.
* (4) `Apply<S1,S2>` is assumed to apply the provided function to provided value
* and return the result.
* ```csharp
* ```java
* public class MyGeneric<T> {
* public void Set(T x) { ... }
* public T Get() { ... }
* public S Apply<S>(Func<T, S> f) { ... }
* public S2 Apply<S1, S2>(S1 x, Func<S1, S2> f) { ... }
* public void set(T x) { ... }
* public T get() { ... }
* public <S> S apply<S>(Function<T, S> f) { ... }
* public <S1,S2> S2 apply<S1, S2>(S1 x, Function<S1, S2> f) { ... }
* }
* ```
*/