BCEL - Como capturar todos os métodos predecessores?

3 respostas
Tiago_Farias

Olá galera!

Estou utilizando a lib BCEL pra analisar bytecode. Já consigo ler as estruturas básicas das classes como métodos, atributos, blocos static e etc. Agora minha dúvida é:

como retornar todos os métodos que podem anteceder a chamada de um método, digamos, m() ?

Ex: Suponha que meu no meu fluxo de programa eu tenha: a() q chama b() q chama c() ou m(). Se eu pedir os ancestrais ou predecessores de m() ele deve me mostrar a() e b(). O mesmo ocorrendo com c(), que tem como predecessores a() e b().

Qualquer ajuda será grandemente apreciada!

Vlw!

3 Respostas

T

Você pode fazer ao contrário (localizar os métodos que o método “a” chama); acho que isso é possível em BCEL. Uma vez feito isso, você pode “inverter” sua estrutura de dados.

Tiago_Farias

Entendi. Mas acho q não entendi a parte de "inverter " a estrutura de dados. Ou melhor, entendi mas não consegui encontrar ligação… Porque se eu tenho os métodos que a() chama (ex: b(), c() e d()), não significa que ao olhar para d() eu saberei que a() o chama. Entende? Não sei se foi isso q vc quis dizer… mas to no aguardo da resposta. =]

Vlw!

T

Basicamente você precisa inverter uma "call tree" (árvore de chamadas).

Digamos que você tenha uma lista de métodos (para simplificar, vou representar os métodos pelos seus nomes):

List <String> metodos;

E a seguir, um mapa nome do método -> nomes dos métodos chamados:

Map <String, List ><String> > metodo2chamados;

Para você determinar quais são os métodos "chamadores" (é o que você quer, na verdade), basta percorrer o mapa metodo2chamados, mais ou menos assim:
import java.util.*;

class ExemploCallTree {
    // utilitário
    // Usamos a chave &quot;s&quot; para inserir em &quot;m&quot; o valor &quot;t&quot;.
    private void insert (Map &lt; String, Set &lt; String &gt; &gt;  m, String s, String t) {
        Set &lt; String&gt; v;
        if (m.containsKey (s)) {
            v = m.get (s);
        } else {
            v = new TreeSet &lt; String&gt;();
            m.put (s, v);
        }
        v.add (t);
    }
    public Map &lt; String, Set &lt; String &gt; &gt;  carregarMetodosChamados() {
        Map &lt; String, Set &lt; String &gt; &gt;  m = new TreeMap &lt; String, Set &lt; String &gt; &gt; ();
        // O método a chama b
        insert (m, &quot;a&quot;, &quot;b&quot;);
        // O método b chama c ou m
        insert (m, &quot;b&quot;, &quot;c&quot;);
        insert (m, &quot;b&quot;, &quot;m&quot;);
        return m;
    }
    // note que aqui estamos invertendo a árvore mas determinando apenas o
    // primeiro nivel de chamadas. Para termos mais niveis, temos de tomar cuidado
    // com rotinas recursivas ou mutuamente recursivas. 
    public Map &lt; String, Set &lt; String &gt; &gt;  determinarMetodosChamadores(Map &lt; String, Set &lt; String &gt; &gt;  metodo2chamados) {
        Map &lt; String, Set &lt; String &gt; &gt;  metodo2chamadores = new TreeMap &lt; String, Set &lt; String &gt; &gt; ();
        for (Map.Entry&lt; String, Set &lt; String &gt; &gt;  entry : metodo2chamados.entrySet()) {
            String chamador = entry.getKey();
            for (String chamado : entry.getValue()) {
                insert (metodo2chamadores, chamado, chamador);
            }
        }
        return metodo2chamadores;
    }
 

    public static void main (String[] args) {
        ExemploCallTree ect = new ExemploCallTree();
        Map &lt; String, Set &lt; String &gt; &gt;  metodo2chamados = ect.carregarMetodosChamados();
        System.out.println (&quot;Metodo -&gt; metodos chamados&quot;);       
        System.out.println (metodo2chamados);
        System.out.println (&quot;Metodo -&gt; metodos chamadores (1 nivel apenas)&quot;);
        Map &lt; String, Set &lt; String &gt; &gt;  metodo2chamadores = ect.determinarMetodosChamadores(metodo2chamados);
        System.out.println (metodo2chamadores);
    }
}

Se você olhar a saída, vai ver que é um pouco diferente do que você está esperando. É que eu estou percorrendo apenas o primeiro nível (ou seja, eu sei que quem chama diretamente c é b, mas não mostro que a chama indiretamente c. Para fazer isso direito, eu precisaria levar em conta que rotinas podem ser recursivas ou mutuamente recursivas, senão o programa entraria em loop.

Criado 26 de março de 2009
Ultima resposta 26 de mar. de 2009
Respostas 3
Participantes 2