Class PurityChecker

java.lang.Object
org.checkerframework.dataflow.util.PurityChecker

public final class PurityChecker extends Object
A visitor that determines the purity (as defined by SideEffectFree, Deterministic, and Pure) of a statement or expression. The entry point is method checkPurity(com.sun.source.util.TreePath, org.checkerframework.javacutil.AnnotationProvider, com.sun.source.tree.MethodTree, javax.annotation.processing.ProcessingEnvironment, boolean, boolean, boolean).

This class does not check SideEffectsOnly, which is the other purity annotation. Verifying @SideEffectsOnly requires parsing the Java expressions in the annotation and viewpoint-adapting them at each call site, which this module cannot do. org.checkerframework.common.basetype.DisallowedSideEffects, which BaseTypeVisitor calls, checks @SideEffectsOnly.

See Also:
  • Method Details

    • checkPurity

      public static PurityChecker.PurityResult checkPurity(TreePath statement, AnnotationProvider annoProvider, @Nullable MethodTree enclosingMethod, @Nullable ProcessingEnvironment env, boolean assumeSideEffectFree, boolean assumeDeterministic, boolean assumePureGetters)
      Compute whether the given statement is side-effect-free, deterministic, or both. Returns a result that can be queried.
      Parameters:
      statement - the statement to check
      annoProvider - the annotation provider
      enclosingMethod - the method declaration that lexically encloses statement, or null if none does. A call to the functional method of one of that method's functional-interface parameters has the purity that the method's callers required of the argument; see functionalParameterCallPurity(AnnotationProvider, ExpressionTree, ExecutableElement, MethodTree, ProcessingEnvironment). Pass the enclosing method for a lambda body too: the body is checked against the functional method that the lambda implements, but the enclosing method's parameters still hold values that its caller was required to check, whenever the lambda runs. Pass null for an arbitrary expression, which no method's contract governs.
      env - the processing environment; used only if enclosingMethod is non-null
      assumeSideEffectFree - true if all methods should be assumed to be @SideEffectFree
      assumeDeterministic - true if all methods should be assumed to be @Deterministic
      assumePureGetters - true if all getter methods should be assumed to be @Pure
      Returns:
      information about whether the given statement is side-effect-free, deterministic, or both
    • checkPurity

      public static PurityChecker.PurityResult checkPurity(List<TreePath> statements, AnnotationProvider annoProvider, @Nullable MethodTree enclosingMethod, @Nullable ProcessingEnvironment env, boolean assumeSideEffectFree, boolean assumeDeterministic, boolean assumePureGetters)
      Compute whether the given statements, taken together, are side-effect-free, deterministic, or both. Returns a result that can be queried.

      Use this rather than calling checkPurity(TreePath, AnnotationProvider, MethodTree, ProcessingEnvironment, boolean, boolean, boolean) once per statement, for code that runs as a unit but is not contiguous in the source code: a constructor together with the instance initializers that run as part of it, for example.

      Parameters:
      statements - the statements to check
      annoProvider - the annotation provider
      enclosingMethod - the method declaration that lexically encloses statements, or null if none does; see checkPurity(TreePath, AnnotationProvider, MethodTree, ProcessingEnvironment, boolean, boolean, boolean)
      env - the processing environment; used only if enclosingMethod is non-null
      assumeSideEffectFree - true if all methods should be assumed to be @SideEffectFree
      assumeDeterministic - true if all methods should be assumed to be @Deterministic
      assumePureGetters - true if all getter methods should be assumed to be @Pure
      Returns:
      information about whether the given statements are side-effect-free, deterministic, or both
    • functionalParameterKinds

      public static EnumSet<PurityKind> functionalParameterKinds(AnnotationProvider annoProvider, @Nullable ExecutableElement method, ProcessingEnvironment env)
      Returns the purity that method requires of every argument passed to one of its functional-interface parameters: the purity kinds of method's own purity annotations, plus side-effect-freedom if method has or inherits @SideEffectsOnly. The result is one set that applies to all of method's functional-interface parameters alike. It depends only on method's annotations, not on which parameter is in question, nor on whether the body ever calls that parameter's functional method.

      Per-parameter computations refine this set. At a call to method, an argument is not required to have a kind that the parameter's functional method already promises, nor to be deterministic if it is side-effect-free and returns no value. Within the body, a call to a parameter's functional method may assume the purity computed by functionalParameterPurity(org.checkerframework.javacutil.AnnotationProvider, javax.lang.model.element.ExecutableElement, int, javax.annotation.processing.ProcessingEnvironment), which also accounts for the methods that method overrides.

      A @SideEffectsOnly method may modify the listed expressions, but each argument passed to one of its functional-interface parameters is required to be side-effect-free. A method inherits @SideEffectsOnly from the methods that it overrides, though @SideEffectsOnly is not inherited as an annotation.

      Parameters:
      annoProvider - the annotation provider
      method - a method or constructor, or null
      env - the processing environment
      Returns:
      the purity kinds that method requires of every argument to one of its functional-interface parameters; empty if method is null or has no purity annotation
    • functionalParameterCallPurity

      public static EnumSet<PurityKind> functionalParameterCallPurity(AnnotationProvider annoProvider, @Nullable ExpressionTree expr, ExecutableElement invoked, @Nullable MethodTree method, ProcessingEnvironment env)
      Returns the purity that a call of invoked on expr may be assumed to have beyond invoked's own annotations, if expr is an effectively final functional-interface parameter of method and invoked is the functional method of expr's type (or overrides it); otherwise returns an empty set. See functionalParameterPurity(AnnotationProvider, ExecutableElement, int, ProcessingEnvironment).

      The code that such an expression denotes has the purity that method promises, because at every call to method the argument was required to have it. Only the functional method carries that guarantee; a default method such as Function.andThen does not.

      Parameters:
      annoProvider - the annotation provider
      expr - an expression, or null
      invoked - a method that expr is used to invoke or to refer to
      method - a method or constructor declaration, or null
      env - the processing environment
      Returns:
      the purity that the call may be assumed to have, or an empty set
    • functionalParameterPurity

      public static EnumSet<PurityKind> functionalParameterPurity(AnnotationProvider annoProvider, ExecutableElement method, int index, ProcessingEnvironment env)
      Returns the purity that the argument passed to method's parameter at index is known to have, beyond the annotations on the functional method of the parameter's type. It is empty if that parameter's type is not a functional interface.

      A call reaches method through its own declaration or through any declaration that it overrides, and each call checks its arguments against the declaration that it invokes. The result is therefore the purity that method promises, less whatever any overridden declaration does not guarantee; see guaranteedFunctionalArgumentPurity(org.checkerframework.javacutil.AnnotationProvider, javax.lang.model.element.ExecutableElement, int, javax.lang.model.element.ExecutableElement, javax.annotation.processing.ProcessingEnvironment). An overridden declaration with no purity annotation guarantees nothing, nor does one whose parameter at index is not a functional interface, such as a type variable.

      Parameters:
      annoProvider - the annotation provider
      method - a method or constructor
      index - the index of one of method's formal parameters
      env - the processing environment
      Returns:
      the purity that the argument at index is known to have
    • parameterFunctionalMethod

      public static @Nullable ExecutableElement parameterFunctionalMethod(ExecutableElement method, int index, ProcessingEnvironment env)
      Returns the functional method of the type of method's formal parameter at index, or null if that parameter does not exist or does not hold code; see functionalMethodOfType(javax.lang.model.type.TypeMirror, javax.annotation.processing.ProcessingEnvironment). A varargs parameter's type is an array, which does not.
      Parameters:
      method - a method or constructor
      index - the index of a formal parameter
      env - the processing environment
      Returns:
      the functional method of the parameter's type, or null
    • isSameOrOverrides

      public static boolean isSameOrOverrides(ExecutableElement method, ExecutableElement other, ProcessingEnvironment env)
      Returns true if method is other or overrides it.
      Parameters:
      method - a method
      other - another method
      env - the processing environment
      Returns:
      true if method is other or overrides it
    • functionalInterfaceType

      public static @Nullable TypeMirror functionalInterfaceType(TypeMirror type, ProcessingEnvironment env)
      Returns type, or its upper bound if it is a type variable, if that is a functional interface type; otherwise returns null. Use TypesUtils.findFunction(javax.lang.model.type.TypeMirror, javax.annotation.processing.ProcessingEnvironment) on the result to obtain the functional method.
      Parameters:
      type - a type
      env - the processing environment
      Returns:
      the functional interface type that type denotes, or null