/* BSD 2-Clause License - see OPAL/LICENSE for details. */ package org.opalj package tac package fpcf package analyses package cg package rta import scala.collection.immutable.ArraySeq import org.opalj.br.DeclaredMethod import org.opalj.br.FieldType import org.opalj.br.Method import org.opalj.br.ReferenceType import org.opalj.br.analyses.DeclaredMethodsKey import org.opalj.br.analyses.ProjectInformationKeys import org.opalj.br.analyses.SomeProject import org.opalj.br.fpcf.BasicFPCFTriggeredAnalysisScheduler import org.opalj.br.fpcf.properties.cg.Callers import org.opalj.br.fpcf.properties.cg.InstantiatedTypes import org.opalj.collection.immutable.UIDSet import org.opalj.fpcf.EOptionP import org.opalj.fpcf.EPS import org.opalj.fpcf.PartialResult import org.opalj.fpcf.ProperPropertyComputationResult import org.opalj.fpcf.PropertyBounds import org.opalj.fpcf.PropertyKind import org.opalj.fpcf.PropertyStore import org.opalj.fpcf.Results import org.opalj.tac.fpcf.properties.TACAI /** * Handles the effect of certain (configured native methods) to the set of instantiated types. * * @author Dominik Helm * @author Florian Kuebler */ class ConfiguredNativeMethodsInstantiatedTypesAnalysis private[analyses] ( final val project: SomeProject ) extends ReachableMethodAnalysis { private val nativeMethodData: Map[DeclaredMethod, Option[Array[EntityAssignment]]] = { ConfiguredMethods.reader .read(p.config, "org.opalj.fpcf.analyses.ConfiguredNativeMethodsAnalysis") .nativeMethods.map { v => (v.method, v.pointsTo) }.toMap } def getInstantiatedTypesUB( instantiatedTypesEOptP: EOptionP[SomeProject, InstantiatedTypes] ): UIDSet[ReferenceType] = { instantiatedTypesEOptP match { case eps: EPS[_, _] => eps.ub.types case _ => UIDSet.empty } } override def processMethod(callContext: ContextType, tacEP: EPS[Method, TACAI]): ProperPropertyComputationResult = processMethodWithoutBody(callContext) override def processMethodWithoutBody(callContext: ContextType): ProperPropertyComputationResult = { val dm = callContext.method val instantiatedTypes = if (nativeMethodData.contains(dm)) { val dataO = nativeMethodData(dm) if (dataO.isEmpty) return Results(); dataO.get.collect { case EntityAssignment(_, as: AllocationSiteDescription) => as.arrayComponentTypes.map(ReferenceType(_)) :+ FieldType(as.instantiatedType).asReferenceType }.flatten } else if (dm.hasSingleDefinedMethod && dm.definedMethod.body.isEmpty && dm.descriptor.returnType.isReferenceType ) { val m = dm.definedMethod val returnType = m.returnType.asReferenceType val types = if (returnType.isArrayType && returnType.asArrayType.elementType.isClassType) Array(returnType, returnType.asArrayType.elementType.asClassType) else Array(returnType) types.filter(t => canBeInstantiated(t, project)) } else return Results(); val instantiatedTypesUB = getInstantiatedTypesUB(propertyStore(project, InstantiatedTypes.key)) val newInstantiatedTypes = UIDSet( ArraySeq.unsafeWrapArray(instantiatedTypes.filterNot(instantiatedTypesUB.contains))* ) if (newInstantiatedTypes.isEmpty) return Results(); PartialResult( p, InstantiatedTypes.key, InstantiatedTypesAnalysis.update(p, newInstantiatedTypes) ) } } object ConfiguredNativeMethodsInstantiatedTypesAnalysisScheduler extends BasicFPCFTriggeredAnalysisScheduler { override def requiredProjectInformation: ProjectInformationKeys = Seq(DeclaredMethodsKey) override def uses: Set[PropertyBounds] = PropertyBounds.ubs(Callers, InstantiatedTypes) override def derivesCollaboratively: Set[PropertyBounds] = PropertyBounds.ubs(InstantiatedTypes) override def derivesEagerly: Set[PropertyBounds] = Set.empty override def register( p: SomeProject, ps: PropertyStore, unused: Null ): ConfiguredNativeMethodsInstantiatedTypesAnalysis = { val analysis = new ConfiguredNativeMethodsInstantiatedTypesAnalysis(p) ps.registerTriggeredComputation(Callers.key, analysis.analyze) analysis } override def triggeredBy: PropertyKind = Callers }