Здесь есть несколько проблем. Вы можете либо заинтересоваться знанием типа Java получателя вызова метода, либо просто узнать, какой класс метода вызывается. Информация о Java более информативна, поскольку она также дает вам общие типы, например. List<String>
в то время как Elements предоставит вам только класс, например. List<E>
.
Получение элемента
Чтобы получить элемент класса, для которого вызывается метод, вы можете сделать следующее:
MethodInvocationTree node = ...;
Element method =
TreeInfo.symbol((JCTree)node.getMethodSelect());
TypeElement invokedClass = (TypeElement)method.getEnclosingElement();
Угловые случаи:
1. invokedClass может быть суперклассом типа приемника. Таким образом, запуск фрагмента на new ArrayList<String>.equals(null)
вернет AbstractList
, а не ArrayList
, поскольку equals() реализован в AbstractList
, а не ArrayList
.
2. При обработке вызовов массива, например. new int[].clone()
вы получите TypeElement
класса Array
.
Получение фактического типа
Чтобы получить тип, нет прямого способа определить тип получателя. Существует некоторая сложность в обработке вызовов методов во внутренних классах, где получатель не указан явно (например, в отличие от OuterClass.this.toString()
). Вот пример реализации:
MethodInvocationTree node = ...;
TypeMirror receiver;
if (methodSel.getKind() == Tree.Kind.MEMBER_SELECT) {
ExpressionTree receiver = ((MemberSelectTree)methodSel).getExpression();
receiverType = ((JCTree)receiver).type;
} else if (methodSel.getKind() == Tree.Kind.IDENTIFIER) {
// need to resolve implicit this, which is described in
// JLS3 15.12.1 and 15.9.2
// A bit too much work that I don't want to work on now
// Look at source code of
// Attr.visitApply(JCMethodInvocation)
// resolveImplicitThis(DiagnosticPosition, Env, Type)
} else
throw new AssertionError("Unexpected type: " + methodSel.getKind());
Примечание:
К сожалению, тип receiver
должен быть TypeMirror
, а не DeclaredType
. При вызове new int[5].clone()
receiver
будет ArrayType
из int[]
, что более информативно, чем предыдущий метод.
Запускаем
Оба предыдущих метода требуют, чтобы компилятор разрешил информацию о типе для классов. В обычных обстоятельствах компилятор разрешает только типы для объявлений методов, но не тела. Следовательно, описанные ранее методы вместо этого будут возвращать null
.
Чтобы компилятор разрешил информацию о типе, вы можете сделать это одним из следующих способов:
1. Используйте класс AbstractTypeProcessor
, который только что был добавлен в репозиторий компилятора для JDK 7. Ознакомьтесь с работой на JSR 308 и их компилятор. Хотя работа ведется в основном над аннотированными типами, она может быть полезна для. Компилятор позволяет вам использовать предоставленный класс обратно совместимым образом с Java 5.
Этот подход позволяет вам писать процессоры, которые вызываются точно так же, как ваши текущие процессоры.
2. Вместо этого используйте JavacTask
и вызовите JavacTask.analyze()
. Посмотрите на основной метод этот тест javac, чтобы узнать, как вызвать посетителя в классах.
Такой подход делает ваш процессор более похожим на инструмент анализа, чем на плагин к компилятору, поскольку вам нужно будет вызывать его напрямую, а не как обычный процесс.
person
notnoop
schedule
30.06.2009