2010-12-01 28 views

Répondre

0

Décrochez la méthode LocalVariablesSorter.visitLocalVariable.

+0

Je l'ai déjà essayé d'utiliser visiLocalVariable mais je veux surveiller tous les accès aux variables et visitLocalVariable a été appelé seulement quand une variable locale a été déclarée – tomermes

+0

droit. Vous devrez maintenir vous-même une carte de l'index au nom de la variable (en fonction des appels à visitLocalvariable) si vous voulez l'utiliser dans un modèle de visiteur. – aioobe

+0

Bien sûr. Merci. – tomermes

2

J'utilise le code ci-dessous:

private LocalVariableNode getLocalVariableNode(VarInsnNode varInsnNode, MethodNode methodNode) { 
     int varIdx = varInsnNode.var; 
     int instrIdx = getInstrIndex(varInsnNode); 
     List<?> localVariables = methodNode.localVariables; 
     for (int idx = 0; idx < localVariables.size(); idx++) { 
      LocalVariableNode localVariableNode = (LocalVariableNode) localVariables.get(idx); 
      if (localVariableNode.index == varIdx) { 
       int scopeEndInstrIndex = getInstrIndex(localVariableNode.end); 
       if (scopeEndInstrIndex >= instrIdx) { 
        // still valid for current line 
        return localVariableNode; 
       } 
      } 
     } 
     throw new RuntimeException("Variable with index " + varIdx + " and scope end >= " + instrIdx 
       + " not found for method " + methodNode.name + "!"); 
    } 

Le problème général est que l'indice de la variable locale peut être réutilisée. Donc vous devez vous assurer que vous obtenez le bon LocalVariableNode correct pour un index donné. Pour ce faire, vous devez vous assurer que la variable donnée est toujours valide à l'emplacement du code où elle est utilisée. Le problème est que vous ne pouvez pas utiliser les numéros de ligne, parce que

  1. la position de départ est la ligne suivante de code après la variable a été définie. Puisque les lignes vides et les commentaires sont ignorés, cela peut être n'importe quelle ligne suivante. Mais puisque le code pourrait réutiliser une variable existante, ceci pourrait également être n'importe quelle ligne avant la ligne courante.

  2. la position de fin peut être avant la position de départ par ligne (par exemple dans une boucle).

  3. le code a peut-être été compilé sans informations de ligne.

Vous avez donc besoin d'utiliser l'index d'instructions, ce qui est toujours correct. Mais est une information interne dans AbstractInsnNode qui ne peut pas être accessible de l'extérieur. Pour contourner ce problème, j'utilise le code suivant, qui casse évidemment l'encapsulation et n'est pas recommandé pour un certain nombre de raisons. Si vous trouvez quelque chose de mieux, faites le moi savoir! Entre-temps, cela fonctionne:

private int getInstrIndex(AbstractInsnNode insnNode) { 
     try { 
      Field indexField = AbstractInsnNode.class.getDeclaredField("index"); 
      indexField.setAccessible(true); 
      Object indexValue = indexField.get(insnNode); 
      return ((Integer) indexValue).intValue(); 
     } catch (Exception exc) { 
      throw new RuntimeException(exc); 
     } 
    }