Bug 345342 - [typing][rename] Dialog-based rename type or compilation unit creates invalid undo in editor context
Summary: [typing][rename] Dialog-based rename type or compilation unit creates invalid...
Status: CLOSED WONTFIX
Alias: None
Product: JDT
Classification: Eclipse Project
Component: Text (show other bugs)
Version: 3.5.2   Edit
Hardware: All All
: P3 major (vote)
Target Milestone: ---   Edit
Assignee: JDT-Text-Inbox CLA
QA Contact:
URL:
Whiteboard: stalebug
Keywords: helpwanted
: 301746 417005 473920 (view as bug list)
Depends on:
Blocks:
 
Reported: 2011-05-10 17:46 EDT by Kris De Volder CLA
Modified: 2020-04-09 14:04 EDT (History)
7 users (show)

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Kris De Volder CLA 2011-05-10 17:46:59 EDT
Build Identifier: 20110301-1815

If we disable the "Rename in editor without dialog" option in the Java preferences page, then undo doesn't work properly for renames triggered from inside the editor.

Reproducible: Always

Steps to Reproduce:
1. Disable the "Rename in editor without dialog" option
2. Create an empty Java project.
3. Add a simple class. This one will do

public class Bar {
	Bar foo;
}

4. Select the name of class in the Java editor
5. Alt-Shift-R
6. Type "Foo" for the new name and click "Finish"
7. Click the edit menu and find "undo" item

Observed:
  - It says "Undo typing" instead of "Undo rename..."
  - Performing the undo marks the file as changed, but doesn't actually make any changes.
  - Trying to save the "changed" file produces an error

java.lang.IllegalArgumentException: Illegal value: -1
	at org.eclipse.core.internal.resources.Resource.revertModificationStamp(Resource.java:1702)
	at org.eclipse.core.internal.filebuffers.ResourceTextFileBuffer.commitFileBufferContent(ResourceTextFileBuffer.java:396)
	at org.eclipse.core.internal.filebuffers.ResourceFileBuffer.commit(ResourceFileBuffer.java:325)
	at org.eclipse.jdt.internal.ui.javaeditor.DocumentAdapter.save(DocumentAdapter.java:472)
	at org.eclipse.jdt.internal.core.CommitWorkingCopyOperation.executeOperation(CommitWorkingCopyOperation.java:123)
	at org.eclipse.jdt.internal.core.JavaModelOperation.run(JavaModelOperation.java:728)
	at org.eclipse.core.internal.resources.Workspace.run(Workspace.java:1975)
	at org.eclipse.jdt.internal.core.JavaModelOperation.runOperation(JavaModelOperation.java:793)
	at org.eclipse.jdt.internal.core.CompilationUnit.commitWorkingCopy(CompilationUnit.java:392)
	at org.eclipse.jdt.internal.ui.javaeditor.CompilationUnitDocumentProvider.commitWorkingCopy(CompilationUnitDocumentProvider.java:1361)
	at org.eclipse.jdt.internal.ui.javaeditor.CompilationUnitDocumentProvider$4.execute(CompilationUnitDocumentProvider.java:1432)
	at org.eclipse.ui.editors.text.TextFileDocumentProvider$DocumentProviderOperation.run(TextFileDocumentProvider.java:132)
	at org.eclipse.ui.actions.WorkspaceModifyDelegatingOperation.execute(WorkspaceModifyDelegatingOperation.java:69)
	at org.eclipse.ui.actions.WorkspaceModifyOperation$1.run(WorkspaceModifyOperation.java:106)
	at org.eclipse.core.internal.resources.Workspace.run(Workspace.java:1975)
	at org.eclipse.ui.actions.WorkspaceModifyOperation.run(WorkspaceModifyOperation.java:118)
	at org.eclipse.ui.internal.editors.text.WorkspaceOperationRunner.run(WorkspaceOperationRunner.java:75)
	at org.eclipse.ui.internal.editors.text.WorkspaceOperationRunner.run(WorkspaceOperationRunner.java:65)
	at org.eclipse.ui.editors.text.TextFileDocumentProvider.executeOperation(TextFileDocumentProvider.java:456)
	at org.eclipse.ui.editors.text.TextFileDocumentProvider.saveDocument(TextFileDocumentProvider.java:772)
	at org.eclipse.ui.texteditor.AbstractTextEditor.performSave(AbstractTextEditor.java:4879)
	at org.eclipse.jdt.internal.ui.javaeditor.CompilationUnitEditor.performSave(CompilationUnitEditor.java:1230)
	at org.eclipse.jdt.internal.ui.javaeditor.CompilationUnitEditor.doSave(CompilationUnitEditor.java:1283)
	at org.eclipse.ui.texteditor.AbstractTextEditor$TextEditorSavable.doSave(AbstractTextEditor.java:7003)
	at org.eclipse.ui.Saveable.doSave(Saveable.java:214)
	at org.eclipse.ui.internal.SaveableHelper.doSaveModel(SaveableHelper.java:349)
	at org.eclipse.ui.internal.SaveableHelper$3.run(SaveableHelper.java:195)
	at org.eclipse.ui.internal.SaveableHelper$5.run(SaveableHelper.java:277)
	at org.eclipse.jface.operation.ModalContext.runInCurrentThread(ModalContext.java:464)
	at org.eclipse.jface.operation.ModalContext.run(ModalContext.java:372)
	at org.eclipse.jface.window.ApplicationWindow$1.run(ApplicationWindow.java:759)
	at org.eclipse.swt.custom.BusyIndicator.showWhile(BusyIndicator.java:70)
	at org.eclipse.jface.window.ApplicationWindow.run(ApplicationWindow.java:756)
	at org.eclipse.ui.internal.WorkbenchWindow.run(WorkbenchWindow.java:2606)
	at org.eclipse.ui.internal.SaveableHelper.runProgressMonitorOperation(SaveableHelper.java:285)
	at org.eclipse.ui.internal.SaveableHelper.runProgressMonitorOperation(SaveableHelper.java:264)
	at org.eclipse.ui.internal.SaveableHelper.saveModels(SaveableHelper.java:207)
	at org.eclipse.ui.internal.SaveableHelper.savePart(SaveableHelper.java:144)
	at org.eclipse.ui.internal.EditorManager.savePart(EditorManager.java:1369)
	at org.eclipse.ui.internal.WorkbenchPage.savePart(WorkbenchPage.java:3334)
	at org.eclipse.ui.internal.WorkbenchPage.saveEditor(WorkbenchPage.java:3347)
	at org.eclipse.ui.internal.SaveAction.run(SaveAction.java:76)
	at org.eclipse.jface.action.Action.runWithEvent(Action.java:498)
	at org.eclipse.ui.commands.ActionHandler.execute(ActionHandler.java:185)
	at org.eclipse.ui.internal.handlers.LegacyHandlerWrapper.execute(LegacyHandlerWrapper.java:109)
	at org.eclipse.core.commands.Command.executeWithChecks(Command.java:476)
	at org.eclipse.core.commands.ParameterizedCommand.executeWithChecks(ParameterizedCommand.java:508)
	at org.eclipse.ui.internal.handlers.HandlerService.executeCommand(HandlerService.java:169)
	at org.eclipse.ui.internal.keys.WorkbenchKeyboard.executeCommand(WorkbenchKeyboard.java:468)
	at org.eclipse.ui.internal.keys.WorkbenchKeyboard.press(WorkbenchKeyboard.java:786)
	at org.eclipse.ui.internal.keys.WorkbenchKeyboard.processKeyEvent(WorkbenchKeyboard.java:885)
	at org.eclipse.ui.internal.keys.WorkbenchKeyboard.filterKeySequenceBindings(WorkbenchKeyboard.java:567)
	at org.eclipse.ui.internal.keys.WorkbenchKeyboard.access$3(WorkbenchKeyboard.java:508)
	at org.eclipse.ui.internal.keys.WorkbenchKeyboard$KeyDownFilter.handleEvent(WorkbenchKeyboard.java:123)
	at org.eclipse.swt.widgets.EventTable.sendEvent(EventTable.java:84)
	at org.eclipse.swt.widgets.Display.filterEvent(Display.java:1524)
	at org.eclipse.swt.widgets.Widget.sendEvent(Widget.java:1257)
	at org.eclipse.swt.widgets.Widget.sendEvent(Widget.java:1282)
	at org.eclipse.swt.widgets.Widget.sendEvent(Widget.java:1267)
	at org.eclipse.swt.widgets.Widget.sendKeyEvent(Widget.java:1294)
	at org.eclipse.swt.widgets.Widget.gtk_key_press_event(Widget.java:730)
	at org.eclipse.swt.widgets.Control.gtk_key_press_event(Control.java:2841)
	at org.eclipse.swt.widgets.Composite.gtk_key_press_event(Composite.java:734)
	at org.eclipse.swt.widgets.Widget.windowProc(Widget.java:1743)
	at org.eclipse.swt.widgets.Control.windowProc(Control.java:4796)
	at org.eclipse.swt.widgets.Display.windowProc(Display.java:4360)
	at org.eclipse.swt.internal.gtk.OS._gtk_main_do_event(Native Method)
	at org.eclipse.swt.internal.gtk.OS.gtk_main_do_event(OS.java:8189)
	at org.eclipse.swt.widgets.Display.eventProc(Display.java:1238)
	at org.eclipse.swt.internal.gtk.OS._g_main_context_iteration(Native Method)
	at org.eclipse.swt.internal.gtk.OS.g_main_context_iteration(OS.java:2237)
	at org.eclipse.swt.widgets.Display.readAndDispatch(Display.java:3159)
	at org.eclipse.ui.internal.Workbench.runEventLoop(Workbench.java:2640)
	at org.eclipse.ui.internal.Workbench.runUI(Workbench.java:2604)
	at org.eclipse.ui.internal.Workbench.access$4(Workbench.java:2438)
	at org.eclipse.ui.internal.Workbench$7.run(Workbench.java:671)
	at org.eclipse.core.databinding.observable.Realm.runWithDefault(Realm.java:332)
	at org.eclipse.ui.internal.Workbench.createAndRunWorkbench(Workbench.java:664)
	at org.eclipse.ui.PlatformUI.createAndRunWorkbench(PlatformUI.java:149)
	at org.eclipse.ui.internal.ide.application.IDEApplication.start(IDEApplication.java:115)
	at org.eclipse.equinox.internal.app.EclipseAppHandle.run(EclipseAppHandle.java:196)
	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:369)
	at org.eclipse.core.runtime.adaptor.EclipseStarter.run(EclipseStarter.java:179)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
	at java.lang.reflect.Method.invoke(Method.java:597)
	at org.eclipse.equinox.launcher.Main.invokeFramework(Main.java:620)
	at org.eclipse.equinox.launcher.Main.basicRun(Main.java:575)
	at org.eclipse.equinox.launcher.Main.run(Main.java:1408)
Comment 1 Kris De Volder CLA 2011-05-10 20:35:01 EDT
I've also been able to trigger (what I think is) the same bug by triggering the refactoring wizard from the package explorer.

How to reproduce.

First follow the same steps as described in the original bug report to create a simple test project.

Steps 1..4 as in orginal report
5. click the class in the package explorer and use "Refactor >> Rename" menu
6. type a new name and click finish.

Now... if you were to trigger the undo immediately from the menu it would work...

However, instead do

7. Click in the editor that has the class to make it get the focus
8. Now open the "Edit >> Undo" method from menu bar.

Observed:

Same as in original bug report:
  - it says "undo typing" (not undo rename)
  - undoing marks file as dirty but makes no aparant changes
  - trying to save the file causes an error "invalid argument -1"
Comment 2 Kris De Volder CLA 2011-05-10 20:38:48 EDT
BTW: it is important to note that given the second way to trigger the bug, it is probably a more significant problem, since the second method of triggering the bug
is possible with "Rename in editor without dialog" on its default setting.
Comment 3 Kris De Volder CLA 2011-05-10 20:52:23 EDT
I think the "weird" edit that causes trouble is the one created in

org.eclipse.text.undo.DocumentUndoManager

At around line 1279 in method transferUndoHistory

Seems to have something to do with copying undo history for a moving file.
Comment 4 Markus Keller CLA 2011-05-11 10:10:41 EDT
Also broken in 3.5.2 and in HEAD. To reproduce with the option enabled, you can also press Alt+Shift+R twice in the editor.

It's not that horrible when the type is inside a package. Then you also have the wrong "Undo Typing" in the editor, but at least the refactoring undo works in the Package Explorer.
Comment 5 Markus Keller CLA 2011-05-11 12:01:27 EDT
I quickly compared the "Rename in Editor" and "Rename in Package Explorer / via dialog" scenarios, and the difference seems to be that in the former case, in DefaultOperationHistory#add(IUndoableOperation) there's already an openComposite operation available, whereas in the latter case, the editor has not been touched and no batch operation is open to which the refactoring operations could be added.
Comment 6 Deepak Azad CLA 2012-01-27 10:36:01 EST
*** Bug 301746 has been marked as a duplicate of this bug. ***
Comment 7 Deepak Azad CLA 2012-01-27 10:40:55 EST
This also happens with Move Refactoring, or any ProcessorBasedRefactoring which moves a java file.
Comment 8 Deepak Azad CLA 2012-01-27 12:05:27 EST
If we can keep an "openComposite operation" in DefaultOperationHistory#add(IUndoableOperation) long enough things work..

For instance I tried introducing a delay in UndoManager2.changePerformed(Change, boolean) before closing the operation, and things work smoothly. Of course, we need a proper way to get the sequence of events right :-)

-------------------------------------------------------------------------
public void changePerformed(Change change, boolean successful) {
	if (fIsOpen && fActiveOperation != null) {
		try {
			Thread.sleep(5000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		fOperationHistory.closeOperation(successful, false, IOperationHistory.EXECUTE);
        fIsOpen= false;
	}
}
-------------------------------------------------------------------------
Comment 9 Deepak Azad CLA 2012-01-27 12:38:51 EST
If you move a java file via a quick assist e.g. using "Move 'A.java' to package 'p'" quick assist then things also work correctly as everything happens in the 'main' thread, and the sequence of events is (somehow) right. 

However, with Rename refactoring via dialog there are two threads involved, see PerformChangeOperation.executeChange(...).
Comment 10 Noopur Gupta CLA 2013-04-23 07:51:59 EDT
The issue is with the sequence of events in the threads of refactoring undo manager (UndoManager2) and DocumentUndoManager.
We need to wait inside UndoManager2.changePerformed(Change, boolean) before closing the composite operation i.e. we want to replace the timed sleep in comment #8 with some valid condition. 

We could try the following approaches:

- Listening to operation history events: 
Before closing the composite operation in refactoring undo manager, we need to know if text editor has finished working or more specifically if DocumentUndoManager has added the UndoableTextChange edit to the operation. 
If the operation is added to an open operation, no event notification is done by history. We get ADDED notification only if the operation is added separately. Hence, we will not get the ADDED notification from history when editor adds it to the open operation.
DONE is sent after closing or executing, but we need to wait before closing the operation.

- Undo contexts: by checking the validity of undo contexts.
Some undo context will probably be deleted because the undo manager gets disposed and recreated on file move, so we might have to add some new API where we can check whether the context is still valid or not.
In changePerformed(..) of refactoring undo manager, fActiveOperation (which is the open operation in history also) contains only 1 undo context (i.e. RefactoringUndoContext) initially. We don't have access to the old/new document undo manager's ObjectUndoContext from the refactoring undo manager to check if it is valid or not, until the new document undo manager has added the new operation to history.
Comment 11 Noopur Gupta CLA 2013-09-11 09:42:18 EDT
*** Bug 417005 has been marked as a duplicate of this bug. ***
Comment 12 Noopur Gupta CLA 2015-08-04 09:31:54 EDT
*** Bug 473920 has been marked as a duplicate of this bug. ***
Comment 13 Eclipse Genie CLA 2020-04-09 14:04:42 EDT
This bug hasn't had any activity in quite some time. Maybe the problem got resolved, was a duplicate of something else, or became less pressing for some reason - or maybe it's still relevant but just hasn't been looked at yet. As such, we're closing this bug.

If you have further information on the current state of the bug, please add it and reopen this bug. The information can be, for example, that the problem still occurs, that you still want the feature, that more information is needed, or that the bug is (for whatever reason) no longer relevant.

--
The automated Eclipse Genie.