作为我的Eclipse插件项目的一部分,我需要跟踪方法的添加,删除和更改,以实现我所追求的功能。
通过JavaCore.addElementChangedListener
注册一个监听器并递归遍历IJavaElementDelta
,直到IJavaElementDelta.getElement()
提供对受影响方法的引用,我能够捕获方法的添加和删除。
E.g。我将方法a
添加到课程B
中我得到:
[Working copy] B.java[*]: {CHILDREN | FINE GRAINED | AST AFFECTED}
B[*]: {CHILDREN | FINE GRAINED}
a()[+]: {}]
问题是当编辑现有方法时不会发生这种情况:当我修改方法的实现并为其触发更改事件时,delta的解析在包含此方法的类中停止,而不是延伸到它
E.g。我在类a
中修改方法B
我得到了:
[Working copy] B.java[*]: {CONTENT | FINE GRAINED | AST AFFECTED}
此信息不包含有关方法a
的信息,即使其实现刚刚更改。此问题可能部分与此旧的Eclipse错误报告https://bugs.eclipse.org/bugs/show_bug.cgi?id=327753
因此,问题是:如何跟踪并获得有关其实施方式发生变化的方法的通知(无需多次构建和存储AST)?
答案 0 :(得分:1)
经过一番严谨的调查后,我得出的结论是,如果没有与AST相关的信息,就无法捕捉到方法内部的变化。因此,我一直在寻找最有效的方法来存储所需的最少信息,以及最适合比较这些信息的方法。
这是我提出的解决方案,根据几天的测试,它似乎足够高效,可以在每一个ElementChangedEvent
期间执行。
// during each user-invoked-compile, these are processed and cleared
private static HashMap<String, IMethod> added = new HashMap<String, IMethod>();
private static HashMap<String, IMethod> changed = new HashMap<String, IMethod>();
private static HashMap<String, IMethod> removed = new HashMap<String, IMethod>();
// this persists through out the entire session
private static HashMap<String, ASTNode> subtrees = new HashMap<String, ASTNode>();
private static void attachModelPart() {
JavaCore.addElementChangedListener(new IElementChangedListener() {
@Override
public void elementChanged(ElementChangedEvent event) {
... // added and removed IMethod handling
IJavaElementDelta delta = event.getDelta();
if (delta.getElement() instanceof CompilationUnit) {
delta.getCompilationUnitAST().accept(new ASTVisitor() {
@Override
public boolean visit(MethodDeclaration node) {
String mName = ((TypeDeclaration) node.getParent()).getName()
.getFullyQualifiedName() + "." + node.getName().getFullyQualifiedName();
// Finding match for this methods name(mName) in saved method subtrees...
boolean methodHasChanged = false;
if (subtrees.containsKey(mName)) {
// Found match
// Comparing new subtree to one saved during an earlier event (using ASTNode.subtreeMatch())
methodHasChanged = !node.subtreeMatch(new ASTMatcher(), subtrees.get(mName));
} else {
// No earlier entry found, definitely changed
methodHasChanged = true;
}
if (methodHasChanged) {
// "changed" is a HashMap of IMethods that have been earlierly identified as changed
// "added" works similarly but for added methods (using IJavaElementDelta.getAddedChildren())
if (!changed.containsKey(mName) && !added.containsKey(mName)) {
// Method has indeed changed and is not yet queued for further actions
changed.put(mName, (IMethod) node.resolveBinding().getJavaElement());
}
}
// "subtrees" must be updated with every method's AST subtree in order for this to work
subtrees.put(mName, node);
// continue visiting after first MethodDeclaration
return true;
}
});
}
}
}
}
非常欢迎评论!