]> git.uio.no Git - ifi-stolz-refaktor.git/blame - case-study/jdt-before/ui/org/eclipse/jdt/internal/ui/text/java/LazyJavaTypeCompletionProposal.java
Case Study: adding data and statistics
[ifi-stolz-refaktor.git] / case-study / jdt-before / ui / org / eclipse / jdt / internal / ui / text / java / LazyJavaTypeCompletionProposal.java
CommitLineData
1b2798f6
EK
1/*******************************************************************************
2 * Copyright (c) 2000, 2011 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 * IBM Corporation - initial API and implementation
10 *******************************************************************************/
11package org.eclipse.jdt.internal.ui.text.java;
12
13import org.eclipse.core.runtime.CoreException;
14import org.eclipse.core.runtime.NullProgressMonitor;
15
16import org.eclipse.text.edits.TextEdit;
17
18import org.eclipse.jface.preference.IPreferenceStore;
19
20import org.eclipse.jface.text.BadLocationException;
21import org.eclipse.jface.text.IDocument;
22import org.eclipse.jface.text.contentassist.IContextInformation;
23
24import org.eclipse.jdt.core.CompletionProposal;
25import org.eclipse.jdt.core.ICompilationUnit;
26import org.eclipse.jdt.core.IJavaProject;
27import org.eclipse.jdt.core.IType;
28import org.eclipse.jdt.core.JavaCore;
29import org.eclipse.jdt.core.JavaModelException;
30import org.eclipse.jdt.core.Signature;
31import org.eclipse.jdt.core.dom.CompilationUnit;
32import org.eclipse.jdt.core.dom.rewrite.ImportRewrite;
33
34import org.eclipse.jdt.internal.corext.codemanipulation.ContextSensitiveImportRewriteContext;
35import org.eclipse.jdt.internal.corext.codemanipulation.StubUtility;
36import org.eclipse.jdt.internal.corext.util.JavaModelUtil;
37import org.eclipse.jdt.internal.corext.util.QualifiedTypeNameHistory;
38
39import org.eclipse.jdt.ui.PreferenceConstants;
40import org.eclipse.jdt.ui.SharedASTProvider;
41import org.eclipse.jdt.ui.text.java.JavaContentAssistInvocationContext;
42
43import org.eclipse.jdt.internal.ui.JavaPlugin;
44
45
46/**
47 * If passed compilation unit is not null, the replacement string will be seen as a qualified type name.
48 */
49public class LazyJavaTypeCompletionProposal extends LazyJavaCompletionProposal {
50 /** Triggers for types. Do not modify. */
51 protected static final char[] TYPE_TRIGGERS= new char[] { '.', '\t', '[', '(', ' ' };
52 /** Triggers for types in javadoc. Do not modify. */
53 protected static final char[] JDOC_TYPE_TRIGGERS= new char[] { '#', '}', ' ', '.' };
54
55 /** The compilation unit, or <code>null</code> if none is available. */
56 protected final ICompilationUnit fCompilationUnit;
57
58 private String fQualifiedName;
59 private String fSimpleName;
60 private ImportRewrite fImportRewrite;
61 private ContextSensitiveImportRewriteContext fImportContext;
62
63 public LazyJavaTypeCompletionProposal(CompletionProposal proposal, JavaContentAssistInvocationContext context) {
64 super(proposal, context);
65 fCompilationUnit= context.getCompilationUnit();
66 fQualifiedName= null;
67 }
68
69 void setImportRewrite(ImportRewrite importRewrite) {
70 fImportRewrite= importRewrite;
71 }
72
73 public final String getQualifiedTypeName() {
74 if (fQualifiedName == null)
75 fQualifiedName= String.valueOf(Signature.toCharArray(Signature.getTypeErasure(fProposal.getSignature())));
76 return fQualifiedName;
77 }
78
79 protected final String getSimpleTypeName() {
80 if (fSimpleName == null)
81 fSimpleName= Signature.getSimpleName(getQualifiedTypeName());
82 return fSimpleName;
83 }
84
85 /*
86 * @see org.eclipse.jdt.internal.ui.text.java.LazyJavaCompletionProposal#computeReplacementString()
87 */
88 @Override
89 protected String computeReplacementString() {
90 String replacement= super.computeReplacementString();
91
92 /* No import rewriting ever from within the import section. */
93 if (isImportCompletion())
94 return replacement;
95
96 /* Always use the simple name for non-formal javadoc references to types. */
97 // TODO fix
98 if (fProposal.getKind() == CompletionProposal.TYPE_REF && fInvocationContext.getCoreContext().isInJavadocText())
99 return getSimpleTypeName();
100
101 String qualifiedTypeName= getQualifiedTypeName();
102
103 // Type in package info must be fully qualified.
104 if (fCompilationUnit != null && JavaModelUtil.isPackageInfo(fCompilationUnit))
105 return qualifiedTypeName;
106
107 if (qualifiedTypeName.indexOf('.') == -1 && replacement.length() > 0)
108 // default package - no imports needed
109 return qualifiedTypeName;
110
111 /*
112 * If the user types in the qualification, don't force import rewriting on him - insert the
113 * qualified name.
114 */
115 IDocument document= fInvocationContext.getDocument();
116 if (document != null) {
117 String prefix= getPrefix(document, getReplacementOffset() + getReplacementLength());
118 int dotIndex= prefix.lastIndexOf('.');
119 // match up to the last dot in order to make higher level matching still work (camel case...)
120 if (dotIndex != -1 && qualifiedTypeName.toLowerCase().startsWith(prefix.substring(0, dotIndex + 1).toLowerCase()))
121 return qualifiedTypeName;
122 }
123
124 /*
125 * The replacement does not contain a qualification (e.g. an inner type qualified by its
126 * parent) - use the replacement directly.
127 */
128 if (replacement.indexOf('.') == -1) {
129 if (isInJavadoc())
130 return getSimpleTypeName(); // don't use the braces added for javadoc link proposals
131 return replacement;
132 }
133
134 /* Add imports if the preference is on. */
135 if (fImportRewrite == null)
136 fImportRewrite= createImportRewrite();
137 if (fImportRewrite != null) {
138 return fImportRewrite.addImport(qualifiedTypeName, fImportContext);
139 }
140
141 // fall back for the case we don't have an import rewrite (see allowAddingImports)
142
143 /* No imports for implicit imports. */
144 if (fCompilationUnit != null && JavaModelUtil.isImplicitImport(Signature.getQualifier(qualifiedTypeName), fCompilationUnit)) {
145 return Signature.getSimpleName(qualifiedTypeName);
146 }
147
148 /* Default: use the fully qualified type name. */
149 return qualifiedTypeName;
150 }
151
152 protected final boolean isImportCompletion() {
153 char[] completion= fProposal.getCompletion();
154 if (completion.length == 0)
155 return false;
156
157 char last= completion[completion.length - 1];
158 /*
159 * Proposals end in a semicolon when completing types in normal imports or when completing
160 * static members, in a period when completing types in static imports.
161 */
162 return last == ';' || last == '.';
163 }
164
165 private ImportRewrite createImportRewrite() {
166 if (fCompilationUnit != null && allowAddingImports() && !JavaModelUtil.isPackageInfo(fCompilationUnit)) {
167 try {
168 CompilationUnit cu= getASTRoot(fCompilationUnit);
169 if (cu == null) {
170 ImportRewrite rewrite= StubUtility.createImportRewrite(fCompilationUnit, true);
171 fImportContext= null;
172 return rewrite;
173 } else {
174 ImportRewrite rewrite= StubUtility.createImportRewrite(cu, true);
175 fImportContext= new ContextSensitiveImportRewriteContext(cu, fInvocationContext.getInvocationOffset(), rewrite);
176 return rewrite;
177 }
178 } catch (CoreException x) {
179 JavaPlugin.log(x);
180 }
181 }
182 return null;
183 }
184
185 private CompilationUnit getASTRoot(ICompilationUnit compilationUnit) {
186 return SharedASTProvider.getAST(compilationUnit, SharedASTProvider.WAIT_NO, new NullProgressMonitor());
187 }
188
189 /*
190 * @see org.eclipse.jdt.internal.ui.text.java.LazyJavaCompletionProposal#apply(org.eclipse.jface.text.IDocument, char, int)
191 */
192 @Override
193 public void apply(IDocument document, char trigger, int offset) {
194 try {
195 boolean insertClosingParenthesis= trigger == '(' && autocloseBrackets();
196 if (insertClosingParenthesis) {
197 StringBuffer replacement= new StringBuffer(getReplacementString());
198 updateReplacementWithParentheses(replacement);
199 setReplacementString(replacement.toString());
200 trigger= '\0';
201 }
202
203 super.apply(document, trigger, offset);
204
205 if (fImportRewrite != null && fImportRewrite.hasRecordedChanges()) {
206 int oldLen= document.getLength();
207 fImportRewrite.rewriteImports(new NullProgressMonitor()).apply(document, TextEdit.UPDATE_REGIONS);
208 setReplacementOffset(getReplacementOffset() + document.getLength() - oldLen);
209 }
210
211 if (insertClosingParenthesis)
212 setUpLinkedMode(document, ')');
213
214 rememberSelection();
215 } catch (CoreException e) {
216 JavaPlugin.log(e);
217 } catch (BadLocationException e) {
218 JavaPlugin.log(e);
219 }
220 }
221
222 protected void updateReplacementWithParentheses(StringBuffer replacement) {
223 FormatterPrefs prefs= getFormatterPrefs();
224
225 if (prefs.beforeOpeningParen)
226 replacement.append(SPACE);
227 replacement.append(LPAREN);
228
229
230 if (prefs.afterOpeningParen)
231 replacement.append(SPACE);
232
233 setCursorPosition(replacement.length());
234
235 if (prefs.afterOpeningParen)
236 replacement.append(SPACE);
237
238 replacement.append(RPAREN);
239 }
240
241 /**
242 * Remembers the selection in the content assist history.
243 *
244 * @throws JavaModelException if anything goes wrong
245 * @since 3.2
246 */
247 protected final void rememberSelection() throws JavaModelException {
248 IType lhs= fInvocationContext.getExpectedType();
249 IType rhs= (IType) getJavaElement();
250 if (lhs != null && rhs != null)
251 JavaPlugin.getDefault().getContentAssistHistory().remember(lhs, rhs);
252
253 QualifiedTypeNameHistory.remember(getQualifiedTypeName());
254 }
255
256 /**
257 * Returns <code>true</code> if imports may be added. The return value depends on the context
258 * and preferences only and does not take into account the contents of the compilation unit or
259 * the kind of proposal. Even if <code>true</code> is returned, there may be cases where no
260 * imports are added for the proposal. For example:
261 * <ul>
262 * <li>when completing within the import section</li>
263 * <li>when completing informal javadoc references (e.g. within <code>&lt;code&gt;</code>
264 * tags)</li>
265 * <li>when completing a type that conflicts with an existing import</li>
266 * <li>when completing an implicitly imported type (same package, <code>java.lang</code>
267 * types)</li>
268 * </ul>
269 * <p>
270 * The decision whether a qualified type or the simple type name should be inserted must take
271 * into account these different scenarios.
272 * </p>
273 * <p>
274 * Subclasses may extend.
275 * </p>
276 *
277 * @return <code>true</code> if imports may be added, <code>false</code> if not
278 */
279 protected boolean allowAddingImports() {
280 if (isInJavadoc()) {
281 // TODO fix
282// if (!fContext.isInJavadocFormalReference())
283// return false;
284 if (fProposal.getKind() == CompletionProposal.TYPE_REF && fInvocationContext.getCoreContext().isInJavadocText())
285 return false;
286
287 if (!isJavadocProcessingEnabled())
288 return false;
289 }
290
291 IPreferenceStore preferenceStore= JavaPlugin.getDefault().getPreferenceStore();
292 return preferenceStore.getBoolean(PreferenceConstants.CODEASSIST_ADDIMPORT);
293 }
294
295 private boolean isJavadocProcessingEnabled() {
296 IJavaProject project= fCompilationUnit.getJavaProject();
297 boolean processJavadoc;
298 if (project == null)
299 processJavadoc= JavaCore.ENABLED.equals(JavaCore.getOption(JavaCore.COMPILER_DOC_COMMENT_SUPPORT));
300 else
301 processJavadoc= JavaCore.ENABLED.equals(project.getOption(JavaCore.COMPILER_DOC_COMMENT_SUPPORT, true));
302 return processJavadoc;
303 }
304
305 /*
306 * @see org.eclipse.jdt.internal.ui.text.java.LazyJavaCompletionProposal#isValidPrefix(java.lang.String)
307 */
308 @Override
309 protected boolean isValidPrefix(String prefix) {
310 return isPrefix(prefix, getSimpleTypeName()) || isPrefix(prefix, getQualifiedTypeName());
311 }
312
313 /*
314 * @see org.eclipse.jdt.internal.ui.text.java.JavaCompletionProposal#getCompletionText()
315 */
316 @Override
317 public CharSequence getPrefixCompletionText(IDocument document, int completionOffset) {
318 String prefix= getPrefix(document, completionOffset);
319
320 String completion;
321 // return the qualified name if the prefix is already qualified
322 if (prefix.indexOf('.') != -1)
323 completion= getQualifiedTypeName();
324 else
325 completion= getSimpleTypeName();
326
327 if (isCamelCaseMatching())
328 return getCamelCaseCompound(prefix, completion);
329
330 return completion;
331 }
332
333 /*
334 * @see org.eclipse.jdt.internal.ui.text.java.LazyJavaCompletionProposal#computeTriggerCharacters()
335 */
336 @Override
337 protected char[] computeTriggerCharacters() {
338 return isInJavadoc() ? JDOC_TYPE_TRIGGERS : TYPE_TRIGGERS;
339 }
340
341 /*
342 * @see org.eclipse.jdt.internal.ui.text.java.LazyJavaCompletionProposal#computeProposalInfo()
343 */
344 @Override
345 protected ProposalInfo computeProposalInfo() {
346 if (fCompilationUnit != null) {
347 IJavaProject project= fCompilationUnit.getJavaProject();
348 if (project != null)
349 return new TypeProposalInfo(project, fProposal);
350 }
351 return super.computeProposalInfo();
352 }
353
354 /*
355 * @see org.eclipse.jdt.internal.ui.text.java.LazyJavaCompletionProposal#computeSortString()
356 */
357 @Override
358 protected String computeSortString() {
359 // try fast sort string to avoid display string creation
360 return getSimpleTypeName() + Character.MIN_VALUE + getQualifiedTypeName();
361 }
362
363 /*
364 * @see org.eclipse.jdt.internal.ui.text.java.LazyJavaCompletionProposal#computeRelevance()
365 */
366 @Override
367 protected int computeRelevance() {
368 /*
369 * There are two histories: the RHS history remembers types used for the current expected
370 * type (left hand side), while the type history remembers recently used types in general).
371 *
372 * The presence of an RHS ranking is a much more precise sign for relevance as it proves the
373 * subtype relationship between the proposed type and the expected type.
374 *
375 * The "recently used" factor (of either the RHS or general history) is less important, it should
376 * not override other relevance factors such as if the type is already imported etc.
377 */
378 float rhsHistoryRank= fInvocationContext.getHistoryRelevance(getQualifiedTypeName());
379 float typeHistoryRank= QualifiedTypeNameHistory.getDefault().getNormalizedPosition(getQualifiedTypeName());
380
381 int recencyBoost= Math.round((rhsHistoryRank + typeHistoryRank) * 5);
382 int rhsBoost= rhsHistoryRank > 0.0f ? 50 : 0;
383 int baseRelevance= super.computeRelevance();
384
385 return baseRelevance + rhsBoost + recencyBoost;
386 }
387
388 /*
389 * @see org.eclipse.jdt.internal.ui.text.java.LazyJavaCompletionProposal#computeContextInformation()
390 * @since 3.3
391 */
392 @Override
393 protected IContextInformation computeContextInformation() {
394 char[] signature= fProposal.getSignature();
395 char[][] typeParameters= Signature.getTypeArguments(signature);
396 if (typeParameters.length == 0)
397 return super.computeContextInformation();
398
399 ProposalContextInformation contextInformation= new ProposalContextInformation(fProposal);
400 if (fContextInformationPosition != 0 && fProposal.getCompletion().length == 0)
401 contextInformation.setContextInformationPosition(fContextInformationPosition);
402 return contextInformation;
403
404 }
405}