RCP: JDT 根据org.eclipse.jdt.core.IJavaElement对象获取org.eclipse.jdt.core.dom.ASTNode对象

时间:2024-05-14 22:34:38

JDT中有两套Java文件模型映射。

其核心类\接口分别为:

org.eclipse.jdt.core.IJavaElement和org.eclipse.jdt.core.dom.ASTNode

IJavaElement是Java Element的通用“协议”,即是对Java包、类、方法、变量、注解等等元素的规范。

它可以用于映射java文件,也可以映射class文件,任何java方面的元素都能找到其对应的实现类。

ASTNode是Java ast(语法分析树)的建模,用于构建java语句,它只能用于java文件分析,对class文件无能为力。其侧重点是语法。

举个例子,一个类,比如java.util.List

在IJavaElement中要使用,必须有java.util.List作为IType存在。

在ASTNode中使用,则只需要用户知道“java.util.List"这个字符串即可。

IJavaElement常用于分析Java相关的元素

ASTNode常用来解析和构建Java文件

在实际使用中,我们经常会涉及到两个实现类之间的转化。

比如根据IMethod来查找MethodDeclaration

JDT提供了一个方法的工具类NodeFinder。使用方式如下:

NodeFinder.perform(domUnit,
method.getSourceRange())

这里要特别注意的是sourceRange,它代表了指定对象(类、方法等)在java类定义里的储存位置,它有两个标量,offset和length。

所以,我们还可以使用以下方式:

 NodeFinder.perform(domUnit,mj.getOffset(),ms.getLength());

这里要特别注意的地方是,如果该method的源码具备注释(comment),该方法会产生问题,会找不到MethodDeclaration,取而代之的是父级的TypeDeclaration。

原因在于jdt(至少是3.7.0及更早版本)的BUG,IMethod记录comment的offset和length,但是ASTNode并没有相应的记录,如果使用上方的方法,NodeFinder会认为范围超限,属于类范围而非方法范围。

所以,我们需要一个小小的改动:

IMethod method = (IMethod) methodElement
.getAncestor(IJavaElement.METHOD);
try {
ISourceRange ms = method.getSourceRange();
ISourceRange mj = method.getJavadocRange(); if (ms.getOffset() == mj.getOffset()) {
// 消除注释的影响
return (MethodDeclaration) NodeFinder.perform(domUnit,
method.getSourceRange());
} else {
return (MethodDeclaration) NodeFinder.perform(domUnit,
mj.getOffset(),
ms.getLength() - mj.getOffset() + ms.getOffset());
}
} catch (JavaModelException e) {
e.printStackTrace();
}

注意红色部分,它用于去除多余的注释部分,计算出准确的方法体范围。