]> git.uio.no Git - ifi-stolz-refaktor.git/blame - case-study/jdt-before/core refactoring/org/eclipse/jdt/internal/corext/refactoring/structure/ChangeTypeRefactoring.java
Case Study: adding data and statistics
[ifi-stolz-refaktor.git] / case-study / jdt-before / core refactoring / org / eclipse / jdt / internal / corext / refactoring / structure / ChangeTypeRefactoring.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.structure;
12
13import java.util.ArrayList;
14import java.util.Arrays;
15import java.util.Collection;
16import java.util.HashMap;
17import java.util.HashSet;
18import java.util.Iterator;
19import java.util.List;
20import java.util.Map;
21import java.util.Set;
22import java.util.StringTokenizer;
23
24import org.eclipse.core.runtime.Assert;
25import org.eclipse.core.runtime.CoreException;
26import org.eclipse.core.runtime.IProgressMonitor;
27import org.eclipse.core.runtime.NullProgressMonitor;
28import org.eclipse.core.runtime.OperationCanceledException;
29import org.eclipse.core.runtime.SubProgressMonitor;
30
31import org.eclipse.text.edits.MultiTextEdit;
32import org.eclipse.text.edits.TextEditGroup;
33
34import org.eclipse.ltk.core.refactoring.Change;
35import org.eclipse.ltk.core.refactoring.Refactoring;
36import org.eclipse.ltk.core.refactoring.RefactoringDescriptor;
37import org.eclipse.ltk.core.refactoring.RefactoringStatus;
38
39import org.eclipse.jdt.core.ICompilationUnit;
40import org.eclipse.jdt.core.IField;
41import org.eclipse.jdt.core.IJavaElement;
42import org.eclipse.jdt.core.IJavaProject;
43import org.eclipse.jdt.core.IMethod;
44import org.eclipse.jdt.core.JavaModelException;
45import org.eclipse.jdt.core.dom.AST;
46import org.eclipse.jdt.core.dom.ASTNode;
47import org.eclipse.jdt.core.dom.CompilationUnit;
48import org.eclipse.jdt.core.dom.Expression;
49import org.eclipse.jdt.core.dom.FieldDeclaration;
50import org.eclipse.jdt.core.dom.IBinding;
51import org.eclipse.jdt.core.dom.IMethodBinding;
52import org.eclipse.jdt.core.dom.ITypeBinding;
53import org.eclipse.jdt.core.dom.IVariableBinding;
54import org.eclipse.jdt.core.dom.MethodDeclaration;
55import org.eclipse.jdt.core.dom.NodeFinder;
56import org.eclipse.jdt.core.dom.ParameterizedType;
57import org.eclipse.jdt.core.dom.QualifiedName;
58import org.eclipse.jdt.core.dom.SimpleName;
59import org.eclipse.jdt.core.dom.SingleVariableDeclaration;
60import org.eclipse.jdt.core.dom.Type;
61import org.eclipse.jdt.core.dom.UnionType;
62import org.eclipse.jdt.core.dom.VariableDeclarationExpression;
63import org.eclipse.jdt.core.dom.VariableDeclarationFragment;
64import org.eclipse.jdt.core.dom.VariableDeclarationStatement;
65import org.eclipse.jdt.core.dom.rewrite.ASTRewrite;
66import org.eclipse.jdt.core.dom.rewrite.ImportRewrite;
67import org.eclipse.jdt.core.dom.rewrite.TargetSourceRangeComputer;
68import org.eclipse.jdt.core.refactoring.CompilationUnitChange;
69import org.eclipse.jdt.core.refactoring.IJavaRefactorings;
70import org.eclipse.jdt.core.refactoring.descriptors.GeneralizeTypeDescriptor;
71import org.eclipse.jdt.core.refactoring.descriptors.JavaRefactoringDescriptor;
72import org.eclipse.jdt.core.search.IJavaSearchConstants;
73import org.eclipse.jdt.core.search.IJavaSearchScope;
74import org.eclipse.jdt.core.search.SearchPattern;
75
76import org.eclipse.jdt.internal.core.refactoring.descriptors.RefactoringSignatureDescriptorFactory;
77import org.eclipse.jdt.internal.corext.codemanipulation.StubUtility;
78import org.eclipse.jdt.internal.corext.dom.ASTNodeFactory;
79import org.eclipse.jdt.internal.corext.dom.Bindings;
80import org.eclipse.jdt.internal.corext.refactoring.Checks;
81import org.eclipse.jdt.internal.corext.refactoring.CollectingSearchRequestor;
82import org.eclipse.jdt.internal.corext.refactoring.JDTRefactoringDescriptorComment;
83import org.eclipse.jdt.internal.corext.refactoring.JavaRefactoringArguments;
84import org.eclipse.jdt.internal.corext.refactoring.JavaRefactoringDescriptorUtil;
85import org.eclipse.jdt.internal.corext.refactoring.RefactoringCoreMessages;
86import org.eclipse.jdt.internal.corext.refactoring.RefactoringScopeFactory;
87import org.eclipse.jdt.internal.corext.refactoring.RefactoringSearchEngine;
88import org.eclipse.jdt.internal.corext.refactoring.SearchResultGroup;
89import org.eclipse.jdt.internal.corext.refactoring.changes.DynamicValidationRefactoringChange;
90import org.eclipse.jdt.internal.corext.refactoring.rename.MethodChecks;
91import org.eclipse.jdt.internal.corext.refactoring.rename.RippleMethodFinder2;
92import org.eclipse.jdt.internal.corext.refactoring.typeconstraints.ASTCreator;
93import org.eclipse.jdt.internal.corext.refactoring.typeconstraints.CompositeOrTypeConstraint;
94import org.eclipse.jdt.internal.corext.refactoring.typeconstraints.ConstraintCollector;
95import org.eclipse.jdt.internal.corext.refactoring.typeconstraints.ConstraintOperator;
96import org.eclipse.jdt.internal.corext.refactoring.typeconstraints.ConstraintVariable;
97import org.eclipse.jdt.internal.corext.refactoring.typeconstraints.ConstraintVariableFactory;
98import org.eclipse.jdt.internal.corext.refactoring.typeconstraints.ExpressionVariable;
99import org.eclipse.jdt.internal.corext.refactoring.typeconstraints.FullConstraintCreator;
100import org.eclipse.jdt.internal.corext.refactoring.typeconstraints.ITypeConstraint;
101import org.eclipse.jdt.internal.corext.refactoring.typeconstraints.ParameterTypeVariable;
102import org.eclipse.jdt.internal.corext.refactoring.typeconstraints.ReturnTypeVariable;
103import org.eclipse.jdt.internal.corext.refactoring.typeconstraints.SimpleTypeConstraint;
104import org.eclipse.jdt.internal.corext.refactoring.typeconstraints.TypeConstraintFactory;
105import org.eclipse.jdt.internal.corext.refactoring.typeconstraints.TypeVariable;
106import org.eclipse.jdt.internal.corext.refactoring.util.RefactoringASTParser;
107import org.eclipse.jdt.internal.corext.refactoring.util.ResourceUtil;
108import org.eclipse.jdt.internal.corext.util.Messages;
109import org.eclipse.jdt.internal.corext.util.SearchUtils;
110
111import org.eclipse.jdt.ui.JavaElementLabels;
112
113import org.eclipse.jdt.internal.ui.JavaPlugin;
114import org.eclipse.jdt.internal.ui.javaeditor.ASTProvider;
115import org.eclipse.jdt.internal.ui.viewsupport.BasicElementLabels;
116import org.eclipse.jdt.internal.ui.viewsupport.BindingLabelProvider;
117
118/**
119 * @author tip
120 */
121public class ChangeTypeRefactoring extends Refactoring {
122
123 private static final String ATTRIBUTE_TYPE= "type"; //$NON-NLS-1$
124
125 private final Map<ICompilationUnit, List<ITypeConstraint>> fConstraintCache;
126 /**
127 * Offset of the selected text area.
128 */
129 private int fSelectionStart;
130
131 /**
132 * Length of the selected text area.
133 */
134 private int fSelectionLength;
135
136 /**
137 * Offset of the effective selection
138 */
139 private int fEffectiveSelectionStart;
140
141 /**
142 * Length of the effective selection
143 */
144 private int fEffectiveSelectionLength;
145
146 /**
147 * ICompilationUnit containing the selection.
148 */
149 private ICompilationUnit fCu;
150
151 /**
152 * If the selection corresponds to a method parameter/return type, this field stores
153 * a reference to its IMethodBinding, otherwise this field remains null. Used during
154 * search for references in other CUs, and for determining the ConstraintVariable
155 * that corresponds to the selection
156 */
157 private IMethodBinding fMethodBinding;
158
159 /**
160 * If the selection corresponds to a method parameter, this field stores the parameter
161 * index (0 = first parameter for static methods, 0 = this for nonstatic methods). The
162 * value -1 is stored in the field if the selection corresponds to a method return type.
163 */
164 private int fParamIndex;
165
166 /**
167 * The name of the selected parameter, or <code>null</code>.
168 */
169 private String fParamName;
170
171 /**
172 * If the selection corresponds to a field, this field stores a reference to its IVariableBinding,
173 * otherwise this field remains null. Used during search for references in other CUs.
174 */
175 private IVariableBinding fFieldBinding;
176
177 /**
178 * The compilation units that contain constraint variables related to the selection
179 */
180 private ICompilationUnit[] fAffectedUnits;
181
182 /**
183 * The constraint variables that are of interest to this refactoring. This includes
184 * the constraint var. corresponding to the text selection, and possibly additional
185 * elements due to method overriding, method calls, etc.
186 */
187 private Collection<ConstraintVariable> fRelevantVars;
188
189 /**
190 * The set of types (other than the original type) that can be given to
191 * the selected ASTNode.
192 */
193 private final Collection<ITypeBinding> fValidTypes;
194
195 /**
196 * The type constraints that are related to the selected ASTNode.
197 */
198 private Collection<ITypeConstraint> fRelevantConstraints;
199
200 /**
201 * All type constraints in affected compilation units.
202 */
203 private Collection<ITypeConstraint> fAllConstraints;
204
205 /**
206 * The name of the new type of the selected declaration.
207 */
208 private String fSelectedTypeName;
209
210 /**
211 * The new type of the selected declaration.
212 */
213 private ITypeBinding fSelectedType;
214
215 /**
216 * Organizes SearchResults by CompilationUnit
217 */
218 private Map<ICompilationUnit, SearchResultGroup> fCuToSearchResultGroup= new HashMap<ICompilationUnit, SearchResultGroup>();
219
220
221 /**
222 * ITypeBinding for java.lang.Object
223 */
224 private ITypeBinding fObject;
225
226 public ITypeBinding getObject(){
227 return fObject;
228 }
229
230 /**
231 * Control debugging output.
232 */
233 private static final boolean DEBUG= false;
234
235 private ConstraintVariable fCv;
236 private IBinding fSelectionBinding;
237 private ITypeBinding fSelectionTypeBinding;
238 private ConstraintCollector fCollector;
239
240 public ChangeTypeRefactoring(ICompilationUnit cu, int selectionStart, int selectionLength) {
241 this(cu, selectionStart, selectionLength, null);
242 }
243
244 /**
245 * Constructor for ChangeTypeRefactoring (invoked from tests only)
246 * @param cu the compilation unit
247 * @param selectionStart selection offset
248 * @param selectionLength selection length
249 * @param selectedType selected type
250 */
251 public ChangeTypeRefactoring(ICompilationUnit cu, int selectionStart, int selectionLength, String selectedType) {
252 Assert.isTrue(selectionStart >= 0);
253 Assert.isTrue(selectionLength >= 0);
254
255 fSelectionStart= selectionStart;
256 fSelectionLength= selectionLength;
257
258 fEffectiveSelectionStart= selectionStart;
259 fEffectiveSelectionLength= selectionLength;
260
261 fCu= cu;
262
263 if (selectedType != null)
264 fSelectedTypeName= selectedType;
265
266 fConstraintCache= new HashMap<ICompilationUnit, List<ITypeConstraint>>();
267 fValidTypes= new HashSet<ITypeBinding>();
268 }
269
270 public ChangeTypeRefactoring(JavaRefactoringArguments arguments, RefactoringStatus status) {
271 this(null, 0, 0, null);
272 RefactoringStatus initializeStatus= initialize(arguments);
273 status.merge(initializeStatus);
274 }
275
276 // ------------------------------------------------------------------------------------------------- //
277
278 /*
279 * @see org.eclipse.jdt.internal.corext.refactoring.base.Refactoring#checkActivation(org.eclipse.core.runtime.IProgressMonitor)
280 */
281 @Override
282 public RefactoringStatus checkInitialConditions(IProgressMonitor pm) throws CoreException {
283 if (fCu == null || !fCu.isStructureKnown())
284 return RefactoringStatus.createFatalErrorStatus(RefactoringCoreMessages.ChangeTypeRefactoring_invalidSelection);
285 return checkSelection(new SubProgressMonitor(pm, 1));
286 }
287
288 private void setSelectionRanges(Expression exp){
289 fEffectiveSelectionStart= exp.getStartPosition();
290 fEffectiveSelectionLength= exp.getLength();
291 fSelectionBinding= ExpressionVariable.resolveBinding(exp);
292 setOriginalType(exp.resolveTypeBinding());
293 }
294
295 /**
296 * Check if the right type of AST Node is selected. Create the TypeHierarchy needed to
297 * bring up the wizard.
298 * @param pm progress monitor
299 * @return returns the resulting status
300 */
301 private RefactoringStatus checkSelection(IProgressMonitor pm) {
302 try {
303 pm.beginTask("", 5); //$NON-NLS-1$
304
305 ASTNode node= getTargetNode(fCu, fSelectionStart, fSelectionLength);
306 if (DEBUG) {
307 System.out.println(
308 "selection: [" //$NON-NLS-1$
309 + fSelectionStart
310 + "," //$NON-NLS-1$
311 + (fSelectionStart + fSelectionLength)
312 + "] in " //$NON-NLS-1$
313 + fCu.getElementName());
314 System.out.println("node= " + node + ", type= " + node.getClass().getName()); //$NON-NLS-1$ //$NON-NLS-2$
315 }
316
317 TypeConstraintFactory typeConstraintFactory = new TypeConstraintFactory(){
318 @Override
319 public boolean filter(ConstraintVariable v1, ConstraintVariable v2, ConstraintOperator o){
320 if (o.isStrictSubtypeOperator()) //TODO: explain why these can be excluded
321 return true;
322 //Don't create constraint if fSelectionTypeBinding is not involved:
323 if (v1.getBinding() != null && v2.getBinding() != null
324 && ! Bindings.equals(v1.getBinding(), fSelectionTypeBinding)
325 && ! Bindings.equals(v2.getBinding(), fSelectionTypeBinding)) {
326 if (PRINT_STATS) fNrFiltered++;
327 return true;
328 }
329 return super.filter(v1, v2, o);
330 }
331 };
332 fCollector= new ConstraintCollector(new FullConstraintCreator(new ConstraintVariableFactory(), typeConstraintFactory));
333 String selectionValid= determineSelection(node);
334 if (selectionValid != null){
335 if (DEBUG){
336 System.out.println("invalid selection: " + selectionValid); //$NON-NLS-1$
337 }
338 return RefactoringStatus.createFatalErrorStatus(selectionValid);
339 }
340
341 if (fMethodBinding != null) {
342 IMethod selectedMethod= (IMethod) fMethodBinding.getJavaElement();
343 if (selectedMethod == null){
344 return RefactoringStatus.createFatalErrorStatus(RefactoringCoreMessages.ChangeTypeRefactoring_insideLocalTypesNotSupported);
345 }
346 }
347
348 pm.worked(1);
349
350 RefactoringStatus result= new RefactoringStatus();
351
352 if (DEBUG){
353 System.out.println("fSelectionTypeBinding: " + fSelectionTypeBinding.getName()); //$NON-NLS-1$
354 }
355
356 // produce error message if array or primitive type is selected
357 if (fSelectionTypeBinding.isArray()){
358 return RefactoringStatus.createFatalErrorStatus(RefactoringCoreMessages.ChangeTypeRefactoring_arraysNotSupported);
359 }
360 if (fSelectionTypeBinding.isPrimitive()){
361 return RefactoringStatus.createFatalErrorStatus(RefactoringCoreMessages.ChangeTypeRefactoring_primitivesNotSupported);
362 }
363 if (checkOverriddenBinaryMethods())
364 return RefactoringStatus.createFatalErrorStatus(RefactoringCoreMessages.ChangeTypeRefactoring_notSupportedOnBinary);
365
366 if (fSelectionTypeBinding.isLocal()){
367 return RefactoringStatus.createFatalErrorStatus(RefactoringCoreMessages.ChangeTypeRefactoring_localTypesNotSupported);
368 }
369
370 if (fFieldBinding != null && fFieldBinding.getDeclaringClass().isLocal()){
371 return RefactoringStatus.createFatalErrorStatus(RefactoringCoreMessages.ChangeTypeRefactoring_insideLocalTypesNotSupported);
372 }
373
374 if (fSelectionTypeBinding.isTypeVariable()){
375 return RefactoringStatus.createFatalErrorStatus(RefactoringCoreMessages.ChangeTypeRefactoring_typeParametersNotSupported);
376 }
377
378 if (fSelectionTypeBinding.isEnum()){
379 return RefactoringStatus.createFatalErrorStatus(RefactoringCoreMessages.ChangeTypeRefactoring_enumsNotSupported);
380 }
381
382 pm.worked(1);
383
384 if (fSelectedType != null){ // if invoked from unit test, compute valid types here
385 computeValidTypes(new NullProgressMonitor());
386 }
387 return result;
388 } finally {
389 pm.done();
390 }
391 }
392
393 private boolean checkOverriddenBinaryMethods() {
394 if (fMethodBinding != null){
395 Set<ITypeBinding> declaringSupertypes= getDeclaringSuperTypes(fMethodBinding);
396 for (Iterator<ITypeBinding> iter= declaringSupertypes.iterator(); iter.hasNext();) {
397 ITypeBinding superType= iter.next();
398 IMethodBinding overriddenMethod= findMethod(fMethodBinding, superType);
399 Assert.isNotNull(overriddenMethod);//because we asked for declaring types
400 IMethod iMethod= (IMethod) overriddenMethod.getJavaElement();
401 if (iMethod.isBinary()){
402 return true;
403 }
404 }
405 }
406 return false;
407 }
408
409 // copied from FullConstraintCreator
410 private static IMethodBinding findMethod(IMethodBinding methodBinding, ITypeBinding type) {
411 if (methodBinding.getDeclaringClass().equals(type))
412 return methodBinding;
413 return Bindings.findOverriddenMethodInType(type, methodBinding);
414 }
415
416 // copied from FullConstraintCreator
417 private static Set<ITypeBinding> getDeclaringSuperTypes(IMethodBinding methodBinding) {
418 ITypeBinding[] allSuperTypes= Bindings.getAllSuperTypes(methodBinding.getDeclaringClass());
419 Set<ITypeBinding> result= new HashSet<ITypeBinding>();
420 for (int i= 0; i < allSuperTypes.length; i++) {
421 ITypeBinding type= allSuperTypes[i];
422 if (findMethod(methodBinding, type) != null)
423 result.add(type);
424 }
425 return result;
426 }
427
428 /**
429 * Do the actual work of computing allowable types. Invoked by the wizard when
430 * "compute" button is pressed
431 * @param pm the progress monitor
432 * @return the valid types
433 */
434 public Collection<ITypeBinding> computeValidTypes(IProgressMonitor pm) {
435
436 pm.beginTask(RefactoringCoreMessages.ChangeTypeRefactoring_checking_preconditions, 100);
437
438 try {
439 fCv= findConstraintVariableForSelectedNode(new SubProgressMonitor(pm, 3));
440 if (DEBUG) System.out.println("selected CV: " + fCv + //$NON-NLS-1$
441 " (" + fCv.getClass().getName() + //$NON-NLS-1$
442 ")"); //$NON-NLS-1$
443
444 if (pm.isCanceled())
445 throw new OperationCanceledException();
446 fRelevantVars= findRelevantConstraintVars(fCv, new SubProgressMonitor(pm, 50));
447
448 if (DEBUG)
449 printCollection("relevant vars:", fRelevantVars); //$NON-NLS-1$
450
451 if (pm.isCanceled())
452 throw new OperationCanceledException();
453 fRelevantConstraints= findRelevantConstraints(fRelevantVars, new SubProgressMonitor(pm, 30));
454
455 if (pm.isCanceled())
456 throw new OperationCanceledException();
457 fValidTypes.addAll(computeValidTypes(fSelectionTypeBinding, fRelevantVars,
458 fRelevantConstraints, new SubProgressMonitor(pm, 20)));
459
460 if (DEBUG)
461 printCollection("valid types:", getValidTypeNames()); //$NON-NLS-1$
462 } catch (CoreException e) {
463 JavaPlugin.logErrorMessage("Error occurred during computation of valid types: " + e.toString()); //$NON-NLS-1$
464 fValidTypes.clear(); // error occurred during computation of valid types
465 }
466
467 pm.done();
468
469 return fValidTypes;
470 }
471
472
473 /*
474 * @see org.eclipse.jdt.internal.corext.refactoring.base.Refactoring#checkInput(org.eclipse.core.runtime.IProgressMonitor)
475 */
476 @Override
477 public RefactoringStatus checkFinalConditions(IProgressMonitor pm) throws CoreException {
478 pm.beginTask(RefactoringCoreMessages.ChangeTypeRefactoring_checking_preconditions, 1);
479
480 RefactoringStatus result= Checks.validateModifiesFiles(
481 ResourceUtil.getFiles(fAffectedUnits), getValidationContext());
482
483 pm.done();
484 return result;
485 }
486// TODO: do sanity check somewhere if the refactoring changes any files.
487 /*
488 * @see org.eclipse.jdt.internal.corext.refactoring.base.IRefactoring#createChange(org.eclipse.core.runtime.IProgressMonitor)
489 */
490 @Override
491 public Change createChange(IProgressMonitor pm) throws CoreException {
492 pm.beginTask(RefactoringCoreMessages.ChangeTypeMessages_CreateChangesForChangeType, 1);
493 try {
494 Map<ICompilationUnit, Set<ConstraintVariable>> relevantVarsByUnit= new HashMap<ICompilationUnit, Set<ConstraintVariable>>();
495 groupChangesByCompilationUnit(relevantVarsByUnit);
496 final Map<String, String> arguments= new HashMap<String, String>();
497 String project= null;
498 IJavaProject javaProject= fCu.getJavaProject();
499 if (javaProject != null)
500 project= javaProject.getElementName();
501 final String description= RefactoringCoreMessages.ChangeTypeRefactoring_descriptor_description_short;
502 final String header= Messages.format(RefactoringCoreMessages.ChangeTypeRefactoring_descriptor_description, new String[] { BindingLabelProvider.getBindingLabel(fSelectionBinding, JavaElementLabels.ALL_FULLY_QUALIFIED), BindingLabelProvider.getBindingLabel(fSelectedType, JavaElementLabels.ALL_FULLY_QUALIFIED)});
503 final JDTRefactoringDescriptorComment comment= new JDTRefactoringDescriptorComment(project, this, header);
504 comment.addSetting(Messages.format(RefactoringCoreMessages.ChangeTypeRefactoring_original_element_pattern, BindingLabelProvider.getBindingLabel(fSelectionBinding, JavaElementLabels.ALL_FULLY_QUALIFIED)));
505 comment.addSetting(Messages.format(RefactoringCoreMessages.ChangeTypeRefactoring_original_type_pattern, BindingLabelProvider.getBindingLabel(getOriginalType(), JavaElementLabels.ALL_FULLY_QUALIFIED)));
506 comment.addSetting(Messages.format(RefactoringCoreMessages.ChangeTypeRefactoring_refactored_type_pattern, BindingLabelProvider.getBindingLabel(fSelectedType, JavaElementLabels.ALL_FULLY_QUALIFIED)));
507 final GeneralizeTypeDescriptor descriptor= RefactoringSignatureDescriptorFactory.createGeneralizeTypeDescriptor(project, description, comment.asString(), arguments, (RefactoringDescriptor.STRUCTURAL_CHANGE | JavaRefactoringDescriptor.JAR_REFACTORING | JavaRefactoringDescriptor.JAR_SOURCE_ATTACHMENT));
508 arguments.put(JavaRefactoringDescriptorUtil.ATTRIBUTE_INPUT, JavaRefactoringDescriptorUtil.elementToHandle(project, fCu));
509 arguments.put(JavaRefactoringDescriptorUtil.ATTRIBUTE_SELECTION, new Integer(fSelectionStart).toString() + " " + new Integer(fSelectionLength).toString()); //$NON-NLS-1$
510 arguments.put(ATTRIBUTE_TYPE, fSelectedType.getQualifiedName());
511 final DynamicValidationRefactoringChange result= new DynamicValidationRefactoringChange(descriptor, RefactoringCoreMessages.ChangeTypeRefactoring_allChanges);
512 for (Iterator<ICompilationUnit>it= relevantVarsByUnit.keySet().iterator(); it.hasNext();) {
513 ICompilationUnit icu= it.next();
514 Set<ConstraintVariable> cVars= relevantVarsByUnit.get(icu);
515 CompilationUnitChange cuChange= new CompilationUnitChange(getName(), icu);
516 addAllChangesFor(icu, cVars, cuChange);
517 result.add(cuChange);
518 pm.worked(1);
519 if (pm.isCanceled())
520 throw new OperationCanceledException();
521 }
522 return result;
523 } finally {
524 pm.done();
525 }
526 }
527
528 /**
529 * Apply all changes related to a single ICompilationUnit
530 * @param icu the compilation unit
531 * @param vars
532 * @param unitChange
533 * @throws CoreException
534 */
535 private void addAllChangesFor(ICompilationUnit icu, Set<ConstraintVariable> vars, CompilationUnitChange unitChange) throws CoreException {
536 CompilationUnit unit= new RefactoringASTParser(ASTProvider.SHARED_AST_LEVEL).parse(icu, false);
537 ASTRewrite unitRewriter= ASTRewrite.create(unit.getAST());
538 MultiTextEdit root= new MultiTextEdit();
539 unitChange.setEdit(root); // Adam sez don't need this, but then unitChange.addGroupDescription() fails an assertion!
540
541 String typeName= updateImports(unit, root);
542 updateCu(unit, vars, unitChange, unitRewriter, typeName);
543 root.addChild(unitRewriter.rewriteAST());
544 }
545
546 private class SourceRangeComputer extends TargetSourceRangeComputer {
547 @Override
548 public SourceRange computeSourceRange(ASTNode node) {
549 return new SourceRange(node.getStartPosition(),node.getLength());
550 }
551 }
552
553 private void updateCu(CompilationUnit unit, Set<ConstraintVariable> vars, CompilationUnitChange unitChange,
554 ASTRewrite unitRewriter, String typeName) throws JavaModelException {
555
556 // use custom SourceRangeComputer to avoid losing comments
557 unitRewriter.setTargetSourceRangeComputer(new SourceRangeComputer());
558
559 for (Iterator<ConstraintVariable> it=vars.iterator(); it.hasNext(); ){
560 ConstraintVariable cv = it.next();
561 ASTNode decl= findDeclaration(unit, cv);
562 if ((decl instanceof SimpleName || decl instanceof QualifiedName) && cv instanceof ExpressionVariable) {
563 ASTNode gp= decl.getParent().getParent();
564 updateType(unit, getType(gp), unitChange, unitRewriter, typeName); // local variable or parameter
565 } else if (decl instanceof MethodDeclaration || decl instanceof FieldDeclaration) {
566 updateType(unit, getType(decl), unitChange, unitRewriter, typeName); // method return or field type
567 } else if (decl instanceof ParameterizedType){
568 updateType(unit, getType(decl), unitChange, unitRewriter, typeName);
569 }
570 }
571 }
572
573 private void updateType(CompilationUnit cu, Type oldType, CompilationUnitChange unitChange,
574 ASTRewrite unitRewriter, String typeName) {
575
576 String oldName= fSelectionTypeBinding.getName();
577 String[] keys= { BasicElementLabels.getJavaElementName(oldName), BasicElementLabels.getJavaElementName(typeName)};
578 String description= Messages.format(RefactoringCoreMessages.ChangeTypeRefactoring_typeChange, keys);
579 TextEditGroup gd= new TextEditGroup(description);
580 AST ast= cu.getAST();
581
582 ASTNode nodeToReplace= oldType;
583 if (fSelectionTypeBinding.isParameterizedType() && !fSelectionTypeBinding.isRawType()){
584 if (oldType.isSimpleType()){
585 nodeToReplace= oldType.getParent();
586 }
587 }
588
589 //TODO handle types other than simple & parameterized (e.g., arrays)
590 Assert.isTrue(fSelectedType.isClass() || fSelectedType.isInterface());
591
592 Type newType= null;
593 if (!fSelectedType.isParameterizedType()){
594 newType= ast.newSimpleType(ASTNodeFactory.newName(ast, typeName));
595 } else {
596 newType= createParameterizedType(ast, fSelectedType);
597 }
598
599 unitRewriter.replace(nodeToReplace, newType, gd);
600 unitChange.addTextEditGroup(gd);
601 }
602
603 /**
604 * Creates the appropriate ParameterizedType node. Recursion is needed to
605 * handle the nested case (e.g., Vector<Vector<String>>).
606 * @param ast
607 * @param typeBinding
608 * @return the created type
609 */
610 private Type createParameterizedType(AST ast, ITypeBinding typeBinding){
611 if (typeBinding.isParameterizedType() && !typeBinding.isRawType()){
612 Type baseType= ast.newSimpleType(ASTNodeFactory.newName(ast, typeBinding.getErasure().getName()));
613 ParameterizedType newType= ast.newParameterizedType(baseType);
614 for (int i=0; i < typeBinding.getTypeArguments().length; i++){
615 ITypeBinding typeArg= typeBinding.getTypeArguments()[i];
616 Type argType= createParameterizedType(ast, typeArg); // recursive call
617 newType.typeArguments().add(argType);
618 }
619 return newType;
620 } else {
621 if (!typeBinding.isTypeVariable()){
622 return ast.newSimpleType(ASTNodeFactory.newName(ast, typeBinding.getErasure().getName()));
623 } else {
624 return ast.newSimpleType(ast.newSimpleName(typeBinding.getName()));
625 }
626 }
627 }
628
629
630
631 private void groupChangesByCompilationUnit(Map<ICompilationUnit, Set<ConstraintVariable>> relevantVarsByUnit) {
632 for (Iterator<ConstraintVariable> it= fRelevantVars.iterator(); it.hasNext();) {
633 ConstraintVariable cv= it.next();
634 if (!(cv instanceof ExpressionVariable) && !(cv instanceof ReturnTypeVariable)){
635 continue;
636 }
637 ICompilationUnit icu = null;
638 if (cv instanceof ExpressionVariable) {
639 ExpressionVariable ev = (ExpressionVariable)cv;
640 icu = ev.getCompilationUnitRange().getCompilationUnit();
641 } else if (cv instanceof ReturnTypeVariable){
642 ReturnTypeVariable rtv = (ReturnTypeVariable)cv;
643 IMethodBinding mb= rtv.getMethodBinding();
644 icu= ((IMethod) mb.getJavaElement()).getCompilationUnit();
645 }
646 if (!relevantVarsByUnit.containsKey(icu)){
647 relevantVarsByUnit.put(icu, new HashSet<ConstraintVariable>());
648 }
649 relevantVarsByUnit.get(icu).add(cv);
650 }
651 }
652
653 private ASTNode findDeclaration(CompilationUnit root, ConstraintVariable cv) throws JavaModelException {
654
655 if (fFieldBinding != null){
656 IField f= (IField) fFieldBinding.getJavaElement();
657 return ASTNodeSearchUtil.getFieldDeclarationNode(f, root);
658 }
659
660 if (cv instanceof ExpressionVariable){
661 for (Iterator<ITypeConstraint> iter= fAllConstraints.iterator(); iter.hasNext();) {
662 ITypeConstraint constraint= iter.next();
663 if (constraint.isSimpleTypeConstraint()){
664 SimpleTypeConstraint stc= (SimpleTypeConstraint)constraint;
665 if (stc.isDefinesConstraint() && stc.getLeft().equals(cv)){
666 ConstraintVariable right= stc.getRight();
667 if (right instanceof TypeVariable){
668 TypeVariable typeVariable= (TypeVariable)right;
669 return NodeFinder.perform(root, typeVariable.getCompilationUnitRange().getSourceRange());
670 }
671 }
672 }
673 }
674 } else if (cv instanceof ReturnTypeVariable) {
675 ReturnTypeVariable rtv= (ReturnTypeVariable) cv;
676 IMethodBinding mb= rtv.getMethodBinding();
677 IMethod im= (IMethod) mb.getJavaElement();
678 return ASTNodeSearchUtil.getMethodDeclarationNode(im, root);
679 }
680 return null;
681 }
682
683 private static Type getType(ASTNode node) {
684 switch(node.getNodeType()){
685 case ASTNode.SINGLE_VARIABLE_DECLARATION:
686 return ((SingleVariableDeclaration) node).getType();
687 case ASTNode.FIELD_DECLARATION:
688 return ((FieldDeclaration) node).getType();
689 case ASTNode.VARIABLE_DECLARATION_STATEMENT:
690 return ((VariableDeclarationStatement) node).getType();
691 case ASTNode.VARIABLE_DECLARATION_EXPRESSION:
692 return ((VariableDeclarationExpression) node).getType();
693 case ASTNode.METHOD_DECLARATION:
694 return ((MethodDeclaration)node).getReturnType2();
695 case ASTNode.PARAMETERIZED_TYPE:
696 return ((ParameterizedType)node).getType();
697 default:
698 Assert.isTrue(false);
699 return null;
700 }
701 }
702
703 /*
704 * @see org.eclipse.jdt.internal.corext.refactoring.base.IRefactoring#getName()
705 */
706 @Override
707 public String getName() {
708 return RefactoringCoreMessages.ChangeTypeRefactoring_name;
709 }
710
711 // ------------------------------------------------------------------------------------------------- //
712 // Method for examining if a suitable kind of ASTNode was selected. Information about this node and
713 // its parents in the AST are stored in fields fBinding, theMethod, and theField
714
715 /**
716 * Determines what kind of ASTNode has been selected.
717 * @param node the node
718 * @return A non-null String containing an error message
719 * is returned if the ChangeTypeRefactoring refactoring cannot be applied to the selected ASTNode.
720 * A return value of null indicates a valid selection.
721 */
722 private String determineSelection(ASTNode node) {
723 if (node == null) {
724 return RefactoringCoreMessages.ChangeTypeRefactoring_invalidSelection;
725 } else {
726
727 if (DEBUG) System.out.println("node nodeType= " + node.getClass().getName()); //$NON-NLS-1$
728 if (DEBUG) System.out.println("parent nodeType= " + node.getParent().getClass().getName()); //$NON-NLS-1$
729 if (DEBUG) System.out.println("GrandParent nodeType= " + node.getParent().getParent().getClass().getName()); //$NON-NLS-1$
730
731 ASTNode parent= node.getParent();
732 ASTNode grandParent= parent.getParent();
733 if (grandParent == null)
734 return nodeTypeNotSupported();
735
736 // adjustment needed if part of a parameterized type is selected
737 if (grandParent.getNodeType() == ASTNode.PARAMETERIZED_TYPE){
738 node= grandParent;
739 }
740
741 // adjustment needed if part of a qualified name is selected
742 ASTNode current= null;
743 if (node.getNodeType() == ASTNode.QUALIFIED_NAME){
744 current= node;
745 while (current.getNodeType() == ASTNode.QUALIFIED_NAME){
746 current= current.getParent();
747 }
748 if (current.getNodeType() != ASTNode.SIMPLE_TYPE){
749 return nodeTypeNotSupported();
750 }
751 node= current.getParent();
752 } else if (parent.getNodeType() == ASTNode.QUALIFIED_NAME){
753 current= parent;
754 while (current.getNodeType() == ASTNode.QUALIFIED_NAME){
755 current= current.getParent();
756 }
757 if (current.getNodeType() != ASTNode.SIMPLE_TYPE){
758 return nodeTypeNotSupported();
759 }
760 node= current.getParent();
761 }
762
763 fObject= node.getAST().resolveWellKnownType("java.lang.Object"); //$NON-NLS-1$
764 switch (node.getNodeType()) {
765 case ASTNode.SIMPLE_NAME :
766 return simpleNameSelected((SimpleName)node);
767 case ASTNode.VARIABLE_DECLARATION_STATEMENT :
768 return variableDeclarationStatementSelected((VariableDeclarationStatement) node);
769 case ASTNode.FIELD_DECLARATION :
770 return fieldDeclarationSelected((FieldDeclaration) node);
771 case ASTNode.SINGLE_VARIABLE_DECLARATION :
772 return singleVariableDeclarationSelected((SingleVariableDeclaration) node);
773 case ASTNode.PARAMETERIZED_TYPE:
774 return parameterizedTypeSelected((ParameterizedType) node);
775 default :
776 return nodeTypeNotSupported();
777 }
778 }
779 }
780 /**
781 * The selection corresponds to an ASTNode on which "ChangeTypeRefactoring" is not defined.
782 * @return the message
783 */
784 private static String nodeTypeNotSupported() {
785 return RefactoringCoreMessages.ChangeTypeRefactoring_notSupportedOnNodeType;
786 }
787
788 /**
789 * The selection corresponds to a SingleVariableDeclaration
790 * @param svd
791 * @return the message
792 */
793 private String singleVariableDeclarationSelected(SingleVariableDeclaration svd) {
794 SimpleName name = svd.getName();
795 setSelectionRanges(name);
796 return simpleNameSelected(name);
797 }
798
799 /**
800 * The selection corresponds to a ParameterizedType (return type of method)
801 * @param pt the type
802 * @return the message
803 */
804 private String parameterizedTypeSelected(ParameterizedType pt) {
805 ASTNode parent= pt.getParent();
806 if (parent.getNodeType() == ASTNode.METHOD_DECLARATION){
807 fMethodBinding= ((MethodDeclaration)parent).resolveBinding();
808 fParamIndex= -1;
809 fEffectiveSelectionStart= pt.getStartPosition();
810 fEffectiveSelectionLength= pt.getLength();
811 setOriginalType(pt.resolveBinding());
812 } else if (parent.getNodeType() == ASTNode.SINGLE_VARIABLE_DECLARATION){
813 return singleVariableDeclarationSelected((SingleVariableDeclaration)parent);
814 } else if (parent.getNodeType() == ASTNode.VARIABLE_DECLARATION_STATEMENT){
815 return variableDeclarationStatementSelected((VariableDeclarationStatement)parent);
816 } else if (parent.getNodeType() == ASTNode.FIELD_DECLARATION){
817 return fieldDeclarationSelected((FieldDeclaration)parent);
818 } else {
819 return nodeTypeNotSupported();
820 }
821 return null;
822 }
823
824 /**
825 * The selection corresponds to a VariableDeclarationStatement
826 * @param vds the name
827 * @return the message
828 */
829 private String variableDeclarationStatementSelected(VariableDeclarationStatement vds) {
830 if (vds.fragments().size() != 1) {
831 return RefactoringCoreMessages.ChangeTypeRefactoring_multiDeclarationsNotSupported;
832 } else {
833 VariableDeclarationFragment elem= (VariableDeclarationFragment) vds.fragments().iterator().next();
834 SimpleName name= elem.getName();
835 setSelectionRanges(name);
836 return simpleNameSelected(name);
837 }
838 }
839
840 /**
841 * The selection corresponds to a FieldDeclaration
842 * @param fieldDeclaration the field
843 * @return the message
844 */
845 private String fieldDeclarationSelected(FieldDeclaration fieldDeclaration) {
846 if (fieldDeclaration.fragments().size() != 1) {
847 return RefactoringCoreMessages.ChangeTypeRefactoring_multiDeclarationsNotSupported;
848 } else {
849 VariableDeclarationFragment elem= (VariableDeclarationFragment) fieldDeclaration.fragments().iterator().next();
850 fFieldBinding= elem.resolveBinding();
851 SimpleName name= elem.getName();
852 setSelectionRanges(name);
853 return simpleNameSelected(name);
854 }
855 }
856
857 /**
858 * The selection corresponds to a SimpleName
859 * @param simpleName the name
860 * @return the message
861 */
862 private String simpleNameSelected(SimpleName simpleName) {
863 ASTNode parent= simpleName.getParent();
864 ASTNode grandParent= parent.getParent();
865
866 if (parent.getNodeType() == ASTNode.VARIABLE_DECLARATION_STATEMENT){
867 VariableDeclarationStatement vds= (VariableDeclarationStatement)parent;
868 if (vds.fragments().size() > 1){
869 return RefactoringCoreMessages.ChangeTypeRefactoring_multiDeclarationsNotSupported;
870 }
871 } else if (parent.getNodeType() == ASTNode.VARIABLE_DECLARATION_FRAGMENT) {
872 if (grandParent.getNodeType() == ASTNode.VARIABLE_DECLARATION_STATEMENT){
873 VariableDeclarationStatement vds= (VariableDeclarationStatement)grandParent;
874 if (vds.fragments().size() > 1) {
875 return RefactoringCoreMessages.ChangeTypeRefactoring_multiDeclarationsNotSupported;
876 }
877 setSelectionRanges(simpleName);
878 } else if (grandParent.getNodeType() == ASTNode.VARIABLE_DECLARATION_EXPRESSION) {
879 VariableDeclarationExpression vde= (VariableDeclarationExpression)grandParent;
880 if (vde.fragments().size() > 1) {
881 return RefactoringCoreMessages.ChangeTypeRefactoring_multiDeclarationsNotSupported;
882 }
883 setSelectionRanges(simpleName);
884 } else if (grandParent.getNodeType() == ASTNode.FIELD_DECLARATION) {
885 FieldDeclaration fd= (FieldDeclaration)grandParent;
886 if (fd.fragments().size() > 1){
887 return RefactoringCoreMessages.ChangeTypeRefactoring_multiDeclarationsNotSupported;
888 }
889 VariableDeclarationFragment fragment = (VariableDeclarationFragment)parent;
890 fFieldBinding= fragment.resolveBinding();
891 setSelectionRanges(fragment.getName());
892 } else {
893 return RefactoringCoreMessages.ChangeTypeRefactoring_notSupportedOnNodeType;
894 }
895 } else if (parent.getNodeType() == ASTNode.SINGLE_VARIABLE_DECLARATION) {
896 SingleVariableDeclaration singleVariableDeclaration= (SingleVariableDeclaration) parent;
897 if (singleVariableDeclaration.getType() instanceof UnionType) {
898 return RefactoringCoreMessages.ChangeTypeRefactoring_uniontypeNotSupported;
899 }
900 if ((grandParent.getNodeType() == ASTNode.METHOD_DECLARATION)) {
901 fMethodBinding= ((MethodDeclaration)grandParent).resolveBinding();
902 setOriginalType(simpleName.resolveTypeBinding());
903 fParamIndex= ((MethodDeclaration)grandParent).parameters().indexOf(parent);
904 fParamName= singleVariableDeclaration.getName().getIdentifier();
905 } else {
906 setSelectionRanges(singleVariableDeclaration.getName());
907 }
908 } else if (parent.getNodeType() == ASTNode.SIMPLE_TYPE && (grandParent.getNodeType() == ASTNode.SINGLE_VARIABLE_DECLARATION)) {
909 ASTNode greatGrandParent= grandParent.getParent();
910 SingleVariableDeclaration singleVariableDeclaration= (SingleVariableDeclaration) grandParent;
911 if (singleVariableDeclaration.getExtraDimensions() > 0 || singleVariableDeclaration.isVarargs()) {
912 return RefactoringCoreMessages.ChangeTypeRefactoring_arraysNotSupported;
913 }
914 if (greatGrandParent != null && greatGrandParent.getNodeType() == ASTNode.METHOD_DECLARATION) {
915 fMethodBinding= ((MethodDeclaration)greatGrandParent).resolveBinding();
916 fParamIndex= ((MethodDeclaration)greatGrandParent).parameters().indexOf(grandParent);
917 fParamName= singleVariableDeclaration.getName().getIdentifier();
918 setSelectionRanges(simpleName);
919 } else {
920 setSelectionRanges(singleVariableDeclaration.getName());
921 }
922 } else if (parent.getNodeType() == ASTNode.SIMPLE_TYPE && grandParent.getNodeType() == ASTNode.METHOD_DECLARATION) {
923 fMethodBinding= ((MethodDeclaration)grandParent).resolveBinding();
924 setOriginalType(fMethodBinding.getReturnType());
925 fParamIndex= -1;
926 } else if (parent.getNodeType() == ASTNode.METHOD_DECLARATION &&
927 grandParent.getNodeType() == ASTNode.TYPE_DECLARATION) {
928 MethodDeclaration methodDeclaration= (MethodDeclaration)parent;
929 if (methodDeclaration.getName().equals(simpleName) || methodDeclaration.thrownExceptions().contains(simpleName)){
930 return RefactoringCoreMessages.ChangeTypeRefactoring_notSupportedOnNodeType;
931 }
932 fMethodBinding= ((MethodDeclaration)parent).resolveBinding();
933 fParamIndex= -1;
934 } else if (
935 parent.getNodeType() == ASTNode.SIMPLE_TYPE && (grandParent.getNodeType() == ASTNode.VARIABLE_DECLARATION_STATEMENT)) {
936 return variableDeclarationStatementSelected((VariableDeclarationStatement) grandParent);
937 } else if (parent.getNodeType() == ASTNode.CAST_EXPRESSION) {
938 ASTNode decl= findDeclaration(parent.getRoot(), fSelectionStart, fSelectionLength+1);
939 VariableDeclarationFragment fragment= (VariableDeclarationFragment)decl;
940 SimpleName name = fragment.getName();
941 setSelectionRanges(name);
942 } else if (parent.getNodeType() == ASTNode.SIMPLE_TYPE &&
943 grandParent.getNodeType() == ASTNode.FIELD_DECLARATION) {
944 return fieldDeclarationSelected((FieldDeclaration) grandParent);
945 } else if (parent.getNodeType() == ASTNode.SIMPLE_TYPE &&
946 grandParent.getNodeType() == ASTNode.ARRAY_TYPE){
947 return RefactoringCoreMessages.ChangeTypeRefactoring_arraysNotSupported;
948 } else if (parent.getNodeType() == ASTNode.QUALIFIED_NAME){
949 setSelectionRanges(simpleName);
950 } else {
951 return RefactoringCoreMessages.ChangeTypeRefactoring_notSupportedOnNodeType;
952 }
953 return null;
954 }
955
956 // ------------------------------------------------------------------------------------------------- //
957 // Methods for examining & solving type constraints. This includes:
958 // (1) locating the ConstraintVariable corresponding to the selected ASTNode
959 // (2) finding all ConstraintVariables "related" to (1) via overriding, method calls, field access
960 // (3) find all ITypeConstraints of interest that mention ConstraintVariables in (2)
961 // (4) determining all ITypes for which the ITypeConstraints in (3) are satisfied
962
963 /**
964 * Find a ConstraintVariable that corresponds to the selected ASTNode.
965 * @param pm
966 * @return the ConstraintVariable
967 */
968 private ConstraintVariable findConstraintVariableForSelectedNode(IProgressMonitor pm) {
969 pm.beginTask(RefactoringCoreMessages.ChangeTypeRefactoring_analyzingMessage, 100);
970 ICompilationUnit[] cus= { fCu }; // only search in CU containing selection
971
972 if (DEBUG){
973 System.out.println("Effective selection: " + fEffectiveSelectionStart + "/" + fEffectiveSelectionLength); //$NON-NLS-1$ //$NON-NLS-2$
974 }
975
976 Collection<ITypeConstraint> allConstraints= getConstraints(cus, new SubProgressMonitor(pm, 50));
977
978 IProgressMonitor subMonitor= new SubProgressMonitor(pm, 50);
979 subMonitor.beginTask(RefactoringCoreMessages.ChangeTypeRefactoring_analyzingMessage, allConstraints.size());
980 for (Iterator<ITypeConstraint> it= allConstraints.iterator(); it.hasNext(); ) {
981 subMonitor.worked(1);
982 ITypeConstraint tc= it.next();
983 if (! (tc instanceof SimpleTypeConstraint))
984 continue;
985 SimpleTypeConstraint stc= (SimpleTypeConstraint) tc;
986 if (matchesSelection(stc.getLeft()))
987 return stc.getLeft();
988 if (matchesSelection(stc.getRight()))
989 return stc.getRight();
990 }
991 subMonitor.done();
992 pm.done();
993 Assert.isTrue(false, RefactoringCoreMessages.ChangeTypeRefactoring_noMatchingConstraintVariable);
994 return null;
995 }
996
997 /**
998 * Determine if a given ConstraintVariable matches the selected ASTNode.
999 * @param cv the ConstraintVariable
1000 * @return <code>true</code> if the given ConstraintVariable matches the selected ASTNode
1001 */
1002 private boolean matchesSelection(ConstraintVariable cv){
1003 if (cv instanceof ExpressionVariable){
1004 ExpressionVariable ev= (ExpressionVariable)cv;
1005 return (fSelectionBinding != null && Bindings.equals(fSelectionBinding, ev.getExpressionBinding()));
1006 } else if (cv instanceof ParameterTypeVariable){
1007 ParameterTypeVariable ptv = (ParameterTypeVariable)cv;
1008 if (fMethodBinding != null && Bindings.equals(ptv.getMethodBinding(), fMethodBinding) &&
1009 ptv.getParameterIndex() == fParamIndex){
1010 return true;
1011 }
1012 } else if (cv instanceof ReturnTypeVariable){
1013 ReturnTypeVariable rtv = (ReturnTypeVariable)cv;
1014 if (fMethodBinding != null && Bindings.equals(rtv.getMethodBinding(), fMethodBinding) &&
1015 fParamIndex == -1){
1016 return true;
1017 }
1018 }
1019 return false;
1020 }
1021
1022 /**
1023 * Determine the set of constraint variables related to the selected
1024 * expression. In addition to the expression itself, this consists of
1025 * any expression that is defines-equal to it, and any expression equal
1026 * to it.
1027 * @param cv
1028 * @param pm
1029 * @return the constraint variables
1030 * @throws CoreException
1031 */
1032 private Collection<ConstraintVariable> findRelevantConstraintVars(ConstraintVariable cv, IProgressMonitor pm) throws CoreException {
1033 pm.beginTask(RefactoringCoreMessages.ChangeTypeRefactoring_analyzingMessage, 150);
1034 Collection<ConstraintVariable> result= new HashSet<ConstraintVariable>();
1035 result.add(cv);
1036 ICompilationUnit[] cus= collectAffectedUnits(new SubProgressMonitor(pm, 50));
1037 Collection<ITypeConstraint> allConstraints= getConstraints(cus, new SubProgressMonitor(pm, 50));
1038
1039 List<ConstraintVariable> workList= new ArrayList<ConstraintVariable>(result);
1040 while(! workList.isEmpty()){
1041
1042 pm.worked(10);
1043
1044 ConstraintVariable first= workList.remove(0);
1045 for (Iterator<ITypeConstraint> iter= allConstraints.iterator(); iter.hasNext();) {
1046 pm.worked(1);
1047 ITypeConstraint typeConstraint= iter.next();
1048 if (! typeConstraint.isSimpleTypeConstraint())
1049 continue;
1050 SimpleTypeConstraint stc= (SimpleTypeConstraint)typeConstraint;
1051 if (! stc.isDefinesConstraint() && ! stc.isEqualsConstraint())
1052 continue;
1053 ConstraintVariable match= match(first, stc.getLeft(), stc.getRight());
1054 if (match instanceof ExpressionVariable
1055 || match instanceof ParameterTypeVariable
1056 || match instanceof ReturnTypeVariable){
1057 if (! result.contains(match)){
1058 workList.add(match);
1059 result.add(match);
1060 }
1061 }
1062 }
1063 }
1064
1065 pm.done();
1066
1067 return result;
1068 }
1069 private static ConstraintVariable match(ConstraintVariable matchee, ConstraintVariable left, ConstraintVariable right) {
1070 if (matchee.equals(left))
1071 return right;
1072 if (matchee.equals(right))
1073 return left;
1074 return null;
1075 }
1076
1077 /**
1078 * Select the type constraints that involve the selected ASTNode.
1079 * @param relevantConstraintVars
1080 * @param pm
1081 * @return the result
1082 * @throws CoreException
1083 */
1084 private Collection<ITypeConstraint> findRelevantConstraints(Collection<ConstraintVariable> relevantConstraintVars,
1085 IProgressMonitor pm) throws CoreException {
1086
1087 ICompilationUnit[] cus= collectAffectedUnits(new SubProgressMonitor(pm, 100));
1088
1089 fAllConstraints= getConstraints(cus, new SubProgressMonitor(pm, 900));
1090
1091 pm.beginTask(RefactoringCoreMessages.ChangeTypeRefactoring_analyzingMessage, 1000 + fAllConstraints.size());
1092
1093
1094 if (DEBUG) printCollection("type constraints: ", fAllConstraints); //$NON-NLS-1$
1095 Collection<ITypeConstraint> result= new ArrayList<ITypeConstraint>();
1096 for (Iterator<ITypeConstraint> it= fAllConstraints.iterator(); it.hasNext(); ) {
1097 ITypeConstraint tc= it.next();
1098 if (tc.isSimpleTypeConstraint()) {
1099 SimpleTypeConstraint stc= (SimpleTypeConstraint) tc;
1100 if (stc.isDefinesConstraint() || stc.isEqualsConstraint())
1101 continue;
1102 if (stc.getLeft().equals(stc.getRight()))
1103 continue;
1104 if (isNull(stc.getLeft()))
1105 continue;
1106 if (relevantConstraintVars.contains(stc.getLeft()) || relevantConstraintVars.contains(stc.getRight()))
1107 result.add(tc);
1108 } else {
1109 CompositeOrTypeConstraint cotc= (CompositeOrTypeConstraint) tc;
1110 ITypeConstraint[] components= cotc.getConstraints();
1111 for (int i= 0; i < components.length; i++) {
1112 ITypeConstraint component= components[i];
1113 SimpleTypeConstraint simpleComponent= (SimpleTypeConstraint) component;
1114 if (relevantConstraintVars.contains(simpleComponent.getLeft()))
1115 result.add(tc);
1116 }
1117 }
1118 pm.worked(1);
1119 }
1120 if (DEBUG)
1121 printCollection("selected constraints: ", result); //$NON-NLS-1$
1122 pm.done();
1123 return result;
1124 }
1125
1126 /**
1127 * Finds the declaration of the ASTNode in a given AST at a specified offset and with a specified length
1128 * @param root the AST
1129 * @param start start
1130 * @param length length
1131 * @return the declaring node
1132 */
1133 private static ASTNode findDeclaration(final ASTNode root, final int start, final int length){
1134 ASTNode node= NodeFinder.perform(root, start, length);
1135 Assert.isTrue(node instanceof SimpleName, String.valueOf(node.getNodeType()));
1136 Assert.isTrue(root instanceof CompilationUnit, String.valueOf(root.getNodeType()));
1137 return ((CompilationUnit)root).findDeclaringNode(((SimpleName)node).resolveBinding());
1138 }
1139
1140 // For debugging
1141 static String print(Collection<ITypeBinding> types){
1142 if (types.isEmpty())
1143 return "{ }"; //$NON-NLS-1$
1144 String result = "{ "; //$NON-NLS-1$
1145 for (Iterator<ITypeBinding> it=types.iterator(); it.hasNext(); ){
1146 ITypeBinding type= it.next();
1147 result += type.getQualifiedName();
1148 if (it.hasNext()){
1149 result += ", "; //$NON-NLS-1$
1150 } else {
1151 result += " }"; //$NON-NLS-1$
1152 }
1153 }
1154 return result;
1155 }
1156
1157
1158 /**
1159 * Determines the set of types for which a set of type constraints is satisfied.
1160 * @param originalType
1161 * @param relevantVars
1162 * @param relevantConstraints
1163 * @param pm
1164 * @return the valid types
1165 * @throws JavaModelException
1166 */
1167 private Collection<ITypeBinding> computeValidTypes(ITypeBinding originalType,
1168 Collection<ConstraintVariable> relevantVars,
1169 Collection<ITypeConstraint> relevantConstraints,
1170 IProgressMonitor pm) throws JavaModelException {
1171
1172 Collection<ITypeBinding> result= new HashSet<ITypeBinding>();
1173
1174 Collection<ITypeBinding> allTypes = new HashSet<ITypeBinding>();
1175 allTypes.addAll(getAllSuperTypes(originalType));
1176
1177 pm.beginTask(RefactoringCoreMessages.ChangeTypeRefactoring_analyzingMessage, allTypes.size());
1178
1179 for (Iterator<ITypeBinding> it= allTypes.iterator(); it.hasNext(); ) {
1180 ITypeBinding type= it.next();
1181 if (isValid(type, relevantVars, relevantConstraints, new SubProgressMonitor(pm, 1))) {
1182 result.add(type);
1183 }
1184 }
1185 // "changing" to the original type is a no-op
1186 result.remove(originalType);
1187
1188 // TODO: remove all types that are not visible --- need to check visibility in the CUs for
1189 // all relevant constraint variables
1190
1191 pm.done();
1192
1193 return result;
1194 }
1195
1196 /**
1197 * Determines if a given type satisfies a set of type constraints.
1198 * @param type
1199 * @param relevantVars
1200 * @param constraints
1201 * @param pm
1202 * @return <code>true</code> if a the type satisfies a set of type constraints.
1203 * @throws JavaModelException
1204 */
1205 private boolean isValid(ITypeBinding type,
1206 Collection<ConstraintVariable> relevantVars,
1207 Collection<ITypeConstraint> constraints,
1208 IProgressMonitor pm) throws JavaModelException {
1209 pm.beginTask(RefactoringCoreMessages.ChangeTypeRefactoring_analyzingMessage, constraints.size());
1210 for (Iterator<ITypeConstraint> it= constraints.iterator(); it.hasNext(); ) {
1211 ITypeConstraint tc= it.next();
1212 if (tc instanceof SimpleTypeConstraint) {
1213 if (!(isValidSimpleConstraint(type, relevantVars, (SimpleTypeConstraint) tc)))
1214 return false;
1215 } else if (tc instanceof CompositeOrTypeConstraint) {
1216 if (!(isValidOrConstraint(type, relevantVars, (CompositeOrTypeConstraint) tc)))
1217 return false;
1218 }
1219 pm.worked(1);
1220 }
1221 pm.done();
1222 return true;
1223 }
1224
1225 private boolean isValidSimpleConstraint(ITypeBinding type,
1226 Collection<ConstraintVariable> relevantVars,
1227 SimpleTypeConstraint stc){
1228 if (relevantVars.contains(stc.getLeft())) { // upper bound
1229 if (!isSubTypeOf(type, findType(stc.getRight()))) {
1230 return false;
1231 }
1232 }
1233 return true;
1234 }
1235
1236 private boolean isValidOrConstraint(ITypeBinding type,
1237 Collection<ConstraintVariable> relevantVars,
1238 CompositeOrTypeConstraint cotc){
1239 ITypeConstraint[] components= cotc.getConstraints();
1240 for (int i= 0; i < components.length; i++) {
1241 if (components[i] instanceof SimpleTypeConstraint) {
1242 SimpleTypeConstraint sc= (SimpleTypeConstraint) components[i];
1243 if (relevantVars.contains(sc.getLeft())) { // upper bound
1244 if (isSubTypeOf(type, findType(sc.getRight())))
1245 return true;
1246 } else if (relevantVars.contains(sc.getRight())) { // lower bound
1247 if (isSubTypeOf(findType(sc.getLeft()), type))
1248 return true;
1249 }
1250 }
1251 }
1252 return false;
1253 }
1254
1255
1256 private ITypeBinding findType(ConstraintVariable cv) {
1257 return cv.getBinding();
1258 }
1259
1260 /**
1261 * Gather constraints associated with a set of compilation units.
1262 * @param referringCus
1263 * @param pm
1264 * @return the constraints
1265 */
1266 private Collection<ITypeConstraint> getConstraints(ICompilationUnit[] referringCus, IProgressMonitor pm) {
1267 pm.beginTask(RefactoringCoreMessages.ChangeTypeRefactoring_analyzingMessage, referringCus.length);
1268 Collection<ITypeConstraint> result= new ArrayList<ITypeConstraint>();
1269 for (int i= 0; i < referringCus.length; i++) {
1270 result.addAll(getConstraints(referringCus[i]));
1271 pm.worked(1);
1272 if (pm.isCanceled())
1273 throw new OperationCanceledException();
1274 }
1275 pm.done();
1276 return result;
1277 }
1278
1279 private List<ITypeConstraint> getConstraints(ICompilationUnit unit) {
1280 if (fConstraintCache.containsKey(unit))
1281 return fConstraintCache.get(unit);
1282
1283 CompilationUnit cu= ASTCreator.createAST(unit, null);
1284
1285 // only generate type constraints for relevant MethodDeclaration subtrees
1286 if (fMethodBinding != null && fCuToSearchResultGroup.containsKey(unit)){
1287 SearchResultGroup group= fCuToSearchResultGroup.get(unit);
1288 ASTNode[] nodes= ASTNodeSearchUtil.getAstNodes(group.getSearchResults(), cu);
1289 for (int i=0; i < nodes.length; i++){
1290 ASTNode node = nodes[i];
1291 if (fMethodBinding != null){
1292 // find MethodDeclaration above it in the tree
1293 ASTNode n= node;
1294 while (!(n instanceof MethodDeclaration)){
1295 n = n.getParent();
1296 }
1297 MethodDeclaration md = (MethodDeclaration)n;
1298 md.accept(fCollector);
1299 }
1300 }
1301 } else {
1302 cu.accept(fCollector);
1303 }
1304 List<ITypeConstraint> constraints= Arrays.asList(fCollector.getConstraints());
1305 fConstraintCache.put(unit, constraints);
1306 return constraints;
1307 }
1308
1309 /**
1310 * update a CompilationUnit's imports after changing the type of declarations
1311 * @param astRoot the AST
1312 * @param rootEdit the resulting edit
1313 * @return the type name to use
1314 * @throws CoreException
1315 */
1316 private String updateImports(CompilationUnit astRoot, MultiTextEdit rootEdit) throws CoreException{
1317 ImportRewrite rewrite= StubUtility.createImportRewrite(astRoot, true);
1318 String typeName= rewrite.addImport(fSelectedType.getQualifiedName());
1319 rootEdit.addChild(rewrite.rewriteImports(null));
1320 return typeName;
1321 }
1322
1323 // ------------------------------------------------------------------------------------------------- //
1324 // Miscellaneous helper methods
1325
1326 /**
1327 * Returns the Collection of types that can be given to the selected declaration.
1328 * @return return the valid type bindings
1329 */
1330 public Collection<ITypeBinding> getValidTypes() {
1331 return fValidTypes;
1332 }
1333
1334 public ITypeBinding getOriginalType(){
1335 return fSelectionTypeBinding;
1336 }
1337
1338 private void setOriginalType(ITypeBinding originalType){
1339 fSelectionTypeBinding= originalType;
1340 fSelectedType= findSuperTypeByName(originalType, fSelectedTypeName);
1341 }
1342
1343 public String getTarget() {
1344 String typeName= fSelectionTypeBinding == null ? "" : fSelectionTypeBinding.getName() + " "; //$NON-NLS-1$//$NON-NLS-2$
1345 if (fFieldBinding != null) {
1346 return typeName + fFieldBinding.getName();
1347 } else if (fMethodBinding != null) {
1348 if (fParamIndex == -1) {
1349 return typeName + fMethodBinding.getName() + "(...)"; //$NON-NLS-1$
1350 } else {
1351 return typeName + fParamName;
1352 }
1353 } else if (fSelectionBinding != null) {
1354 return typeName + fSelectionBinding.getName();
1355 } else {
1356 return typeName;
1357 }
1358 }
1359
1360 /**
1361 * Returns the Collection<String> of names of types that can be given to the selected declaration.
1362 * (used in tests only)
1363 * @return Collection<String> of names of types that can be given to the selected declaration
1364 */
1365 public Collection<String> getValidTypeNames() {
1366 Collection<String> typeNames= new ArrayList<String>();
1367 for (Iterator<ITypeBinding> it= fValidTypes.iterator(); it.hasNext();) {
1368 ITypeBinding type= it.next();
1369 typeNames.add(type.getQualifiedName());
1370 }
1371
1372 return typeNames;
1373 }
1374
1375 /**
1376 * Find the ASTNode for the given source text selection, if it is a type
1377 * declaration, or null otherwise.
1378 * @param unit The compilation unit in which the selection was made
1379 * @param offset
1380 * @param length
1381 * @return ASTNode
1382 */
1383 private ASTNode getTargetNode(ICompilationUnit unit, int offset, int length) {
1384 CompilationUnit root= ASTCreator.createAST(unit, null);
1385 ASTNode node= NodeFinder.perform(root, offset, length);
1386 return node;
1387 }
1388
1389 /**
1390 * Determines the set of compilation units that may give rise to type constraints that
1391 * we are interested in. This involves searching for overriding/overridden methods,
1392 * method calls, field accesses.
1393 * @param pm the monitor
1394 * @return the affected units
1395 * @throws CoreException
1396 */
1397 private ICompilationUnit[] collectAffectedUnits(IProgressMonitor pm) throws CoreException {
1398 // BUG: currently, no type constraints are generated for methods that are related
1399 // but that do not override each other. As a result, we may miss certain relevant
1400 // variables
1401
1402 pm.beginTask(RefactoringCoreMessages.ChangeTypeRefactoring_analyzingMessage, 100);
1403
1404 if (fAffectedUnits != null) {
1405 if (DEBUG) printCollection("affected units: ", Arrays.asList(fAffectedUnits)); //$NON-NLS-1$
1406 pm.worked(100);
1407 return fAffectedUnits;
1408 }
1409 if (fMethodBinding != null) {
1410 if (fMethodBinding != null) {
1411
1412
1413 IMethod selectedMethod= (IMethod) fMethodBinding.getJavaElement();
1414 if (selectedMethod == null) {
1415 // can't happen since we checked it up front in check initial conditions
1416 Assert.isTrue(false, RefactoringCoreMessages.ChangeTypeRefactoring_no_method);
1417 }
1418
1419 // the following code fragment appears to be the source of a memory leak, when
1420 // GT is repeatedly applied
1421
1422 IMethod root= selectedMethod;
1423 if (! root.getDeclaringType().isInterface() && MethodChecks.isVirtual(root)) {
1424 final SubProgressMonitor subMonitor= new SubProgressMonitor(pm, 5);
1425 IMethod inInterface= MethodChecks.isDeclaredInInterface(root, root.getDeclaringType().newTypeHierarchy(new SubProgressMonitor(subMonitor, 1)), subMonitor);
1426 if (inInterface != null && !inInterface.equals(root))
1427 root= inInterface;
1428 }
1429
1430 // end code fragment
1431
1432 IMethod[] rippleMethods= RippleMethodFinder2.getRelatedMethods(
1433 root, new SubProgressMonitor(pm, 15), null);
1434 SearchPattern pattern= RefactoringSearchEngine.createOrPattern(
1435 rippleMethods, IJavaSearchConstants.ALL_OCCURRENCES);
1436
1437 // To compute the scope we have to use the selected method. Otherwise we
1438 // might start from the wrong project.
1439 IJavaSearchScope scope= RefactoringScopeFactory.create(selectedMethod);
1440 CollectingSearchRequestor csr= new CollectingSearchRequestor();
1441
1442 SearchResultGroup[] groups= RefactoringSearchEngine.search(
1443 pattern,
1444 null,
1445 scope,
1446 csr,
1447 new SubProgressMonitor(pm, 80),
1448 new RefactoringStatus()); //TODO: deal with errors from non-CU matches
1449
1450 fAffectedUnits= getCus(groups);
1451 }
1452 } else if (fFieldBinding != null) {
1453 IField iField= (IField) fFieldBinding.getJavaElement();
1454 if (iField == null) {
1455 // can't happen since we checked it up front in check initial conditions
1456 Assert.isTrue(false, RefactoringCoreMessages.ChangeTypeRefactoring_no_filed);
1457 }
1458 SearchPattern pattern= SearchPattern.createPattern(
1459 iField, IJavaSearchConstants.ALL_OCCURRENCES, SearchUtils.GENERICS_AGNOSTIC_MATCH_RULE);
1460 IJavaSearchScope scope= RefactoringScopeFactory.create(iField);
1461 CollectingSearchRequestor csr= new CollectingSearchRequestor();
1462 SearchResultGroup[] groups=
1463 RefactoringSearchEngine.search(pattern, null, scope, csr, new SubProgressMonitor(pm, 100),
1464 new RefactoringStatus()); //TODO: deal with errors from non-CU matches
1465 fAffectedUnits= getCus(groups);
1466 } else {
1467 // otherwise, selection was a local variable and we only have to search the CU
1468 // containing the selection
1469 fAffectedUnits= new ICompilationUnit[] { fCu };
1470 }
1471 if (DEBUG) {
1472 System.out.println("Determining affected CUs:"); //$NON-NLS-1$
1473 for (int i= 0; i < fAffectedUnits.length; i++) {
1474 System.out.println(" affected CU: " + fAffectedUnits[i].getElementName()); //$NON-NLS-1$
1475 }
1476 }
1477 pm.done();
1478 return fAffectedUnits;
1479 }
1480
1481 public void setSelectedType(ITypeBinding type){
1482 fSelectedType= type;
1483 }
1484
1485 // -------------------------------------------------------------------------------------------- //
1486 // TODO The following utility methods should probably be moved to another class
1487
1488 /**
1489 * Determines if a constraint variable corresponds to the constant "null".
1490 * @param cv
1491 * @return <code>true</code> if the constraint variable corresponds to the constant "null".
1492 */
1493 private static boolean isNull(ConstraintVariable cv) {
1494 return cv instanceof ExpressionVariable && ((ExpressionVariable)cv).getExpressionType() == ASTNode.NULL_LITERAL;
1495 }
1496
1497
1498 /*
1499 * For debugging.
1500 */
1501 void printCollection(String title, Collection<?> l) {
1502 System.out.println(l.size() + " " + title); //$NON-NLS-1$
1503 for (Iterator<?> it= l.iterator(); it.hasNext();) {
1504 System.out.println(" " + it.next()); //$NON-NLS-1$
1505 }
1506 }
1507
1508 /**
1509 * Returns the compilation units that contain the search results.
1510 * @param groups
1511 * @return the CUs
1512 */
1513 private ICompilationUnit[] getCus(SearchResultGroup[] groups) {
1514 List<ICompilationUnit> result= new ArrayList<ICompilationUnit>(groups.length);
1515 for (int i= 0; i < groups.length; i++) {
1516 SearchResultGroup group= groups[i];
1517 ICompilationUnit cu= group.getCompilationUnit();
1518 if (cu != null) {
1519 result.add(cu);
1520 fCuToSearchResultGroup.put(cu, group);
1521 }
1522 }
1523 return result.toArray(new ICompilationUnit[result.size()]);
1524 }
1525
1526 /**
1527 * This always includes the type itself. It will include type
1528 * Object for any type other than Object
1529 * @param type
1530 * @return the super types
1531 */
1532 public Set<ITypeBinding> getAllSuperTypes(ITypeBinding type){
1533 Set<ITypeBinding> result= new HashSet<ITypeBinding>();
1534 result.add(type);
1535 if (type.getSuperclass() != null){
1536 result.addAll(getAllSuperTypes(type.getSuperclass()));
1537 }
1538 ITypeBinding[] interfaces= type.getInterfaces();
1539 for (int i=0; i < interfaces.length; i++){
1540 result.addAll(getAllSuperTypes(interfaces[i]));
1541 }
1542 if ((type != fObject) && !contains(result, fObject)){
1543 result.add(fObject);
1544 }
1545 return result;
1546 }
1547
1548 private ITypeBinding findSuperTypeByName(ITypeBinding type, String superTypeName){
1549 Set<ITypeBinding> superTypes= getAllSuperTypes(type);
1550 for (Iterator<ITypeBinding> it= superTypes.iterator(); it.hasNext(); ){
1551 ITypeBinding sup= it.next();
1552 if (sup.getQualifiedName().equals(superTypeName)){
1553 return sup;
1554 }
1555 }
1556 return null;
1557 }
1558
1559 public boolean isSubTypeOf(ITypeBinding type1, ITypeBinding type2){
1560
1561 // to ensure that, e.g., Comparable<String> is considered a subtype of raw Comparable
1562 if (type1.isParameterizedType() && type1.getTypeDeclaration().isEqualTo(type2.getTypeDeclaration())){
1563 return true;
1564 }
1565 Set<ITypeBinding> superTypes= getAllSuperTypes(type1);
1566 return contains(superTypes, type2);
1567 }
1568
1569 private static boolean contains(Collection<ITypeBinding> c, ITypeBinding binding){
1570 for (Iterator<ITypeBinding> it=c.iterator(); it.hasNext(); ){
1571 ITypeBinding b = it.next();
1572 if (Bindings.equals(b, binding)) return true;
1573 }
1574 return false;
1575 }
1576
1577 private RefactoringStatus initialize(JavaRefactoringArguments arguments) {
1578 final String selection= arguments.getAttribute(JavaRefactoringDescriptorUtil.ATTRIBUTE_SELECTION);
1579 if (selection != null) {
1580 int offset= -1;
1581 int length= -1;
1582 final StringTokenizer tokenizer= new StringTokenizer(selection);
1583 if (tokenizer.hasMoreTokens())
1584 offset= Integer.valueOf(tokenizer.nextToken()).intValue();
1585 if (tokenizer.hasMoreTokens())
1586 length= Integer.valueOf(tokenizer.nextToken()).intValue();
1587 if (offset >= 0 && length >= 0) {
1588 fSelectionStart= offset;
1589 fSelectionLength= length;
1590 } else
1591 return RefactoringStatus.createFatalErrorStatus(Messages.format(RefactoringCoreMessages.InitializableRefactoring_illegal_argument, new Object[] { selection, JavaRefactoringDescriptorUtil.ATTRIBUTE_SELECTION}));
1592 } else
1593 return RefactoringStatus.createFatalErrorStatus(Messages.format(RefactoringCoreMessages.InitializableRefactoring_argument_not_exist, JavaRefactoringDescriptorUtil.ATTRIBUTE_SELECTION));
1594 final String handle= arguments.getAttribute(JavaRefactoringDescriptorUtil.ATTRIBUTE_INPUT);
1595 if (handle != null) {
1596 final IJavaElement element= JavaRefactoringDescriptorUtil.handleToElement(arguments.getProject(), handle, false);
1597 if (element == null || !element.exists() || element.getElementType() != IJavaElement.COMPILATION_UNIT)
1598 return JavaRefactoringDescriptorUtil.createInputFatalStatus(element, getName(), IJavaRefactorings.GENERALIZE_TYPE);
1599 else
1600 fCu= (ICompilationUnit) element;
1601 } else
1602 return RefactoringStatus.createFatalErrorStatus(Messages.format(RefactoringCoreMessages.InitializableRefactoring_argument_not_exist, JavaRefactoringDescriptorUtil.ATTRIBUTE_INPUT));
1603 final String type= arguments.getAttribute(ATTRIBUTE_TYPE);
1604 if (type != null && !"".equals(type)) //$NON-NLS-1$
1605 fSelectedTypeName= type;
1606 else
1607 return RefactoringStatus.createFatalErrorStatus(Messages.format(RefactoringCoreMessages.InitializableRefactoring_argument_not_exist, ATTRIBUTE_TYPE));
1608 return new RefactoringStatus();
1609 }
1610}