自定义 Eclipse 重构预览中的错误

Posted

技术标签:

【中文标题】自定义 Eclipse 重构预览中的错误【英文标题】:Error in Preview of Custom Eclipse refactoring 【发布时间】:2010-12-17 20:03:23 【问题描述】:

我正在实施新的 Eclipse 重构。这将使开发人员能够将前置条件语句从子方法拉到父方法。

当我在重构向导中选择“完成”时,这一切都可以正常工作,但是当我选择“预览”时,我收到一个错误“没有提供目标编辑”。这似乎是由ASTRewrite.rewriteAST() 返回的TextEdit 中的问题引起的。但是我不知道为什么。

异常的堆栈跟踪发生在我的Refactoring.createChange() 代码运行后,更改用于生成预览。

org.eclipse.text.edits.MalformedTreeException: No target edit provided.
at org.eclipse.text.edits.MoveSourceEdit.performConsistencyCheck(MoveSourceEdit.java:208)
at org.eclipse.text.edits.TextEdit.traverseConsistencyCheck(TextEdit.java:873)
at org.eclipse.text.edits.MoveSourceEdit.traverseConsistencyCheck(MoveSourceEdit.java:183)
at org.eclipse.text.edits.TextEdit.traverseConsistencyCheck(TextEdit.java:869)
at org.eclipse.text.edits.TextEdit.traverseConsistencyCheck(TextEdit.java:869)
at org.eclipse.text.edits.TextEditProcessor.checkIntegrityDo(TextEditProcessor.java:176)
at org.eclipse.text.edits.TextEdit.dispatchCheckIntegrity(TextEdit.java:743)
at org.eclipse.text.edits.TextEditProcessor.performEdits(TextEditProcessor.java:151)
at org.eclipse.ltk.core.refactoring.TextChange.getPreviewDocument(TextChange.java:534)
at org.eclipse.ltk.core.refactoring.TextChange.getPreviewDocument(TextChange.java:403)
at org.eclipse.ltk.core.refactoring.TextChange.getPreviewContent(TextChange.java:411)
at org.eclipse.ltk.internal.ui.refactoring.TextEditChangePreviewViewer.setInput(TextEditChangePreviewViewer.java:209)
at org.eclipse.ltk.internal.ui.refactoring.AbstractChangeNode.feedInput(AbstractChangeNode.java:99)
at org.eclipse.ltk.internal.ui.refactoring.PreviewWizardPage.showPreview(PreviewWizardPage.java:598)
at org.eclipse.ltk.internal.ui.refactoring.PreviewWizardPage.access$6(PreviewWizardPage.java:583)
at org.eclipse.ltk.internal.ui.refactoring.PreviewWizardPage$7.selectionChanged(PreviewWizardPage.java:574)
at org.eclipse.jface.viewers.Viewer$2.run(Viewer.java:162)
at org.eclipse.core.runtime.SafeRunner.run(SafeRunner.java:42)
at org.eclipse.core.runtime.Platform.run(Platform.java:888)
at org.eclipse.ui.internal.JFaceUtil$1.run(JFaceUtil.java:48)
at org.eclipse.jface.util.SafeRunnable.run(SafeRunnable.java:175)
at org.eclipse.jface.viewers.Viewer.fireSelectionChanged(Viewer.java:160)
at org.eclipse.jface.viewers.StructuredViewer.updateSelection(StructuredViewer.java:2132)
at org.eclipse.jface.viewers.StructuredViewer.setSelection(StructuredViewer.java:1669)
at org.eclipse.jface.viewers.TreeViewer.setSelection(TreeViewer.java:1124)
at org.eclipse.jface.viewers.Viewer.setSelection(Viewer.java:392)
at org.eclipse.ltk.internal.ui.refactoring.PreviewWizardPage.setVisible(PreviewWizardPage.java:505)
at org.eclipse.ltk.internal.ui.refactoring.RefactoringWizardDialog2.makeVisible(RefactoringWizardDialog2.java:762)
at org.eclipse.ltk.internal.ui.refactoring.RefactoringWizardDialog2.showCurrentPage(RefactoringWizardDialog2.java:477)
at org.eclipse.ltk.internal.ui.refactoring.RefactoringWizardDialog2.nextOrPreviewPressed(RefactoringWizardDialog2.java:507)
at org.eclipse.ltk.internal.ui.refactoring.RefactoringWizardDialog2.access$2(RefactoringWizardDialog2.java:492)
at org.eclipse.ltk.internal.ui.refactoring.RefactoringWizardDialog2$1.widgetSelected(RefactoringWizardDialog2.java:691)
at org.eclipse.swt.widgets.TypedListener.handleEvent(TypedListener.java:228)
at org.eclipse.swt.widgets.EventTable.sendEvent(EventTable.java:84)
at org.eclipse.swt.widgets.Widget.sendEvent(Widget.java:1003)
at org.eclipse.swt.widgets.Display.runDeferredEvents(Display.java:3880)
at org.eclipse.swt.widgets.Display.readAndDispatch(Display.java:3473)
at org.eclipse.jface.window.Window.runEventLoop(Window.java:825)
at org.eclipse.jface.window.Window.open(Window.java:801)
at org.eclipse.ltk.ui.refactoring.RefactoringWizardOpenOperation$1.run(RefactoringWizardOpenOperation.java:143)
at org.eclipse.swt.custom.BusyIndicator.showWhile(BusyIndicator.java:70)
at org.eclipse.ltk.ui.refactoring.RefactoringWizardOpenOperation.run(RefactoringWizardOpenOperation.java:155)
at org.jmlspecs.eclipse.refactor.action.AbstractMethodActionDelegate.run(AbstractMethodActionDelegate.java:78)
at org.jmlspecs.eclipse.refactor.action.AbstractMethodActionDelegate.run(AbstractMethodActionDelegate.java:67)
at org.eclipse.ui.internal.PluginAction.runWithEvent(PluginAction.java:251)
at org.eclipse.jface.action.ActionContributionItem.handleWidgetSelection(ActionContributionItem.java:584)
at org.eclipse.jface.action.ActionContributionItem.access$2(ActionContributionItem.java:501)
at org.eclipse.jface.action.ActionContributionItem$6.handleEvent(ActionContributionItem.java:452)
at org.eclipse.swt.widgets.EventTable.sendEvent(EventTable.java:84)
at org.eclipse.swt.widgets.Widget.sendEvent(Widget.java:1003)
at org.eclipse.swt.widgets.Display.runDeferredEvents(Display.java:3880)
at org.eclipse.swt.widgets.Display.readAndDispatch(Display.java:3473)
at org.eclipse.ui.internal.Workbench.runEventLoop(Workbench.java:2405)
at org.eclipse.ui.internal.Workbench.runUI(Workbench.java:2369)
at org.eclipse.ui.internal.Workbench.access$4(Workbench.java:2221)
at org.eclipse.ui.internal.Workbench$5.run(Workbench.java:500)
at org.eclipse.core.databinding.observable.Realm.runWithDefault(Realm.java:332)
at org.eclipse.ui.internal.Workbench.createAndRunWorkbench(Workbench.java:493)
at org.eclipse.ui.PlatformUI.createAndRunWorkbench(PlatformUI.java:149)
at org.eclipse.ui.internal.ide.application.IDEApplication.start(IDEApplication.java:113)
at org.eclipse.equinox.internal.app.EclipseAppHandle.run(EclipseAppHandle.java:194)
at org.eclipse.core.runtime.internal.adaptor.EclipseAppLauncher.runApplication(EclipseAppLauncher.java:110)
at org.eclipse.core.runtime.internal.adaptor.EclipseAppLauncher.start(EclipseAppLauncher.java:79)
at org.eclipse.core.runtime.adaptor.EclipseStarter.run(EclipseStarter.java:368)
at org.eclipse.core.runtime.adaptor.EclipseStarter.run(EclipseStarter.java:179)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at org.eclipse.equinox.launcher.Main.invokeFramework(Main.java:559)
at org.eclipse.equinox.launcher.Main.basicRun(Main.java:514)
at org.eclipse.equinox.launcher.Main.run(Main.java:1311)
at org.eclipse.equinox.launcher.Main.main(Main.java:1287)

目前执行更改的代码如下所示:

CompilationUnit sourceNode = ...
ASTRewrite sourceRewrite = ASTRewrite.create(sourceNode.getAST());

Statement statement = ...
sourceRewrite.createMoveTarget(statement);

CompilationUnit destinationNode = ...
MethodDeclaration destinationMethod = ...
ASTRewrite destinationRewrite = ASTRewrite.create(destinationNode.getAST());

ListRewrite lrw = destinationRewrite.getListRewrite(destinationMethod.getBody(),
    Block.STATEMENTS_PROPERTY);

lrw.insertFirst(statement, null);

我知道createMoveTarget 的使用方式不是它的记录方式,但是当我按照下面的文档进行操作时,该语句已从源中删除但未移至目的地,我仍然得到相同的错误预览。

CompilationUnit sourceNode = ...
ASTRewrite sourceRewrite = ASTRewrite.create(sourceNode.getAST());

Statement statement = ...
Statement replacement = sourceRewrite.createMoveTarget(statement);
sourceRewrite.remove(statement, null);

CompilationUnit destinationNode = ...
MethodDeclaration destinationMethod = ...
ASTRewrite destinationRewrite = ASTRewrite.create(destinationNode.getAST());

ListRewrite lrw = destinationRewrite.getListRewrite(destinationMethod.getBody(),
    Block.STATEMENTS_PROPERTY);

lrw.insertFirst(replacement, null);

这是正在执行重构的示例。

之前:

class A 
    foo(int a) 
        return a * 2;
    


class B 
    foo(int a) 
        JC.requires(a > 1);

        return a * 3;
    

之后:

class A 
    foo(int a) 
        JC.requires(a > 1);

        return a * 2;
    


class B extends A 
    foo(int a)         
        return a * 3;
    

【问题讨论】:

您的重构示例实际上并不是重构,因为它会改变语义,但这取决于您。由于堆栈中的部分源不可用,因此很难判断代码有什么问题。也许您应该跟踪为什么没有调用 MoveSourceEdit.setTargetEdit 或使用 null 参数调用。 嗨,Petr,感谢您的建议。我将更详细地研究这一点,并将 Eclipse 重构与我自己的重构进行比较。关于重构规范时语义的变化,这是非常有趣的,因为它与该领域的大多数学术工作相呼应。然而 Fowler 的定义只保留了行为,例如 pull up 方法改变了类层次结构的语义。我可能会通过在语句中添加一个新子句来添加一个保留语义的选项。无论如何,我有兴趣与您进一步讨论这个问题。 【参考方案1】:

我发现 eclipse.org 文章对我入门最有帮助。

开始调试代码的一个好地方是在 org.eclipse.jdt.core.dom.rewrite.ASTRewrite 上设置断点,尤其是 rewriteAST() 方法,然后触发一些重构。

这里有一些你可能会觉得有用的。您是否正在寻找有关如何处理 AST 的具体内容或一般意义?

http://www.ibm.com/developerworks/opensource/library/os-ast/  
http://blog.sahits.ch/?p=228
http://www.vogella.com/articles/EclipseJDT/article.html

【讨论】:

您好,感谢您的提示和链接。我看到了 ibm 和 vogella 的链接,但没有看到另一个。自从我编写此代码以来已经有很长时间了,它是硕士论文的一部分,并且足够实用。我将在接下来的几周内挖掘代码,看看我是否能解决这个问题。每次调试jdt时我都迷路了。间接级别是无穷无尽的,库存重构是通过私有抽象层实现的,这使得它们难以破译。

以上是关于自定义 Eclipse 重构预览中的错误的主要内容,如果未能解决你的问题,请参考以下文章

Android布局预览器在添加自定义LinearLayout时抛出错误

Prorogate PassportJS 中的自定义错误

FastReports自定义预览问题

自定义微信分享链接(使用JS-SDK) + 实现预览pdf

闪烁窗口不适用于 TabbedThumbnail(自定义任务栏预览)

带有自定义预览的 WMD Markdown 编辑器