2016-06-12 1 views
0

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?

Répondre

2

Dans ce cas, vous devez spécifier (pour l'assistant) que vous avez besoin d'un AIResult avec un type spécifique de domaine. (OPAL-AI fait un usage intensif de la soi-disant types dépendant de chemin.)

La modification suivante de la signature de la méthode d'aide doit aider:

def evaluateAIResult(
    analysisResult: AIResult { val domain: l1.DefaultDomain /*or whatever your domain requirements are*/}, 
    pc: Int, 
    calleeDescriptor: MethodDescriptor, 
    callDescriptor: MethodDescriptor): Iterable[(Int, Set[FieldType])] = {... 
+0

Merci, cela a fonctionné pour moi. Mais j'ai dû changer DefaultDomain à DefaultDomain [URL]. – mariotrageser