Je développe une analyse statique de Java Bytecode en utilisant le framework OPAL.OPAL: Pourquoi SingleOriginReference ne peut plus être trouvé après l'externalisation du code dans une méthode?
J'ai actuellement besoin de changer la structure du code, pour ajouter une fonctionnalité.
Cette origine dans une grande méthode, dont je dois extérioriser une partie dans une méthode distincte:
def singleCallUpperTypeBounds(
caller: Method,
pc: Int,
calleeDescriptor: MethodDescriptor,
project: Project[URL],
callGraph: CallGraph,
propertyStore: PropertyStore): Iterable[(Int, Set[FieldType])] = {
val classFile = project.classFile(caller)
val callDescriptor = caller.body.get.instructions(pc) match {
case INVOKEVIRTUAL(_, _, d) ⇒ d
case INVOKESPECIAL(_, _, d) ⇒ d
case INVOKESTATIC(_, _, d) ⇒ d
case INVOKEINTERFACE(_, _, d) ⇒ d
}
val analysisResult = if (!notClientCallable(caller, propertyStore) || worklist.contains(caller))
BaseAI.perform(classFile, caller, new DefaultDomain(project, classFile, caller))(None)
else {
val callerTypeMap = intermediateResult.getOrElse(caller, {
worklist = worklist.+:(caller)
val result = singleMethodUpperTypeBounds(caller, project, callGraph, propertyStore)
worklist = worklist.diff(Seq(caller))
result
})
//Create all combinations of the upper type bounds of the parameters.
//If a parameter is not in the TypeMap,
//e.g. because it is a primitive value, add it as a one element set.
val typeCombinations = allCombinations(caller.descriptor.parameterTypes.zipWithIndex.map {
case (t, index) =>
callerTypeMap.getOrElse(index,
Set[FieldType](caller.descriptor.parameterTypes(index)))
})
println(typeCombinations)
//TODO Use the type combinations
BaseAI.perform(classFile, caller, new DefaultDomain(project, classFile, caller))(None)
}
if (analysisResult.evaluatedInstructions.contains(pc))
for {
parameterIndex ← callDescriptor.parameterTypes.zipWithIndex.collect {
//we are not interested in primitive array types
case (t: ReferenceType, index) if {
//may be the case for sinature polymorphic methods
if (index >= calleeDescriptor.parametersCount) {
true
} else {
val expectedType = calleeDescriptor.parameterType(index)
!(expectedType.isArrayType && expectedType.asArrayType.elementType.isBaseType)
}
} ⇒ index
}
compileTimeType = callDescriptor.parameterType(parameterIndex)
stackIndex = (callDescriptor.parametersCount - 1) - parameterIndex
} yield {
val operand = analysisResult.operandsArray(pc)(stackIndex)
val runTimeTypes: Set[FieldType] = operand match {
case v: analysisResult.domain.SingleOriginReferenceValue ⇒
v.upperTypeBound.foldLeft(Set[FieldType]())((set, t) ⇒ set + t)
case analysisResult.domain.MultipleReferenceValues(singleOriginReferenceValues) ⇒
singleOriginReferenceValues.foldLeft(Set[FieldType]())((set, sorv) ⇒ set ++
sorv.upperTypeBound.foldLeft(Set[FieldType]())((s, t) ⇒ s + t))
}
(parameterIndex, runTimeTypes)
}
//If the call was not evaluated, it is on a dead path. So ignore this call.
else {
Set[(Int, Set[FieldType])]()
}
}
Voilà pourquoi j'externalisées grand si le bloc à la fin dans une méthode distincte:
def evaluateAIResult(
analysisResult: AIResult,
pc: Int,
calleeDescriptor: MethodDescriptor,
callDescriptor: MethodDescriptor): Iterable[(Int, Set[FieldType])] = {
if (analysisResult.evaluatedInstructions.contains(pc))
for {
parameterIndex ← callDescriptor.parameterTypes.zipWithIndex.collect {
//we are not interested in primitive array types
case (t: ReferenceType, index) if {
//may be the case for sinature polymorphic methods
if (index >= calleeDescriptor.parametersCount) {
true
} else {
val expectedType = calleeDescriptor.parameterType(index)
!(expectedType.isArrayType && expectedType.asArrayType.elementType.isBaseType)
}
} ⇒ index
}
compileTimeType = callDescriptor.parameterType(parameterIndex)
stackIndex = (callDescriptor.parametersCount - 1) - parameterIndex
} yield {
val operand = analysisResult.operandsArray(pc)(stackIndex)
val runTimeTypes: Set[FieldType] = operand match {
case v: analysisResult.domain.SingleOriginReferenceValue ⇒
v.upperTypeBound.foldLeft(Set[FieldType]())((set, t) ⇒ set + t)
case analysisResult.domain.MultipleReferenceValues(singleOriginReferenceValues) ⇒
singleOriginReferenceValues.foldLeft(Set[FieldType]())((set, sorv) ⇒ set ++
sorv.upperTypeBound.foldLeft(Set[FieldType]())((s, t) ⇒ s + t))
}
(parameterIndex, runTimeTypes)
}
//If the call was not evaluated, it is on a dead path. So ignore this call.
else {
Set[(Int, Set[FieldType])]()
}
}
pour une raison quelconque, je reçois maintenant des erreurs pour ces lignes Scala IDE:
case v: analysisResult.domain.SingleOriginReferenceValue ⇒
v.upperTypeBound.foldLeft(Set[FieldType]())((set, t) ⇒ set + t)
case analysisResult.domain.MultipleReferenceValues(singleOriginReferenceValues) ⇒
singleOriginReferenceValues.foldLeft(Set[FieldType]())((set, sorv) ⇒ set ++
sorv.upperTypeBound.foldLeft(Set[FieldType]())((s, t) ⇒ s + t))
Les messages d'erreur sont les suivantes:
Type SingleOriginReferenceValue ne fait pas partie de org.opalj.ai.Domain
et
valeur MultipleReferenceValues ne fait pas partie de l'organigramme. opalj.ai.Domain
Avant d'externaliser ce if-block dans une méthode distincte, ces messages d'erreur ot se produire. La modification de ces lignes à
case v: SingleOriginReferenceValue ⇒
v.upperTypeBound.foldLeft(Set[FieldType]())((set, t) ⇒ set + t)
case MultipleReferenceValues(singleOriginReferenceValues) ⇒
singleOriginReferenceValues.foldLeft(Set[FieldType]())((set, sorv) ⇒ set ++
sorv.upperTypeBound.foldLeft(Set[FieldType]())((s, t) ⇒ s + t))
et de faire les importations importation org.opalj.ai.domain.l1.ReferenceValues.SingleOriginReferenceValue org.opalj.ai.domain.l1.ReferenceValues.MultipleReferenceValues à l'importation ne pas non plus Aidez-moi.
Quelqu'un peut-il me dire, qu'est-ce qui ne va pas ici?
Merci, cela a fonctionné pour moi. Mais j'ai dû changer DefaultDomain à DefaultDomain [URL]. – mariotrageser