Tôi đang cố viết một bộ xử lý chú thích ở định dạng JSR 269 sử dụng API của trình biên dịch cây javac để thực hiện một số phân tích mã nguồn. Tôi quan tâm đến các biểu thức chọn thành viên, chẳng hạn như các cuộc gọi phương thức.Làm cách nào để nhận loại biểu thức trong MemberSelectTree từ plugin javac?
Tôi có thể dễ dàng nhận tên của phương thức (hoặc trường, v.v.) đang được chọn. Nhưng tôi muốn biết loại thành viên nào đang được chọn, và tôi dường như không thể tìm ra cách đơn giản để làm điều này. Trees.getTypeMirror
trả về null
cho tất cả mọi thứ tôi thử gọi nó trên (và Javadoc không đưa ra gợi ý).
Tôi cho rằng tôi thấu đáo có thể phân tích tất cả các loại biểu hiện ở phía bên trái của thành viên lựa chọn và xác định loại tĩnh của biểu thức bằng cách phân tích đệ quy: NewClassTree
, TypeCastTree
, MethodInvocationTree
, ArrayAccessTree
, và nhiều người khác. Nhưng điều này có vẻ như rất nhiều công việc dễ bị lỗi, và rõ ràng javac đã biết loại tĩnh của biểu thức vì nó cần thông tin này cho nhiều mục đích. Nhưng làm cách nào để tôi có quyền truy cập vào thông tin loại này?
Những gì tôi có cho đến nay:
import com.sun.source.tree.MemberSelectTree;
import com.sun.source.tree.MethodInvocationTree;
import com.sun.source.util.TreePath;
import com.sun.source.util.TreePathScanner;
import com.sun.source.util.Trees;
import java.util.Set;
import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.RoundEnvironment;
import javax.annotation.processing.SupportedAnnotationTypes;
import javax.annotation.processing.SupportedSourceVersion;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.Element;
import javax.lang.model.element.TypeElement;
@SupportedAnnotationTypes("*")
@SupportedSourceVersion(SourceVersion.RELEASE_6)
public class PublicProcessor extends AbstractProcessor {
public @Override boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
for (Element e : roundEnv.getRootElements()) {
final Trees trees = Trees.instance(processingEnv);
final TreePath root = trees.getPath(e);
new TreePathScanner<Void,Void>() {
public @Override Void visitMethodInvocation(MethodInvocationTree node, Void p) {
System.err.println("visiting method invocation: " + node + " of kind: " + node.getMethodSelect().getKind());
TreePath expr = TreePath.getPath(root, node);
System.err.println(" of type: " + trees.getTypeMirror(expr));
return super.visitMethodInvocation(node, p);
}
public @Override Void visitMemberSelect(MemberSelectTree node, Void p) {
System.err.println("accessing member: " + node.getIdentifier());
System.err.println(" from: " + getCurrentPath().getCompilationUnit().getSourceFile().toUri());
TreePath expr = TreePath.getPath(root, node.getExpression());
System.err.println(" in expr: " + expr.getLeaf());
System.err.println(" of type: " + trees.getTypeMirror(expr));
return super.visitMemberSelect(node, p);
}
}.scan(root, null);
}
return true;
}
}
và những gì nó in khi chạy trên một số phương pháp làm cho mã đơn giản gọi:
visiting method invocation: new Class().method() of kind: MEMBER_SELECT
of type: null
accessing member: method
from: .../Whatever.java
in expr: new Class()
of type: null
Cảm ơn câu hỏi đó, điều này thực sự là một ví dụ ngắn gọn cho API biên dịch cây. Đối với bản ghi, trên 'processingEnv' xuất phát từ phương thức' init (ProcessingEnvironment) 'cũng nên được ghi đè. Oh, và JRockit 1.6.0_29 vẫn hiển thị "null". – mgaert
Không cần ghi đè 'AbstractProcessor.init' trong hầu hết các trường hợp. –