diff --git a/OPAL/tac/src/main/scala/org/opalj/tac/fpcf/analyses/SystemPropertiesAnalysisScheduler.scala b/OPAL/tac/src/main/scala/org/opalj/tac/fpcf/analyses/SystemPropertiesAnalysisScheduler.scala index e35ccd3c9e..d3aeea5e59 100644 --- a/OPAL/tac/src/main/scala/org/opalj/tac/fpcf/analyses/SystemPropertiesAnalysisScheduler.scala +++ b/OPAL/tac/src/main/scala/org/opalj/tac/fpcf/analyses/SystemPropertiesAnalysisScheduler.scala @@ -26,13 +26,13 @@ import org.opalj.fpcf.PropertyStore import org.opalj.fpcf.Results import org.opalj.fpcf.UBP import org.opalj.tac.cg.TypeIteratorKey -import org.opalj.tac.fpcf.analyses.cg.ReachableMethodAnalysis +import org.opalj.tac.fpcf.analyses.cg.DefinedBodyReachableMethodAnalysis import org.opalj.tac.fpcf.properties.TACAI import org.opalj.value.ValueInformation class SystemPropertiesAnalysisScheduler private[analyses] ( final val project: SomeProject -) extends ReachableMethodAnalysis { +) extends DefinedBodyReachableMethodAnalysis { def processMethod( callContext: ContextType, diff --git a/OPAL/tac/src/main/scala/org/opalj/tac/fpcf/analyses/TACAIBasedAnalysisState.scala b/OPAL/tac/src/main/scala/org/opalj/tac/fpcf/analyses/TACAIBasedAnalysisState.scala index 4e9c3b34e9..152dada8b3 100644 --- a/OPAL/tac/src/main/scala/org/opalj/tac/fpcf/analyses/TACAIBasedAnalysisState.scala +++ b/OPAL/tac/src/main/scala/org/opalj/tac/fpcf/analyses/TACAIBasedAnalysisState.scala @@ -26,12 +26,10 @@ trait TACAIBasedAnalysisState[TheContextType <: Context] def callContext: ContextType protected[this] var _tacDependee: EOptionP[Method, TACAI] - assert((_tacDependee eq null) || (_tacDependee.hasUBP && _tacDependee.ub.tac.isDefined)) + assert(_tacDependee.hasUBP && _tacDependee.ub.tac.isDefined) - abstract override def hasOpenDependencies: Boolean = { - (_tacDependee ne null) && _tacDependee.isRefinable || super.hasOpenDependencies - } - final def hasTACDependee: Boolean = _tacDependee.isRefinable + abstract override def hasOpenDependencies: Boolean = _tacDependee.isRefinable || super.hasOpenDependencies + final def isTACDependeeRefinable: Boolean = _tacDependee.isRefinable /** * Inherited classes that introduce new dependencies must override this method and call add a @@ -39,7 +37,7 @@ trait TACAIBasedAnalysisState[TheContextType <: Context] */ abstract override def dependees: Set[SomeEOptionP] = { val otherDependees = super.dependees - if ((_tacDependee ne null) && _tacDependee.isRefinable) + if (_tacDependee.isRefinable) otherDependees + _tacDependee else otherDependees @@ -49,12 +47,7 @@ trait TACAIBasedAnalysisState[TheContextType <: Context] _tacDependee = tacDependee } - final def tac: TACode[TACMethodParameter, DUVar[ValueInformation]] = { - _tacDependee.ub.tac.get - } - - final def tacDependee: EOptionP[Method, TACAI] = { - _tacDependee - } + final def tac: TACode[TACMethodParameter, DUVar[ValueInformation]] = _tacDependee.ub.tac.get + final def tacDependee: EOptionP[Method, TACAI] = _tacDependee } diff --git a/OPAL/tac/src/main/scala/org/opalj/tac/fpcf/analyses/cg/CGState.scala b/OPAL/tac/src/main/scala/org/opalj/tac/fpcf/analyses/cg/CGState.scala index fcf7b55e85..d39ad81b03 100644 --- a/OPAL/tac/src/main/scala/org/opalj/tac/fpcf/analyses/cg/CGState.scala +++ b/OPAL/tac/src/main/scala/org/opalj/tac/fpcf/analyses/cg/CGState.scala @@ -16,10 +16,11 @@ import org.opalj.tac.fpcf.properties.TACAI /** * @author Florian Kuebler */ -class CGState[ContextType <: Context]( - override val callContext: ContextType, - override protected[this] var _tacDependee: EOptionP[Method, TACAI] -) extends BaseAnalysisState with TypeIteratorState with TACAIBasedAnalysisState[ContextType] { +class CGState[TheContextType <: Context]( + val callContext: TheContextType +) extends BaseAnalysisState with TypeIteratorState with ContextualAnalysis { + + override type ContextType = TheContextType // maps a definition site to the receiver var private[this] val _virtualCallSites: mutable.Map[CallSite, (V, Set[ReferenceType])] = @@ -38,3 +39,11 @@ class CGState[ContextType <: Context]( def hasNonFinalCallSite: Boolean = _virtualCallSites.nonEmpty } + +/** + * @author Maximilian RĂ¼sch + */ +class TACAIBasedCGState[ContextType <: Context]( + callContext: ContextType, + override protected[this] var _tacDependee: EOptionP[Method, TACAI] +) extends CGState[ContextType](callContext) with TACAIBasedAnalysisState[ContextType] diff --git a/OPAL/tac/src/main/scala/org/opalj/tac/fpcf/analyses/cg/CallGraphAnalysis.scala b/OPAL/tac/src/main/scala/org/opalj/tac/fpcf/analyses/cg/CallGraphAnalysis.scala index 08ee8a8553..54febc855a 100644 --- a/OPAL/tac/src/main/scala/org/opalj/tac/fpcf/analyses/cg/CallGraphAnalysis.scala +++ b/OPAL/tac/src/main/scala/org/opalj/tac/fpcf/analyses/cg/CallGraphAnalysis.scala @@ -20,6 +20,7 @@ import org.opalj.br.fpcf.properties.cg.Callees import org.opalj.br.fpcf.properties.cg.Callers import org.opalj.br.fpcf.properties.cg.OnlyCallersWithUnknownContext import org.opalj.fpcf.Entity +import org.opalj.fpcf.EOptionP import org.opalj.fpcf.EPK import org.opalj.fpcf.EPS import org.opalj.fpcf.InterimEUBP @@ -56,14 +57,13 @@ import org.opalj.value.IsSObjectValue class CallGraphAnalysis private[cg] ( override val project: SomeProject ) extends ReachableMethodAnalysis with TypeConsumerAnalysis { - type LocalTypeInformation private[this] val isMethodOverridable: Method => Answer = project.get(IsOverridableMethodKey) private[this] lazy val getCBSTargets = project.get(CallBySignatureKey) private[this] val resovleCallBySignature = project.config.getBoolean("org.opalj.br.analyses.cg.callBySignatureResolution") - def c(state: CGState[ContextType])(eps: SomeEPS): ProperPropertyComputationResult = { + def c(state: TACAIBasedCGState[ContextType])(eps: SomeEPS): ProperPropertyComputationResult = { eps match { case UBP(tacai: TACAI) if tacai.tac.isDefined => state.updateTACDependee(eps.asInstanceOf[EPS[Method, TACAI]]) @@ -74,7 +74,7 @@ class CallGraphAnalysis private[cg] ( case UBP(_: TACAI) => throw new IllegalStateException("there was already a tac defined") - case EPS(e) => + case EPS(_) => val relevantCallSites = state.dependersOf(eps.toEPK).asInstanceOf[Set[CallSite]] // ensures, that we only add new calls @@ -121,17 +121,16 @@ class CallGraphAnalysis private[cg] ( override final def processMethod( callContext: ContextType, - tacEP: EPS[Method, TACAI] + tacEPOpt: EOptionP[Method, TACAI] ): ProperPropertyComputationResult = { - val state = new CGState[ContextType](callContext, tacEP) - if (tacEP ne null) + if (tacEPOpt.hasUBP) { + val state = new TACAIBasedCGState[ContextType](callContext, tacEPOpt) processMethod(state, new DirectCalls()) - else - returnResult(new DirectCalls(), enforceCalleesResult = true)(state) + } else { + Results(new DirectCalls().partialResults(callContext, enforceCalleesResult = true)) + } } - override final val processesMethodsWithoutBody = true - protected[this] def doHandleVirtualCall( callContext: ContextType, call: Call[V] with VirtualCall[V], @@ -139,7 +138,7 @@ class CallGraphAnalysis private[cg] ( specializedDeclaringClassType: ReferenceType, isPrecise: Boolean, calleesAndCallers: DirectCalls - )(implicit state: CGState[ContextType]): Unit = { + )(implicit state: TACAIBasedCGState[ContextType]): Unit = { val callerType = callContext.method.declaringClassType val callSite = CallSite(pc, call.name, call.descriptor, call.declaringClass) @@ -209,7 +208,7 @@ class CallGraphAnalysis private[cg] ( } protected final def processMethod( - state: CGState[ContextType], + state: TACAIBasedCGState[ContextType], calls: DirectCalls ): ProperPropertyComputationResult = { val tac = state.tac @@ -294,13 +293,13 @@ class CallGraphAnalysis private[cg] ( case _ => // nothing to do } - returnResult(calls, true)(state) + returnResult(calls, enforceCalleesResult = true)(state) } protected[this] def returnResult( calleesAndCallers: DirectCalls, enforceCalleesResult: Boolean = false - )(implicit state: CGState[ContextType]): ProperPropertyComputationResult = { + )(implicit state: TACAIBasedCGState[ContextType]): ProperPropertyComputationResult = { val results = calleesAndCallers.partialResults(state.callContext, enforceCalleesResult) // FIXME: This won't work for refinable TACs as state.hasNonFinalCallSite may return false @@ -388,7 +387,7 @@ class CallGraphAnalysis private[cg] ( call: Call[V] with VirtualCall[V], pc: Int, calleesAndCallers: DirectCalls - )(implicit state: CGState[ContextType]): Unit = { + )(implicit state: TACAIBasedCGState[ContextType]): Unit = { val rvs = call.receiver.asVar.value.asReferenceValue.allValues for (rv <- rvs) rv match { case _: IsSArrayValue => @@ -422,7 +421,7 @@ class CallGraphAnalysis private[cg] ( call: Call[V] with VirtualCall[V], pc: Int, calleesAndCallers: DirectCalls - )(implicit state: CGState[ContextType]): Unit = { + )(implicit state: TACAIBasedCGState[ContextType]): Unit = { doHandleVirtualCall(callContext, call, pc, calleeType, isPrecise = true, calleesAndCallers) } } diff --git a/OPAL/tac/src/main/scala/org/opalj/tac/fpcf/analyses/cg/DoPrivilegedCGAnalysis.scala b/OPAL/tac/src/main/scala/org/opalj/tac/fpcf/analyses/cg/DoPrivilegedCGAnalysis.scala index 6dbb90df42..692c29b5f1 100644 --- a/OPAL/tac/src/main/scala/org/opalj/tac/fpcf/analyses/cg/DoPrivilegedCGAnalysis.scala +++ b/OPAL/tac/src/main/scala/org/opalj/tac/fpcf/analyses/cg/DoPrivilegedCGAnalysis.scala @@ -72,8 +72,10 @@ class DoPrivilegedMethodAnalysis private[cg] ( if (params.nonEmpty && params.head.isDefined) { val param = params.head.get.asVar - implicit val state: CGState[ContextType] = - new CGState[ContextType](callerContext, FinalEP(callerContext.method.definedMethod, TheTACAI(tac))) + implicit val state: TACAIBasedCGState[ContextType] = new TACAIBasedCGState[ContextType]( + callerContext, + FinalEP(callerContext.method.definedMethod, TheTACAI(tac)) + ) val thisActual = persistentUVar(param)(state.tac.stmts) @@ -93,8 +95,7 @@ class DoPrivilegedMethodAnalysis private[cg] ( thisVar: V, thisActual: Some[(ValueInformation, IntTrieSet)], calls: IndirectCalls - )(implicit state: CGState[ContextType]): ProperPropertyComputationResult = { - + )(implicit state: TACAIBasedCGState[ContextType]): ProperPropertyComputationResult = { val partialResults = calls.partialResults(state.callContext) if (state.hasOpenDependencies) Results( @@ -127,7 +128,7 @@ class DoPrivilegedMethodAnalysis private[cg] ( } def c( - state: CGState[ContextType], + state: TACAIBasedCGState[ContextType], thisVar: V, thisActual: Some[(ValueInformation, IntTrieSet)] )(eps: SomeEPS): ProperPropertyComputationResult = { diff --git a/OPAL/tac/src/main/scala/org/opalj/tac/fpcf/analyses/cg/ReachableMethodAnalysis.scala b/OPAL/tac/src/main/scala/org/opalj/tac/fpcf/analyses/cg/ReachableMethodAnalysis.scala index 052283fbed..3d5d5a1f5c 100644 --- a/OPAL/tac/src/main/scala/org/opalj/tac/fpcf/analyses/cg/ReachableMethodAnalysis.scala +++ b/OPAL/tac/src/main/scala/org/opalj/tac/fpcf/analyses/cg/ReachableMethodAnalysis.scala @@ -13,8 +13,8 @@ import org.opalj.br.fpcf.FPCFAnalysis import org.opalj.br.fpcf.properties.cg.Callers import org.opalj.br.fpcf.properties.cg.NoCallers import org.opalj.fpcf.EOptionP +import org.opalj.fpcf.EPK import org.opalj.fpcf.EPS -import org.opalj.fpcf.FinalP import org.opalj.fpcf.InterimPartialResult import org.opalj.fpcf.NoResult import org.opalj.fpcf.ProperPropertyComputationResult @@ -36,18 +36,9 @@ trait ReachableMethodAnalysis extends FPCFAnalysis with TypeConsumerAnalysis { final def analyze(declaredMethod: DeclaredMethod): PropertyComputationResult = { val callersEOptP = propertyStore(declaredMethod, Callers.key) - (callersEOptP: @unchecked) match { - case FinalP(NoCallers) => - // nothing to do, since there is no caller - return NoResult; - - case eps: EPS[_, _] => - if (eps.ub eq NoCallers) { - // we can not create a dependency here, so the analysis is not allowed to create - // such a result - throw new IllegalStateException("illegal immediate result for callers") - } - // the method is reachable, so we analyze it! + + if (callersEOptP.isFinal && callersEOptP.ub == NoCallers) { + return NoResult; } // we only allow defined methods @@ -65,47 +56,41 @@ trait ReachableMethodAnalysis extends FPCFAnalysis with TypeConsumerAnalysis { return processMethodWithoutBody(callersEOptP); val tacEP = propertyStore(method, TACAI.key) - if (tacEP.hasUBP && tacEP.ub.tac.isDefined) { - processMethod(callersEOptP, null, tacEP.asEPS) + processMethod(callersEOptP, NoCallers, tacEP) } else { InterimPartialResult(Set(tacEP), continuationForTAC(declaredMethod)) } } - protected val processesMethodsWithoutBody = false - protected def processMethodWithoutBody( eOptP: EOptionP[DeclaredMethod, Callers] - ): PropertyComputationResult = { - if (processesMethodsWithoutBody) { - processMethod(eOptP, null, null) - } else - NoResult - } + ): PropertyComputationResult = processMethod(eOptP, NoCallers, EPK(eOptP.e.definedMethod, TACAI.key)) private[this] def processMethod( - eOptP: EOptionP[DeclaredMethod, Callers], - seen: Callers, - tacEP: EPS[Method, TACAI] + eOptP: EOptionP[DeclaredMethod, Callers], + oldCallers: Callers, + tacEOptP: EOptionP[Method, TACAI] ): ProperPropertyComputationResult = { + val newCallers = if (eOptP.hasUBP) eOptP.ub else NoCallers var results: List[ProperPropertyComputationResult] = Nil - eOptP.ub.forNewCalleeContexts(seen, eOptP.e) { calleeContext => + + newCallers.forNewCalleeContexts(oldCallers, eOptP.e) { calleeContext => val theCalleeContext = if (calleeContext.hasContext) calleeContext.asInstanceOf[ContextType] else typeIterator.newContext(eOptP.e) - results ::= processMethod(theCalleeContext, tacEP) + results ::= processMethod(theCalleeContext, tacEOptP) } Results( - InterimPartialResult(Set(eOptP), continuationForCallers(eOptP.ub, tacEP)), + InterimPartialResult(Set(eOptP), continuationForCallers(newCallers, tacEOptP)), results ) } def processMethod( callContext: ContextType, - tacEP: EPS[Method, TACAI] + tacEOptP: EOptionP[Method, TACAI] ): ProperPropertyComputationResult protected def continuationForTAC( @@ -115,7 +100,7 @@ trait ReachableMethodAnalysis extends FPCFAnalysis with TypeConsumerAnalysis { case UBP(tac: TACAI) if tac.tac.isDefined => processMethod( propertyStore(declaredMethod, Callers.key), - null, + NoCallers, someEPS.asInstanceOf[EPS[Method, TACAI]] ) case _ => @@ -125,12 +110,28 @@ trait ReachableMethodAnalysis extends FPCFAnalysis with TypeConsumerAnalysis { private[this] def continuationForCallers( oldCallers: Callers, - tacEP: EPS[Method, TACAI] + tacEOptP: EOptionP[Method, TACAI] )( update: SomeEPS ): ProperPropertyComputationResult = { val newCallers = update.asInstanceOf[EPS[DeclaredMethod, Callers]] - processMethod(newCallers, oldCallers, tacEP) + processMethod(newCallers, oldCallers, tacEOptP) } +} +trait DefinedBodyReachableMethodAnalysis extends ReachableMethodAnalysis { + + override protected final def processMethodWithoutBody( + eOptP: EOptionP[DeclaredMethod, Callers] + ): PropertyComputationResult = NoResult + + override final def processMethod( + callContext: ContextType, + tacEPOpt: EOptionP[Method, TACAI] + ): ProperPropertyComputationResult = processMethod(callContext, tacEPOpt.asEPS) + + def processMethod( + callContext: ContextType, + tacEP: EPS[Method, TACAI] + ): ProperPropertyComputationResult } diff --git a/OPAL/tac/src/main/scala/org/opalj/tac/fpcf/analyses/cg/SerializationRelatedCallsAnalysis.scala b/OPAL/tac/src/main/scala/org/opalj/tac/fpcf/analyses/cg/SerializationRelatedCallsAnalysis.scala index 429ea4ebd7..e67ac481be 100644 --- a/OPAL/tac/src/main/scala/org/opalj/tac/fpcf/analyses/cg/SerializationRelatedCallsAnalysis.scala +++ b/OPAL/tac/src/main/scala/org/opalj/tac/fpcf/analyses/cg/SerializationRelatedCallsAnalysis.scala @@ -83,7 +83,7 @@ class OOSWriteObjectAnalysis private[analyses] ( val receiver = persistentUVar(param) val parameters = Seq(receiverOption.flatMap(os => persistentUVar(os.asVar))) - implicit val state: CGState[ContextType] = new CGState[ContextType]( + implicit val state: TACAIBasedCGState[ContextType] = new TACAIBasedCGState[ContextType]( callerContext, FinalEP(callerContext.method.definedMethod, TheTACAI(tac)) ) @@ -101,7 +101,7 @@ class OOSWriteObjectAnalysis private[analyses] ( receiverVar: V, receiver: Option[(ValueInformation, IntTrieSet)], parameters: Seq[Option[(ValueInformation, IntTrieSet)]], - state: CGState[ContextType] + state: TACAIBasedCGState[ContextType] )(eps: SomeEPS): ProperPropertyComputationResult = { val pc = state.dependersOf(eps.toEPK).head.asInstanceOf[Int] @@ -126,7 +126,7 @@ class OOSWriteObjectAnalysis private[analyses] ( receiver: Option[(ValueInformation, IntTrieSet)], parameters: Seq[Option[(ValueInformation, IntTrieSet)]], indirectCalls: IndirectCalls - )(implicit state: CGState[ContextType]): ProperPropertyComputationResult = { + )(implicit state: TACAIBasedCGState[ContextType]): ProperPropertyComputationResult = { val results = indirectCalls.partialResults(state.callContext) if (state.hasOpenDependencies) Results( @@ -144,7 +144,7 @@ class OOSWriteObjectAnalysis private[analyses] ( receiver: Option[(ValueInformation, IntTrieSet)], parameters: Seq[Option[(ValueInformation, IntTrieSet)]], indirectCalls: IndirectCalls - )(implicit state: CGState[ContextType]): Unit = { + )(implicit state: TACAIBasedCGState[ContextType]): Unit = { typeIterator.foreachType( param, typeIterator.typesProperty(param, callContext, callPC.asInstanceOf[Entity], state.tac.stmts) diff --git a/OPAL/tac/src/main/scala/org/opalj/tac/fpcf/analyses/cg/ThreadRelatedCallsAnalysis.scala b/OPAL/tac/src/main/scala/org/opalj/tac/fpcf/analyses/cg/ThreadRelatedCallsAnalysis.scala index 212859f57d..7b4d2e10ae 100644 --- a/OPAL/tac/src/main/scala/org/opalj/tac/fpcf/analyses/cg/ThreadRelatedCallsAnalysis.scala +++ b/OPAL/tac/src/main/scala/org/opalj/tac/fpcf/analyses/cg/ThreadRelatedCallsAnalysis.scala @@ -62,7 +62,7 @@ class ThreadStartAnalysis private[cg] ( isDirect: Boolean ): ProperPropertyComputationResult = { val partialAnalysisResults = new ThreadStartAnalysisResults() - implicit val state: CGState[ContextType] = new CGState[ContextType]( + implicit val state: TACAIBasedCGState[ContextType] = new TACAIBasedCGState[ContextType]( callerContext, FinalEP(callerContext.method.definedMethod, TheTACAI(tac)) ) @@ -80,7 +80,7 @@ class ThreadStartAnalysis private[cg] ( def returnResult( receiver: V, partialAnalysisResults: ThreadStartAnalysisResults - )(implicit state: CGState[ContextType]): ProperPropertyComputationResult = { + )(implicit state: TACAIBasedCGState[ContextType]): ProperPropertyComputationResult = { val runnableResults = Results(partialAnalysisResults.partialResults(state.callContext)) if (state.hasOpenDependencies) Results( @@ -91,12 +91,12 @@ class ThreadStartAnalysis private[cg] ( Results(runnableResults) } - def c(receiver: V, state: CGState[ContextType])(eps: SomeEPS): ProperPropertyComputationResult = { + def c(receiver: V, state: TACAIBasedCGState[ContextType])(eps: SomeEPS): ProperPropertyComputationResult = { val epk = eps.toEPK // ensures, that we only add new vm reachable methods val partialAnalysisResults = new ThreadStartAnalysisResults() - implicit val _state: CGState[ContextType] = state + implicit val _state: TACAIBasedCGState[ContextType] = state eps.ub match { case _: TACAI => @@ -178,7 +178,7 @@ class ThreadStartAnalysis private[cg] ( callPC: Int, receiver: V, partialAnalysisResults: ThreadStartAnalysisResults - )(implicit state: CGState[ContextType]): Unit = { + )(implicit state: TACAIBasedCGState[ContextType]): Unit = { // a call to Thread.start will trigger the JVM to later on call Thread.exit() val exitMethod = project.specialCall( ObjectType.Thread, @@ -480,7 +480,7 @@ class UncaughtExceptionHandlerAnalysis private[analyses] ( ): ProperPropertyComputationResult = { val vmReachableMethods = new VMReachableMethods() - implicit val state: CGState[ContextType] = new CGState[ContextType]( + implicit val state: TACAIBasedCGState[ContextType] = new TACAIBasedCGState[ContextType]( callerContext, FinalEP(callerContext.method.definedMethod, TheTACAI(tac)) ) @@ -497,7 +497,7 @@ class UncaughtExceptionHandlerAnalysis private[analyses] ( def c( receiver: V, - state: CGState[ContextType] + state: TACAIBasedCGState[ContextType] )(eps: SomeEPS): ProperPropertyComputationResult = { val epk = eps.toEPK val pc = state.dependersOf(epk).head.asInstanceOf[Int] @@ -521,7 +521,7 @@ class UncaughtExceptionHandlerAnalysis private[analyses] ( def returnResult( receiver: V, vmReachableMethods: VMReachableMethods - )(implicit state: CGState[ContextType]): ProperPropertyComputationResult = { + )(implicit state: TACAIBasedCGState[ContextType]): ProperPropertyComputationResult = { val results = vmReachableMethods.partialResults(state.callContext) if (state.hasOpenDependencies) Results( @@ -545,7 +545,7 @@ class UncaughtExceptionHandlerAnalysis private[analyses] ( receiver: V, callPC: Int, vmReachableMethods: VMReachableMethods - )(implicit state: CGState[ContextType]): Unit = { + )(implicit state: TACAIBasedCGState[ContextType]): Unit = { typeIterator.foreachType( receiver, typeIterator.typesProperty(receiver, callContext, callPC.asInstanceOf[Entity], state.tac.stmts) diff --git a/OPAL/tac/src/main/scala/org/opalj/tac/fpcf/analyses/cg/reflection/ReflectionRelatedCallsAnalysis.scala b/OPAL/tac/src/main/scala/org/opalj/tac/fpcf/analyses/cg/reflection/ReflectionRelatedCallsAnalysis.scala index eea59fccf9..205890eba6 100644 --- a/OPAL/tac/src/main/scala/org/opalj/tac/fpcf/analyses/cg/reflection/ReflectionRelatedCallsAnalysis.scala +++ b/OPAL/tac/src/main/scala/org/opalj/tac/fpcf/analyses/cg/reflection/ReflectionRelatedCallsAnalysis.scala @@ -139,7 +139,7 @@ class ClassForNameAnalysis private[analyses] ( loadedClassesUB: UIDSet[ObjectType], callContext: ContextType, val callPC: Int - ) extends CGState[ContextType](callContext, null) { + ) extends CGState[ContextType](callContext) { var hasFailed = false private[this] var _loadedClassesUB: UIDSet[ObjectType] = loadedClassesUB @@ -334,7 +334,7 @@ class ClassNewInstanceAnalysis private[analyses] ( isDirect: Boolean ): ProperPropertyComputationResult = { implicit val indirectCalls: IndirectCalls = new IndirectCalls() - implicit val state: CGState[ContextType] = new CGState[ContextType]( + implicit val state: TACAIBasedCGState[ContextType] = new TACAIBasedCGState[ContextType]( callerContext, FinalEP(callerContext.method.definedMethod, TheTACAI(tac)) ) @@ -352,7 +352,7 @@ class ClassNewInstanceAnalysis private[analyses] ( classRef: V, callPC: Int, indirectCalls: IndirectCalls - )(implicit state: CGState[ContextType]): ProperPropertyComputationResult = { + )(implicit state: TACAIBasedCGState[ContextType]): ProperPropertyComputationResult = { val results = indirectCalls.partialResults(state.callContext) if (state.hasOpenDependencies) Results( @@ -366,10 +366,10 @@ class ClassNewInstanceAnalysis private[analyses] ( private[this] def c( classRef: V, callPC: Int, - state: CGState[ContextType] + state: TACAIBasedCGState[ContextType] )(eps: SomeEPS): ProperPropertyComputationResult = { implicit val indirectCalls: IndirectCalls = new IndirectCalls() - implicit val _state: CGState[ContextType] = state + implicit val _state: TACAIBasedCGState[ContextType] = state val epk = eps.toEPK @@ -426,8 +426,8 @@ class ClassNewInstanceAnalysis private[analyses] ( callPC: Int, classExpr: V, stmts: Array[Stmt[V]] - )(implicit indirectCalls: IndirectCalls, state: CGState[ContextType]): Unit = { - implicit val highSoundness = HighSoundnessMode("class") + )(implicit indirectCalls: IndirectCalls, state: TACAIBasedCGState[ContextType]): Unit = { + implicit val highSoundness: Boolean = HighSoundnessMode("class") val matchers = Set( MatcherUtil.constructorMatcher, @@ -450,7 +450,7 @@ class ClassNewInstanceAnalysis private[analyses] ( private[this] def failure( callPC: Int - )(implicit indirectCalls: IndirectCalls, state: CGState[ContextType]): Unit = { + )(implicit indirectCalls: IndirectCalls, state: TACAIBasedCGState[ContextType]): Unit = { if (HighSoundnessMode.contains("class")) { val matchers: Set[MethodMatcher] = Set( MatcherUtil.constructorMatcher, @@ -489,7 +489,7 @@ class ConstructorNewInstanceAnalysis private[analyses] ( ): ProperPropertyComputationResult = { implicit val indirectCalls: IndirectCalls = new IndirectCalls() - implicit val state: CGState[ContextType] = new CGState[ContextType]( + implicit val state: TACAIBasedCGState[ContextType] = new TACAIBasedCGState[ContextType]( callerContext, FinalEP(callerContext.method.definedMethod, TheTACAI(tac)) ) @@ -506,7 +506,7 @@ class ConstructorNewInstanceAnalysis private[analyses] ( def returnResult( constructor: V, indirectCalls: IndirectCalls - )(implicit state: CGState[ContextType]): ProperPropertyComputationResult = { + )(implicit state: TACAIBasedCGState[ContextType]): ProperPropertyComputationResult = { val results = indirectCalls.partialResults(state.callContext) if (state.hasOpenDependencies) Results( @@ -521,9 +521,9 @@ class ConstructorNewInstanceAnalysis private[analyses] ( private type classDependerType = (Int, Seq[Option[(ValueInformation, IntTrieSet)]], Set[MethodMatcher], V, Array[Stmt[V]]) - def c(constructor: V, state: CGState[ContextType])(eps: SomeEPS): ProperPropertyComputationResult = { + def c(constructor: V, state: TACAIBasedCGState[ContextType])(eps: SomeEPS): ProperPropertyComputationResult = { implicit val indirectCalls: IndirectCalls = new IndirectCalls() - implicit val _state: CGState[ContextType] = state + implicit val _state: TACAIBasedCGState[ContextType] = state val epk = eps.toEPK @@ -589,7 +589,7 @@ class ConstructorNewInstanceAnalysis private[analyses] ( constructor: V, newInstanceParams: Seq[Option[Expr[V]]], stmts: Array[Stmt[V]] - )(implicit state: CGState[ContextType], indirectCalls: IndirectCalls): Unit = { + )(implicit state: TACAIBasedCGState[ContextType], indirectCalls: IndirectCalls): Unit = { val actualParamsNewInstanceOpt = if (newInstanceParams.nonEmpty && newInstanceParams.head.isDefined) @@ -648,7 +648,7 @@ class ConstructorNewInstanceAnalysis private[analyses] ( actualParams: Seq[Option[(ValueInformation, IntTrieSet)]], baseMatchers: Set[MethodMatcher], stmts: Array[Stmt[V]] - )(implicit indirectCalls: IndirectCalls, state: CGState[ContextType]): Set[MethodMatcher] = { + )(implicit indirectCalls: IndirectCalls, state: TACAIBasedCGState[ContextType]): Set[MethodMatcher] = { var matchers = baseMatchers stmts(constructorDefSite).asAssignment.expr match { case call @ VirtualFunctionCall( @@ -664,11 +664,11 @@ class ConstructorNewInstanceAnalysis private[analyses] ( matchers += PublicMethodMatcher } - implicit val highSoundness = HighSoundnessMode("method") + implicit val highSoundness: Boolean = HighSoundnessMode("method") matchers += MatcherUtil.retrieveParameterTypesBasedMethodMatcher(params.head, callPC, stmts) if (!matchers.contains(NoMethodsMatcher)) { - implicit val highSoundness = HighSoundnessMode("class") + implicit val highSoundness: Boolean = HighSoundnessMode("class") matchers += MatcherUtil.retrieveClassBasedMethodMatcher( context, receiver.asVar, @@ -703,7 +703,7 @@ class ConstructorNewInstanceAnalysis private[analyses] ( callPC: Int, params: Seq[Option[(ValueInformation, IntTrieSet)]], baseMatchers: Set[MethodMatcher] - )(implicit indirectCalls: IndirectCalls, state: CGState[ContextType]): Unit = { + )(implicit indirectCalls: IndirectCalls, state: TACAIBasedCGState[ContextType]): Unit = { if (HighSoundnessMode.contains(highSoundnessKey)) { addCalls(state.callContext, callPC, constructorReceiver(callPC), params, baseMatchers + AllMethodsMatcher) } else { @@ -736,7 +736,7 @@ class MethodInvokeAnalysis private[analyses] ( ): ProperPropertyComputationResult = { implicit val indirectCalls: IndirectCalls = new IndirectCalls() - implicit val state: CGState[ContextType] = new CGState[ContextType]( + implicit val state: TACAIBasedCGState[ContextType] = new TACAIBasedCGState[ContextType]( callerContext, FinalEP(callerContext.method.definedMethod, TheTACAI(tac)) ) @@ -753,7 +753,7 @@ class MethodInvokeAnalysis private[analyses] ( def returnResult( methodVar: V, indirectCalls: IndirectCalls - )(implicit state: CGState[ContextType]): ProperPropertyComputationResult = { + )(implicit state: TACAIBasedCGState[ContextType]): ProperPropertyComputationResult = { val results = indirectCalls.partialResults(state.callContext) if (state.hasOpenDependencies) Results( @@ -785,9 +785,9 @@ class MethodInvokeAnalysis private[analyses] ( Array[Stmt[V]] ) - def c(methodVar: V, state: CGState[ContextType])(eps: SomeEPS): ProperPropertyComputationResult = { + def c(methodVar: V, state: TACAIBasedCGState[ContextType])(eps: SomeEPS): ProperPropertyComputationResult = { implicit val indirectCalls: IndirectCalls = new IndirectCalls() - implicit val _state: CGState[ContextType] = state + implicit val _state: TACAIBasedCGState[ContextType] = state val epk = eps.toEPK @@ -803,7 +803,7 @@ class MethodInvokeAnalysis private[analyses] ( addCalls(state.callContext, callPC, _ => receiver, params, allMatchers) } else { - implicit val highSoundness = HighSoundnessMode("method") + implicit val highSoundness: Boolean = HighSoundnessMode("method") AllocationsUtil.continuationForAllocation[methodDependerType, ContextType]( eps, @@ -881,8 +881,8 @@ class MethodInvokeAnalysis private[analyses] ( private[this] def getClassMatcher( data: nameDependerType, matchers: Set[MethodMatcher] - )(implicit state: CGState[ContextType], indirectCalls: IndirectCalls): MethodMatcher = { - implicit val highSoundness = HighSoundnessMode("class") + )(implicit state: TACAIBasedCGState[ContextType], indirectCalls: IndirectCalls): MethodMatcher = { + implicit val highSoundness: Boolean = HighSoundnessMode("class") MatcherUtil.retrieveClassBasedMethodMatcher( data._8, data._7, @@ -901,8 +901,8 @@ class MethodInvokeAnalysis private[analyses] ( method: V, methodParams: Seq[Option[Expr[V]]], stmts: Array[Stmt[V]] - )(implicit state: CGState[ContextType], indirectCalls: IndirectCalls): Unit = { - implicit val highSoundness = HighSoundnessMode("method") + )(implicit state: TACAIBasedCGState[ContextType], indirectCalls: IndirectCalls): Unit = { + implicit val highSoundness: Boolean = HighSoundnessMode("method") val methodInvokeReceiver = methodParams.head.map(_.asVar) if (methodInvokeReceiver.isDefined) { @@ -962,8 +962,8 @@ class MethodInvokeAnalysis private[analyses] ( actualParams: Seq[Option[(ValueInformation, IntTrieSet)]], baseMatchers: Set[MethodMatcher], stmts: Array[Stmt[V]] - )(implicit indirectCalls: IndirectCalls, state: CGState[ContextType]): Set[MethodMatcher] = { - implicit val highSoundness = HighSoundnessMode("method") + )(implicit indirectCalls: IndirectCalls, state: TACAIBasedCGState[ContextType]): Set[MethodMatcher] = { + implicit val highSoundness: Boolean = HighSoundnessMode("method") var matchers = baseMatchers stmts(methodDefSite).asAssignment.expr match { @@ -1025,7 +1025,7 @@ class MethodInvokeAnalysis private[analyses] ( receiver: Option[(ValueInformation, IntTrieSet)], params: Seq[Option[(ValueInformation, IntTrieSet)]], baseMatchers: Set[MethodMatcher] - )(implicit indirectCalls: IndirectCalls, state: CGState[ContextType]): Unit = { + )(implicit indirectCalls: IndirectCalls, state: TACAIBasedCGState[ContextType]): Unit = { if (HighSoundnessMode.contains(highSoundnessKey)) { addCalls(state.callContext, callPC, _ => receiver, params, baseMatchers + AllMethodsMatcher) } else { @@ -1052,7 +1052,7 @@ class MethodHandleInvokeAnalysis private[analyses] ( ): ProperPropertyComputationResult = { implicit val indirectCalls: IndirectCalls = new IndirectCalls() - implicit val state: CGState[ContextType] = new CGState[ContextType]( + implicit val state: TACAIBasedCGState[ContextType] = new TACAIBasedCGState[ContextType]( callerContext, FinalEP(callerContext.method.definedMethod, TheTACAI(tac)) ) @@ -1085,7 +1085,7 @@ class MethodHandleInvokeAnalysis private[analyses] ( def returnResult( methodHandle: V, indirectCalls: IndirectCalls - )(implicit state: CGState[ContextType]): ProperPropertyComputationResult = { + )(implicit state: TACAIBasedCGState[ContextType]): ProperPropertyComputationResult = { val results = indirectCalls.partialResults(state.callContext) if (state.hasOpenDependencies) Results( @@ -1116,9 +1116,9 @@ class MethodHandleInvokeAnalysis private[analyses] ( private type classDependerType = (Int, Boolean, Seq[Option[(ValueInformation, IntTrieSet)]], Set[MethodMatcher], V, Array[Stmt[V]]) - def c(methodHandle: V, state: CGState[ContextType])(eps: SomeEPS): ProperPropertyComputationResult = { + def c(methodHandle: V, state: TACAIBasedCGState[ContextType])(eps: SomeEPS): ProperPropertyComputationResult = { implicit val indirectCalls: IndirectCalls = new IndirectCalls() - implicit val _state: CGState[ContextType] = state + implicit val _state: TACAIBasedCGState[ContextType] = state val epk = eps.toEPK @@ -1126,7 +1126,7 @@ class MethodHandleInvokeAnalysis private[analyses] ( val (callPC, isVirtual, params, matchers, _, _) = state.dependersOf(epk).head.asInstanceOf[classDependerType] val classes = eps.asInstanceOf[EPS[_, ForNameClasses]].ub.classes.flatMap { - case ot: ObjectType if isVirtual => project.classHierarchy.allSubtypes(ot, true) + case ot: ObjectType if isVirtual => project.classHierarchy.allSubtypes(ot, reflexive = true) case ot: ObjectType => Set(ot) case _: ArrayType => Set(ObjectType.Object) } @@ -1135,7 +1135,7 @@ class MethodHandleInvokeAnalysis private[analyses] ( addCalls(state.callContext, callPC, allMatchers, params) } else { - implicit val highSoundness = HighSoundnessMode("method") + implicit val highSoundness: Boolean = HighSoundnessMode("method") AllocationsUtil.continuationForAllocation[methodHandleDependerType, ContextType]( eps, @@ -1197,7 +1197,7 @@ class MethodHandleInvokeAnalysis private[analyses] ( () => failure("class", data._1, data._3, data._4), onlyObjectTypes = false ).flatMap { tpe => - if (data._2) project.classHierarchy.allSubtypes(tpe.asObjectType, true) + if (data._2) project.classHierarchy.allSubtypes(tpe.asObjectType, reflexive = true) else Set(if (tpe.isObjectType) tpe.asObjectType else ObjectType.Object) } @@ -1219,8 +1219,8 @@ class MethodHandleInvokeAnalysis private[analyses] ( private[this] def getClassMatcher( data: nameDependerType, matchers: Set[MethodMatcher] - )(implicit state: CGState[ContextType], indirectCalls: IndirectCalls): MethodMatcher = { - implicit val highSoundness = HighSoundnessMode("class") + )(implicit state: TACAIBasedCGState[ContextType], indirectCalls: IndirectCalls): MethodMatcher = { + implicit val highSoundness: Boolean = HighSoundnessMode("class") MatcherUtil.retrieveClassBasedMethodMatcher( data._8, data._7, @@ -1239,7 +1239,7 @@ class MethodHandleInvokeAnalysis private[analyses] ( callPC: Int, params: Seq[Option[(ValueInformation, IntTrieSet)]], baseMatchers: Set[MethodMatcher] - )(implicit indirectCalls: IndirectCalls, state: CGState[ContextType]): Unit = { + )(implicit indirectCalls: IndirectCalls, state: TACAIBasedCGState[ContextType]): Unit = { if (HighSoundnessMode.contains(highSoundnessKey)) { addCalls(state.callContext, callPC, baseMatchers + AllMethodsMatcher, params) } else { @@ -1255,7 +1255,7 @@ class MethodHandleInvokeAnalysis private[analyses] ( descriptorOpt: Option[MethodDescriptor], isSignaturePolymorphic: Boolean, stmts: Array[Stmt[V]] - )(implicit state: CGState[ContextType], indirectCalls: IndirectCalls): Unit = { + )(implicit state: TACAIBasedCGState[ContextType], indirectCalls: IndirectCalls): Unit = { // IMPROVE: for signature polymorphic calls, we could also use the method descriptor (return type) val actualInvokeParamsOpt = if (isSignaturePolymorphic) Some(invokeParams.map(_.map(_.asVar))) @@ -1311,7 +1311,7 @@ class MethodHandleInvokeAnalysis private[analyses] ( persistentActualParams: Seq[Option[(ValueInformation, IntTrieSet)]], baseMatchers: Set[MethodMatcher], stmts: Array[Stmt[V]] - )(implicit indirectCalls: IndirectCalls, state: CGState[ContextType]): Set[MethodMatcher] = { + )(implicit indirectCalls: IndirectCalls, state: TACAIBasedCGState[ContextType]): Set[MethodMatcher] = { var matchers = baseMatchers val definition = stmts(methodHandleDefSite).asAssignment.expr @@ -1338,7 +1338,10 @@ class MethodHandleInvokeAnalysis private[analyses] ( if (rcvr.isNull.isYes) Set.empty[ObjectType] else if (rcvr.leastUpperType.get.isArrayType) Set(ObjectType.Object) else if (rcvr.isPrecise) Set(rcvr.leastUpperType.get.asObjectType) - else project.classHierarchy.allSubtypes(rcvr.leastUpperType.get.asObjectType, true) + else project.classHierarchy.allSubtypes( + rcvr.leastUpperType.get.asObjectType, + reflexive = true + ) ) } else None @@ -1423,7 +1426,7 @@ class MethodHandleInvokeAnalysis private[analyses] ( project ) if (!matchers.contains(NoMethodsMatcher)) { - implicit val highSoundness = HighSoundnessMode("method") + implicit val highSoundness: Boolean = HighSoundnessMode("method") matchers += (if (isConstructor) MatcherUtil.constructorMatcher else MatcherUtil.retrieveNameBasedMethodMatcher( @@ -1452,7 +1455,7 @@ class MethodHandleInvokeAnalysis private[analyses] ( else if (rcvr.isPrecise) Set(rcvr.leastUpperType.get.asObjectType) else project.classHierarchy.allSubtypes( rcvr.leastUpperType.get.asObjectType, - true + reflexive = true ) ) } diff --git a/OPAL/tac/src/main/scala/org/opalj/tac/fpcf/analyses/cg/xta/ArrayInstantiationsAnalysis.scala b/OPAL/tac/src/main/scala/org/opalj/tac/fpcf/analyses/cg/xta/ArrayInstantiationsAnalysis.scala index 25d111036f..d526c506a2 100644 --- a/OPAL/tac/src/main/scala/org/opalj/tac/fpcf/analyses/cg/xta/ArrayInstantiationsAnalysis.scala +++ b/OPAL/tac/src/main/scala/org/opalj/tac/fpcf/analyses/cg/xta/ArrayInstantiationsAnalysis.scala @@ -43,7 +43,7 @@ import org.opalj.tac.fpcf.properties.TACAI final class ArrayInstantiationsAnalysis( val project: SomeProject, selectSetEntity: TypeSetEntitySelector -) extends ReachableMethodAnalysis { +) extends DefinedBodyReachableMethodAnalysis { override def processMethod( callContext: ContextType, diff --git a/OPAL/tac/src/main/scala/org/opalj/tac/fpcf/analyses/cg/xta/TypePropagationAnalysis.scala b/OPAL/tac/src/main/scala/org/opalj/tac/fpcf/analyses/cg/xta/TypePropagationAnalysis.scala index c9d7318881..d5af0d3001 100644 --- a/OPAL/tac/src/main/scala/org/opalj/tac/fpcf/analyses/cg/xta/TypePropagationAnalysis.scala +++ b/OPAL/tac/src/main/scala/org/opalj/tac/fpcf/analyses/cg/xta/TypePropagationAnalysis.scala @@ -56,7 +56,7 @@ import org.opalj.tac.fpcf.properties.TACAI final class TypePropagationAnalysis private[analyses] ( val project: SomeProject, selectTypeSetEntity: TypeSetEntitySelector -) extends ReachableMethodAnalysis { +) extends DefinedBodyReachableMethodAnalysis { private[this] val debug = false private[this] val _trace: TypePropagationTrace = new TypePropagationTrace() diff --git a/OPAL/tac/src/main/scala/org/opalj/tac/fpcf/analyses/fieldaccess/FieldAccessInformationAnalysis.scala b/OPAL/tac/src/main/scala/org/opalj/tac/fpcf/analyses/fieldaccess/FieldAccessInformationAnalysis.scala index 1350a201c5..783034e206 100644 --- a/OPAL/tac/src/main/scala/org/opalj/tac/fpcf/analyses/fieldaccess/FieldAccessInformationAnalysis.scala +++ b/OPAL/tac/src/main/scala/org/opalj/tac/fpcf/analyses/fieldaccess/FieldAccessInformationAnalysis.scala @@ -37,7 +37,7 @@ import org.opalj.fpcf.Results import org.opalj.fpcf.SomeEPS import org.opalj.fpcf.UBP import org.opalj.tac.fpcf.analyses.cg.BaseAnalysisState -import org.opalj.tac.fpcf.analyses.cg.ReachableMethodAnalysis +import org.opalj.tac.fpcf.analyses.cg.DefinedBodyReachableMethodAnalysis import org.opalj.tac.fpcf.analyses.cg.persistentUVar import org.opalj.tac.fpcf.properties.TACAI import org.opalj.tac.fpcf.properties.TheTACAI @@ -166,7 +166,7 @@ private[fieldaccess] class EagerTacBasedFieldAccessInformationAnalysis( private[fieldaccess] class ReachableTacBasedFieldAccessInformationAnalysis( val project: SomeProject -) extends FieldAccessInformationAnalysis with ReachableMethodAnalysis { +) extends FieldAccessInformationAnalysis with DefinedBodyReachableMethodAnalysis { override def processMethod(callContext: ContextType, tacEP: EPS[Method, TACAI]): ProperPropertyComputationResult = { implicit val state: State = new State(callContext, tacEP) diff --git a/OPAL/tac/src/main/scala/org/opalj/tac/fpcf/analyses/pointsto/AbstractPointsToAnalysis.scala b/OPAL/tac/src/main/scala/org/opalj/tac/fpcf/analyses/pointsto/AbstractPointsToAnalysis.scala index 2a8c5efedd..3961387c3d 100644 --- a/OPAL/tac/src/main/scala/org/opalj/tac/fpcf/analyses/pointsto/AbstractPointsToAnalysis.scala +++ b/OPAL/tac/src/main/scala/org/opalj/tac/fpcf/analyses/pointsto/AbstractPointsToAnalysis.scala @@ -51,7 +51,7 @@ import org.opalj.fpcf.UBP import org.opalj.log.OPALLogger.logOnce import org.opalj.log.Warn import org.opalj.tac.common.DefinitionSite -import org.opalj.tac.fpcf.analyses.cg.ReachableMethodAnalysis +import org.opalj.tac.fpcf.analyses.cg.DefinedBodyReachableMethodAnalysis import org.opalj.tac.fpcf.properties.TACAI import org.opalj.value.IsMultipleReferenceValue import org.opalj.value.IsReferenceValue @@ -64,7 +64,7 @@ import org.opalj.value.ValueInformation * * @author Florian Kuebler */ -trait AbstractPointsToAnalysis extends PointsToAnalysisBase with ReachableMethodAnalysis { +trait AbstractPointsToAnalysis extends PointsToAnalysisBase with DefinedBodyReachableMethodAnalysis { override def processMethod( callContext: ContextType, @@ -78,7 +78,7 @@ trait AbstractPointsToAnalysis extends PointsToAnalysisBase with ReachableMethod private[this] def doProcessMethod( implicit state: State ): ProperPropertyComputationResult = { - if (state.hasTACDependee) + if (state.isTACDependeeRefinable) throw new IllegalStateException("points to analysis does not support refinement based tac") val tac = state.tac val method = state.callContext.method.definedMethod