1 /*******************************************************************************
2  * Copyright (c) 2000, 2020 IBM Corporation and others.
3  *
4  * This program and the accompanying materials
5  * are made available under the terms of the Eclipse Public License 2.0
6  * which accompanies this distribution, and is available at
7  * https://www.eclipse.org/legal/epl-2.0/
8  *
9  * SPDX-License-Identifier: EPL-2.0
10  *
11  * Contributors:
12  *     IBM Corporation - initial API and implementation
13  *******************************************************************************/
14 package org.eclipse.jdt.internal.ui.refactoring.actions;
15 
16 import org.eclipse.core.runtime.CoreException;
17 
18 import org.eclipse.jface.dialogs.MessageDialog;
19 import org.eclipse.jface.preference.IPreferenceStore;
20 import org.eclipse.jface.viewers.IStructuredSelection;
21 
22 import org.eclipse.jface.text.IDocument;
23 import org.eclipse.jface.text.ITextSelection;
24 
25 import org.eclipse.ui.IWorkbenchSite;
26 
27 import org.eclipse.jdt.core.IField;
28 import org.eclipse.jdt.core.IJavaElement;
29 import org.eclipse.jdt.core.IPackageFragment;
30 import org.eclipse.jdt.core.IType;
31 import org.eclipse.jdt.core.ITypeRoot;
32 import org.eclipse.jdt.core.JavaModelException;
33 import org.eclipse.jdt.core.dom.AST;
34 import org.eclipse.jdt.core.dom.ASTNode;
35 import org.eclipse.jdt.core.dom.SimpleName;
36 
37 import org.eclipse.jdt.internal.corext.refactoring.RefactoringAvailabilityTester;
38 import org.eclipse.jdt.internal.corext.refactoring.RefactoringExecutionStarter;
39 import org.eclipse.jdt.internal.corext.util.JavaModelUtil;
40 
41 import org.eclipse.jdt.ui.JavaUI;
42 import org.eclipse.jdt.ui.PreferenceConstants;
43 import org.eclipse.jdt.ui.actions.SelectionDispatchAction;
44 
45 import org.eclipse.jdt.internal.ui.JavaPlugin;
46 import org.eclipse.jdt.internal.ui.actions.ActionUtil;
47 import org.eclipse.jdt.internal.ui.actions.SelectionConverter;
48 import org.eclipse.jdt.internal.ui.javaeditor.CompilationUnitEditor;
49 import org.eclipse.jdt.internal.ui.javaeditor.EditorUtility;
50 import org.eclipse.jdt.internal.ui.javaeditor.JavaEditor;
51 import org.eclipse.jdt.internal.ui.javaeditor.JavaTextSelection;
52 import org.eclipse.jdt.internal.ui.refactoring.RefactoringMessages;
53 import org.eclipse.jdt.internal.ui.refactoring.reorg.RenameLinkedMode;
54 import org.eclipse.jdt.internal.ui.text.correction.CorrectionCommandHandler;
55 import org.eclipse.jdt.internal.ui.text.correction.proposals.LinkedNamesAssistProposal;
56 import org.eclipse.jdt.internal.ui.util.ExceptionHandler;
57 
58 public class RenameJavaElementAction extends SelectionDispatchAction {
59 
60 	private JavaEditor fEditor;
61 
RenameJavaElementAction(IWorkbenchSite site)62 	public RenameJavaElementAction(IWorkbenchSite site) {
63 		super(site);
64 	}
65 
RenameJavaElementAction(JavaEditor editor)66 	public RenameJavaElementAction(JavaEditor editor) {
67 		this(editor.getEditorSite());
68 		fEditor= editor;
69 		setEnabled(SelectionConverter.canOperateOn(fEditor));
70 	}
71 
72 	//---- Structured selection ------------------------------------------------
73 
74 	@Override
selectionChanged(IStructuredSelection selection)75 	public void selectionChanged(IStructuredSelection selection) {
76 		try {
77 			if (selection.size() == 1) {
78 				setEnabled(canEnable(selection));
79 				return;
80 			}
81 		} catch (JavaModelException e) {
82 			// http://bugs.eclipse.org/bugs/show_bug.cgi?id=19253
83 			if (JavaModelUtil.isExceptionToBeLogged(e))
84 				JavaPlugin.log(e);
85 		} catch (CoreException e) {
86 			JavaPlugin.log(e);
87 		}
88 		setEnabled(false);
89 	}
90 
canEnable(IStructuredSelection selection)91 	private static boolean canEnable(IStructuredSelection selection) throws CoreException {
92 		IJavaElement element= getJavaElement(selection);
93 		if (element == null)
94 			return false;
95 		return RefactoringAvailabilityTester.isRenameElementAvailable(element);
96 	}
97 
getJavaElement(IStructuredSelection selection)98 	private static IJavaElement getJavaElement(IStructuredSelection selection) {
99 		if (selection.size() != 1)
100 			return null;
101 		Object first= selection.getFirstElement();
102 		if (! (first instanceof IJavaElement))
103 			return null;
104 		return (IJavaElement)first;
105 	}
106 
107 	@Override
run(IStructuredSelection selection)108 	public void run(IStructuredSelection selection) {
109 		IJavaElement element= getJavaElement(selection);
110 		if (element == null)
111 			return;
112 		if (!ActionUtil.isEditable(getShell(), element))
113 			return;
114 		try {
115 			run(element, false);
116 		} catch (CoreException e){
117 			ExceptionHandler.handle(e, RefactoringMessages.RenameJavaElementAction_name, RefactoringMessages.RenameJavaElementAction_exception);
118 		}
119 	}
120 
121 	//---- text selection ------------------------------------------------------------
122 
123 	@Override
selectionChanged(ITextSelection selection)124 	public void selectionChanged(ITextSelection selection) {
125 		if (selection instanceof JavaTextSelection) {
126 			try {
127 				JavaTextSelection javaTextSelection= (JavaTextSelection)selection;
128 				IJavaElement[] elements= javaTextSelection.resolveElementAtOffset();
129 				if (isVarTypeSelection(javaTextSelection)) {
130 					setEnabled(false);
131 				}
132 				else {
133 					if (elements.length == 1) {
134 						setEnabled(RefactoringAvailabilityTester.isRenameElementAvailable(elements[0]));
135 					} else {
136 						ASTNode node= javaTextSelection.resolveCoveringNode();
137 						setEnabled(node instanceof SimpleName);
138 					}
139 				}
140 			} catch (CoreException e) {
141 				setEnabled(false);
142 			}
143 		} else {
144 			setEnabled(true);
145 		}
146 	}
147 
148 	@Override
run(ITextSelection selection)149 	public void run(ITextSelection selection) {
150 		if (!ActionUtil.isEditable(fEditor))
151 			return;
152 		if (canRunInEditor() && !isVarTypeSelection(selection))
153 			doRun();
154 		else
155 			MessageDialog.openInformation(getShell(), RefactoringMessages.RenameAction_rename, RefactoringMessages.RenameAction_unavailable);
156 	}
157 
doRun()158 	public void doRun() {
159 		RenameLinkedMode activeLinkedMode= RenameLinkedMode.getActiveLinkedMode();
160 		if (activeLinkedMode != null) {
161 			if (activeLinkedMode.isCaretInLinkedPosition()) {
162 				activeLinkedMode.startFullDialog();
163 				return;
164 			} else {
165 				activeLinkedMode.cancel();
166 			}
167 		}
168 
169 		try {
170 			IJavaElement element= getJavaElementFromEditor();
171 			IPreferenceStore store= JavaPlugin.getDefault().getPreferenceStore();
172 			boolean lightweight= store.getBoolean(PreferenceConstants.REFACTOR_LIGHTWEIGHT);
173 			if (element != null && RefactoringAvailabilityTester.isRenameElementAvailable(element)) {
174 				run(element, lightweight);
175 				return;
176 			} else if (lightweight) {
177 				// fall back to local rename:
178 				CorrectionCommandHandler handler= new CorrectionCommandHandler(fEditor, LinkedNamesAssistProposal.ASSIST_ID, true);
179 				if (handler.doExecute()) {
180 					fEditor.setStatusLineErrorMessage(RefactoringMessages.RenameJavaElementAction_started_rename_in_file);
181 					return;
182 				}
183 			}
184 		} catch (CoreException e) {
185 			ExceptionHandler.handle(e, RefactoringMessages.RenameJavaElementAction_name, RefactoringMessages.RenameJavaElementAction_exception);
186 		}
187 		MessageDialog.openInformation(getShell(), RefactoringMessages.RenameJavaElementAction_name, RefactoringMessages.RenameJavaElementAction_not_available);
188 	}
189 
canRunInEditor()190 	public boolean canRunInEditor() {
191 		if (RenameLinkedMode.getActiveLinkedMode() != null)
192 			return true;
193 
194 		try {
195 			IJavaElement element= getJavaElementFromEditor();
196 			if (element == null)
197 				return true;
198 
199 			return RefactoringAvailabilityTester.isRenameElementAvailable(element);
200 		} catch (JavaModelException e) {
201 			if (JavaModelUtil.isExceptionToBeLogged(e))
202 				JavaPlugin.log(e);
203 		} catch (CoreException e) {
204 			JavaPlugin.log(e);
205 		}
206 		return false;
207 	}
208 
getJavaElementFromEditor()209 	private IJavaElement getJavaElementFromEditor() throws JavaModelException {
210 		IJavaElement[] elements= SelectionConverter.codeResolve(fEditor);
211 		if (elements == null || elements.length != 1)
212 			return null;
213 		if (elements[0].getElementType() == IJavaElement.LOCAL_VARIABLE) {
214 			IJavaElement element= elements[0];
215 			IJavaElement parent= element.getParent();
216 			if(parent != null && parent.getElementType() == IJavaElement.FIELD) {
217 				IField parentField= (IField) parent;
218 				IJavaElement topParent= parent.getParent();
219 				if(topParent != null && topParent.getElementType() == IJavaElement.TYPE) {
220 					if (((IType)topParent).isRecord()) {
221 						return parentField;
222 					}
223 				}
224 			}
225 		}
226 		return elements[0];
227 	}
228 
229 	//---- helper methods -------------------------------------------------------------------
230 
run(IJavaElement element, boolean lightweight)231 	private void run(IJavaElement element, boolean lightweight) throws CoreException {
232 		// Work around for http://dev.eclipse.org/bugs/show_bug.cgi?id=19104
233 		if (! ActionUtil.isEditable(fEditor, getShell(), element))
234 			return;
235 		//XXX workaround bug 31998
236 		if (ActionUtil.mustDisableJavaModelAction(getShell(), element))
237 			return;
238 
239 		if (lightweight && fEditor instanceof CompilationUnitEditor && ! (element instanceof IPackageFragment)) {
240 			new RenameLinkedMode(element, (CompilationUnitEditor) fEditor).start();
241 		} else {
242 			RefactoringExecutionStarter.startRenameRefactoring(element, getShell());
243 		}
244 	}
245 
isVarTypeSelection(ITextSelection textSelection)246 	private boolean isVarTypeSelection(ITextSelection textSelection) {
247 		if (textSelection instanceof JavaTextSelection) {
248 			ASTNode node= ((JavaTextSelection) textSelection).resolveCoveringNode();
249 			if (node instanceof SimpleName && node.getAST().apiLevel() >= AST.JLS10 && ((SimpleName) node).isVar()) {
250 				return true;
251 			}
252 		} else if (textSelection != null) {
253 			ITypeRoot typeRoot= EditorUtility.getEditorInputJavaElement(fEditor, true);
254 			if (typeRoot != null) {
255 				IDocument document= JavaUI.getDocumentProvider().getDocument(fEditor.getEditorInput());
256 				if (document != null) {
257 					JavaTextSelection javaTextSelection= new JavaTextSelection(typeRoot, document, textSelection.getOffset(), textSelection.getLength());
258 					return isVarTypeSelection(javaTextSelection);
259 				}
260 			}
261 		}
262 		return false;
263 	}
264 }
265