]> git.uio.no Git - ifi-stolz-refaktor.git/blame - case-study/jdt-before/core refactoring/org/eclipse/jdt/internal/corext/refactoring/structure/IntroduceParameterObjectProcessor.java
Case Study: adding data and statistics
[ifi-stolz-refaktor.git] / case-study / jdt-before / core refactoring / org / eclipse / jdt / internal / corext / refactoring / structure / IntroduceParameterObjectProcessor.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.HashMap;
16import java.util.Iterator;
17import java.util.List;
18import java.util.Map;
19
20import org.eclipse.core.runtime.Assert;
21import org.eclipse.core.runtime.CoreException;
22import org.eclipse.core.runtime.IProgressMonitor;
23import org.eclipse.core.runtime.OperationCanceledException;
24
25import org.eclipse.ltk.core.refactoring.Change;
26import org.eclipse.ltk.core.refactoring.RefactoringStatus;
27import org.eclipse.ltk.core.refactoring.participants.CheckConditionsContext;
28import org.eclipse.ltk.core.refactoring.resource.ResourceChange;
29
30import org.eclipse.jdt.core.ICompilationUnit;
31import org.eclipse.jdt.core.IJavaElement;
32import org.eclipse.jdt.core.IJavaProject;
33import org.eclipse.jdt.core.IMethod;
34import org.eclipse.jdt.core.IPackageFragmentRoot;
35import org.eclipse.jdt.core.ISourceRange;
36import org.eclipse.jdt.core.IType;
37import org.eclipse.jdt.core.JavaModelException;
38import org.eclipse.jdt.core.NamingConventions;
39import org.eclipse.jdt.core.compiler.IProblem;
40import org.eclipse.jdt.core.dom.AST;
41import org.eclipse.jdt.core.dom.ASTNode;
42import org.eclipse.jdt.core.dom.ASTVisitor;
43import org.eclipse.jdt.core.dom.ArrayCreation;
44import org.eclipse.jdt.core.dom.ArrayInitializer;
45import org.eclipse.jdt.core.dom.ArrayType;
46import org.eclipse.jdt.core.dom.Block;
47import org.eclipse.jdt.core.dom.ClassInstanceCreation;
48import org.eclipse.jdt.core.dom.CompilationUnit;
49import org.eclipse.jdt.core.dom.Expression;
50import org.eclipse.jdt.core.dom.ExpressionStatement;
51import org.eclipse.jdt.core.dom.FieldAccess;
52import org.eclipse.jdt.core.dom.IBinding;
53import org.eclipse.jdt.core.dom.IMethodBinding;
54import org.eclipse.jdt.core.dom.ITypeBinding;
55import org.eclipse.jdt.core.dom.IVariableBinding;
56import org.eclipse.jdt.core.dom.Message;
57import org.eclipse.jdt.core.dom.MethodDeclaration;
58import org.eclipse.jdt.core.dom.MethodInvocation;
59import org.eclipse.jdt.core.dom.Modifier.ModifierKeyword;
60import org.eclipse.jdt.core.dom.Name;
61import org.eclipse.jdt.core.dom.NodeFinder;
62import org.eclipse.jdt.core.dom.NullLiteral;
63import org.eclipse.jdt.core.dom.QualifiedName;
64import org.eclipse.jdt.core.dom.SimpleName;
65import org.eclipse.jdt.core.dom.SingleVariableDeclaration;
66import org.eclipse.jdt.core.dom.StructuralPropertyDescriptor;
67import org.eclipse.jdt.core.dom.SuperFieldAccess;
68import org.eclipse.jdt.core.dom.SuperMethodInvocation;
69import org.eclipse.jdt.core.dom.Type;
70import org.eclipse.jdt.core.dom.TypeDeclaration;
71import org.eclipse.jdt.core.dom.rewrite.ASTRewrite;
72import org.eclipse.jdt.core.dom.rewrite.ImportRewrite.ImportRewriteContext;
73import org.eclipse.jdt.core.dom.rewrite.ListRewrite;
74import org.eclipse.jdt.core.refactoring.descriptors.IntroduceParameterObjectDescriptor;
75import org.eclipse.jdt.core.refactoring.descriptors.IntroduceParameterObjectDescriptor.Parameter;
76import org.eclipse.jdt.core.refactoring.descriptors.JavaRefactoringDescriptor;
77import org.eclipse.jdt.core.refactoring.participants.IRefactoringProcessorIds;
78
79import org.eclipse.jdt.internal.core.refactoring.descriptors.RefactoringSignatureDescriptorFactory;
80import org.eclipse.jdt.internal.corext.codemanipulation.ContextSensitiveImportRewriteContext;
81import org.eclipse.jdt.internal.corext.codemanipulation.StubUtility;
82import org.eclipse.jdt.internal.corext.dom.ASTNodes;
83import org.eclipse.jdt.internal.corext.dom.TypeBindingVisitor;
84import org.eclipse.jdt.internal.corext.refactoring.Checks;
85import org.eclipse.jdt.internal.corext.refactoring.JDTRefactoringDescriptorComment;
86import org.eclipse.jdt.internal.corext.refactoring.ParameterInfo;
87import org.eclipse.jdt.internal.corext.refactoring.RefactoringCoreMessages;
88import org.eclipse.jdt.internal.corext.util.JavaModelUtil;
89import org.eclipse.jdt.internal.corext.util.Messages;
90
91import org.eclipse.jdt.internal.ui.JavaPlugin;
92import org.eclipse.jdt.internal.ui.text.correction.ASTResolving;
93import org.eclipse.jdt.internal.ui.viewsupport.BasicElementLabels;
94
95public class IntroduceParameterObjectProcessor extends ChangeSignatureProcessor {
96
97 private final class ParameterObjectCreator implements IDefaultValueAdvisor {
98 public Expression createDefaultExpression(List<Expression> invocationArguments, ParameterInfo addedInfo, List<ParameterInfo> parameterInfos, MethodDeclaration enclosingMethod, boolean isRecursive, CompilationUnitRewrite cuRewrite) {
99 final AST ast= cuRewrite.getAST();
100 final ASTRewrite rewrite= cuRewrite.getASTRewrite();
101 if (isRecursive && canReuseParameterObject(invocationArguments, addedInfo, parameterInfos, enclosingMethod)) {
102 return ast.newSimpleName(addedInfo.getNewName());
103 }
104 ClassInstanceCreation classCreation= ast.newClassInstanceCreation();
105
106 int startPosition= enclosingMethod != null ? enclosingMethod.getStartPosition() : cuRewrite.getRoot().getStartPosition();
107 ContextSensitiveImportRewriteContext context= fParameterObjectFactory.createParameterClassAwareContext(fCreateAsTopLevel, cuRewrite, startPosition);
108 classCreation.setType(fParameterObjectFactory.createType(fCreateAsTopLevel, cuRewrite, startPosition));
109 List<Expression> constructorArguments= classCreation.arguments();
110 for (Iterator<ParameterInfo> iter= parameterInfos.iterator(); iter.hasNext();) {
111 ParameterInfo pi= iter.next();
112 if (isValidField(pi)) {
113 if (pi.isOldVarargs()) {
114 boolean isLastParameter= !iter.hasNext();
115 constructorArguments.addAll(computeVarargs(invocationArguments, pi, isLastParameter, cuRewrite, context));
116 } else {
117 Expression exp= invocationArguments.get(pi.getOldIndex());
118 importNodeTypes(exp, cuRewrite, context);
119 constructorArguments.add(moveNode(exp, rewrite));
120 }
121 }
122 }
123 return classCreation;
124 }
125
126 public Type createType(String newTypeName, int startPosition, CompilationUnitRewrite cuRewrite) {
127 return fParameterObjectFactory.createType(fCreateAsTopLevel, cuRewrite, startPosition);
128 }
129
130 private boolean canReuseParameterObject(List<Expression> invocationArguments, ParameterInfo addedInfo, List<ParameterInfo> parameterInfos, MethodDeclaration enclosingMethod) {
131 Assert.isNotNull(enclosingMethod);
132 List<SingleVariableDeclaration> parameters= enclosingMethod.parameters();
133 for (Iterator<ParameterInfo> iter= parameterInfos.iterator(); iter.hasNext();) {
134 ParameterInfo pi= iter.next();
135 if (isValidField(pi)) {
136 if (!pi.isInlined())
137 return false;
138 ASTNode node= invocationArguments.get(pi.getOldIndex());
139 if (!isParameter(pi, node, parameters, addedInfo.getNewName())) {
140 return false;
141 }
142 }
143 }
144 return true;
145 }
146
147 private List<Expression> computeVarargs(List<Expression> invocationArguments, ParameterInfo varArgPI, boolean isLastParameter, CompilationUnitRewrite cuRewrite, ContextSensitiveImportRewriteContext context) {
148 boolean isEmptyVarArg= varArgPI.getOldIndex() >= invocationArguments.size();
149 ASTRewrite rewrite= cuRewrite.getASTRewrite();
150 AST ast= cuRewrite.getAST();
151 ASTNode lastNode= isEmptyVarArg ? null : invocationArguments.get(varArgPI.getOldIndex());
152 List<Expression> constructorArguments= new ArrayList<Expression>();
153 if (lastNode instanceof ArrayCreation) {
154 ArrayCreation creation= (ArrayCreation) lastNode;
155 ITypeBinding arrayType= creation.resolveTypeBinding();
156 if (arrayType != null && arrayType.isAssignmentCompatible(varArgPI.getNewTypeBinding())) {
157 constructorArguments.add(moveNode(creation, rewrite));
158 return constructorArguments;
159 }
160 }
161 if (isLastParameter) {
162 // copy all varargs
163 for (int i= varArgPI.getOldIndex(); i < invocationArguments.size(); i++) {
164 Expression node= invocationArguments.get(i);
165 importNodeTypes(node, cuRewrite, context);
166 constructorArguments.add(moveNode(node, rewrite));
167 }
168 } else { // new signature would be String...args, int
169 if (lastNode instanceof NullLiteral) {
170 NullLiteral nullLiteral= (NullLiteral) lastNode;
171 constructorArguments.add(moveNode(nullLiteral, rewrite));
172 } else {
173 ArrayCreation creation= ast.newArrayCreation();
174 creation.setType((ArrayType) importBinding(varArgPI.getNewTypeBinding(), cuRewrite, context));
175 ArrayInitializer initializer= ast.newArrayInitializer();
176 List<Expression> expressions= initializer.expressions();
177 for (int i= varArgPI.getOldIndex(); i < invocationArguments.size(); i++) {
178 Expression node= invocationArguments.get(i);
179 importNodeTypes(node, cuRewrite, context);
180 expressions.add(moveNode(node, rewrite));
181 }
182 if (expressions.isEmpty())
183 creation.dimensions().add(ast.newNumberLiteral("0")); //$NON-NLS-1$
184 else
185 creation.setInitializer(initializer);
186 constructorArguments.add(creation);
187 }
188 }
189 return constructorArguments;
190 }
191
192 public Type importBinding(ITypeBinding newTypeBinding, CompilationUnitRewrite cuRewrite, ImportRewriteContext context) {
193 Type type= cuRewrite.getImportRewrite().addImport(newTypeBinding, cuRewrite.getAST(), context);
194 cuRewrite.getImportRemover().registerAddedImports(type);
195 return type;
196 }
197
198 private void importNodeTypes(ASTNode node, final CompilationUnitRewrite cuRewrite, final ImportRewriteContext context) {
199 ASTResolving.visitAllBindings(node, new TypeBindingVisitor() {
200 public boolean visit(ITypeBinding nodeBinding) {
201 importBinding(nodeBinding, cuRewrite, context);
202 return false;
203 }
204 });
205 }
206 }
207
208 private boolean isParameter(ParameterInfo pi, ASTNode node, List<SingleVariableDeclaration> enclosingMethodParameters, String qualifier) {
209 if (node instanceof Name) {
210 Name name= (Name) node;
211 IVariableBinding binding= ASTNodes.getVariableBinding(name);
212 if (binding != null && binding.isParameter()) {
213 return binding.getName().equals(getNameInScope(pi, enclosingMethodParameters));
214 } else {
215 if (node instanceof QualifiedName) {
216 QualifiedName qn= (QualifiedName) node;
217 return qn.getFullyQualifiedName().equals(JavaModelUtil.concatenateName(qualifier, getNameInScope(pi, enclosingMethodParameters)));
218 }
219 }
220 }
221 return false;
222 }
223
224 private final class RewriteParameterBody extends BodyUpdater {
225 @Override
226 public void updateBody(MethodDeclaration methodDeclaration, final CompilationUnitRewrite cuRewrite, RefactoringStatus result) throws CoreException {
227 // ensure that the parameterObject is imported
228 fParameterObjectFactory.createType(fCreateAsTopLevel, cuRewrite, methodDeclaration.getStartPosition());
229 if (cuRewrite.getCu().equals(getCompilationUnit()) && !fParameterClassCreated) {
230 createParameterClass(methodDeclaration, cuRewrite);
231 fParameterClassCreated= true;
232 }
233 Block body= methodDeclaration.getBody();
234 final List<SingleVariableDeclaration> parameters= methodDeclaration.parameters();
235 if (body != null) { // abstract methods don't have bodies
236 final ASTRewrite rewriter= cuRewrite.getASTRewrite();
237 ListRewrite bodyStatements= rewriter.getListRewrite(body, Block.STATEMENTS_PROPERTY);
238 List<ParameterInfo> managedParams= getParameterInfos();
239 for (Iterator<ParameterInfo> iter= managedParams.iterator(); iter.hasNext();) {
240 final ParameterInfo pi= iter.next();
241 if (isValidField(pi)) {
242 if (isReadOnly(pi, body, parameters, null)) {
243 body.accept(new ASTVisitor(false) {
244
245 @Override
246 public boolean visit(SimpleName node) {
247 updateSimpleName(rewriter, pi, node, parameters, cuRewrite.getCu().getJavaProject());
248 return false;
249 }
250
251 });
252 pi.setInlined(true);
253 } else {
254 ExpressionStatement initializer= fParameterObjectFactory.createInitializer(pi, getParameterName(), cuRewrite);
255 bodyStatements.insertFirst(initializer, null);
256 }
257 }
258 }
259 }
260
261
262 }
263
264 private void updateSimpleName(ASTRewrite rewriter, ParameterInfo pi, SimpleName node, List<SingleVariableDeclaration> enclosingParameters, IJavaProject project) {
265 AST ast= rewriter.getAST();
266 IBinding binding= node.resolveBinding();
267 Expression replacementNode= fParameterObjectFactory.createFieldReadAccess(pi, getParameterName(), ast, project, false, null);
268 if (binding instanceof IVariableBinding) {
269 IVariableBinding variable= (IVariableBinding) binding;
270 if (variable.isParameter() && variable.getName().equals(getNameInScope(pi, enclosingParameters))) {
271 rewriter.replace(node, replacementNode, null);
272 }
273 } else {
274 ASTNode parent= node.getParent();
275 if (!(parent instanceof QualifiedName || parent instanceof FieldAccess || parent instanceof SuperFieldAccess)) {
276 if (node.getIdentifier().equals(getNameInScope(pi, enclosingParameters))) {
277 rewriter.replace(node, replacementNode, null);
278 }
279 }
280 }
281 }
282
283 private boolean isReadOnly(final ParameterInfo pi, Block block, final List<SingleVariableDeclaration> enclosingMethodParameters, final String qualifier) {
284 class NotWrittenDetector extends ASTVisitor {
285 boolean notWritten= true;
286
287 @Override
288 public boolean visit(SimpleName node) {
289 if (isParameter(pi, node, enclosingMethodParameters, qualifier) && ASTResolving.isWriteAccess(node))
290 notWritten= false;
291 return false;
292 }
293
294 @Override
295 public boolean visit(SuperFieldAccess node) {
296 return false;
297 }
298 }
299 NotWrittenDetector visitor= new NotWrittenDetector();
300 block.accept(visitor);
301 return visitor.notWritten;
302 }
303
304 @Override
305 public boolean needsParameterUsedCheck() {
306 return false;
307 }
308
309 }
310
311 private static final String PARAMETER_CLASS_APPENDIX= "Parameter"; //$NON-NLS-1$
312
313 private static final String DEFAULT_PARAMETER_OBJECT_NAME= "parameterObject"; //$NON-NLS-1$
314
315 private MethodDeclaration fMethodDeclaration;
316
317 private ParameterObjectFactory fParameterObjectFactory;
318
319 private boolean fCreateAsTopLevel= true;
320
321 private ParameterInfo fParameterObjectReference;
322
323 private boolean fParameterClassCreated= false;
324
325 private List<ResourceChange> fOtherChanges;
326
327 public IntroduceParameterObjectProcessor(IntroduceParameterObjectDescriptor descriptor) throws JavaModelException {
328 super(descriptor.getMethod());
329 IMethod method= descriptor.getMethod();
330 Assert.isNotNull(method);
331 initializeFields(method);
332 setBodyUpdater(new RewriteParameterBody());
333 setDefaultValueAdvisor(new ParameterObjectCreator());
334 configureRefactoring(descriptor, this);
335 }
336
337 private void configureRefactoring(final IntroduceParameterObjectDescriptor parameter, IntroduceParameterObjectProcessor ref) {
338 ref.setCreateAsTopLevel(parameter.isTopLevel());
339 ref.setCreateGetter(parameter.isGetters());
340 ref.setCreateSetter(parameter.isSetters());
341 ref.setDelegateUpdating(parameter.isDelegate());
342 ref.setDeprecateDelegates(parameter.isDeprecateDelegate());
343 if (parameter.getClassName() != null)
344 ref.setClassName(parameter.getClassName());
345 if (parameter.getPackageName() != null)
346 ref.setPackage(parameter.getPackageName());
347 if (parameter.getParameterName() != null)
348 ref.setParameterName(parameter.getParameterName());
349 List<ParameterInfo> pis= ref.getParameterInfos();
350 Parameter[] parameters= parameter.getParameters();
351 if (parameters == null)
352 parameters= IntroduceParameterObjectDescriptor.createParameters(getMethod());
353 Map<Integer, ParameterInfo> paramIndex= new HashMap<Integer, ParameterInfo>();
354 for (Iterator<ParameterInfo> iter= pis.iterator(); iter.hasNext();) {
355 ParameterInfo pi= iter.next();
356 paramIndex.put(new Integer(pi.getOldIndex()), pi);
357 }
358 paramIndex.put(new Integer(ParameterInfo.INDEX_FOR_ADDED), fParameterObjectReference);
359 pis.clear();
360 for (int i= 0; i < parameters.length; i++) {
361 Parameter param= parameters[i];
362 ParameterInfo pi= paramIndex.get(new Integer(param.getIndex()));
363 pis.add(pi);
364 if (param != IntroduceParameterObjectDescriptor.PARAMETER_OBJECT) {
365 pi.setCreateField(param.isCreateField());
366 if (pi.isCreateField()) {
367 String fieldName= param.getFieldName();
368 if (fieldName != null)
369 pi.setNewName(fieldName);
370 }
371 }
372 }
373 }
374
375 private void initializeFields(IMethod method) {
376 fParameterObjectFactory= new ParameterObjectFactory();
377 String methodName= method.getElementName();
378 String className= String.valueOf(Character.toUpperCase(methodName.charAt(0)));
379 if (methodName.length() > 1)
380 className+= methodName.substring(1);
381 className+= PARAMETER_CLASS_APPENDIX;
382
383 fParameterObjectReference= ParameterInfo.createInfoForAddedParameter(className, DEFAULT_PARAMETER_OBJECT_NAME);
384 fParameterObjectFactory.setClassName(className);
385
386 IType declaringType= method.getDeclaringType();
387 Assert.isNotNull(declaringType);
388 fParameterObjectFactory.setPackage(declaringType.getPackageFragment().getElementName());
389
390 updateReferenceType();
391 }
392
393 @Override
394 public RefactoringStatus checkFinalConditions(IProgressMonitor pm, CheckConditionsContext context) throws CoreException, OperationCanceledException {
395 RefactoringStatus status= new RefactoringStatus();
396 IMethod method= getMethod();
397 // TODO: Check for availability
398 status.merge(Checks.checkTypeName(fParameterObjectFactory.getClassName(), method));
399 status.merge(Checks.checkIdentifier(getParameterName(), method));
400 if (status.hasFatalError())
401 return status;
402 status.merge(super.checkFinalConditions(pm, context));
403 return status;
404 }
405
406 @Override
407 public RefactoringStatus checkInitialConditions(IProgressMonitor pm) throws CoreException, OperationCanceledException {
408 RefactoringStatus status= new RefactoringStatus();
409 status.merge(super.checkInitialConditions(pm));
410 if (status.hasFatalError())
411 return status;
412 CompilationUnit astRoot= getBaseCuRewrite().getRoot();
413 ISourceRange nameRange= getMethod().getNameRange();
414 ASTNode selectedNode= NodeFinder.perform(astRoot, nameRange.getOffset(), nameRange.getLength());
415 if (selectedNode == null) {
416 return mappingErrorFound(status, selectedNode);
417 }
418 fMethodDeclaration= (MethodDeclaration) ASTNodes.getParent(selectedNode, MethodDeclaration.class);
419 if (fMethodDeclaration == null) {
420 return mappingErrorFound(status, selectedNode);
421 }
422 IMethodBinding resolveBinding= fMethodDeclaration.resolveBinding();
423 if (resolveBinding == null) {
424 if (!processCompilerError(status, selectedNode))
425 status.addFatalError(RefactoringCoreMessages.IntroduceParameterObjectRefactoring_error_cannot_resolve_type);
426 return status;
427 }
428
429 ITypeBinding declaringClass= resolveBinding.getDeclaringClass();
430 if (fParameterObjectFactory.getPackage() == null)
431 fParameterObjectFactory.setPackage(declaringClass.getPackage().getName());
432 if (fParameterObjectFactory.getEnclosingType() == null)
433 fParameterObjectFactory.setEnclosingType(declaringClass.getQualifiedName());
434
435 List<ParameterInfo> parameterInfos= super.getParameterInfos();
436 for (Iterator<ParameterInfo> iter= parameterInfos.iterator(); iter.hasNext();) {
437 ParameterInfo pi= iter.next();
438 if (!pi.isAdded()) {
439 if (pi.getOldName().equals(pi.getNewName())) // may have been
440 // set to
441 // something
442 // else after
443 // creation
444 pi.setNewName(getFieldName(pi));
445 }
446 }
447 if (!parameterInfos.contains(fParameterObjectReference)) {
448 parameterInfos.add(0, fParameterObjectReference);
449 }
450 Map<String, IVariableBinding> bindingMap= new HashMap<String, IVariableBinding>();
451 for (Iterator<SingleVariableDeclaration> iter= fMethodDeclaration.parameters().iterator(); iter.hasNext();) {
452 SingleVariableDeclaration sdv= iter.next();
453 bindingMap.put(sdv.getName().getIdentifier(), sdv.resolveBinding());
454 }
455 for (Iterator<ParameterInfo> iter= parameterInfos.iterator(); iter.hasNext();) {
456 ParameterInfo pi= iter.next();
457 if (pi != fParameterObjectReference)
458 pi.setOldBinding(bindingMap.get(pi.getOldName()));
459 }
460 fParameterObjectFactory.setVariables(parameterInfos);
461 return status;
462 }
463
464 @Override
465 protected boolean shouldReport(IProblem problem, CompilationUnit cu) {
466 if (!super.shouldReport(problem, cu))
467 return false;
468 ASTNode node= ASTNodeSearchUtil.getAstNode(cu, problem.getSourceStart(), problem.getSourceEnd() - problem.getSourceStart() + 1);
469 if (node instanceof Type) {
470 Type type= (Type) node;
471 if (problem.getID() == IProblem.UndefinedType && getClassName().equals(ASTNodes.getTypeName(type))) {
472 return false;
473 }
474 }
475 if (node instanceof Name) {
476 Name name= (Name) node;
477 if (problem.getID() == IProblem.ImportNotFound && getPackage().indexOf(name.getFullyQualifiedName()) != -1)
478 return false;
479 if (problem.getID() == IProblem.MissingTypeInMethod) {
480 StructuralPropertyDescriptor locationInParent= name.getLocationInParent();
481 String[] arguments= problem.getArguments();
482 if ((locationInParent == MethodInvocation.NAME_PROPERTY || locationInParent == SuperMethodInvocation.NAME_PROPERTY)
483 && arguments.length > 3
484 && arguments[3].endsWith(getClassName()))
485 return false;
486 }
487 }
488 return true;
489 }
490
491 public String getClassName() {
492 return fParameterObjectFactory.getClassName();
493 }
494
495 public ITypeBinding getContainingClass() {
496 return fMethodDeclaration.resolveBinding().getDeclaringClass();
497 }
498
499 private String getMappingErrorMessage() {
500 return RefactoringCoreMessages.IntroduceParameterObjectRefactoring_cannotalanyzemethod_mappingerror;
501 }
502
503 public String getFieldName(ParameterInfo element) {
504 IJavaProject javaProject= getCompilationUnit().getJavaProject();
505 String stripped= NamingConventions.getBaseName(NamingConventions.VK_PARAMETER, element.getOldName(), javaProject);
506 int dim= element.getNewTypeBinding() != null ? element.getNewTypeBinding().getDimensions() : 0;
507 return StubUtility.getVariableNameSuggestions(NamingConventions.VK_INSTANCE_FIELD, javaProject, stripped, dim, null, true)[0];
508 }
509
510 @Override
511 public Change[] getAllChanges() {
512 ArrayList<Change> changes= new ArrayList<Change>();
513 changes.addAll(Arrays.asList(super.getAllChanges()));
514 changes.addAll(fOtherChanges);
515 return changes.toArray(new Change[changes.size()]);
516 }
517
518 @Override
519 protected void clearManagers() {
520 super.clearManagers();
521 fOtherChanges= new ArrayList<ResourceChange>();
522 fParameterClassCreated= false;
523 }
524
525 @Override
526 public String getProcessorName() {
527 return RefactoringCoreMessages.IntroduceParameterObjectRefactoring_refactoring_name;
528 }
529
530 @Override
531 public String getIdentifier() {
532 return IRefactoringProcessorIds.INTRODUCE_PARAMETER_OBJECT_PROCESSOR;
533 }
534
535 @Override
536 public JavaRefactoringDescriptor createDescriptor() {
537 IntroduceParameterObjectDescriptor ipod= RefactoringSignatureDescriptorFactory.createIntroduceParameterObjectDescriptor();
538 ipod.setMethod(getMethod());
539 ipod.setClassName(getClassName());
540 ipod.setDelegate(getDelegateUpdating());
541 ipod.setDeprecateDelegate(getDeprecateDelegates());
542 ipod.setGetters(isCreateGetter());
543 ipod.setSetters(isCreateSetter());
544 ipod.setPackageName(getPackage());
545 ipod.setParameterName(getParameterName());
546 ipod.setTopLevel(isCreateAsTopLevel());
547
548 ArrayList<Parameter> parameters= new ArrayList<Parameter>();
549 List<ParameterInfo> pis= getParameterInfos();
550 for (Iterator<ParameterInfo> iter= pis.iterator(); iter.hasNext();) {
551 ParameterInfo pi= iter.next();
552 if (pi.isAdded()) {
553 parameters.add(IntroduceParameterObjectDescriptor.PARAMETER_OBJECT);
554 } else {
555 IntroduceParameterObjectDescriptor.Parameter parameter= new IntroduceParameterObjectDescriptor.Parameter(pi.getOldIndex());
556 if (pi.isCreateField()) {
557 parameter.setCreateField(true);
558 parameter.setFieldName(pi.getNewName());
559 }
560 parameters.add(parameter);
561 }
562 }
563 ipod.setParameters(parameters.toArray(new Parameter[parameters.size()]));
564 String project= getCompilationUnit().getJavaProject().getElementName();
565 try {
566 ipod.setComment(createComment(project).asString());
567 } catch (JavaModelException e) {
568 JavaPlugin.log(e);
569 }
570 ipod.setProject(project);
571 ipod.setDescription(getProcessorName());
572 ipod.setFlags(getDescriptorFlags());
573 return ipod;
574 }
575
576 private JDTRefactoringDescriptorComment createComment(String project) throws JavaModelException {
577 String header= Messages.format(RefactoringCoreMessages.IntroduceParameterObjectRefactoring_descriptor_description, getOldMethodSignature());
578 JDTRefactoringDescriptorComment comment= new JDTRefactoringDescriptorComment(project, this, header);
579 comment.addSetting(Messages.format(RefactoringCoreMessages.IntroduceParameterObjectRefactoring_descriptor_object_class, BasicElementLabels.getJavaElementName(fParameterObjectFactory.getClassName())));
580 if (fCreateAsTopLevel) {
581 comment.addSetting(Messages.format(RefactoringCoreMessages.IntroduceParameterObjectRefactoring_descriptor_package, BasicElementLabels.getJavaElementName(fParameterObjectFactory.getPackage())));
582 } else {
583 comment.addSetting(Messages.format(RefactoringCoreMessages.IntroduceParameterObjectRefactoring_descriptor_enclosing_type, BasicElementLabels.getJavaElementName(fParameterObjectFactory.getEnclosingType())));
584 }
585 List<ParameterInfo> infos= getParameterInfos();
586 List<String> kept= new ArrayList<String>();
587 List<String> fields= new ArrayList<String>();
588 for (Iterator<ParameterInfo> iter= infos.iterator(); iter.hasNext();) {
589 ParameterInfo pi= iter.next();
590 if (pi.isCreateField()) {
591 fields.add(pi.getNewName());
592 } else {
593 if (!pi.isAdded()) {
594 kept.add(pi.getNewName());
595 }
596 }
597 }
598
599 comment.addSetting(JDTRefactoringDescriptorComment.createCompositeSetting(RefactoringCoreMessages.IntroduceParameterObjectRefactoring_descriptor_fields, fields.toArray(new String[0])));
600 if (!kept.isEmpty())
601 comment.addSetting(JDTRefactoringDescriptorComment.createCompositeSetting(RefactoringCoreMessages.IntroduceParameterObjectRefactoring_descriptor_keep_parameter, kept.toArray(new String[0])));
602 if (fParameterObjectFactory.isCreateGetter())
603 comment.addSetting(RefactoringCoreMessages.IntroduceParameterObjectRefactoring_descriptor_create_getter);
604 if (fParameterObjectFactory.isCreateSetter())
605 comment.addSetting(RefactoringCoreMessages.IntroduceParameterObjectRefactoring_descriptor_create_setter);
606 return comment;
607 }
608
609 @Override
610 protected String doGetRefactoringChangeName() {
611 return getProcessorName();
612 }
613
614 public String getParameterName() {
615 return fParameterObjectReference.getNewName();
616 }
617
618 public boolean isCreateGetter() {
619 return fParameterObjectFactory.isCreateGetter();
620 }
621
622 public boolean isCreateSetter() {
623 return fParameterObjectFactory.isCreateSetter();
624 }
625
626 public boolean isCreateAsTopLevel() {
627 return fCreateAsTopLevel;
628 }
629
630 /**
631 * Checks if the given parameter info has been selected for field creation
632 *
633 * @param pi parameter info
634 * @return true if the given parameter info has been selected for field
635 * creation
636 */
637 private boolean isValidField(ParameterInfo pi) {
638 return pi.isCreateField() & !pi.isAdded();
639 }
640
641 private RefactoringStatus mappingErrorFound(RefactoringStatus result, ASTNode node) {
642 if (node != null && (node.getFlags() & ASTNode.MALFORMED) != 0 && processCompilerError(result, node))
643 return result;
644 result.addFatalError(getMappingErrorMessage());
645 return result;
646 }
647
648 public void moveFieldDown(ParameterInfo selected) {
649 fParameterObjectFactory.moveDown(selected);
650 }
651
652 public void moveFieldUp(ParameterInfo selected) {
653 fParameterObjectFactory.moveUp(selected);
654 }
655
656 private boolean processCompilerError(RefactoringStatus result, ASTNode node) {
657 Message[] messages= ASTNodes.getMessages(node, ASTNodes.INCLUDE_ALL_PARENTS);
658 if (messages.length == 0)
659 return false;
660 result.addFatalError(Messages.format(RefactoringCoreMessages.IntroduceParameterObjectRefactoring_cannotanalysemethod_compilererror,
661 new String[] { messages[0].getMessage() }));
662 return true;
663 }
664
665 public void setClassName(String className) {
666 fParameterObjectFactory.setClassName(className);
667 updateReferenceType();
668 }
669
670 private void updateReferenceType() {
671 if (fCreateAsTopLevel)
672 fParameterObjectReference.setNewTypeName(JavaModelUtil.concatenateName(fParameterObjectFactory.getPackage(), fParameterObjectFactory
673 .getClassName()));
674 else
675 fParameterObjectReference.setNewTypeName(JavaModelUtil.concatenateName(fParameterObjectFactory.getEnclosingType(),
676 fParameterObjectFactory.getClassName()));
677 }
678
679 public void setCreateGetter(boolean createGetter) {
680 fParameterObjectFactory.setCreateGetter(createGetter);
681 }
682
683 public void setCreateSetter(boolean createSetter) {
684 fParameterObjectFactory.setCreateSetter(createSetter);
685 }
686
687 public void setPackageName(String packageName) {
688 fParameterObjectFactory.setPackage(packageName);
689 updateReferenceType();
690 }
691
692 public void setParameterName(String paramName) {
693 this.fParameterObjectReference.setNewName(paramName);
694 }
695
696 public void setCreateAsTopLevel(boolean topLevel) {
697 this.fCreateAsTopLevel= topLevel;
698 updateReferenceType();
699 }
700
701 public void updateParameterPosition() {
702 fParameterObjectFactory.updateParameterPosition(fParameterObjectReference);
703 }
704
705 private void createParameterClass(MethodDeclaration methodDeclaration, CompilationUnitRewrite cuRewrite) throws CoreException {
706 if (fCreateAsTopLevel) {
707 IPackageFragmentRoot root= (IPackageFragmentRoot) cuRewrite.getCu().getAncestor(IJavaElement.PACKAGE_FRAGMENT_ROOT);
708 fOtherChanges.addAll(fParameterObjectFactory.createTopLevelParameterObject(root));
709 } else {
710 ASTRewrite rewriter= cuRewrite.getASTRewrite();
711 TypeDeclaration enclosingType= (TypeDeclaration) methodDeclaration.getParent();
712 ListRewrite bodyRewrite= rewriter.getListRewrite(enclosingType, TypeDeclaration.BODY_DECLARATIONS_PROPERTY);
713 String fqn= enclosingType.getName().getFullyQualifiedName();
714 TypeDeclaration classDeclaration= fParameterObjectFactory.createClassDeclaration(fqn, cuRewrite, null);
715 classDeclaration.modifiers().add(rewriter.getAST().newModifier(ModifierKeyword.PUBLIC_KEYWORD));
716 classDeclaration.modifiers().add(rewriter.getAST().newModifier(ModifierKeyword.STATIC_KEYWORD));
717 bodyRewrite.insertBefore(classDeclaration, methodDeclaration, null);
718 }
719 }
720
721 public String getPackage() {
722 return fParameterObjectFactory.getPackage();
723 }
724
725 public void setPackage(String typeQualifier) {
726 fParameterObjectFactory.setPackage(typeQualifier);
727 }
728
729 private String getNameInScope(ParameterInfo pi, List<SingleVariableDeclaration> enclosingMethodParameters) {
730 Assert.isNotNull(enclosingMethodParameters);
731 boolean emptyVararg= pi.getOldIndex() >= enclosingMethodParameters.size();
732 if (!emptyVararg) {
733 SingleVariableDeclaration svd= enclosingMethodParameters.get(pi.getOldIndex());
734 return svd.getName().getIdentifier();
735 }
736 return null;
737 }
738
739 public String getNewTypeName() {
740 return fParameterObjectReference.getNewTypeName();
741 }
742
743 public ICompilationUnit getCompilationUnit() {
744 return getBaseCuRewrite().getCu();
745 }
746
747 @Override
748 protected int getDescriptorFlags() {
749 return super.getDescriptorFlags() | JavaRefactoringDescriptor.JAR_SOURCE_ATTACHMENT;
750 }
751
752}