Capture the method of invoking refactorings
The refactoring logs of CodingSpectator should include the method the refactoring was invoked. There are 8 ways that I know of to invoke a refactoring:
- From the menu
Refactor - Via the shortcut key for the list of refactorings (ALT+SHIFT+T)
- Right click and invoke from the Refactor item
- Using the direct shortcut key to invoke the refactoring (e.g. ALT+SHIFT+R for the rename refactoring)
- Invoking the refactoring from the list of refactorings proposed by the quick assist pop-up menu (CTRL+1)
- A selection of quick assists can be assigned to a direct shortcut. By default, these are:
- Rename in file: Ctrl+2, R
- Assign to local: Ctrl+2, L
- Assign to field: Ctrl+2, F
- Invoking the refactoring using the quick fix.
- Drag and drop
Some quick fixes will implicitly invoke refactorings. Here's the only example that we know so far (are there more?):
package a;
class C1 {
}
If C1 was not declared in package a, then there wil be a quick-fix annotation on the editor. Click on it and it will suggest two things: move the package or delete the package declaration. If you select move package, it will implicitly invoke the move refactoring (this is captured in the refactoring logs).
Currently, CodingSpectator distinguishes invocations of refactorings through quick assist from others. It might be useful to distinguish other methods of invoking refactorings as well.
There is another way to invoke refactorings (it might be the same category as one of those listed above): you can right-click on the structured view (Package Explorer or Outline View).
Let's classify the Package Explorer and Outline View (and possibly other views) as graphical structured view of source code. It would be interesting to see how developers prefer to invoke the refactorings:
- Through the text editor (keyboard shortcuts, right-click, quick fix, etc)
- Through the graphical structured views (right-click only as far as I know)
@vazexqi: You can invoke the refactoring menu from the graphical structured views by using ALT+SHIFT+T keyboard shortcut.
Here' my investigation notes for the evening:
There are 2 refactoring suggestions present when you invoke CTRL+1 quick assist shortcut.
They are from this file: CorrectionMessages.properties
RenameRefactoringProposal_name=Rename in workspace LinkedNamesAssistProposal_description=Rename in file
org.eclipse.jdt.internal.ui.text.correction.CorrectionMessages has a truck load of strings for being referenced for correction suggestions. org.eclipse.jdt.internal.ui.text.correction.proposals.RenameRefactoringProposal contains Mohsen's changes to say that the refactoring was invoked through quick assist. org.eclipse.jface.text.contentassist.ICompletionProposal seems to be the common base class for all the context sensitive proposals. There are other interfaces that exist for backward compatibility. org.eclipse.jface.text.contentassist.ICompletionListener are interfaces for listening to the content assist events. org.eclipse.jface.text.contentassist.ContentAssistant registers listeners for capturing events about invoking content assistant code.
QUICK ASSIST:
org.eclipse.jdt.ui.text.java.IQuickFixProcessor org.eclipse.jdt.internal.ui.text.correction.QuickFixProcessor is the concrete class for checking the problems. org.eclipse.jdt.internal.ui.text.correction.JavaCorrectionProcessor gets the correction proposals for all the QuickFixProcessor instances in the system.
Consider a file in a JAVA project called C.java with the following contents.
public class D {
}
Now, you can invoke the quick fix from insider the editor to rename the compilation unit to D.java.
When you do this, the file gets renamed and the compilation issue gets resolved. However, eclipse doesn't seem to record this change. Also, the RenameCompilationUnit refactoring processor does not get invoked. It looks like quick fixes don't reuse refactoring classes and compute the changes themselves.
When I invoke the completion popup via CTRL + 1 and pick an action to perform, line 933 gets executed.
This holds good for my previous comment.
Now, let's say that you type sysout inside a method and hit CTRL + 1, you'll see the following:
- Create local variable 'sysout'.
- Create field 'sysout'.
- Create parameter 'sysout'
- Remove assignment
- Rename in file
When in this state, the user can do one of the 2 actions:
-
Hits the
ESCkey and quits the suggestions. In this case, theorg.eclipse.jface.text.contentassist.CompletionProposalPopup.verifyKey(VerifyEvent)would execute to lineswitch (key) { case 0x1B: // Esc e.doit = false; hide(); break; }
No further action is taken.
-
Hits the
ENTERkey. In this case, theverifyKeymethod would execute this part of the switch:case '\n': // Ctrl-Enter on w2k case '\r': // Enter e.doit= false; insertSelectedProposalWithMask(e.stateMask); break;
insertSelectedProposalWithMask is executed.
In this method, the ICompletionProposal that was selected by the user is fetched and the change is performed.
There is a subtle difference between the correction performed when invoked via CTRL + 1 and CTRL + SPACE.
Inside the method org.eclipse.jface.text.contentassist.CompletionProposalPopup.insertProposal(ICompletionProposal, char, int, int), the instance of the proposal called is different.
In the case of CTRL + 1 invocation, the proposal is an instance of org.eclipse.jdt.internal.ui.text.correction.proposals.ChangeCorrectionProposal. So, line 933 is executed.
Now, consider this scenario of invoking CTRL + SPACE to kick off the template proposal.
In this case, the flow is the same, except that an instance of org.eclipse.jface.text.contentassist.ICompletionProposalExtension2 is executed in line 927.
Another way to look at this is org.eclipse.jface.text.contentassist.ContentAssistant.isAutoInserting() is true when invoked through CTRL + SPACE.
I see two possibilities here:
- Let's take jface and modify the
CompletionProposalPopupclass. - Play around with
org.eclipse.jface.text.contentassist.ContentAssistantand see if we can add ourselves as a listener. Referorg.eclipse.jface.text.contentassist.ContentAssistant.addContentAssistListener(IContentAssistListener, int).
Why was the issue closed? Was it incorporated into a different issue? Or did we choose to use a different approach? Or is this issue no longer important?
Anyway, my question about the previous comment is: is there a way that we can hook into the invocation mechanism without touching the jface code? JFace is quite low-level and is depended on by many other plug-ins so it is very risky to modify.
I didn't close this issue. I don't know how that happened.
Notes for the evening: When eclipse first starts up, org.eclipse.jdt.ui.actions.RefactorActionGroup.RefactorActionGroup(IWorkbenchSite, ISelectionProvider) is created. From then on, it's cached. It is here that the refactoring actions are created.
One of the implementations, org.eclipse.jdt.ui.actions.RenameAction has been touched by @vazexqi and @reprogrammer to know if the invocation was through quickAssist.
/org.eclipse.jdt.ui holds references to the menu items that are present on the right click action.
RenameInformationPopup_EnterNewName=Enter new name, press {0} to refactor
Here's the stack trace when the initialization of the org.eclipse.jdt.ui.actions.RefactorActionGroup takes place:
Thread [main] (Suspended (breakpoint at line 66 in RenameAction))
RenameAction.<init>(IWorkbenchSite) line: 66
RefactorActionGroup.<init>(IWorkbenchSite, ISelectionProvider) line: 371
RefactorActionGroup.<init>(IViewPart) line: 205
JavaNavigatorRefactorActionProvider.init(ICommonActionExtensionSite) line: 60
NavigatorActionService$6.run() line: 373
SafeRunner.run(ISafeRunnable) line: 42
NavigatorActionService.initialize(String, String, CommonActionProvider) line: 369
NavigatorActionService.access$2(NavigatorActionService, String, String, CommonActionProvider) line: 366
NavigatorActionService$5.run() line: 351
SafeRunner.run(ISafeRunnable) line: 42
NavigatorActionService.getActionProviderInstance(CommonActionProviderDescriptor) line: 347
NavigatorActionService$3.run() line: 257
SafeRunner.run(ISafeRunnable) line: 42
NavigatorActionService.fillActionBars(IActionBars) line: 253
CommonNavigatorManager.selectionChanged(SelectionChangedEvent) line: 222
Viewer$2.run() line: 162
SafeRunner.run(ISafeRunnable) line: 42
JFaceUtil$1.run(ISafeRunnable) line: 49
SafeRunnable.run(ISafeRunnable) line: 175
CommonViewer(Viewer).fireSelectionChanged(SelectionChangedEvent) line: 160
CommonViewer(StructuredViewer).updateSelection(ISelection) line: 2162
CommonViewer(StructuredViewer).handleSelect(SelectionEvent) line: 1190
CommonViewer.handleSelect(SelectionEvent) line: 478
StructuredViewer$4.widgetSelected(SelectionEvent) line: 1220
OpenStrategy.fireSelectionEvent(SelectionEvent) line: 228
OpenStrategy.access$4(OpenStrategy, SelectionEvent) line: 222
OpenStrategy$1.handleEvent(Event) line: 389
EventTable.sendEvent(Event) line: 84
Tree(Widget).sendEvent(Event) line: 1258
Display.runDeferredEvents() line: 3540
Display.readAndDispatch() line: 3161
Workbench.runEventLoop(Window$IExceptionHandler, Display) line: 2640
Workbench.runUI() line: 2604
Workbench.access$4(Workbench) line: 2438
Workbench$7.run() line: 671
Realm.runWithDefault(Realm, Runnable) line: 332
Workbench.createAndRunWorkbench(Display, WorkbenchAdvisor) line: 664
PlatformUI.createAndRunWorkbench(Display, WorkbenchAdvisor) line: 149
IDEApplication.start(IApplicationContext) line: 115
EclipseAppHandle.run(Object) line: 196
EclipseAppLauncher.runApplication(Object) line: 110
EclipseAppLauncher.start(Object) line: 79
EclipseStarter.run(Object) line: 369
EclipseStarter.run(String[], Runnable) line: 179
NativeMethodAccessorImpl.invoke0(Method, Object, Object[]) line: not available [native method]
NativeMethodAccessorImpl.invoke(Object, Object[]) line: 39
DelegatingMethodAccessorImpl.invoke(Object, Object[]) line: 25
Method.invoke(Object, Object...) line: 597
Main.invokeFramework(String[], URL[]) line: 619
Main.basicRun(String[]) line: 574
Main.run(String[]) line: 1407
Main.main(String[]) line: 1383
@vazexqi guess I found why the issue closes. When you hit the Comment & Close button on chrome on ubuntu, the issue is closed. The earlier behavior was, the issue wouldn't be closed :)
When eclipse first starts up, org.eclipse.jdt.ui.actions.RefactorActionGroup.RefactorActionGroup(IWorkbenchSite, ISelectionProvider) is created. From then on, it's cached. It is here that the refactoring actions are created.
One of the implementations, org.eclipse.jdt.ui.actions.RenameAction has been touched by @vazexqi and @reprogrammer to know if the invocation was through quickAssist.
When refactoring menu is invoked through SHIFT + CTRL + T, org.eclipse.jdt.ui.actions.RefactorActionGroup.fillQuickMenu(IMenuManager) gets invoked. This is due to the call from org.eclipse.ui.actions.QuickMenuCreator.createMenu()
When I right click on the project to see the menu options, this is what happens: org.eclipse.jdt.internal.ui.navigator.JavaNavigatorRefactorActionProvider.fillContextMenu(IMenuManager) gets invoked.
@reprogrammer and I found out that the drag-and-drop mechanism for Move Refactoring is called through this the ReorgMoveStarter class.
This information might be useful to get started on capturing the drag-and-drop invocation mechanism.