diff --git a/src/site/tutorial/ClassImmutabilityAnalysis.scala b/src/site/tutorial/ClassImmutabilityAnalysis.scala
index c40d6b5230..0b71c7d70c 100644
--- a/src/site/tutorial/ClassImmutabilityAnalysis.scala
+++ b/src/site/tutorial/ClassImmutabilityAnalysis.scala
@@ -10,12 +10,12 @@ import org.opalj.br.analyses.ProjectInformationKeys
import org.opalj.br.analyses.SomeProject
import org.opalj.br.fpcf.BasicFPCFEagerAnalysisScheduler
import org.opalj.br.fpcf.BasicFPCFLazyAnalysisScheduler
-import org.opalj.fpcf.FPCFAnalysesManagerKey
import org.opalj.br.fpcf.FPCFAnalysis
import org.opalj.br.fpcf.FPCFAnalysisScheduler
import org.opalj.fpcf.Entity
import org.opalj.fpcf.EOptionP
import org.opalj.fpcf.FallbackReason
+import org.opalj.fpcf.FPCFAnalysesManagerKey
import org.opalj.fpcf.InterimResult
import org.opalj.fpcf.OrderedProperty
import org.opalj.fpcf.ProperPropertyComputationResult
diff --git a/src/site/tutorial/CollaborativeAnalyses.md b/src/site/tutorial/CollaborativeAnalyses.md
index ebb6667751..cf2b78e2f9 100644
--- a/src/site/tutorial/CollaborativeAnalyses.md
+++ b/src/site/tutorial/CollaborativeAnalyses.md
@@ -50,12 +50,12 @@ Now, let's implement the (simplified) analysis.
As usual, we start by creating an analysis class with an analysis function:
```scala
class InstantiatedTypesAnalysis(val project: SomeProject) extends FPCFAnalysis {
- implicit private val declaredMethods: DeclaredMethods = project.get(DeclaredMethodsKey)
+ implicit private val contextProvider: ContextProvider = project.get(ContextProviderKey)
def analyzeMethod(method: DeclaredMethod): PropertyComputationResult = { [...] }
}
```
-We need a [`ProjectInformationKey`](/library/api/SNAPSHOT/org/opalj/br/analyses/ProjectInformationKey.html) here, namely the `DeclaredMethodsKey`, as this will later be needed implicitly to resolve calls with the call graph.
+We need a [`ProjectInformationKey`](/library/api/SNAPSHOT/org/opalj/br/analyses/ProjectInformationKey.html) here, namely the `ContextProviderKey`, as this will later be needed implicitly to resolve calls with the call graph.
The analysis function takes a [`DeclaredMethod`](/library/api/SNAPSHOT/org/opalj/br/DeclaredMethod.html) (a representation of a method in the context of its class) as the entity to be analyzed as we want to find all classes instantiated by methods that potentially called (i.e., that are not *dead*).
Note that unlike most analyses, we will however *not* compute a result just for this entity, we just use it to compute its effect on the set of instantiated classes *anywhere* in the analyzed program.
@@ -112,7 +112,7 @@ We use a [`PartialResult`](/library/api/SNAPSHOT/org/opalj/fpcf/NoResult.html) h
The partial result takes the entity (we use `project` here, since the set of instantiated classes is global to the whole program that is analyzed) and the key of the property that we compute.
Finally, it takes a function that will get the current value of that property and computes an update to it.
To do so, we check whether there already is a property present and extract its upper bound.
-If that upper bound already contains our class, we return `None` to signal that no update is necessary, otherwise we create an updated result, which is an [`InterimEUBP`](/library/api/SNAPSHOT/org/opalj/fpcf/InterimEUBP.html), i.e., a not yet final result consisting of an entity (`project`) and its property, which is the old set of instantiated classes extended by the class type of the analyzed constructor.
+If that upper bound already contains our class, we return `None` to signal that no update is necessary, otherwise we create an updated result, which is an [`InterimEUBP`](/library/api/SNAPSHOT/org/opalj/fpcf/InterimEUBP.html), i.e., a not yet final result consisting of an entity (E; `project`) and and upper bound (UB) for its property (P), which is the old set of instantiated classes extended by the class type of the analyzed constructor.
If, on the other hand, no property has been computed so far, the update function will be called with an [`EPK`](/library/api/SNAPSHOT/org/opalj/fpcf/EPK.html), i.e., a tuple of the entity and the key of the property.
In that case, we return property that contains just the class type of the analyzed constructor.
@@ -167,12 +167,13 @@ def checkCallers(callersProperty: EOptionP[DeclaredMethod, Callers]): PropertyCo
```
Now we can iterate over all callers known so far (the second part of the tuple, the actual program counter of the call is irrelevant here).
-The `callers` method implicitly requires the `DeclaredMethods`, which is why we got that at the beginning of our analysis class.
+The `callers` method takes the callee method (the entity `e` of our callers property) to properly resolve calls.
+It also implicitly requires the `ContextProvider`, which is why we got that at the beginning of our analysis class.
```scala
def checkCallers(callersProperty: EOptionP[DeclaredMethod, Callers]): PropertyComputationResult = {
[...]
- for((caller, _, isDirect) <- callers.callers) {
+ for((caller, _, isDirect) <- callers.callers(callersProperty.e)) {
if (!isDirect)
return result()
@@ -192,7 +193,7 @@ If it isn't, again the constructor must have been called explicitly.
If the caller is a constructor, we now check whether it belongs to a direct subclass:
```scala
-for((caller, _, isDirect) <- callers.callers){
+for((caller, _, isDirect) <- callers.callers(callersProperty.e)){
[...]
val callerClass = project.classFile(caller.declaringClassType)
@@ -209,7 +210,7 @@ The same is true if we know the class, but it has no superclass (this mainly con
If we didn't return a result yet, we have established that the caller is a constructor of a direct subclass.
However, it may still have an explicit call to the analyzed constructor, thus we have to look for such call in its instructions:
```scala
-for((caller, _, isDirect) <- callers.callers){
+for((caller, _, isDirect) <- callers.callers(callersProperty.e)){
[...]
val body = caller.definedMethod.body.get
@@ -224,14 +225,15 @@ Finally, they also can't be abstract or implemented by a native method, thus the
Now we can look for explicit instantiations of the analyzed constructor's class:
```scala
-for((caller, _, isDirect) <- callers.callers){
+for((caller, _, isDirect) <- callers.callers(callersProperty.e)){
[...]
- if(body.exists((_, instruction) => instruction == NEW(instantiatedType)))
+ if (body.exists(_.instruction == NEW(instantiatedType)))
return result()
}
```
-If there is a `NEW` instruction for that class, that is an explicit instantiation and we return a respective result.
+If there is a `NEW` instruction for that class, that is an explicit instantiation.
+Thus, we return a respective result.
Otherwise, we now know that this caller is a constructor of a direct subclass that only calls the analyzed constructor as part of its own initialization and thus, it doesn't actually instantiate the class of the analyzed constructor.
If we didn't find any caller that caused an explicit instantiation, there still might be more callers that we just don't know yet.
@@ -280,7 +282,7 @@ This completes our analysis, now we have to provide a scheduler for it.
We use an [`FPCFTriggeredAnalysisScheduler`](/library/api/SNAPSHOT/org/opalj/br/fpcf/FPCFTriggeredAnalysisScheduler.html)[note] that allows us to trigger our analysis whenever a method is found to be reachable in the call graph.
```scala
object InstantiatedTypesAnalysisScheduler extends BasicFPCFTriggeredAnalysisScheduler {
- override def requiredProjectInformation: ProjectInformationKeys = Seq(DeclaredMethodsKey)
+ override def requiredProjectInformation: ProjectInformationKeys = Seq(ContextProviderKey)
override def uses: Set[PropertyBounds] = PropertyBounds.ubs(InstantiatedTypes, Callers)
@@ -288,7 +290,7 @@ object InstantiatedTypesAnalysisScheduler extends BasicFPCFTriggeredAnalysisSche
}
```
As usual, we first have to provide the used `ProjectInformationKeys` and fixed-point properties.
-Remember we used the `DeclaredMethodsKey` in our analysis, so we have to specify it here.
+Remember we used the `ContextProviderKey` in our analysis, so we have to specify it here.
Also, we use upper bounds from the `InstantiatedTypes` and `Callers` lattices.
Note that `PropertyBounds.ubs(...)` is a shorthand for `Set(PropertyBounds.ub(...), ...)`.
@@ -333,7 +335,7 @@ As a last step, we implement a simple runner to test our analysis.
object InstantiatedTypesRunner extends ProjectAnalysisApplication {
override def doAnalyze(project: Project[URL], parameters: Seq[String], isInterrupted: () => Boolean): BasicReport = {
val (propertyStore, _) = project.get(FPCFAnalysesManagerKey).runAll(
- CHACallGraphAnalysisScheduler,
+ CallGraphAnalysisScheduler,
InstantiatedTypesAnalysisScheduler
)
@@ -346,7 +348,8 @@ object InstantiatedTypesRunner extends ProjectAnalysisApplication {
}
}
```
-It executes our analysis alongside a class-hierarchy analysis (CHA) call graph and prints the number of instantiated types to the console.
+It executes our analysis alongside a call-graph analysis and prints the number of instantiated types to the console.
+The kind of call-graph analysis executed actually depends on the `ContextProviderKey` (or rather its `TypeIterator` special case), which we didn't set up here, so it defaults to a class-hierarchy analysis (CHA).
Note that when querying the property store for the `InstantiatedTypes` property key, we know that it must be a final result because all analyses have been completed by that point.
Remember to specify the program that you want to analyze with the "-cp=" parameter.
diff --git a/src/site/tutorial/FixedPointAnalyses.md b/src/site/tutorial/FixedPointAnalyses.md
index b8e1143e87..18a01dade7 100644
--- a/src/site/tutorial/FixedPointAnalyses.md
+++ b/src/site/tutorial/FixedPointAnalyses.md
@@ -317,7 +317,7 @@ Because OPAL doesn't know in advance that we will only ever query the property s
Thus, we provide a second entry point to our analysis, `lazilyAnalyzeClassImmutability`, that takes any type of entity and, if it is a classfile, analyzes it.
We just throw an exception if the entity is not a classfile, as we can only process classfiles.
-Now we are ready to implement a [`FPCFLazyAnalysisScheduler`](/library/api/SNAPSHOT/org/opalj/br/fpcf/FPCFLazyAnalysisScheduler.html):
+Now we are ready to implement an [`FPCFLazyAnalysisScheduler`](/library/api/SNAPSHOT/org/opalj/br/fpcf/FPCFLazyAnalysisScheduler.html):
```scala
object LazyClassImmutabilityAnalysis extends ClassImmutabilityAnalysisScheduler with BasicFPCFLazyAnalysisScheduler {
@@ -338,7 +338,7 @@ As before, we finally have to return the analysis.
## Running the Analysis
Finally it is time to try our analysis.
-To do so easily, we extend [ProjectAnalysisApplication]() which provides us with an implicit `main` method that parses parameters for us, most importantly the "-cp=" parameter that lets users specify the path to a project that they want to analyze.
+To do so easily, we extend [ProjectAnalysisApplication](/library/api/SNAPSHOT/org/opalj/br/analyses/ProjectAnalysisApplication.html) which provides us with an implicit `main` method that parses parameters for us, most importantly the "-cp=" parameter that lets users specify the path to a project that they want to analyze.
```scala
object ClassImmutabilityRunner extends ProjectAnalysisApplication {
override def doAnalyze(project: Project[URL], parameters: Seq[String], isInterrupted: () => Boolean): BasicReport = { [...] }
@@ -356,7 +356,7 @@ override def doAnalyze(project: Project[URL], parameters: Seq[String], isInterru
[...]
}
```
-We use the [`FPCFAnalysesManagerKey`](/library/api/SNAPSHOT/org/opalj/br/fpcf/FPCFAnalysesManagerKey$.html) to get an [`FPCFAnalysesManager`](/library/api/SNAPSHOT/org/opalj/br/fpcf/FPCFAnalysesManager.html) that will run our analyses.
+We use the [`FPCFAnalysesManagerKey`](/library/api/SNAPSHOT/org/opalj/fpcf/FPCFAnalysesManagerKey$.html) to get an [`FPCFAnalysesManager`](/library/api/SNAPSHOT/org/opalj/fpcf/FPCFAnalysesManager.html) that will run our analyses.
We just pass all analyses that we want to execute to the `runAll` method.
Note that we assume that a `LazyFieldImmutabilityAnalysis` has been implemented as well.
As long as that doesn't exist, you can remove that line and OPAL will use the fallback value of the `FieldImmutability` lattice whenever a field immutability is queried.
diff --git a/src/site/tutorial/InstantiatedTypesAnalysis.scala b/src/site/tutorial/InstantiatedTypesAnalysis.scala
index 904c35fcaf..51b727f208 100644
--- a/src/site/tutorial/InstantiatedTypesAnalysis.scala
+++ b/src/site/tutorial/InstantiatedTypesAnalysis.scala
@@ -4,8 +4,6 @@ import org.opalj.collection.immutable.UIDSet
import org.opalj.br.DeclaredMethod
import org.opalj.br.ClassType
import org.opalj.br.analyses.BasicReport
-import org.opalj.br.analyses.DeclaredMethods
-import org.opalj.br.analyses.DeclaredMethodsKey
import org.opalj.br.analyses.Project
import org.opalj.br.analyses.ProjectAnalysisApplication
import org.opalj.br.analyses.ProjectInformationKeys
@@ -14,13 +12,15 @@ 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.br.fpcf.BasicFPCFTriggeredAnalysisScheduler
-import org.opalj.fpcf.FPCFAnalysesManagerKey
+import org.opalj.br.fpcf.ContextProviderKey
+import org.opalj.br.fpcf.analyses.ContextProvider
import org.opalj.br.instructions.NEW
import org.opalj.fpcf.Entity
import org.opalj.fpcf.EOptionP
import org.opalj.fpcf.EPK
import org.opalj.fpcf.FallbackReason
import org.opalj.fpcf.FinalP
+import org.opalj.fpcf.FPCFAnalysesManagerKey
import org.opalj.fpcf.InterimEUBP
import org.opalj.fpcf.InterimPartialResult
import org.opalj.fpcf.InterimUBP
@@ -36,7 +36,7 @@ import org.opalj.fpcf.PropertyMetaInformation
import org.opalj.fpcf.PropertyStore
import org.opalj.fpcf.SomeEPS
import org.opalj.fpcf.UBP
-import org.opalj.tac.fpcf.analyses.cg.CHACallGraphAnalysisScheduler
+import org.opalj.tac.fpcf.analyses.cg.CallGraphAnalysisScheduler
/* LATTICE */
@@ -69,7 +69,7 @@ object InstantiatedTypes extends InstantiatedTypesPropertyMetaInformation {
/* ANALYSIS */
class InstantiatedTypesAnalysis(val project: SomeProject) extends FPCFAnalysis {
- implicit private val declaredMethods: DeclaredMethods = project.get(DeclaredMethodsKey)
+ implicit private val contextProvider: ContextProvider = project.get(ContextProviderKey)
def analyzeMethod(method: DeclaredMethod): PropertyComputationResult = {
if (method.name != "")
@@ -111,7 +111,7 @@ class InstantiatedTypesAnalysis(val project: SomeProject) extends FPCFAnalysis {
if (callers.hasCallersWithUnknownContext || callers.hasVMLevelCallers)
return result()
- for ((caller, _, isDirect) <- callers.callers) {
+ for ((caller, _, isDirect) <- callers.callers(callersProperty.e)) {
if (!isDirect)
return result()
@@ -125,7 +125,7 @@ class InstantiatedTypesAnalysis(val project: SomeProject) extends FPCFAnalysis {
val body = caller.definedMethod.body.get
- if (body.exists((_, instruction) => instruction == NEW(instantiatedType)))
+ if (body.exists(_.instruction == NEW(instantiatedType)))
return result()
}
@@ -151,7 +151,7 @@ class InstantiatedTypesAnalysis(val project: SomeProject) extends FPCFAnalysis {
/* SCHEDULER */
object InstantiatedTypesAnalysisScheduler extends BasicFPCFTriggeredAnalysisScheduler {
- override def requiredProjectInformation: ProjectInformationKeys = Seq(DeclaredMethodsKey)
+ override def requiredProjectInformation: ProjectInformationKeys = Seq(ContextProviderKey)
override def uses: Set[PropertyBounds] = PropertyBounds.ubs(InstantiatedTypes, Callers)
@@ -173,7 +173,7 @@ object InstantiatedTypesAnalysisScheduler extends BasicFPCFTriggeredAnalysisSche
object InstantiatedTypesRunner extends ProjectAnalysisApplication {
override def doAnalyze(project: Project[URL], parameters: Seq[String], isInterrupted: () => Boolean): BasicReport = {
val (propertyStore, _) = project.get(FPCFAnalysesManagerKey).runAll(
- CHACallGraphAnalysisScheduler,
+ CallGraphAnalysisScheduler,
InstantiatedTypesAnalysisScheduler
)
diff --git a/src/site/tutorial/Lattices.md b/src/site/tutorial/Lattices.md
index e4c437b031..a1a0e1b47e 100644
--- a/src/site/tutorial/Lattices.md
+++ b/src/site/tutorial/Lattices.md
@@ -19,7 +19,7 @@ sealed trait ClassImmutabilityPropertyMetaInformation extends PropertyMetaInform
```
We use it to provide the type of the property.
-Second, the property companion object provides the [PropertyKey]():
+Second, the property companion object provides the [PropertyKey](/library/api/SNAPSHOT/org/opalj/fpcf/PropertyKey.html):
```scala
object ClassImmutability extends ClassImmutabilityPropertyMetaInformation {
final val key: PropertyKey[ClassImmutability] = PropertyKey.create(
@@ -99,7 +99,7 @@ override def checkIsEqualOrBetterThan(e: Entity, other: ClassImmutability): Unit
```
However, it may be better to provide optimized implementations for your individual lattice values if the `meet` operation is not trivial.
-The second option to consider is [`AggregatedProperty`](/library/api/SNAPSHOT/org/opalj/br/fpcf/properties/AggregatedProperty.html).
+The second option to consider is [`AggregatedProperty`](/library/api/SNAPSHOT/org/opalj/fpcf/AggregatedProperty.html).
Some properties really represent an aggregation of another property, e.g., `ClassImmutability` aggregates the `FieldImmutability` of a class' instance fields.
In such cases, one often needs to convert between corresponding values of the two lattices.
Also, the partial order and thus `meet` operator are equivalent and need to be defined only once.
diff --git a/src/site/tutorial/Schedulers.md b/src/site/tutorial/Schedulers.md
index 1eab30dcdf..906f612284 100644
--- a/src/site/tutorial/Schedulers.md
+++ b/src/site/tutorial/Schedulers.md
@@ -16,9 +16,9 @@ override def uses: Set[PropertyBounds] = Set(PropertyBounds.ub(FieldImmutability
```
This consists of two parts:
-First, `requiredProjectInformation` gives the [`ProjectInformationKey`s](/library/api/SNAPSHOT/org/opalj/br/analyses/ProjectInformationKey.html) that your analysis uses.
+First, `requiredProjectInformation` gives the [`ProjectInformationKey`s](/library/api/SNAPSHOT/org/opalj/si/ProjectInformationKey.html) that your analysis uses.
ProjectInformationKeys provide aggregated information about a project, such as a call graph or the set of methods that access each field.
-Here, we specified the [`FieldAccessInformationKey`](/library/api/SNAPSHOT/org/opalj/br/analyses/FieldAccessInformationKey$.html) that you can use with [`Project.get()`](/library/api/SNAPSHOT/org/opalj/br/analyses/Project.html#get[T%3C:AnyRef](pik:org.opalj.br.analyses.ProjectInformationKey[T,_]):T) to get [`FieldAccessInformation`](/library/api/SNAPSHOT/org/opalj/br/analyses/FieldAccessInformation.html), i.e., information about where each field is read or written.
+Here, we specified the [`FieldAccessInformationKey`](/library/api/SNAPSHOT/org/opalj/br/analyses/FieldAccessInformationKey$.html) that you can use with [`Project.get()`](/library/api/SNAPSHOT/org/opalj/si/Project.html#get[T%3C:AnyRef](pik:org.opalj.si.ProjectInformationKey[T,_]):T) to get [`FieldAccessInformation`](/library/api/SNAPSHOT/org/opalj/br/analyses/FieldAccessInformation.html), i.e., information about where each field is read or written.
Second, `uses` gives the results of fixed-point analyses that your analysis requires.
Here, our analysis uses upper bounds for both `FieldImmutability` and `ClassImmutability`.
@@ -30,7 +30,7 @@ Let's take a look at the individual scheduler types now.
## Eager Scheduling
-The [`FPCFEagerAnalysisScheduler`](/library/api/SNAPSHOT/org/opalj/br/fpcf/FPCFEagerAnalysisScheduler.html) is for simple analyses that compute some properties for a number of entities that you know in advance.
+The [`FPCFEagerAnalysisScheduler`](/library/api/SNAPSHOT/org/opalj/fpcf/FPCFEagerAnalysisScheduler.html) is for simple analyses that compute some properties for a number of entities that you know in advance.
For example, you could compute the immutability for all fields of all classes in your analyzed program like this:
```scala
object EagerFieldImmutabilityAnalysis extends BasicFPCFEagerAnalysisScheduler {
@@ -52,7 +52,7 @@ Note that you can specify more than just one type of result if your analysis com
[Collaborative Analyses](/tutorial/CollaborativeAnalyses.html) use the `derivesCollaboratively` instead and you can combine both if necessary.
The eager scheduler's entry point is the `start` method.
-You are given the [`Project`](/library/api/SNAPSHOT/org/opalj/br/analyses/Project.html), i.e., your analyzed program and the [`PropertyStore`](/library/api/SNAPSHOT/org/opalj/fpcf/PropertyStore.html) that will execute your analyses.
+You are given the [`Project`](/library/api/SNAPSHOT/org/opalj/si/Project.html), i.e., your analyzed program and the [`PropertyStore`](/library/api/SNAPSHOT/org/opalj/fpcf/PropertyStore.html) that will execute your analyses.
You can also get some initialization data if you need it, see [Advanced Scheduling](#advanced-scheduling) below for more information.
After creating your analysis, you use `scheduleEagerComputation` to schedule it.
@@ -62,7 +62,7 @@ In the end, you return your analysis object.
## Lazy Scheduling
-The [`FPCFLazyAnalysisScheduler`](/library/api/SNAPSHOT/org/opalj/br/fpcf/FPCFEagerAnalysisScheduler.html) lets you compute properties only for entities that need them, i.e., properties that are queried by other analyses[note].
+The [`FPCFLazyAnalysisScheduler`](/library/api/SNAPSHOT/org/opalj/fpcf/FPCFEagerAnalysisScheduler.html) lets you compute properties only for entities that need them, i.e., properties that are queried by other analyses[note].
Let's again implement a scheduler for a field immutability analysis:
```scala
object LazyFieldImmutabilityAnalysis extends BasicFPCFLazyAnalysisScheduler {
@@ -87,7 +87,7 @@ As before, the analysis function must return a PropertyComputationResult.
## Transformers
-The [`FPCFTransformerScheduler`](/library/api/SNAPSHOT/org/opalj/br/fpcf/FPCFTransformerScheduler.html) is a special kind of lazy scheduler.
+The [`FPCFTransformerScheduler`](/library/api/SNAPSHOT/org/opalj/fpcf/FPCFTransformerScheduler.html) is a special kind of lazy scheduler.
As with a lazy scheduler, properties are only computed for entities that are queried.
However, in contrast to the lazy scheduler, the analysis function is only called once some other property for the same entity has a final result.
@@ -118,7 +118,7 @@ The analysis function here takes two arguments: the entity (as with lazy schedul
## Triggered Scheduling
-The [`FPCFTriggeredAnalysisScheduler`](/library/api/SNAPSHOT/org/opalj/br/fpcf/FPCFTriggeredAnalysisScheduler.html) lets you start a computation for an entity only once you know that this entity does have some other property.
+The [`FPCFTriggeredAnalysisScheduler`](/library/api/SNAPSHOT/org/opalj/fpcf/FPCFTriggeredAnalysisScheduler.html) lets you start a computation for an entity only once you know that this entity does have some other property.
Different to a transformer, that other property does not have to have a final result yet, though.
Let's see an example of how to use this for a call graph module:
```scala