]> git.uio.no Git - ifi-stolz-refaktor.git/blame - case-study/jdt-after/ui/org/eclipse/jdt/internal/ui/text/java/ParameterGuessingProposal.java
Case Study: adding data and statistics
[ifi-stolz-refaktor.git] / case-study / jdt-after / ui / org / eclipse / jdt / internal / ui / text / java / ParameterGuessingProposal.java
CommitLineData
1b2798f6
EK
1/*******************************************************************************
2 * Copyright (c) 2000, 2012 IBM Corporation and others.
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Eclipse Public License v1.0
5 * which accompanies this distribution, and is available at
6 * http://www.eclipse.org/legal/epl-v10.html
7 *
8 * Contributors:
9 * Andrew McCullough - initial API and implementation
10 * IBM Corporation - general improvement and bug fixes, partial reimplementation
11 *******************************************************************************/
12package org.eclipse.jdt.internal.ui.text.java;
13
14import org.eclipse.swt.SWT;
15import org.eclipse.swt.events.VerifyEvent;
16import org.eclipse.swt.graphics.Point;
17import org.eclipse.swt.widgets.Shell;
18
19import org.eclipse.core.runtime.Platform;
20
21import org.eclipse.jface.dialogs.MessageDialog;
22
23import org.eclipse.jface.text.BadLocationException;
24import org.eclipse.jface.text.BadPositionCategoryException;
25import org.eclipse.jface.text.IDocument;
26import org.eclipse.jface.text.IPositionUpdater;
27import org.eclipse.jface.text.IRegion;
28import org.eclipse.jface.text.Position;
29import org.eclipse.jface.text.Region;
30import org.eclipse.jface.text.contentassist.ICompletionProposal;
31import org.eclipse.jface.text.link.ILinkedModeListener;
32import org.eclipse.jface.text.link.InclusivePositionUpdater;
33import org.eclipse.jface.text.link.LinkedModeModel;
34import org.eclipse.jface.text.link.LinkedModeUI;
35import org.eclipse.jface.text.link.LinkedModeUI.ExitFlags;
36import org.eclipse.jface.text.link.LinkedPosition;
37import org.eclipse.jface.text.link.LinkedPositionGroup;
38import org.eclipse.jface.text.link.ProposalPosition;
39
40import org.eclipse.ui.IEditorPart;
41
42import org.eclipse.ui.texteditor.link.EditorLinkedModeUI;
43
44import org.eclipse.jdt.core.CompletionContext;
45import org.eclipse.jdt.core.CompletionProposal;
46import org.eclipse.jdt.core.IJavaElement;
47import org.eclipse.jdt.core.JavaModelException;
48import org.eclipse.jdt.core.Signature;
49
50import org.eclipse.jdt.internal.corext.template.java.SignatureUtil;
51
52import org.eclipse.jdt.ui.text.java.JavaContentAssistInvocationContext;
53
54import org.eclipse.jdt.internal.ui.JavaPlugin;
55import org.eclipse.jdt.internal.ui.javaeditor.EditorHighlightingSynchronizer;
56import org.eclipse.jdt.internal.ui.javaeditor.JavaEditor;
57
58
59/**
60 * This is a {@link org.eclipse.jdt.internal.ui.text.java.JavaCompletionProposal} which includes templates
61 * that represent the best guess completion for each parameter of a method.
62 */
63public class ParameterGuessingProposal extends JavaMethodCompletionProposal {
64
65 /**
66 * Creates a {@link ParameterGuessingProposal} or <code>null</code> if the core context isn't available or extended.
67 *
68 * @param proposal the original completion proposal
69 * @param context the currrent context
70 * @param fillBestGuess if set, the best guess will be filled in
71 *
72 * @return a proposal or <code>null</code>
73 */
74 public static ParameterGuessingProposal createProposal(CompletionProposal proposal, JavaContentAssistInvocationContext context, boolean fillBestGuess) {
75 CompletionContext coreContext= context.getCoreContext();
76 if (coreContext != null && coreContext.isExtended()) {
77 return new ParameterGuessingProposal(proposal, context, coreContext, fillBestGuess);
78 }
79 return null;
80 }
81
82
83
84 /** Tells whether this class is in debug mode. */
85 private static final boolean DEBUG= "true".equalsIgnoreCase(Platform.getDebugOption("org.eclipse.jdt.ui/debug/ResultCollector")); //$NON-NLS-1$//$NON-NLS-2$
86
87 ICompletionProposal[][] fChoices; // initialized by guessParameters()
88 Position[] fPositions; // initialized by guessParameters()
89
90 private IRegion fSelectedRegion; // initialized by apply()
91 private IPositionUpdater fUpdater;
92
93 private final boolean fFillBestGuess;
94
95 private final CompletionContext fCoreContext;
96
97 private ParameterGuessingProposal(CompletionProposal proposal, JavaContentAssistInvocationContext context, CompletionContext coreContext, boolean fillBestGuess) {
98 super(proposal, context);
99 fCoreContext= coreContext;
100 fFillBestGuess= fillBestGuess;
101 }
102
103 private IJavaElement getEnclosingElement() {
104 return fCoreContext.getEnclosingElement();
105 }
106
107 private IJavaElement[][] getAssignableElements() {
108 char[] signature= SignatureUtil.fix83600(getProposal().getSignature());
109 char[][] types= Signature.getParameterTypes(signature);
110
111 IJavaElement[][] assignableElements= new IJavaElement[types.length][];
112 for (int i= 0; i < types.length; i++) {
113 assignableElements[i]= fCoreContext.getVisibleElements(new String(types[i]));
114 }
115 return assignableElements;
116 }
117
118 /*
119 * @see ICompletionProposalExtension#apply(IDocument, char)
120 */
121 @Override
122 public void apply(final IDocument document, char trigger, int offset) {
123 try {
124 super.apply(document, trigger, offset);
125
126 int baseOffset= getReplacementOffset();
127 String replacement= getReplacementString();
128
129 if (fPositions != null && getTextViewer() != null) {
130
131 LinkedModeModel model= new LinkedModeModel();
132
133 for (int i= 0; i < fPositions.length; i++) {
134 LinkedPositionGroup group= new LinkedPositionGroup();
135 int positionOffset= fPositions[i].getOffset();
136 int positionLength= fPositions[i].getLength();
137
138 if (fChoices[i].length < 2) {
139 group.addPosition(new LinkedPosition(document, positionOffset, positionLength, LinkedPositionGroup.NO_STOP));
140 } else {
141 ensurePositionCategoryInstalled(document, model);
142 document.addPosition(getCategory(), fPositions[i]);
143 group.addPosition(new ProposalPosition(document, positionOffset, positionLength, LinkedPositionGroup.NO_STOP, fChoices[i]));
144 }
145 model.addGroup(group);
146 }
147
148 model.forceInstall();
149 JavaEditor editor= getJavaEditor();
150 if (editor != null) {
151 model.addLinkingListener(new EditorHighlightingSynchronizer(editor));
152 }
153
154 LinkedModeUI ui= new EditorLinkedModeUI(model, getTextViewer());
155 ui.setExitPosition(getTextViewer(), baseOffset + replacement.length(), 0, Integer.MAX_VALUE);
156 ui.setExitPolicy(new ExitPolicy(')', document) {
157 @Override
158 public ExitFlags doExit(LinkedModeModel model2, VerifyEvent event, int offset2, int length) {
159 if (event.character == ',') {
160 for (int i= 0; i < fPositions.length - 1; i++) { // not for the last one
161 Position position= fPositions[i];
162 if (position.offset <= offset2 && offset2 + length <= position.offset + position.length) {
163 event.character= '\t';
164 event.keyCode= SWT.TAB;
165 return null;
166 }
167 }
168 }
169 return super.doExit(model2, event, offset2, length);
170 }
171 });
172 ui.setCyclingMode(LinkedModeUI.CYCLE_WHEN_NO_PARENT);
173 ui.setDoContextInfo(true);
174 ui.enter();
175 fSelectedRegion= ui.getSelectedRegion();
176
177 } else {
178 fSelectedRegion= new Region(baseOffset + replacement.length(), 0);
179 }
180
181 } catch (BadLocationException e) {
182 ensurePositionCategoryRemoved(document);
183 JavaPlugin.log(e);
184 openErrorDialog(e);
185 } catch (BadPositionCategoryException e) {
186 ensurePositionCategoryRemoved(document);
187 JavaPlugin.log(e);
188 openErrorDialog(e);
189 }
190 }
191
192 /*
193 * @see org.eclipse.jdt.internal.ui.text.java.JavaMethodCompletionProposal#needsLinkedMode()
194 */
195 @Override
196 protected boolean needsLinkedMode() {
197 return false; // we handle it ourselves
198 }
199
200 /*
201 * @see org.eclipse.jdt.internal.ui.text.java.JavaMethodCompletionProposal#computeReplacementString()
202 */
203 @Override
204 protected String computeReplacementString() {
205
206 if (!hasParameters() || !hasArgumentList())
207 return super.computeReplacementString();
208
209 long millis= DEBUG ? System.currentTimeMillis() : 0;
210 String replacement;
211 try {
212 replacement= computeGuessingCompletion();
213 } catch (JavaModelException x) {
214 fPositions= null;
215 fChoices= null;
216 JavaPlugin.log(x);
217 openErrorDialog(x);
218 return super.computeReplacementString();
219 }
220 if (DEBUG) System.err.println("Parameter Guessing: " + (System.currentTimeMillis() - millis)); //$NON-NLS-1$
221
222 return replacement;
223 }
224
225 /**
226 * Creates the completion string. Offsets and Lengths are set to the offsets and lengths of the
227 * parameters.
228 *
229 * @return the completion string
230 * @throws JavaModelException if parameter guessing failed
231 */
232 private String computeGuessingCompletion() throws JavaModelException {
233
234 StringBuffer buffer= new StringBuffer();
235 appendMethodNameReplacement(buffer);
236
237 FormatterPrefs prefs= getFormatterPrefs();
238
239 return prefs.generated_1904169089833146011(buffer, this);
240 }
241
242 /**
243 * Returns the currently active java editor, or <code>null</code> if it
244 * cannot be determined.
245 *
246 * @return the currently active java editor, or <code>null</code>
247 */
248 private JavaEditor getJavaEditor() {
249 IEditorPart part= JavaPlugin.getActivePage().getActiveEditor();
250 if (part instanceof JavaEditor)
251 return (JavaEditor) part;
252 else
253 return null;
254 }
255
256 ICompletionProposal[][] guessParameters(char[][] parameterNames) throws JavaModelException {
257 // find matches in reverse order. Do this because people tend to declare the variable meant for the last
258 // parameter last. That is, local variables for the last parameter in the method completion are more
259 // likely to be closer to the point of code completion. As an example consider a "delegation" completion:
260 //
261 // public void myMethod(int param1, int param2, int param3) {
262 // someOtherObject.yourMethod(param1, param2, param3);
263 // }
264 //
265 // The other consideration is giving preference to variables that have not previously been used in this
266 // code completion (which avoids "someOtherObject.yourMethod(param1, param1, param1)";
267
268 int count= parameterNames.length;
269 fPositions= new Position[count];
270 fChoices= new ICompletionProposal[count][];
271
272 String[] parameterTypes= getParameterTypes();
273 ParameterGuesser guesser= new ParameterGuesser(getEnclosingElement());
274 IJavaElement[][] assignableElements= getAssignableElements();
275
276 for (int i= count - 1; i >= 0; i--) {
277 String paramName= new String(parameterNames[i]);
278 Position position= new Position(0,0);
279
280 boolean isLastParameter= i == count - 1;
281 ICompletionProposal[] argumentProposals= guesser.parameterProposals(parameterTypes[i], paramName, position, assignableElements[i], fFillBestGuess, isLastParameter);
282 if (argumentProposals.length == 0) {
283 JavaCompletionProposal proposal= new JavaCompletionProposal(paramName, 0, paramName.length(), null, paramName, 0);
284 argumentProposals= proposal.generated_2597104358469167081(isLastParameter);
285 }
286
287 fPositions[i]= position;
288 fChoices[i]= argumentProposals;
289 }
290
291 return fChoices;
292 }
293
294 private String[] getParameterTypes() {
295 char[] signature= SignatureUtil.fix83600(fProposal.getSignature());
296 char[][] types= Signature.getParameterTypes(signature);
297
298 String[] ret= new String[types.length];
299 for (int i= 0; i < types.length; i++) {
300 ret[i]= new String(Signature.toCharArray(types[i]));
301 }
302 return ret;
303 }
304
305 /*
306 * @see ICompletionProposal#getSelection(IDocument)
307 */
308 @Override
309 public Point getSelection(IDocument document) {
310 if (fSelectedRegion == null)
311 return new Point(getReplacementOffset(), 0);
312
313 return new Point(fSelectedRegion.getOffset(), fSelectedRegion.getLength());
314 }
315
316 private void openErrorDialog(Exception e) {
317 Shell shell= getTextViewer().getTextWidget().getShell();
318 MessageDialog.openError(shell, JavaTextMessages.ParameterGuessingProposal_error_msg, e.getMessage());
319 }
320
321 private void ensurePositionCategoryInstalled(final IDocument document, LinkedModeModel model) {
322 if (!document.containsPositionCategory(getCategory())) {
323 document.addPositionCategory(getCategory());
324 fUpdater= new InclusivePositionUpdater(getCategory());
325 document.addPositionUpdater(fUpdater);
326
327 model.addLinkingListener(new ILinkedModeListener() {
328
329 /*
330 * @see org.eclipse.jface.text.link.ILinkedModeListener#left(org.eclipse.jface.text.link.LinkedModeModel, int)
331 */
332 public void left(LinkedModeModel environment, int flags) {
333 ensurePositionCategoryRemoved(document);
334 }
335
336 public void suspend(LinkedModeModel environment) {}
337 public void resume(LinkedModeModel environment, int flags) {}
338 });
339 }
340 }
341
342 private void ensurePositionCategoryRemoved(IDocument document) {
343 if (document.containsPositionCategory(getCategory())) {
344 try {
345 document.removePositionCategory(getCategory());
346 } catch (BadPositionCategoryException e) {
347 // ignore
348 }
349 document.removePositionUpdater(fUpdater);
350 }
351 }
352
353 private String getCategory() {
354 return "ParameterGuessingProposal_" + toString(); //$NON-NLS-1$
355 }
356
357}