#java #eclipse #abstract-syntax-tree
#java #eclipse #абстрактное синтаксическое дерево
Вопрос:
Как я могу получить имена методов, вызываемых в каждом объявлении метода программы, используя анализатор AST (абстрактного синтаксического дерева)? До сих пор мне удалось получить все имена объявления методов и все имена вызываемых методов, но я хочу знать, какой метод какие методы вызывает. Например, я хочу видеть, что метод m1
вызывает методы mA
и mB
, в то время как метод m2
вызывает методы mC
и mD
и т.д.
[РЕДАКТИРОВАТЬ 9.11.2011 IDB, переписывая расширенный комментарий новичка обратно в текст исходного вопроса. Надеюсь, я правильно ее расшифровал. Я надеюсь, что автор вернется и исправит по мере необходимости]:
Моя проблема, похоже, заключается в том, что в API-интерфейсе MethodDeclaration (Eclipse) нет функции getinvokedmethod для вызова. Вот мой код:
public class MethodVisitor extends ASTVisitor {
List<MethodDeclaration> methods = new ArrayList<MethodDeclaration>();
@Override public boolean visit(MethodDeclaration node) {
methods.add(node);
return super.visit(node); }
public List<MethodDeclaration> getMethods()
{ return methods; }
List<MethodInvocation> methods1 = new ArrayList<MethodInvocation>();
@Override public boolean visit(MethodInvocation node)
{ methods1.add(node);
return super.visit(node); }
public List<MethodInvocation> getMethods1()
{ return methods1; }
}
...
for (MethodDeclaration method : visitor .getMethods())
{ System.out.println("Method name: " method.getName()
" Return type: " method.getReturnType2()
" Is constructor: " method.isConstructor()
" Method invoked: " ASTNode.METHOD_INVOCATION );
); }
for (MethodInvocation method1 : visitor .getMethods1())
{ System.out.println("Method name invoked: " method1.getName() ); }
Ответ №1:
У меня была такая же проблема. Это было мое решение:
final HashMap<MethodDeclaration, ArrayList<MethodInvocation>> invocationsForMethods =
new HashMap<MethodDeclaration, ArrayList<MethodInvocation>>();
CompilationUnit cu = (CompilationUnit) ap.createAST(null);
cu.accept(new ASTVisitor() {
private MethodDeclaration activeMethod;
@Override
public boolean visit(MethodDeclaration node) {
activeMethod = node;
return super.visit(node);
}
@Override
public boolean visit(MethodInvocation node) {
if (invocationsForMethods.get(activeMethod) == null) {
invocationsForMethods.put(activeMethod, new ArrayList<MethodInvocation>());
}
invocationsForMethods.get(activeMethod).add(node);
return super.visit(node);
}
});
Теперь можно попросить invocationsForMethods.keySet()
получить все объявления метода для используемого AST
и invocationsForMethods.get(key)
возвращает все вызовы метода для объявления, заданного в качестве ключа.
Ответ №2:
Если вы хотите знать, какой конкретный метод mB (из всех, которые называются «mB» во всем вашем обширном массиве классов) вызывается m1, вам нужно больше, чем просто AST. Вам нужна полная таблица символов, которая связывает использование каждого символа с возможными определениями, которые ему соответствуют.
Процесс вычисления такой таблицы символов сложен для многих языков и очень сложен для Java (но далеко не так плох, как для C ). Кто-то должен закодировать правила поиска идентификатора в условиях (локальных) областей, наследования, перегрузок, подразумеваемых приведений и т.д., И справочное руководство по Java посвящает значительную часть своего содержимого объяснению этого. Вы не хотите делать это самостоятельно.
Что вам действительно нужно, так это полный интерфейс Java, в котором есть как AST, так и соответствующие таблицы символов для каждого метода, который вы хотите проверить. Я думаю, вы можете получить это из интерфейсов к (Sun?) Компилятор Java (я лично не знаю, как это сделать), из компилятора Jikes, из модуля Eclipse Java AST (?) и из таких инструментов, как наш интерфейс Java. Другой подход заключается в обработке файлов классов, которые содержат вызовы методов в форме JVM, с преимуществом, которое все инструкции JVM создали с использованием таблицы символов.
Если вы хотите вычислить вызовы m1, mA вызывает вызовы mQ …. mZ, вам нужен инструмент, который готов читать всю базу исходного кода сразу. Компиляторы не сделают этого за вас, но вы можете использовать Eclipse или наш интерфейс для этого.
Комментарии:
1. Спирос: Дополнительная информация, которую вы предоставили в качестве справочной информации к вашему вопросу, действительно должна быть добавлена к самому вопросу. После разбиения ваших блоков кода на фрагменты размером с комментарий должно быть очевидно, что он в основном нечитаем. Вполне вероятно, что другие, читающие мой ответ, могут пропустить эти комментарии и пропустят дополнительные. Вы можете отредактировать свой вопрос; смотрите «кнопку» ** редактировать ** под вашим вопросом. Я беру на себя смелость перенести добавленные вами комментарии в ваш вопрос (высокого ранга, чтобы пользователи могли это сделать), чтобы помочь вам. Чтобы завершить эту очистку, вы можете удалить эти комментарии.