2

Eclipseプラグインプロジェクトの一環として、必要な機能を実装するために、メソッドの追加、削除、および変更を追跡する必要があります。

リスナーを登録し、が影響を受けるメソッドへの参照を与えるまでJavaCore.addElementChangedListener再帰的にトラバースすることで、メソッドの追加と削除をキャプチャできます。IJavaElementDeltaIJavaElementDelta.getElement()

たとえば、取得aしたクラスにメソッドを追加します。B

[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}

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 に答える