All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.opalj.br.fpcf.properties.ThrownExceptions.scala Maven / Gradle / Ivy

The newest version!
/* BSD 2-Clause License - see OPAL/LICENSE for details. */
package org.opalj
package br
package fpcf
package properties

import org.opalj.fpcf.Property
import org.opalj.fpcf.PropertyKey
import org.opalj.fpcf.PropertyMetaInformation
import org.opalj.br.collection.{TypesSet => BRTypesSet}

sealed trait ThrownExceptionsPropertyMetaInformation extends PropertyMetaInformation {

    final type Self = ThrownExceptions

}

/**
 * The set of exceptions that are potentially thrown by a specific method.
 * This includes the set of exceptions thrown by (transitively) called methods (if any).
 * The property '''does not take the exceptions of methods which override the respective
 * method into account'''.
 * Nevertheless, in case of a method call all potential receiver methods are
 * taken into consideration.
 *
 * Note that it may be possible to compute some meaningful upper type bound for the set of
 * thrown exceptions even if methods are called for which the set of thrown exceptions is unknown.
 * This is generally the case if those calls are all done in a try block but the catch/finally
 * blocks only calls known methods - if any.
 * An example is shown next and even if we assume that we don't know
 * the exceptions potentially thrown by `Class.forName`, we could still determine that this method
 * will never throw an exception.
 * {{{
 * object Validator {
 *      def isAvailable(s : String) : Boolean = {
 *          try { Class.forName(s); true} finally {return false;}
 *      }
 * }
 * }}}
 *
 * Information about `ThrownExceptions` is generally associated with `DeclaredMethods`. I.e.,
 * the information is not attached to `Method` objects!
 *
 * Note that the top-value of the lattice is the empty set and the bottom value is the set
 * of all exceptions.
 *
 * @author Michael Eichberg
 */
case class ThrownExceptions(
        types: BRTypesSet
)
    extends Property
    with ThrownExceptionsPropertyMetaInformation {

    final def key = ThrownExceptions.key

    /**
     * Returns `true` if and only if the method does not '''yet''' throw exceptions. I.e., if
     * this property is still refinable then this property may still change. Otherwise,
     * the analysis was able to determine that no exceptions are thrown.
     */
    def throwsNoExceptions: Boolean = types.isEmpty

    override def toString: String = {
        if (this == ThrownExceptions.MethodIsNative)
            """ThrownExceptionsAreUnknown(reason="method is native")"""
        else if (this == ThrownExceptions.UnknownExceptionIsThrown)
            """ThrownExceptionsAreUnknown(reason="the exception type is unknown")"""
        else if (this == ThrownExceptions.MethodBodyIsNotAvailable)
            """ThrownExceptionsAreUnknown(reason="method body is not available")"""
        else if (this == ThrownExceptions.AnalysisLimitation)
            """ThrownExceptionsAreUnknown(reason="analysis limitation")"""
        else if (this == ThrownExceptions.MethodCalledThrowsUnknownExceptions)
            """ThrownExceptionsAreUnknown(reason="Method called throws unknown exception")"""
        else if (this == ThrownExceptions.SomeException)
            """ThrownExceptionsAreUnknown(reason="")"""
        else
            s"ThrownExceptions(${types.toString})"
    }
}

object ThrownExceptions extends ThrownExceptionsPropertyMetaInformation {

    def apply(types: BRTypesSet): ThrownExceptions = new ThrownExceptions(types)

    final val key: PropertyKey[ThrownExceptions] = {
        PropertyKey.create[br.DeclaredMethod, ThrownExceptions](
            "ThrownExceptions",
            ThrownExceptionsFallback
        )
    }

    final val NoExceptions: ThrownExceptions = new ThrownExceptions(BRTypesSet.empty)

    //
    // In the following we use specific instances to identify specific reasons...
    //

    final def SomeException = new ThrownExceptions(BRTypesSet.SomeException)

    final val MethodIsNative = new ThrownExceptions(BRTypesSet.SomeException)

    final val UnknownExceptionIsThrown = new ThrownExceptions(BRTypesSet.SomeException)

    final val MethodBodyIsNotAvailable = new ThrownExceptions(BRTypesSet.SomeException)

    final val AnalysisLimitation = new ThrownExceptions(BRTypesSet.SomeException)

    final val MethodIsAbstract = new ThrownExceptions(BRTypesSet.SomeException)

    final val MethodCalledThrowsUnknownExceptions = new ThrownExceptions(BRTypesSet.SomeException)

    final val UnresolvedInvokeDynamicInstruction = new ThrownExceptions(BRTypesSet.SomeException)

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy