]> git.uio.no Git - ifi-stolz-refaktor.git/blame - case-study/jdt-before/core refactoring/org/eclipse/jdt/internal/corext/refactoring/generics/InferTypeArgumentsRefactoring.java
Case Study: adding data and statistics
[ifi-stolz-refaktor.git] / case-study / jdt-before / core refactoring / org / eclipse / jdt / internal / corext / refactoring / generics / InferTypeArgumentsRefactoring.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.corext.refactoring.generics;
12
13import java.util.ArrayList;
14import java.util.Arrays;
15import java.util.HashMap;
16import java.util.HashSet;
17import java.util.Iterator;
18import java.util.List;
19import java.util.Map;
20import java.util.Map.Entry;
21import java.util.Set;
22
23import org.eclipse.core.runtime.CoreException;
24import org.eclipse.core.runtime.IProgressMonitor;
25import org.eclipse.core.runtime.ISafeRunnable;
26import org.eclipse.core.runtime.IStatus;
27import org.eclipse.core.runtime.OperationCanceledException;
28import org.eclipse.core.runtime.SafeRunner;
29import org.eclipse.core.runtime.Status;
30import org.eclipse.core.runtime.SubProgressMonitor;
31
32import org.eclipse.core.resources.IFile;
33
34import org.eclipse.ltk.core.refactoring.Change;
35import org.eclipse.ltk.core.refactoring.ChangeDescriptor;
36import org.eclipse.ltk.core.refactoring.Refactoring;
37import org.eclipse.ltk.core.refactoring.RefactoringChangeDescriptor;
38import org.eclipse.ltk.core.refactoring.RefactoringDescriptor;
39import org.eclipse.ltk.core.refactoring.RefactoringStatus;
40
41import org.eclipse.jdt.core.BindingKey;
42import org.eclipse.jdt.core.ICompilationUnit;
43import org.eclipse.jdt.core.IJavaElement;
44import org.eclipse.jdt.core.IJavaProject;
45import org.eclipse.jdt.core.compiler.IProblem;
46import org.eclipse.jdt.core.dom.ASTNode;
47import org.eclipse.jdt.core.dom.ASTParser;
48import org.eclipse.jdt.core.dom.ASTRequestor;
49import org.eclipse.jdt.core.dom.AbstractTypeDeclaration;
50import org.eclipse.jdt.core.dom.CastExpression;
51import org.eclipse.jdt.core.dom.ClassInstanceCreation;
52import org.eclipse.jdt.core.dom.CompilationUnit;
53import org.eclipse.jdt.core.dom.Expression;
54import org.eclipse.jdt.core.dom.IBinding;
55import org.eclipse.jdt.core.dom.Name;
56import org.eclipse.jdt.core.dom.ParameterizedType;
57import org.eclipse.jdt.core.dom.ParenthesizedExpression;
58import org.eclipse.jdt.core.dom.SimpleType;
59import org.eclipse.jdt.core.dom.Type;
60import org.eclipse.jdt.core.dom.TypeLiteral;
61import org.eclipse.jdt.core.refactoring.CompilationUnitChange;
62import org.eclipse.jdt.core.refactoring.IJavaRefactorings;
63import org.eclipse.jdt.core.refactoring.descriptors.InferTypeArgumentsDescriptor;
64
65import org.eclipse.jdt.internal.core.refactoring.descriptors.RefactoringSignatureDescriptorFactory;
66import org.eclipse.jdt.internal.corext.SourceRangeFactory;
67import org.eclipse.jdt.internal.corext.refactoring.Checks;
68import org.eclipse.jdt.internal.corext.refactoring.JDTRefactoringDescriptorComment;
69import org.eclipse.jdt.internal.corext.refactoring.JavaRefactoringArguments;
70import org.eclipse.jdt.internal.corext.refactoring.JavaRefactoringDescriptorUtil;
71import org.eclipse.jdt.internal.corext.refactoring.RefactoringCoreMessages;
72import org.eclipse.jdt.internal.corext.refactoring.base.JavaStatusContext;
73import org.eclipse.jdt.internal.corext.refactoring.changes.DynamicValidationStateChange;
74import org.eclipse.jdt.internal.corext.refactoring.generics.InferTypeArgumentsUpdate.CuUpdate;
75import org.eclipse.jdt.internal.corext.refactoring.structure.CompilationUnitRewrite;
76import org.eclipse.jdt.internal.corext.refactoring.typeconstraints.types.TType;
77import org.eclipse.jdt.internal.corext.refactoring.typeconstraints.typesets.EnumeratedTypeSet;
78import org.eclipse.jdt.internal.corext.refactoring.typeconstraints.typesets.TypeSet;
79import org.eclipse.jdt.internal.corext.refactoring.typeconstraints2.CastVariable2;
80import org.eclipse.jdt.internal.corext.refactoring.typeconstraints2.CollectionElementVariable2;
81import org.eclipse.jdt.internal.corext.refactoring.typeconstraints2.ConstraintVariable2;
82import org.eclipse.jdt.internal.corext.refactoring.typeconstraints2.TypeVariable2;
83import org.eclipse.jdt.internal.corext.refactoring.util.RefactoringASTParser;
84import org.eclipse.jdt.internal.corext.refactoring.util.ResourceUtil;
85import org.eclipse.jdt.internal.corext.refactoring.util.TextChangeManager;
86import org.eclipse.jdt.internal.corext.util.JavaModelUtil;
87import org.eclipse.jdt.internal.corext.util.Messages;
88
89import org.eclipse.jdt.ui.JavaElementLabels;
90
91import org.eclipse.jdt.internal.ui.IJavaStatusConstants;
92import org.eclipse.jdt.internal.ui.JavaPlugin;
93import org.eclipse.jdt.internal.ui.javaeditor.ASTProvider;
94import org.eclipse.jdt.internal.ui.viewsupport.BasicElementLabels;
95
96public class InferTypeArgumentsRefactoring extends Refactoring {
97
98 private static final String ATTRIBUTE_CLONE= "clone"; //$NON-NLS-1$
99 private static final String ATTRIBUTE_LEAVE= "leave"; //$NON-NLS-1$
100
101 private static final String REWRITTEN= "InferTypeArgumentsRefactoring.rewritten"; //$NON-NLS-1$
102
103 private TextChangeManager fChangeManager;
104 private IJavaElement[] fElements;
105 private InferTypeArgumentsTCModel fTCModel;
106
107 private boolean fAssumeCloneReturnsSameType;
108 private boolean fLeaveUnconstrainedRaw;
109
110 /**
111 * Creates a new infer type arguments refactoring.
112 * @param elements the elements to process, or <code>null</code> if invoked by scripting
113 */
114 public InferTypeArgumentsRefactoring(IJavaElement[] elements) {
115 fElements= elements;
116 }
117
118 public InferTypeArgumentsRefactoring(JavaRefactoringArguments arguments, RefactoringStatus status) {
119 this(null);
120 RefactoringStatus initializeStatus= initialize(arguments);
121 status.merge(initializeStatus);
122 }
123
124 /*
125 * @see org.eclipse.ltk.core.refactoring.Refactoring#getName()
126 */
127 @Override
128 public String getName() {
129 return RefactoringCoreMessages.InferTypeArgumentsRefactoring_name;
130 }
131
132 public void setAssumeCloneReturnsSameType(boolean assume) {
133 fAssumeCloneReturnsSameType= assume;
134 }
135
136 public boolean getAssumeCloneReturnsSameType() {
137 return fAssumeCloneReturnsSameType;
138 }
139
140 public void setLeaveUnconstrainedRaw(boolean raw) {
141 fLeaveUnconstrainedRaw= raw;
142 }
143
144 public boolean getLeaveUnconstrainedRaw() {
145 return fLeaveUnconstrainedRaw;
146 }
147
148 /*
149 * @see org.eclipse.ltk.core.refactoring.Refactoring#checkInitialConditions(org.eclipse.core.runtime.IProgressMonitor)
150 */
151 @Override
152 public RefactoringStatus checkInitialConditions(IProgressMonitor pm) throws CoreException, OperationCanceledException {
153 RefactoringStatus result= check15();
154 pm.done();
155 return result;
156 }
157
158 /*
159 * @see org.eclipse.ltk.core.refactoring.Refactoring#checkFinalConditions(org.eclipse.core.runtime.IProgressMonitor)
160 */
161 @Override
162 public RefactoringStatus checkFinalConditions(final IProgressMonitor pm) throws CoreException, OperationCanceledException {
163 HashMap<IJavaProject, ArrayList<IJavaElement>> projectsToElements= getJavaElementsPerProject(fElements);
164 pm.beginTask("", projectsToElements.size() + 2); //$NON-NLS-1$
165 final RefactoringStatus result= new RefactoringStatus();
166 try {
167 fTCModel= new InferTypeArgumentsTCModel();
168 final InferTypeArgumentsConstraintCreator unitCollector= new InferTypeArgumentsConstraintCreator(fTCModel, fAssumeCloneReturnsSameType);
169
170 for (Iterator<Entry<IJavaProject, ArrayList<IJavaElement>>> iter= projectsToElements.entrySet().iterator(); iter.hasNext(); ) {
171 Entry<IJavaProject, ArrayList<IJavaElement>> entry= iter.next();
172 IJavaProject project= entry.getKey();
173 ArrayList<IJavaElement> javaElementsList= entry.getValue();
174 IJavaElement[] javaElements= javaElementsList.toArray(new IJavaElement[javaElementsList.size()]);
175 List<ICompilationUnit> cus= Arrays.asList(JavaModelUtil.getAllCompilationUnits(javaElements));
176
177 int batchSize= 150;
178 int batches= ((cus.size()-1) / batchSize) + 1;
179 SubProgressMonitor projectMonitor= new SubProgressMonitor(pm, 1);
180 projectMonitor.beginTask("", batches); //$NON-NLS-1$
181 projectMonitor.setTaskName(RefactoringCoreMessages.InferTypeArgumentsRefactoring_building);
182 for (int i= 0; i < batches; i++) {
183 List<ICompilationUnit> batch= cus.subList(i * batchSize, Math.min(cus.size(), (i + 1) * batchSize));
184 ICompilationUnit[] batchCus= batch.toArray(new ICompilationUnit[batch.size()]);
185 final SubProgressMonitor batchMonitor= new SubProgressMonitor(projectMonitor, 1);
186 batchMonitor.subTask(RefactoringCoreMessages.InferTypeArgumentsRefactoring_calculating_dependencies);
187
188 ASTParser parser= ASTParser.newParser(ASTProvider.SHARED_AST_LEVEL);
189 parser.setProject(project);
190 parser.setCompilerOptions(RefactoringASTParser.getCompilerOptions(project));
191 parser.setResolveBindings(true);
192 parser.createASTs(batchCus, new String[0], new ASTRequestor() {
193 @Override
194 public void acceptAST(final ICompilationUnit source, final CompilationUnit ast) {
195 batchMonitor.subTask(BasicElementLabels.getFileName(source));
196
197 SafeRunner.run(new ISafeRunnable() {
198 public void run() throws Exception {
199 IProblem[] problems= ast.getProblems();
200 for (int p= 0; p < problems.length; p++) {
201 if (problems[p].isError()) {
202 String cuName= JavaElementLabels.getElementLabel(source, JavaElementLabels.CU_QUALIFIED);
203 String msg= Messages.format(RefactoringCoreMessages.InferTypeArgumentsRefactoring_error_in_cu_skipped, new Object[] {cuName});
204 result.addError(msg, JavaStatusContext.create(source, SourceRangeFactory.create(problems[p])));
205 return;
206 }
207 }
208 ast.accept(unitCollector);
209 }
210 public void handleException(Throwable exception) {
211 String cuName= JavaElementLabels.getElementLabel(source, JavaElementLabels.CU_QUALIFIED);
212 String msg= Messages.format(RefactoringCoreMessages.InferTypeArgumentsRefactoring_internal_error, new Object[] {cuName});
213 JavaPlugin.log(new Status(IStatus.ERROR, JavaPlugin.getPluginId(), IJavaStatusConstants.INTERNAL_ERROR, msg, null));
214 String msg2= Messages.format(RefactoringCoreMessages.InferTypeArgumentsRefactoring_error_skipped, new Object[] {cuName});
215 result.addError(msg2, JavaStatusContext.create(source));
216 }
217 });
218
219 fTCModel.newCu();
220 }
221 @Override
222 public void acceptBinding(String bindingKey, IBinding binding) {
223 //do nothing
224 }
225 }, batchMonitor);
226 }
227
228 projectMonitor.done();
229 fTCModel.newCu();
230 }
231
232// Display.getDefault().syncExec(new Runnable() {
233// public void run() {
234// MessageDialog.openInformation(Display.getCurrent().getActiveShell(), "Debugging...", "after constraint gen");
235// }
236// });
237
238 pm.setTaskName(RefactoringCoreMessages.InferTypeArgumentsRefactoring_solving);
239 InferTypeArgumentsConstraintsSolver solver= new InferTypeArgumentsConstraintsSolver(fTCModel);
240 InferTypeArgumentsUpdate updates= solver.solveConstraints(new SubProgressMonitor(pm, 1));
241 solver= null; //free caches
242
243 fChangeManager= new TextChangeManager();
244 rewriteDeclarations(updates, new SubProgressMonitor(pm, 1));
245
246 IFile[] filesToModify= ResourceUtil.getFiles(fChangeManager.getAllCompilationUnits());
247 result.merge(Checks.validateModifiesFiles(filesToModify, getValidationContext()));
248 return result;
249 } finally {
250 pm.done();
251 clearGlobalState();
252 }
253 }
254
255 private void clearGlobalState() {
256 TypeSet.resetCount();
257 EnumeratedTypeSet.resetCount();
258 fTCModel= null;
259 }
260
261 private HashMap<IJavaProject, ArrayList<IJavaElement>> getJavaElementsPerProject(IJavaElement[] elements) {
262 HashMap<IJavaProject, ArrayList<IJavaElement>> result= new HashMap<IJavaProject, ArrayList<IJavaElement>>();
263 for (int i= 0; i < elements.length; i++) {
264 IJavaElement element= elements[i];
265 IJavaProject javaProject= element.getJavaProject();
266 ArrayList<IJavaElement> javaElements= result.get(javaProject);
267 if (javaElements == null) {
268 javaElements= new ArrayList<IJavaElement>();
269 result.put(javaProject, javaElements);
270 }
271 javaElements.add(element);
272 }
273 return result;
274 }
275
276 private RefactoringStatus check15() throws CoreException {
277 RefactoringStatus result= new RefactoringStatus();
278 HashSet<IJavaProject> checkedProjects= new HashSet<IJavaProject>();
279
280 for (int i= 0; i < fElements.length; i++) {
281 IJavaProject javaProject= fElements[i].getJavaProject();
282 if (! checkedProjects.contains(javaProject)) {
283 if (! JavaModelUtil.is50OrHigher(javaProject)) {
284 String message= Messages.format(RefactoringCoreMessages.InferTypeArgumentsRefactoring_not50, BasicElementLabels.getJavaElementName(javaProject.getElementName()));
285 result.addFatalError(message);
286 } else if (! JavaModelUtil.is50OrHigherJRE(javaProject)) {
287 String message= Messages.format(RefactoringCoreMessages.InferTypeArgumentsRefactoring_not50Library, BasicElementLabels.getJavaElementName(javaProject.getElementName()));
288 result.addFatalError(message);
289 }
290 checkedProjects.add(javaProject);
291 }
292 }
293 return result;
294 }
295
296 private void rewriteDeclarations(InferTypeArgumentsUpdate update, IProgressMonitor pm) throws CoreException {
297 HashMap<ICompilationUnit, CuUpdate> updates= update.getUpdates();
298
299 Set<Entry<ICompilationUnit, CuUpdate>> entrySet= updates.entrySet();
300 pm.beginTask("", entrySet.size()); //$NON-NLS-1$
301 pm.setTaskName(RefactoringCoreMessages.InferTypeArgumentsRefactoring_creatingChanges);
302 for (Iterator<Entry<ICompilationUnit, CuUpdate>> iter= entrySet.iterator(); iter.hasNext();) {
303 if (pm.isCanceled())
304 throw new OperationCanceledException();
305
306 Entry<ICompilationUnit, CuUpdate> entry= iter.next();
307 ICompilationUnit cu= entry.getKey();
308 pm.worked(1);
309 pm.subTask(BasicElementLabels.getFileName(cu));
310
311 CompilationUnitRewrite rewrite= new CompilationUnitRewrite(cu);
312 rewrite.setResolveBindings(false);
313 CuUpdate cuUpdate= entry.getValue();
314
315 for (Iterator<CollectionElementVariable2> cvIter= cuUpdate.getDeclarations().iterator(); cvIter.hasNext();) {
316 ConstraintVariable2 cv= cvIter.next();
317 rewriteConstraintVariable(cv, rewrite, fTCModel, fLeaveUnconstrainedRaw, null);
318 }
319
320 for (Iterator<CastVariable2> castsIter= cuUpdate.getCastsToRemove().iterator(); castsIter.hasNext();) {
321 CastVariable2 castCv= castsIter.next();
322 rewriteCastVariable(castCv, rewrite, fTCModel);
323 }
324
325 CompilationUnitChange change= rewrite.createChange(true);
326 if (change != null) {
327 fChangeManager.manage(cu, change);
328 }
329 }
330
331 }
332
333 public static ParameterizedType[] inferArguments(SimpleType[] types, InferTypeArgumentsUpdate update, InferTypeArgumentsTCModel model, CompilationUnitRewrite rewrite) {
334 for (int i= 0; i < types.length; i++) {
335 types[i].setProperty(REWRITTEN, null);
336 }
337 List<ParameterizedType> result= new ArrayList<ParameterizedType>();
338 HashMap<ICompilationUnit, CuUpdate> updates= update.getUpdates();
339 Set<Entry<ICompilationUnit, CuUpdate>> entrySet= updates.entrySet();
340 for (Iterator<Entry<ICompilationUnit, CuUpdate>> iter= entrySet.iterator(); iter.hasNext();) {
341
342 Entry<ICompilationUnit, CuUpdate> entry= iter.next();
343
344 rewrite.setResolveBindings(false);
345 CuUpdate cuUpdate= entry.getValue();
346
347 for (Iterator<CollectionElementVariable2> cvIter= cuUpdate.getDeclarations().iterator(); cvIter.hasNext();) {
348 ConstraintVariable2 cv= cvIter.next();
349 ParameterizedType newNode= rewriteConstraintVariable(cv, rewrite, model, false, types);
350 if (newNode != null)
351 result.add(newNode);
352 }
353 }
354 return result.toArray(new ParameterizedType[result.size()]);
355 }
356
357 private static ParameterizedType rewriteConstraintVariable(ConstraintVariable2 cv, CompilationUnitRewrite rewrite, InferTypeArgumentsTCModel tCModel, boolean leaveUnconstraindRaw, SimpleType[] types) {
358 if (cv instanceof CollectionElementVariable2) {
359 ConstraintVariable2 parentElement= ((CollectionElementVariable2) cv).getParentConstraintVariable();
360 if (parentElement instanceof TypeVariable2) {
361 TypeVariable2 typeCv= (TypeVariable2) parentElement;
362 return rewriteTypeVariable(typeCv, rewrite, tCModel, leaveUnconstraindRaw, types);
363 } else {
364 //only rewrite type variables
365 }
366 }
367 return null;
368 }
369
370 private static ParameterizedType rewriteTypeVariable(TypeVariable2 typeCv, CompilationUnitRewrite rewrite, InferTypeArgumentsTCModel tCModel, boolean leaveUnconstraindRaw, SimpleType[] types) {
371 ASTNode node= typeCv.getRange().getNode(rewrite.getRoot());
372 if (node instanceof Name && node.getParent() instanceof Type) {
373 Type originalType= (Type) node.getParent();
374
375 if (types != null && !has(types, originalType))
376 return null;
377
378 // Must rewrite all type arguments in one batch. Do the rewrite when the first one is encountered; skip the others.
379 Object rewritten= originalType.getProperty(REWRITTEN);
380 if (rewritten == REWRITTEN)
381 return null;
382 originalType.setProperty(REWRITTEN, REWRITTEN);
383
384 ArrayList<CollectionElementVariable2> typeArgumentCvs= getTypeArgumentCvs(typeCv, tCModel);
385 Type[] typeArguments= getTypeArguments(originalType, typeArgumentCvs, rewrite, tCModel, leaveUnconstraindRaw);
386 if (typeArguments == null)
387 return null;
388
389 Type movingType= (Type) rewrite.getASTRewrite().createMoveTarget(originalType);
390 ParameterizedType newType= rewrite.getAST().newParameterizedType(movingType);
391
392 for (int i= 0; i < typeArguments.length; i++) {
393 newType.typeArguments().add(typeArguments[i]);
394 }
395
396 rewrite.getASTRewrite().replace(originalType, newType, rewrite.createGroupDescription(RefactoringCoreMessages.InferTypeArgumentsRefactoring_addTypeArguments));
397 return newType;
398 } else {//TODO: other node types?
399 return null;
400 }
401 }
402
403 private static boolean has(SimpleType[] types, Type originalType) {
404 for (int i= 0; i < types.length; i++) {
405 if (types[i] == originalType)
406 return true;
407 }
408 return false;
409 }
410
411 /**
412 * @param baseType the base type
413 * @param typeArgumentCvs type argument constraint variables
414 * @param rewrite the cu rewrite
415 * @param tCModel the type constraints model
416 * @param leaveUnconstraindRaw <code>true</code> to keep unconstrained type references raw,
417 * <code>false</code> to infer <code>&lt;?&gt;</code> if possible
418 * @return the new type arguments, or <code>null</code> iff an argument could not be inferred
419 */
420 private static Type[] getTypeArguments(Type baseType, ArrayList<CollectionElementVariable2> typeArgumentCvs, CompilationUnitRewrite rewrite, InferTypeArgumentsTCModel tCModel, boolean leaveUnconstraindRaw) {
421 if (typeArgumentCvs.size() == 0)
422 return null;
423
424 Type[] typeArguments= new Type[typeArgumentCvs.size()];
425 for (int i= 0; i < typeArgumentCvs.size(); i++) {
426 CollectionElementVariable2 elementCv= typeArgumentCvs.get(i);
427 Type typeArgument;
428 TType chosenType= InferTypeArgumentsConstraintsSolver.getChosenType(elementCv);
429 if (chosenType != null) {
430 if (chosenType.isWildcardType() && ! unboundedWildcardAllowed(baseType))
431 return null; // can't e.g. write "new ArrayList<?>()".
432 if (chosenType.isParameterizedType()) // workaround for bug 99124
433 chosenType= chosenType.getTypeDeclaration();
434 BindingKey bindingKey= new BindingKey(chosenType.getBindingKey());
435 typeArgument= rewrite.getImportRewrite().addImportFromSignature(bindingKey.toSignature(), rewrite.getAST());
436 ArrayList<CollectionElementVariable2> nestedTypeArgumentCvs= getTypeArgumentCvs(elementCv, tCModel);
437 Type[] nestedTypeArguments= getTypeArguments(typeArgument, nestedTypeArgumentCvs, rewrite, tCModel, leaveUnconstraindRaw); //recursion
438 if (nestedTypeArguments != null) {
439 ParameterizedType parameterizedType= rewrite.getAST().newParameterizedType(typeArgument);
440 for (int j= 0; j < nestedTypeArguments.length; j++)
441 parameterizedType.typeArguments().add(nestedTypeArguments[j]);
442 typeArgument= parameterizedType;
443 }
444
445 } else { // couldn't infer an element type (no constraints)
446 if (leaveUnconstraindRaw) {
447 // every guess could be wrong => leave the whole thing raw
448 return null;
449 } else {
450 if (unboundedWildcardAllowed(baseType)) {
451 typeArgument= rewrite.getAST().newWildcardType();
452 } else {
453 String object= rewrite.getImportRewrite().addImport("java.lang.Object"); //$NON-NLS-1$
454 typeArgument= (Type) rewrite.getASTRewrite().createStringPlaceholder(object, ASTNode.SIMPLE_TYPE);
455 }
456 }
457// ASTNode baseTypeParent= baseType.getParent();
458// if (baseTypeParent instanceof ClassInstanceCreation) {
459// //No ? allowed. Take java.lang.Object.
460// typeArgument= rewrite.getAST().newSimpleType(rewrite.getAST().newName(rewrite.getImportRewrite().addImport("java.lang.Object"))); //$NON-NLS-1$
461// } else if (baseTypeParent instanceof ArrayCreation || baseTypeParent instanceof InstanceofExpression) {
462// //Only ? allowed.
463// typeArgument= rewrite.getAST().newWildcardType();
464// } else {
465// //E.g. field type: can put anything. Choosing ? in order to be most constraining.
466// typeArgument= rewrite.getAST().newWildcardType();
467// }
468 }
469 typeArguments[i]= typeArgument;
470 }
471 return typeArguments;
472 }
473
474 private static ArrayList<CollectionElementVariable2> getTypeArgumentCvs(ConstraintVariable2 baseCv, InferTypeArgumentsTCModel tCModel) {
475 Map<String, CollectionElementVariable2> elementCvs= tCModel.getElementVariables(baseCv);
476 ArrayList<CollectionElementVariable2> typeArgumentCvs= new ArrayList<CollectionElementVariable2>();
477 for (Iterator<CollectionElementVariable2> iter= elementCvs.values().iterator(); iter.hasNext();) {
478 CollectionElementVariable2 elementCv= iter.next();
479 int index= elementCv.getDeclarationTypeVariableIndex();
480 if (index != CollectionElementVariable2.NOT_DECLARED_TYPE_VARIABLE_INDEX) {
481 while (index >= typeArgumentCvs.size())
482 typeArgumentCvs.add(null); // fill with null until set(index, ..) is possible
483 typeArgumentCvs.set(index, elementCv);
484 }
485 }
486 return typeArgumentCvs;
487 }
488
489 private static boolean unboundedWildcardAllowed(Type originalType) {
490 ASTNode parent= originalType.getParent();
491 while (parent instanceof Type)
492 parent= parent.getParent();
493
494 if (parent instanceof ClassInstanceCreation) {
495 return false;
496 } else if (parent instanceof AbstractTypeDeclaration) {
497 return false;
498 } else if (parent instanceof TypeLiteral) {
499 return false;
500 }
501 return true;
502 }
503
504 private static ASTNode rewriteCastVariable(CastVariable2 castCv, CompilationUnitRewrite rewrite, InferTypeArgumentsTCModel tCModel) {//, List positionGroups) {
505 ASTNode node= castCv.getRange().getNode(rewrite.getRoot());
506
507 ConstraintVariable2 expressionVariable= castCv.getExpressionVariable();
508 ConstraintVariable2 methodReceiverCv= tCModel.getMethodReceiverCv(expressionVariable);
509 if (methodReceiverCv != null) {
510 TType chosenReceiverType= InferTypeArgumentsConstraintsSolver.getChosenType(methodReceiverCv);
511 if (chosenReceiverType == null)
512 return null;
513 else if (! InferTypeArgumentsTCModel.isAGenericType(chosenReceiverType))
514 return null;
515 else if (hasUnboundElement(methodReceiverCv, tCModel))
516 return null;
517 }
518
519 CastExpression castExpression= (CastExpression) node;
520 Expression expression= castExpression.getExpression();
521 ASTNode nodeToReplace;
522 if (castExpression.getParent() instanceof ParenthesizedExpression)
523 nodeToReplace= castExpression.getParent();
524 else
525 nodeToReplace= castExpression;
526
527 Expression newExpression= (Expression) rewrite.getASTRewrite().createMoveTarget(expression);
528 rewrite.getASTRewrite().replace(nodeToReplace, newExpression, rewrite.createGroupDescription(RefactoringCoreMessages.InferTypeArgumentsRefactoring_removeCast));
529 rewrite.getImportRemover().registerRemovedNode(nodeToReplace);
530 return newExpression;
531 }
532
533 private static boolean hasUnboundElement(ConstraintVariable2 methodReceiverCv, InferTypeArgumentsTCModel tCModel) {
534 ArrayList<CollectionElementVariable2> typeArgumentCvs= getTypeArgumentCvs(methodReceiverCv, tCModel);
535 for (Iterator<CollectionElementVariable2> iter= typeArgumentCvs.iterator(); iter.hasNext();) {
536 CollectionElementVariable2 elementCv= iter.next();
537 TType chosenElementType= InferTypeArgumentsConstraintsSolver.getChosenType(elementCv);
538 if (chosenElementType == null)
539 return true;
540 }
541 return false;
542 }
543
544 /*
545 * @see org.eclipse.ltk.core.refactoring.Refactoring#createChange(org.eclipse.core.runtime.IProgressMonitor)
546 */
547 @Override
548 public Change createChange(IProgressMonitor pm) throws CoreException, OperationCanceledException {
549 pm.beginTask("", 1); //$NON-NLS-1$
550 try {
551 DynamicValidationStateChange result= new DynamicValidationStateChange(RefactoringCoreMessages.InferTypeArgumentsRefactoring_name, fChangeManager.getAllChanges()) {
552
553 @Override
554 public final ChangeDescriptor getDescriptor() {
555 final Map<String, String> arguments= new HashMap<String, String>();
556 final IJavaProject project= getSingleProject();
557 final String description= RefactoringCoreMessages.InferTypeArgumentsRefactoring_descriptor_description;
558 final String header= project != null ? Messages.format(RefactoringCoreMessages.InferTypeArgumentsRefactoring_descriptor_description_project, BasicElementLabels.getJavaElementName(project.getElementName())) : RefactoringCoreMessages.InferTypeArgumentsRefactoring_descriptor_description;
559 final String name= project != null ? project.getElementName() : null;
560 final JDTRefactoringDescriptorComment comment= new JDTRefactoringDescriptorComment(name, this, header);
561 final String[] settings= new String[fElements.length];
562 for (int index= 0; index < settings.length; index++)
563 settings[index]= JavaElementLabels.getTextLabel(fElements[index], JavaElementLabels.ALL_FULLY_QUALIFIED);
564 comment.addSetting(JDTRefactoringDescriptorComment.createCompositeSetting(RefactoringCoreMessages.InferTypeArgumentsRefactoring_original_elements, settings));
565 if (fAssumeCloneReturnsSameType)
566 comment.addSetting(RefactoringCoreMessages.InferTypeArgumentsRefactoring_assume_clone);
567 if (fLeaveUnconstrainedRaw)
568 comment.addSetting(RefactoringCoreMessages.InferTypeArgumentsRefactoring_leave_unconstrained);
569 final InferTypeArgumentsDescriptor descriptor= RefactoringSignatureDescriptorFactory.createInferTypeArgumentsDescriptor(name, description, comment.asString(), arguments, RefactoringDescriptor.STRUCTURAL_CHANGE | RefactoringDescriptor.MULTI_CHANGE);
570 for (int index= 0; index < fElements.length; index++)
571 arguments.put(JavaRefactoringDescriptorUtil.ATTRIBUTE_ELEMENT + (index + 1), JavaRefactoringDescriptorUtil.elementToHandle(name, fElements[index]));
572 arguments.put(ATTRIBUTE_CLONE, Boolean.valueOf(fAssumeCloneReturnsSameType).toString());
573 arguments.put(ATTRIBUTE_LEAVE, Boolean.valueOf(fLeaveUnconstrainedRaw).toString());
574 return new RefactoringChangeDescriptor(descriptor);
575 }
576 };
577 return result;
578 } finally {
579 pm.done();
580 }
581 }
582
583 private IJavaProject getSingleProject() {
584 IJavaProject first= null;
585 for (int index= 0; index < fElements.length; index++) {
586 final IJavaProject project= fElements[index].getJavaProject();
587 if (project != null) {
588 if (first == null)
589 first= project;
590 else if (!project.equals(first))
591 return null;
592 }
593 }
594 return first;
595 }
596
597 private RefactoringStatus initialize(JavaRefactoringArguments arguments) {
598 final String clone= arguments.getAttribute(ATTRIBUTE_CLONE);
599 if (clone != null) {
600 fAssumeCloneReturnsSameType= Boolean.valueOf(clone).booleanValue();
601 } else
602 return RefactoringStatus.createFatalErrorStatus(Messages.format(RefactoringCoreMessages.InitializableRefactoring_argument_not_exist, ATTRIBUTE_CLONE));
603 final String leave= arguments.getAttribute(ATTRIBUTE_LEAVE);
604 if (leave != null) {
605 fLeaveUnconstrainedRaw= Boolean.valueOf(leave).booleanValue();
606 } else
607 return RefactoringStatus.createFatalErrorStatus(Messages.format(RefactoringCoreMessages.InitializableRefactoring_argument_not_exist, ATTRIBUTE_LEAVE));
608 int count= 1;
609 final List<IJavaElement> elements= new ArrayList<IJavaElement>();
610 String handle= null;
611 String attribute= JavaRefactoringDescriptorUtil.ATTRIBUTE_ELEMENT + count;
612 final RefactoringStatus status= new RefactoringStatus();
613 while ((handle= arguments.getAttribute(attribute)) != null) {
614 final IJavaElement element= JavaRefactoringDescriptorUtil.handleToElement(arguments.getProject(), handle, false);
615 if (element == null || !element.exists())
616 return JavaRefactoringDescriptorUtil.createInputFatalStatus(element, getName(), IJavaRefactorings.INFER_TYPE_ARGUMENTS);
617 else
618 elements.add(element);
619 count++;
620 attribute= JavaRefactoringDescriptorUtil.ATTRIBUTE_ELEMENT + count;
621 }
622 fElements= elements.toArray(new IJavaElement[elements.size()]);
623 if (elements.isEmpty())
624 return JavaRefactoringDescriptorUtil.createInputFatalStatus(null, getName(), IJavaRefactorings.INFER_TYPE_ARGUMENTS);
625 if (!status.isOK())
626 return status;
627 return new RefactoringStatus();
628 }
629}