]> git.uio.no Git - ifi-stolz-refaktor.git/blame - case-study/jdt-after/ui/org/eclipse/jdt/internal/ui/text/java/LazyJavaTypeCompletionProposal.java
Case Study: adding data and statistics
[ifi-stolz-refaktor.git] / case-study / jdt-after / 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 prefs.generated_4910881149479547081(replacement, this);
226
227 replacement.append(RPAREN);
228 }
229
230 /**
231 * Remembers the selection in the content assist history.
232 *
233 * @throws JavaModelException if anything goes wrong
234 * @since 3.2
235 */
236 protected final void rememberSelection() throws JavaModelException {
237 IType lhs= fInvocationContext.getExpectedType();
238 IType rhs= (IType) getJavaElement();
239 if (lhs != null && rhs != null)
240 JavaPlugin.getDefault().getContentAssistHistory().remember(lhs, rhs);
241
242 QualifiedTypeNameHistory.remember(getQualifiedTypeName());
243 }
244
245 /**
246 * Returns <code>true</code> if imports may be added. The return value depends on the context
247 * and preferences only and does not take into account the contents of the compilation unit or
248 * the kind of proposal. Even if <code>true</code> is returned, there may be cases where no
249 * imports are added for the proposal. For example:
250 * <ul>
251 * <li>when completing within the import section</li>
252 * <li>when completing informal javadoc references (e.g. within <code>&lt;code&gt;</code>
253 * tags)</li>
254 * <li>when completing a type that conflicts with an existing import</li>
255 * <li>when completing an implicitly imported type (same package, <code>java.lang</code>
256 * types)</li>
257 * </ul>
258 * <p>
259 * The decision whether a qualified type or the simple type name should be inserted must take
260 * into account these different scenarios.
261 * </p>
262 * <p>
263 * Subclasses may extend.
264 * </p>
265 *
266 * @return <code>true</code> if imports may be added, <code>false</code> if not
267 */
268 protected boolean allowAddingImports() {
269 if (isInJavadoc()) {
270 // TODO fix
271// if (!fContext.isInJavadocFormalReference())
272// return false;
273 if (fProposal.getKind() == CompletionProposal.TYPE_REF && fInvocationContext.getCoreContext().isInJavadocText())
274 return false;
275
276 if (!isJavadocProcessingEnabled())
277 return false;
278 }
279
280 IPreferenceStore preferenceStore= JavaPlugin.getDefault().getPreferenceStore();
281 return preferenceStore.getBoolean(PreferenceConstants.CODEASSIST_ADDIMPORT);
282 }
283
284 private boolean isJavadocProcessingEnabled() {
285 IJavaProject project= fCompilationUnit.getJavaProject();
286 boolean processJavadoc;
287 if (project == null)
288 processJavadoc= JavaCore.ENABLED.equals(JavaCore.getOption(JavaCore.COMPILER_DOC_COMMENT_SUPPORT));
289 else
290 processJavadoc= JavaCore.ENABLED.equals(project.getOption(JavaCore.COMPILER_DOC_COMMENT_SUPPORT, true));
291 return processJavadoc;
292 }
293
294 /*
295 * @see org.eclipse.jdt.internal.ui.text.java.LazyJavaCompletionProposal#isValidPrefix(java.lang.String)
296 */
297 @Override
298 protected boolean isValidPrefix(String prefix) {
299 return isPrefix(prefix, getSimpleTypeName()) || isPrefix(prefix, getQualifiedTypeName());
300 }
301
302 /*
303 * @see org.eclipse.jdt.internal.ui.text.java.JavaCompletionProposal#getCompletionText()
304 */
305 @Override
306 public CharSequence getPrefixCompletionText(IDocument document, int completionOffset) {
307 String prefix= getPrefix(document, completionOffset);
308
309 String completion;
310 // return the qualified name if the prefix is already qualified
311 if (prefix.indexOf('.') != -1)
312 completion= getQualifiedTypeName();
313 else
314 completion= getSimpleTypeName();
315
316 if (isCamelCaseMatching())
317 return getCamelCaseCompound(prefix, completion);
318
319 return completion;
320 }
321
322 /*
323 * @see org.eclipse.jdt.internal.ui.text.java.LazyJavaCompletionProposal#computeTriggerCharacters()
324 */
325 @Override
326 protected char[] computeTriggerCharacters() {
327 return isInJavadoc() ? JDOC_TYPE_TRIGGERS : TYPE_TRIGGERS;
328 }
329
330 /*
331 * @see org.eclipse.jdt.internal.ui.text.java.LazyJavaCompletionProposal#computeProposalInfo()
332 */
333 @Override
334 protected ProposalInfo computeProposalInfo() {
335 if (fCompilationUnit != null) {
336 IJavaProject project= fCompilationUnit.getJavaProject();
337 if (project != null)
338 return new TypeProposalInfo(project, fProposal);
339 }
340 return super.computeProposalInfo();
341 }
342
343 /*
344 * @see org.eclipse.jdt.internal.ui.text.java.LazyJavaCompletionProposal#computeSortString()
345 */
346 @Override
347 protected String computeSortString() {
348 // try fast sort string to avoid display string creation
349 return getSimpleTypeName() + Character.MIN_VALUE + getQualifiedTypeName();
350 }
351
352 /*
353 * @see org.eclipse.jdt.internal.ui.text.java.LazyJavaCompletionProposal#computeRelevance()
354 */
355 @Override
356 protected int computeRelevance() {
357 /*
358 * There are two histories: the RHS history remembers types used for the current expected
359 * type (left hand side), while the type history remembers recently used types in general).
360 *
361 * The presence of an RHS ranking is a much more precise sign for relevance as it proves the
362 * subtype relationship between the proposed type and the expected type.
363 *
364 * The "recently used" factor (of either the RHS or general history) is less important, it should
365 * not override other relevance factors such as if the type is already imported etc.
366 */
367 float rhsHistoryRank= fInvocationContext.getHistoryRelevance(getQualifiedTypeName());
368 float typeHistoryRank= QualifiedTypeNameHistory.getDefault().getNormalizedPosition(getQualifiedTypeName());
369
370 int recencyBoost= Math.round((rhsHistoryRank + typeHistoryRank) * 5);
371 int rhsBoost= rhsHistoryRank > 0.0f ? 50 : 0;
372 int baseRelevance= super.computeRelevance();
373
374 return baseRelevance + rhsBoost + recencyBoost;
375 }
376
377 /*
378 * @see org.eclipse.jdt.internal.ui.text.java.LazyJavaCompletionProposal#computeContextInformation()
379 * @since 3.3
380 */
381 @Override
382 protected IContextInformation computeContextInformation() {
383 char[] signature= fProposal.getSignature();
384 char[][] typeParameters= Signature.getTypeArguments(signature);
385 if (typeParameters.length == 0)
386 return super.computeContextInformation();
387
388 ProposalContextInformation contextInformation= new ProposalContextInformation(fProposal);
389 return contextInformation.generated_5335079162214085417(this);
390
391 }
392}