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

org.opalj.hermes.queries.util.APIFeature.scala Maven / Gradle / Ivy

The newest version!
/* BSD 2-Clause License:
 * Copyright (c) 2009 - 2017
 * Software Technology Group
 * Department of Computer Science
 * Technische Universität Darmstadt
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 *  - Redistributions of source code must retain the above copyright notice,
 *    this list of conditions and the following disclaimer.
 *  - Redistributions in binary form must reproduce the above copyright notice,
 *    this list of conditions and the following disclaimer in the documentation
 *    and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */
package org.opalj
package hermes
package queries
package util

import org.opalj.br.MethodDescriptor
import org.opalj.br.ObjectType
import org.opalj.collection.immutable.Chain
import org.opalj.collection.immutable.Naught
import org.opalj.br.instructions.MethodInvocationInstruction

/**
 * A common super trait for API related features such as the usage of common or interesting APIs.
 *
 * @author Michael Reif
 */
sealed abstract class APIFeature {

    /**
     * Returns the feature id of the feature.
     *
     * @note Feature ids have to be unique.
     */
    def featureID: String

    /**
     * Returns all methods of the API that belong to this feature.
     */
    def apiMethods: Chain[APIMethod]
}

/**
 * Common trait that abstracts over all Class extension scenarios.
 *
 */
sealed abstract class ClassExtension extends APIFeature {

    def declClass: ObjectType

    override def apiMethods: Chain[APIMethod] = Naught
}

/**
 * Represents an extension of a specific class
 */
case class APIClassExtension(featureID: String, declClass: ObjectType) extends ClassExtension

/**
 * Common trait that abstracts over instance and static api methods.
 */
sealed abstract class APIMethod extends APIFeature {

    def declClass: ObjectType

    def name: String

    def descriptor: Option[MethodDescriptor]

    def unapply(i: MethodInvocationInstruction): Boolean

    final override val apiMethods = Chain(this)

    /**
     * Return the feature id of the feature.
     *
     * @note Feature ids have to be unique.
     */
    override val featureID: String = {
        val methodName = descriptor.map(_.toJava(name)).getOrElse(name)
        val abbreviatedMethodName = methodName.replaceAll("java.lang.Object", "Object")
        s"${declClass.toJava}\n$abbreviatedMethodName"
    }

}

/**
 * Represents an instance API call.
 *
 * @param  declClass ObjectType of the receiver.
 * @param  name Name of the API method.
 * @param  descriptor Optional method descriptor, is no descriptor assigned, it represents
 *         all methods with the same name, declared in the same class.
 */
case class InstanceAPIMethod(
        declClass:  ObjectType,
        name:       String,
        descriptor: Option[MethodDescriptor]
) extends APIMethod {

    def unapply(i: MethodInvocationInstruction): Boolean = {
        i.isInstanceMethod &&
            this.declClass == i.declaringClass &&
            this.name == i.name &&
            (this.descriptor.isEmpty || this.descriptor.get == i.methodDescriptor)
    }
}

/**
 * Factory for InstanceMethods.
 */
object InstanceAPIMethod {

    def apply(declClass: ObjectType, name: String): InstanceAPIMethod = {
        InstanceAPIMethod(declClass, name, None)
    }

    def apply(declClass: ObjectType, name: String, descriptor: String): InstanceAPIMethod = {
        InstanceAPIMethod(declClass, name, Some(MethodDescriptor(descriptor)))
    }

    def apply(
        declClass:  ObjectType,
        name:       String,
        descriptor: MethodDescriptor
    ): InstanceAPIMethod = {
        InstanceAPIMethod(declClass, name, Some(descriptor))
    }
}

/**
 * Represents a static API call.
 *
 *
 * @param  declClass ObjectType of the receiver.
 * @param  name Name of the API method.
 * @param  descriptor Optional method descriptor, is no descriptor assigned, it represents
 *         all methods with the same name, declared in the same class.
 */
case class StaticAPIMethod(
        declClass:  ObjectType,
        name:       String,
        descriptor: Option[MethodDescriptor]
) extends APIMethod {

    def unapply(i: MethodInvocationInstruction): Boolean = {
        !i.isInstanceMethod &&
            this.declClass == i.declaringClass &&
            this.name == i.name &&
            (this.descriptor.isEmpty || this.descriptor.get == i.methodDescriptor)
    }
}

/**
 * Factory for InstanceMethods.
 */
object StaticAPIMethod {

    def apply(declClass: ObjectType, name: String): StaticAPIMethod = {
        StaticAPIMethod(declClass, name, None)
    }

    def apply(declClass: ObjectType, name: String, descriptor: String): StaticAPIMethod = {
        StaticAPIMethod(declClass, name, Some(MethodDescriptor(descriptor)))
    }

    def apply(
        declClass:  ObjectType,
        name:       String,
        descriptor: MethodDescriptor
    ): StaticAPIMethod = {
        StaticAPIMethod(declClass, name, Some(descriptor))
    }
}

/**
 * Represents a collection of API methods that can be mapped to a single feature. Most APIs provide
 * multiple or slightly different API methods to achieve a single task, hence, it can be helpful to
 * group those methods.
 *
 * @note It is assumed that the passed featureID is unique throughout all feature extractors.
 */
case class APIFeatureGroup(apiMethods: Chain[APIMethod], featureID: String) extends APIFeature




© 2015 - 2025 Weber Informatics LLC | Privacy Policy