2

作为我的 Eclipse 插件项目的一部分,我需要跟踪对方法的添加、删除和更改,以实现我所追求的功能。

通过注册侦听器JavaCore.addElementChangedListener并递归遍历IJavaElementDelta直到IJavaElementDelta.getElement()引用受影响的方法,我能够捕获方法的添加和删除。

例如,我将方法添加aB我得到的类中:

[Working copy] B.java[*]: {CHILDREN | FINE GRAINED | AST AFFECTED}
    B[*]: {CHILDREN | FINE GRAINED}
        a()[+]: {}]

问题是当编辑已经存在的方法时不会发生这种情况:当我修改方法的实现并为其触发更改事件时,增量的解析停止在包含此方法的类上,而不是扩展到它。

例如,我修改了我得到a的类中的方法B

[Working copy] B.java[*]: {CONTENT | FINE GRAINED | AST AFFECTED}

此信息不包含有关 method的信息a,即使它的实现刚刚更改。这个问题可能与这个旧的 Eclipse 错误报告有关https://bugs.eclipse.org/bugs/show_bug.cgi?id=327753

因此,问题是:如何跟踪并获得有关其实现已更改的方法的通知(无需多次构建和存储 AST)?

4

1 回答 1

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;
                    }
                });
            }
        }
    }
}

欢迎评论!

于 2013-03-27T10:37:34.590 回答