OPAL:为什么在将代码外化到方法中之后再也找不到 SingleOriginReference?
OPAL: Why can SingleOriginReference not be found any more after externalizing code into a method?
我正在使用 OPAL 框架开发 Java 字节码的静态分析。
我目前需要更改代码结构,以添加一些功能。
这起源于一个大方法,我不得不将其中的一部分外化到一个单独的方法中:
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])]()
}
}
这就是为什么我将末尾的大 if 块外部化为一个单独的方法:
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])]()
}
}
出于任何原因,我现在在 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))
错误信息如下:
type SingleOriginReferenceValue is not a member of org.opalj.ai.Domain
和
value MultipleReferenceValues is not a member of org.opalj.ai.Domain
在我将这个 if 块外部化为一个单独的方法之前,这些错误消息并没有出现。
将这些行更改为
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))
并进行导入
导入 org.opalj.ai.domain.l1.ReferenceValues.SingleOriginReferenceValue
导入 org.opalj.ai.domain.l1.ReferenceValues.MultipleReferenceValues
也无济于事。
谁能告诉我,这是怎么回事?
在这种情况下,您需要(为助手)指定您需要具有特定类型域的 AIResult。 (OPAL-AI 大量使用所谓的路径依赖类型。)
辅助方法签名的以下更改应该有所帮助:
def evaluateAIResult(
analysisResult: AIResult { val domain: l1.DefaultDomain /*or whatever your domain requirements are*/},
pc: Int,
calleeDescriptor: MethodDescriptor,
callDescriptor: MethodDescriptor): Iterable[(Int, Set[FieldType])] = {...
我正在使用 OPAL 框架开发 Java 字节码的静态分析。
我目前需要更改代码结构,以添加一些功能。
这起源于一个大方法,我不得不将其中的一部分外化到一个单独的方法中:
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])]()
}
}
这就是为什么我将末尾的大 if 块外部化为一个单独的方法:
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])]()
}
}
出于任何原因,我现在在 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))
错误信息如下:
type SingleOriginReferenceValue is not a member of org.opalj.ai.Domain
和
value MultipleReferenceValues is not a member of org.opalj.ai.Domain
在我将这个 if 块外部化为一个单独的方法之前,这些错误消息并没有出现。 将这些行更改为
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))
并进行导入 导入 org.opalj.ai.domain.l1.ReferenceValues.SingleOriginReferenceValue 导入 org.opalj.ai.domain.l1.ReferenceValues.MultipleReferenceValues 也无济于事。
谁能告诉我,这是怎么回事?
在这种情况下,您需要(为助手)指定您需要具有特定类型域的 AIResult。 (OPAL-AI 大量使用所谓的路径依赖类型。)
辅助方法签名的以下更改应该有所帮助:
def evaluateAIResult(
analysisResult: AIResult { val domain: l1.DefaultDomain /*or whatever your domain requirements are*/},
pc: Int,
calleeDescriptor: MethodDescriptor,
callDescriptor: MethodDescriptor): Iterable[(Int, Set[FieldType])] = {...