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

org.opalj.av.checking.ClassMatcher.scala Maven / Gradle / Ivy

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

import scala.util.matching.Regex
import org.opalj.br.ClassFile
import org.opalj.br.VirtualSourceElement
import org.opalj.br.VirtualSourceElement.asVirtualSourceElements
import org.opalj.br.analyses.SomeProject
import org.opalj.bi.AccessFlagsMatcher

/**
 * A class matcher matches classes defined by the respective classes.
 *
 * @author Marco Torsello
 */
trait ClassMatcher extends ClassLevelMatcher {

    def matchMethods: Boolean

    def matchFields: Boolean

}

/**
 * Matches all project and library classes including inner elements like methods and fields defined by
 * the respective classes.
 *
 * @author Marco Torsello
 */
case object AllClasses extends ClassMatcher {

    def matchMethods: Boolean = true

    def matchFields: Boolean = true

    def doesMatch(classFile: ClassFile)(implicit project: SomeProject): Boolean = true

    def extension(implicit project: SomeProject): Set[VirtualSourceElement] = {
        asVirtualSourceElements(project.allClassFiles)
    }

}

/**
 * Default class matcher matches classes defined by the respective classes.
 *
 * @author Marco Torsello
 */
case class DefaultClassMatcher(
        accessFlagsMatcher:       AccessFlagsMatcher   = AccessFlagsMatcher.ANY,
        namePredicate:            NamePredicate        = RegexNamePredicate(""".*""".r),
        annotationsPredicate:     AnnotationsPredicate = AnyAnnotations,
        matchSubclasses:          Boolean              = false,
        matchImplementingclasses: Boolean              = false,
        matchMethods:             Boolean              = true,
        matchFields:              Boolean              = true
) extends ClassMatcher {

    def isSubClass(classFile: ClassFile, project: SomeProject): Boolean = {
        var sourceClassFile: ClassFile = classFile
        while (sourceClassFile.superclassType.nonEmpty) {
            if (namePredicate(sourceClassFile.superclassType.get.fqn))
                return true;

            project.classFile(sourceClassFile.superclassType.get) match {
                case Some(cf) => sourceClassFile = cf
                case None =>
                    return false;
            }
        }

        false
    }

    def implementsInterface(classFile: ClassFile, project: SomeProject): Boolean = {
        classFile.interfaceTypes.exists(i => namePredicate(i.fqn))
    }

    def doesAnnotationMatch(classFile: ClassFile): Boolean = {
        annotationsPredicate(classFile.annotations)
    }

    def doesMatch(classFile: ClassFile)(implicit project: SomeProject): Boolean = {
        val classFileName = classFile.thisType.fqn
        (namePredicate(classFileName) ||
            (matchSubclasses && isSubClass(classFile, project)) ||
            (matchImplementingclasses && implementsInterface(classFile, project))) &&
            (doesAnnotationMatch(classFile)) &&
            accessFlagsMatcher.unapply(classFile.accessFlags)
    }

    def extension(implicit project: SomeProject): Set[VirtualSourceElement] = {
        asVirtualSourceElements(
            project.allClassFiles filter { doesMatch },
            matchMethods,
            matchFields
        )
    }

}

/**
 * Defines several additional factory methods to facilitate the creation of
 * [[ClassMatcher]]s.
 *
 * @author Marco Torsello
 */
object ClassMatcher {

    def apply(namePredicate: NamePredicate): ClassMatcher = {
        new DefaultClassMatcher(namePredicate = namePredicate)
    }

    def apply(annotationsPredicate: AnnotationsPredicate): ClassMatcher = {
        new DefaultClassMatcher(annotationsPredicate = annotationsPredicate)
    }

    def apply(className: String): ClassMatcher = {
        require(className.indexOf('*') == -1)
        new DefaultClassMatcher(namePredicate = Equals(className))
    }

    def apply(className: String, matchPrefix: Boolean): ClassMatcher = {
        require(className.indexOf('*') == -1)
        val namePredicate =
            if (matchPrefix)
                StartsWith(className)
            else
                Equals(className)
        new DefaultClassMatcher(namePredicate = namePredicate)
    }

    def apply(
        className:    String,
        matchPrefix:  Boolean,
        matchMethods: Boolean,
        matchFields:  Boolean
    ): ClassMatcher = {
        require(className.indexOf('*') == -1)

        val namePredicate =
            if (matchPrefix)
                StartsWith(className)
            else
                Equals(className)

        new DefaultClassMatcher(
            namePredicate = namePredicate,
            matchMethods = matchMethods,
            matchFields = matchFields
        )
    }

    def apply(className: String, matchPrefix: Boolean, matchSubclasses: Boolean): ClassMatcher = {
        require(className.indexOf('*') == -1)

        val namePredicate =
            if (matchPrefix)
                StartsWith(className)
            else
                Equals(className)
        new DefaultClassMatcher(
            namePredicate = namePredicate,
            matchSubclasses = matchSubclasses
        )
    }

    def apply(regex: Regex): ClassMatcher = {
        new DefaultClassMatcher(namePredicate = RegexNamePredicate(regex))
    }

    def apply(regex: Regex, matchSubclasses: Boolean): ClassMatcher = {
        new DefaultClassMatcher(
            namePredicate = RegexNamePredicate(regex),
            matchSubclasses = matchSubclasses
        )
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy