001: /*******************************************************************************
002: * Copyright (c) 2000, 2007 IBM Corporation and others.
003: * All rights reserved. This program and the accompanying materials
004: * are made available under the terms of the Eclipse Public License v1.0
005: * which accompanies this distribution, and is available at
006: * http://www.eclipse.org/legal/epl-v10.html
007: *
008: * Contributors:
009: * IBM Corporation - initial API and implementation
010: *******************************************************************************/package org.eclipse.jdt.internal.corext.refactoring.structure;
011:
012: import java.util.ArrayList;
013: import java.util.Arrays;
014: import java.util.HashMap;
015: import java.util.Iterator;
016: import java.util.List;
017: import java.util.Map;
018:
019: import org.eclipse.core.runtime.Assert;
020: import org.eclipse.core.runtime.CoreException;
021: import org.eclipse.core.runtime.IProgressMonitor;
022: import org.eclipse.core.runtime.OperationCanceledException;
023:
024: import org.eclipse.ltk.core.refactoring.Change;
025: import org.eclipse.ltk.core.refactoring.RefactoringStatus;
026: import org.eclipse.ltk.core.refactoring.participants.RefactoringArguments;
027:
028: import org.eclipse.jdt.core.ICompilationUnit;
029: import org.eclipse.jdt.core.IJavaElement;
030: import org.eclipse.jdt.core.IJavaProject;
031: import org.eclipse.jdt.core.IMethod;
032: import org.eclipse.jdt.core.IPackageFragmentRoot;
033: import org.eclipse.jdt.core.ISourceRange;
034: import org.eclipse.jdt.core.IType;
035: import org.eclipse.jdt.core.JavaModelException;
036: import org.eclipse.jdt.core.NamingConventions;
037: import org.eclipse.jdt.core.compiler.IProblem;
038: import org.eclipse.jdt.core.dom.AST;
039: import org.eclipse.jdt.core.dom.ASTNode;
040: import org.eclipse.jdt.core.dom.ASTVisitor;
041: import org.eclipse.jdt.core.dom.ArrayCreation;
042: import org.eclipse.jdt.core.dom.ArrayInitializer;
043: import org.eclipse.jdt.core.dom.ArrayType;
044: import org.eclipse.jdt.core.dom.Block;
045: import org.eclipse.jdt.core.dom.ClassInstanceCreation;
046: import org.eclipse.jdt.core.dom.CompilationUnit;
047: import org.eclipse.jdt.core.dom.Expression;
048: import org.eclipse.jdt.core.dom.ExpressionStatement;
049: import org.eclipse.jdt.core.dom.FieldAccess;
050: import org.eclipse.jdt.core.dom.IBinding;
051: import org.eclipse.jdt.core.dom.IMethodBinding;
052: import org.eclipse.jdt.core.dom.ITypeBinding;
053: import org.eclipse.jdt.core.dom.IVariableBinding;
054: import org.eclipse.jdt.core.dom.Message;
055: import org.eclipse.jdt.core.dom.MethodDeclaration;
056: import org.eclipse.jdt.core.dom.Name;
057: import org.eclipse.jdt.core.dom.NullLiteral;
058: import org.eclipse.jdt.core.dom.QualifiedName;
059: import org.eclipse.jdt.core.dom.SimpleName;
060: import org.eclipse.jdt.core.dom.SingleVariableDeclaration;
061: import org.eclipse.jdt.core.dom.SuperFieldAccess;
062: import org.eclipse.jdt.core.dom.Type;
063: import org.eclipse.jdt.core.dom.TypeDeclaration;
064: import org.eclipse.jdt.core.dom.Modifier.ModifierKeyword;
065: import org.eclipse.jdt.core.dom.rewrite.ASTRewrite;
066: import org.eclipse.jdt.core.dom.rewrite.ListRewrite;
067: import org.eclipse.jdt.core.refactoring.descriptors.IntroduceParameterObjectDescriptor;
068: import org.eclipse.jdt.core.refactoring.descriptors.JavaRefactoringDescriptor;
069: import org.eclipse.jdt.core.refactoring.descriptors.IntroduceParameterObjectDescriptor.Parameter;
070:
071: import org.eclipse.jdt.internal.corext.codemanipulation.StubUtility;
072: import org.eclipse.jdt.internal.corext.dom.ASTNodes;
073: import org.eclipse.jdt.internal.corext.dom.NodeFinder;
074: import org.eclipse.jdt.internal.corext.dom.TypeBindingVisitor;
075: import org.eclipse.jdt.internal.corext.refactoring.Checks;
076: import org.eclipse.jdt.internal.corext.refactoring.JDTRefactoringDescriptorComment;
077: import org.eclipse.jdt.internal.corext.refactoring.ParameterInfo;
078: import org.eclipse.jdt.internal.corext.refactoring.RefactoringCoreMessages;
079: import org.eclipse.jdt.internal.corext.util.JavaModelUtil;
080: import org.eclipse.jdt.internal.corext.util.Messages;
081:
082: import org.eclipse.jdt.internal.ui.JavaPlugin;
083: import org.eclipse.jdt.internal.ui.text.correction.ASTResolving;
084:
085: public class IntroduceParameterObjectRefactoring extends
086: ChangeSignatureRefactoring {
087:
088: private final class ParameterObjectCreator implements
089: IDefaultValueAdvisor {
090: public Expression createDefaultExpression(
091: List invocationArguments, ParameterInfo addedInfo,
092: List parameterInfos, MethodDeclaration enclosingMethod,
093: boolean isRecursive, CompilationUnitRewrite cuRewrite) {
094: final AST ast = cuRewrite.getAST();
095: final ASTRewrite rewrite = cuRewrite.getASTRewrite();
096: if (isRecursive
097: && canReuseParameterObject(invocationArguments,
098: addedInfo, parameterInfos, enclosingMethod)) {
099: return ast.newSimpleName(addedInfo.getNewName());
100: }
101: ClassInstanceCreation classCreation = ast
102: .newClassInstanceCreation();
103:
104: int startPosition = enclosingMethod != null ? enclosingMethod
105: .getStartPosition()
106: : cuRewrite.getRoot().getStartPosition();
107: classCreation.setType(fParameterObjectFactory.createType(
108: fCreateAsTopLevel, cuRewrite, startPosition));
109: List constructorArguments = classCreation.arguments();
110: for (Iterator iter = parameterInfos.iterator(); iter
111: .hasNext();) {
112: ParameterInfo pi = (ParameterInfo) iter.next();
113: if (isValidField(pi)) {
114: if (pi.isOldVarargs()) {
115: boolean isLastParameter = !iter.hasNext();
116: constructorArguments.addAll(computeVarargs(
117: invocationArguments, pi,
118: isLastParameter, cuRewrite));
119: } else {
120: Expression exp = (Expression) invocationArguments
121: .get(pi.getOldIndex());
122: importNodeTypes(exp, cuRewrite);
123: constructorArguments
124: .add(moveNode(exp, rewrite));
125: }
126: }
127: }
128: return classCreation;
129: }
130:
131: public Type createType(String newTypeName, int startPosition,
132: CompilationUnitRewrite cuRewrite) {
133: return fParameterObjectFactory.createType(
134: fCreateAsTopLevel, cuRewrite, startPosition);
135: }
136:
137: private boolean canReuseParameterObject(
138: List invocationArguments, ParameterInfo addedInfo,
139: List parameterInfos, MethodDeclaration enclosingMethod) {
140: Assert.isNotNull(enclosingMethod);
141: List parameters = enclosingMethod.parameters();
142: for (Iterator iter = parameterInfos.iterator(); iter
143: .hasNext();) {
144: ParameterInfo pi = (ParameterInfo) iter.next();
145: if (isValidField(pi)) {
146: if (!pi.isInlined())
147: return false;
148: ASTNode node = (ASTNode) invocationArguments.get(pi
149: .getOldIndex());
150: if (!isParameter(pi, node, parameters, addedInfo
151: .getNewName())) {
152: return false;
153: }
154: }
155: }
156: return true;
157: }
158:
159: private List computeVarargs(List invocationArguments,
160: ParameterInfo varArgPI, boolean isLastParameter,
161: CompilationUnitRewrite cuRewrite) {
162: boolean isEmptyVarArg = varArgPI.getOldIndex() >= invocationArguments
163: .size();
164: ASTRewrite rewrite = cuRewrite.getASTRewrite();
165: AST ast = cuRewrite.getAST();
166: ASTNode lastNode = isEmptyVarArg ? null
167: : (ASTNode) invocationArguments.get(varArgPI
168: .getOldIndex());
169: List constructorArguments = new ArrayList();
170: if (lastNode instanceof ArrayCreation) {
171: ArrayCreation creation = (ArrayCreation) lastNode;
172: ITypeBinding arrayType = creation.resolveTypeBinding();
173: if (arrayType != null
174: && arrayType.isAssignmentCompatible(varArgPI
175: .getNewTypeBinding())) {
176: constructorArguments
177: .add(moveNode(creation, rewrite));
178: return constructorArguments;
179: }
180: }
181: if (isLastParameter) {
182: // copy all varargs
183: for (int i = varArgPI.getOldIndex(); i < invocationArguments
184: .size(); i++) {
185: ASTNode node = (ASTNode) invocationArguments.get(i);
186: importNodeTypes(node, cuRewrite);
187: constructorArguments.add(moveNode(node, rewrite));
188: }
189: } else { // new signature would be String...args, int
190: if (lastNode instanceof NullLiteral) {
191: NullLiteral nullLiteral = (NullLiteral) lastNode;
192: constructorArguments.add(moveNode(nullLiteral,
193: rewrite));
194: } else {
195: ArrayCreation creation = ast.newArrayCreation();
196: creation.setType((ArrayType) importBinding(varArgPI
197: .getNewTypeBinding(), cuRewrite));
198: ArrayInitializer initializer = ast
199: .newArrayInitializer();
200: List expressions = initializer.expressions();
201: for (int i = varArgPI.getOldIndex(); i < invocationArguments
202: .size(); i++) {
203: ASTNode node = (ASTNode) invocationArguments
204: .get(i);
205: importNodeTypes(node, cuRewrite);
206: expressions.add(moveNode(node, rewrite));
207: }
208: if (expressions.isEmpty())
209: creation.dimensions().add(
210: ast.newNumberLiteral("0")); //$NON-NLS-1$
211: else
212: creation.setInitializer(initializer);
213: constructorArguments.add(creation);
214: }
215: }
216: return constructorArguments;
217: }
218:
219: public Type importBinding(ITypeBinding newTypeBinding,
220: CompilationUnitRewrite cuRewrite) {
221: Type type = cuRewrite.getImportRewrite().addImport(
222: newTypeBinding, cuRewrite.getAST());
223: cuRewrite.getImportRemover().registerAddedImports(type);
224: return type;
225: }
226:
227: private void importNodeTypes(ASTNode node,
228: final CompilationUnitRewrite cuRewrite) {
229: ASTResolving.visitAllBindings(node,
230: new TypeBindingVisitor() {
231: public boolean visit(ITypeBinding nodeBinding) {
232: importBinding(nodeBinding, cuRewrite);
233: return false;
234: }
235: });
236: }
237: }
238:
239: private boolean isParameter(ParameterInfo pi, ASTNode node,
240: List enclosingMethodParameters, String qualifier) {
241: if (node instanceof Name) {
242: Name name = (Name) node;
243: IVariableBinding binding = ASTNodes
244: .getVariableBinding(name);
245: if (binding != null && binding.isParameter()) {
246: return binding.getName().equals(
247: getNameInScope(pi, enclosingMethodParameters));
248: } else {
249: if (node instanceof QualifiedName) {
250: QualifiedName qn = (QualifiedName) node;
251: return qn
252: .getFullyQualifiedName()
253: .equals(
254: JavaModelUtil
255: .concatenateName(
256: qualifier,
257: getNameInScope(pi,
258: enclosingMethodParameters)));
259: }
260: }
261: }
262: return false;
263: }
264:
265: private final class RewriteParameterBody extends BodyUpdater {
266: private boolean fParameterClassCreated = false;
267:
268: public void updateBody(MethodDeclaration methodDeclaration,
269: final CompilationUnitRewrite cuRewrite,
270: RefactoringStatus result) throws CoreException {
271: // ensure that the parameterObject is imported
272: fParameterObjectFactory.createType(fCreateAsTopLevel,
273: cuRewrite, methodDeclaration.getStartPosition());
274: if (cuRewrite.getCu().equals(getCompilationUnit())
275: && !fParameterClassCreated) {
276: createParameterClass(methodDeclaration, cuRewrite);
277: fParameterClassCreated = true;
278: }
279: Block body = methodDeclaration.getBody();
280: final List parameters = methodDeclaration.parameters();
281: if (body != null) { // abstract methods don't have bodies
282: final ASTRewrite rewriter = cuRewrite.getASTRewrite();
283: ListRewrite bodyStatements = rewriter.getListRewrite(
284: body, Block.STATEMENTS_PROPERTY);
285: List managedParams = getParameterInfos();
286: for (Iterator iter = managedParams.iterator(); iter
287: .hasNext();) {
288: final ParameterInfo pi = (ParameterInfo) iter
289: .next();
290: if (isValidField(pi)) {
291: if (isReadOnly(pi, body, parameters, null)) {
292: body.accept(new ASTVisitor(false) {
293:
294: public boolean visit(SimpleName node) {
295: updateSimpleName(rewriter, pi,
296: node, parameters, cuRewrite
297: .getCu()
298: .getJavaProject());
299: return false;
300: }
301:
302: });
303: pi.setInlined(true);
304: } else {
305: ExpressionStatement initializer = fParameterObjectFactory
306: .createInitializer(pi,
307: getParameterName(),
308: cuRewrite);
309: bodyStatements.insertFirst(initializer,
310: null);
311: }
312: }
313: }
314: }
315:
316: }
317:
318: private void updateSimpleName(ASTRewrite rewriter,
319: ParameterInfo pi, SimpleName node,
320: List enclosingParameters, IJavaProject project) {
321: AST ast = rewriter.getAST();
322: IBinding binding = node.resolveBinding();
323: Expression replacementNode = fParameterObjectFactory
324: .createFieldReadAccess(pi, getParameterName(), ast,
325: project, false, null);
326: if (binding instanceof IVariableBinding) {
327: IVariableBinding variable = (IVariableBinding) binding;
328: if (variable.isParameter()
329: && variable.getName()
330: .equals(
331: getNameInScope(pi,
332: enclosingParameters))) {
333: rewriter.replace(node, replacementNode, null);
334: }
335: } else {
336: ASTNode parent = node.getParent();
337: if (!(parent instanceof QualifiedName
338: || parent instanceof FieldAccess || parent instanceof SuperFieldAccess)) {
339: if (node.getIdentifier().equals(
340: getNameInScope(pi, enclosingParameters))) {
341: rewriter.replace(node, replacementNode, null);
342: }
343: }
344: }
345: }
346:
347: private boolean isReadOnly(final ParameterInfo pi, Block block,
348: final List enclosingMethodParameters,
349: final String qualifier) {
350: class NotWrittenDetector extends ASTVisitor {
351: boolean notWritten = true;
352:
353: public boolean visit(SimpleName node) {
354: if (isParameter(pi, node,
355: enclosingMethodParameters, qualifier)
356: && ASTResolving.isWriteAccess(node))
357: notWritten = false;
358: return false;
359: }
360:
361: public boolean visit(SuperFieldAccess node) {
362: return false;
363: }
364: }
365: NotWrittenDetector visitor = new NotWrittenDetector();
366: block.accept(visitor);
367: return visitor.notWritten;
368: }
369:
370: public boolean needsParameterUsedCheck() {
371: return false;
372: }
373:
374: }
375:
376: private static final String PARAMETER_CLASS_APPENDIX = "Parameter"; //$NON-NLS-1$
377:
378: private static final String DEFAULT_PARAMETER_OBJECT_NAME = "parameterObject"; //$NON-NLS-1$
379:
380: private MethodDeclaration fMethodDeclaration;
381:
382: private ParameterObjectFactory fParameterObjectFactory;
383:
384: private boolean fCreateAsTopLevel = true;
385:
386: private ParameterInfo fParameterObjectReference;
387:
388: private List/*<Change>*/fOtherChanges;
389:
390: public IntroduceParameterObjectRefactoring(
391: IntroduceParameterObjectDescriptor descriptor)
392: throws JavaModelException {
393: super (descriptor.getMethod());
394: IMethod method = descriptor.getMethod();
395: Assert.isNotNull(method);
396: initializeFields(method);
397: setBodyUpdater(new RewriteParameterBody());
398: setDefaultValueAdvisor(new ParameterObjectCreator());
399: configureRefactoring(descriptor, this );
400: }
401:
402: private void configureRefactoring(
403: final IntroduceParameterObjectDescriptor parameter,
404: IntroduceParameterObjectRefactoring ref)
405: throws JavaModelException {
406: ref.setCreateAsTopLevel(parameter.isTopLevel());
407: ref.setCreateGetter(parameter.isGetters());
408: ref.setCreateSetter(parameter.isSetters());
409: ref.setDelegateUpdating(parameter.isDelegate());
410: ref.setDeprecateDelegates(parameter.isDeprecateDelegate());
411: if (parameter.getClassName() != null)
412: ref.setClassName(parameter.getClassName());
413: if (parameter.getPackageName() != null)
414: ref.setPackage(parameter.getPackageName());
415: if (parameter.getParameterName() != null)
416: ref.setParameterName(parameter.getParameterName());
417: List pis = ref.getParameterInfos();
418: Parameter[] parameters = parameter.getParameters();
419: if (parameters == null)
420: parameters = IntroduceParameterObjectDescriptor
421: .createParameters(getMethod());
422: Map paramIndex = new HashMap();
423: for (Iterator iter = pis.iterator(); iter.hasNext();) {
424: ParameterInfo pi = (ParameterInfo) iter.next();
425: paramIndex.put(new Integer(pi.getOldIndex()), pi);
426: }
427: paramIndex.put(new Integer(ParameterInfo.INDEX_FOR_ADDED),
428: fParameterObjectReference);
429: pis.clear();
430: for (int i = 0; i < parameters.length; i++) {
431: Parameter param = parameters[i];
432: ParameterInfo pi = (ParameterInfo) paramIndex
433: .get(new Integer(param.getIndex()));
434: pis.add(pi);
435: if (param != IntroduceParameterObjectDescriptor.PARAMETER_OBJECT) {
436: pi.setCreateField(param.isCreateField());
437: if (pi.isCreateField()) {
438: String fieldName = param.getFieldName();
439: if (fieldName != null)
440: pi.setNewName(fieldName);
441: }
442: }
443: }
444: }
445:
446: private void initializeFields(IMethod method)
447: throws JavaModelException {
448: fParameterObjectFactory = new ParameterObjectFactory();
449: String methodName = method.getElementName();
450: String className = String.valueOf(Character
451: .toUpperCase(methodName.charAt(0)));
452: if (methodName.length() > 1)
453: className += methodName.substring(1);
454: className += PARAMETER_CLASS_APPENDIX;
455:
456: fParameterObjectReference = ParameterInfo
457: .createInfoForAddedParameter(className,
458: DEFAULT_PARAMETER_OBJECT_NAME);
459: fParameterObjectFactory.setClassName(className);
460:
461: IType declaringType = method.getDeclaringType();
462: Assert.isNotNull(declaringType);
463: fParameterObjectFactory.setPackage(declaringType
464: .getPackageFragment().getElementName());
465:
466: updateReferenceType();
467: }
468:
469: public RefactoringStatus checkFinalConditions(IProgressMonitor pm)
470: throws CoreException, OperationCanceledException {
471: RefactoringStatus status = new RefactoringStatus();
472: IMethod context = getMethod();
473: // TODO: Check for availability
474: status.merge(Checks.checkTypeName(fParameterObjectFactory
475: .getClassName(), context));
476: status.merge(Checks
477: .checkIdentifier(getParameterName(), context));
478: if (status.hasFatalError())
479: return status;
480: status.merge(super .checkFinalConditions(pm));
481: return status;
482: }
483:
484: public RefactoringStatus checkInitialConditions(IProgressMonitor pm)
485: throws CoreException, OperationCanceledException {
486: RefactoringStatus status = new RefactoringStatus();
487: status.merge(super .checkInitialConditions(pm));
488: if (status.hasFatalError())
489: return status;
490: CompilationUnit astRoot = getBaseCuRewrite().getRoot();
491: ISourceRange nameRange = getMethod().getNameRange();
492: ASTNode selectedNode = NodeFinder.perform(astRoot, nameRange
493: .getOffset(), nameRange.getLength());
494: if (selectedNode == null) {
495: return mappingErrorFound(status, selectedNode);
496: }
497: fMethodDeclaration = (MethodDeclaration) ASTNodes.getParent(
498: selectedNode, MethodDeclaration.class);
499: if (fMethodDeclaration == null) {
500: return mappingErrorFound(status, selectedNode);
501: }
502: IMethodBinding resolveBinding = fMethodDeclaration
503: .resolveBinding();
504: if (resolveBinding == null) {
505: if (!processCompilerError(status, selectedNode))
506: status
507: .addFatalError(RefactoringCoreMessages.IntroduceParameterObjectRefactoring_error_cannot_resolve_type);
508: return status;
509: }
510:
511: ITypeBinding declaringClass = resolveBinding
512: .getDeclaringClass();
513: if (fParameterObjectFactory.getPackage() == null)
514: fParameterObjectFactory.setPackage(declaringClass
515: .getPackage().getName());
516: if (fParameterObjectFactory.getEnclosingType() == null)
517: fParameterObjectFactory.setEnclosingType(declaringClass
518: .getQualifiedName());
519:
520: List parameterInfos = super .getParameterInfos();
521: for (Iterator iter = parameterInfos.iterator(); iter.hasNext();) {
522: ParameterInfo pi = (ParameterInfo) iter.next();
523: if (!pi.isAdded()) {
524: if (pi.getOldName().equals(pi.getNewName())) // may have been
525: // set to
526: // something
527: // else after
528: // creation
529: pi.setNewName(getFieldName(pi));
530: }
531: }
532: if (!parameterInfos.contains(fParameterObjectReference)) {
533: parameterInfos.add(0, fParameterObjectReference);
534: }
535: Map bindingMap = new HashMap();
536: for (Iterator iter = fMethodDeclaration.parameters().iterator(); iter
537: .hasNext();) {
538: SingleVariableDeclaration sdv = (SingleVariableDeclaration) iter
539: .next();
540: bindingMap.put(sdv.getName().getIdentifier(), sdv
541: .resolveBinding());
542: }
543: for (Iterator iter = parameterInfos.iterator(); iter.hasNext();) {
544: ParameterInfo pi = (ParameterInfo) iter.next();
545: if (pi != fParameterObjectReference)
546: pi.setOldBinding((IVariableBinding) bindingMap.get(pi
547: .getOldName()));
548: }
549: fParameterObjectFactory.setVariables(parameterInfos);
550: return status;
551: }
552:
553: protected boolean shouldReport(IProblem problem, CompilationUnit cu) {
554: if (!super .shouldReport(problem, cu))
555: return false;
556: ASTNode node = ASTNodeSearchUtil.getAstNode(cu, problem
557: .getSourceStart(), problem.getSourceEnd()
558: - problem.getSourceStart());
559: if (node instanceof Type) {
560: Type type = (Type) node;
561: if (problem.getID() == IProblem.UndefinedType
562: && getClassName()
563: .equals(ASTNodes.getTypeName(type))) {
564: return false;
565: }
566: }
567: if (node instanceof Name) {
568: Name name = (Name) node;
569: if (problem.getID() == IProblem.ImportNotFound
570: && getPackage().indexOf(
571: name.getFullyQualifiedName()) != -1)
572: return false;
573: }
574: return true;
575: }
576:
577: public String getClassName() {
578: return fParameterObjectFactory.getClassName();
579: }
580:
581: public ITypeBinding getContainingClass() {
582: return fMethodDeclaration.resolveBinding().getDeclaringClass();
583: }
584:
585: private String getMappingErrorMessage() {
586: return Messages
587: .format(
588: RefactoringCoreMessages.IntroduceParameterObjectRefactoring_cannotalanyzemethod_mappingerror,
589: new String[] {});
590: }
591:
592: public String getFieldName(ParameterInfo element) {
593: IJavaProject javaProject = getCompilationUnit()
594: .getJavaProject();
595: String stripped = NamingConventions
596: .removePrefixAndSuffixForArgumentName(javaProject,
597: element.getOldName());
598: int dim = element.getNewTypeBinding() != null ? element
599: .getNewTypeBinding().getDimensions() : 0;
600: return StubUtility.getVariableNameSuggestions(
601: StubUtility.INSTANCE_FIELD, javaProject, stripped, dim,
602: null, true)[0];
603: }
604:
605: public Change[] getAllChanges() {
606: ArrayList changes = new ArrayList();
607: changes.addAll(Arrays.asList(super .getAllChanges()));
608: changes.addAll(fOtherChanges);
609: return (Change[]) changes.toArray(new Change[changes.size()]);
610: }
611:
612: protected void clearManagers() {
613: super .clearManagers();
614: fOtherChanges = new ArrayList();
615: }
616:
617: public String getName() {
618: return RefactoringCoreMessages.IntroduceParameterObjectRefactoring_refactoring_name;
619: }
620:
621: public JavaRefactoringDescriptor createDescriptor() {
622: IntroduceParameterObjectDescriptor ipod = new IntroduceParameterObjectDescriptor();
623: ipod.setMethod(getMethod());
624: ipod.setClassName(getClassName());
625: ipod.setDelegate(getDelegateUpdating());
626: ipod.setDeprecateDelegate(getDeprecateDelegates());
627: ipod.setGetters(isCreateGetter());
628: ipod.setSetters(isCreateSetter());
629: ipod.setPackageName(getPackage());
630: ipod.setParameterName(getParameterName());
631: ipod.setTopLevel(isCreateAsTopLevel());
632:
633: ArrayList parameters = new ArrayList();
634: List pis = getParameterInfos();
635: for (Iterator iter = pis.iterator(); iter.hasNext();) {
636: ParameterInfo pi = (ParameterInfo) iter.next();
637: if (pi.isAdded()) {
638: parameters
639: .add(IntroduceParameterObjectDescriptor.PARAMETER_OBJECT);
640: } else {
641: IntroduceParameterObjectDescriptor.Parameter parameter = new IntroduceParameterObjectDescriptor.Parameter(
642: pi.getOldIndex());
643: if (pi.isCreateField()) {
644: parameter.setCreateField(true);
645: parameter.setFieldName(pi.getNewName());
646: }
647: parameters.add(parameter);
648: }
649: }
650: ipod.setParameters((Parameter[]) parameters
651: .toArray(new Parameter[parameters.size()]));
652: String project = getCompilationUnit().getJavaProject()
653: .getElementName();
654: try {
655: ipod.setComment(createComment(project).asString());
656: } catch (JavaModelException e) {
657: JavaPlugin.log(e);
658: }
659: ipod.setProject(project);
660: ipod.setDescription(getName());
661: ipod.setFlags(getDescriptorFlags());
662: return ipod;
663: }
664:
665: private JDTRefactoringDescriptorComment createComment(String project)
666: throws JavaModelException {
667: String header = Messages
668: .format(
669: RefactoringCoreMessages.IntroduceParameterObjectRefactoring_descriptor_description,
670: getOldMethodSignature());
671: JDTRefactoringDescriptorComment comment = new JDTRefactoringDescriptorComment(
672: project, this , header);
673: comment
674: .addSetting(Messages
675: .format(
676: RefactoringCoreMessages.IntroduceParameterObjectRefactoring_descriptor_object_class,
677: fParameterObjectFactory.getClassName()));
678: if (fCreateAsTopLevel) {
679: comment
680: .addSetting(Messages
681: .format(
682: RefactoringCoreMessages.IntroduceParameterObjectRefactoring_descriptor_package,
683: fParameterObjectFactory
684: .getPackage()));
685: } else {
686: comment
687: .addSetting(Messages
688: .format(
689: RefactoringCoreMessages.IntroduceParameterObjectRefactoring_descriptor_enclosing_type,
690: fParameterObjectFactory
691: .getEnclosingType()));
692: }
693: List infos = getParameterInfos();
694: List kept = new ArrayList();
695: List fields = new ArrayList();
696: for (Iterator iter = infos.iterator(); iter.hasNext();) {
697: ParameterInfo pi = (ParameterInfo) iter.next();
698: if (pi.isCreateField()) {
699: fields.add(pi.getNewName());
700: } else {
701: if (!pi.isAdded()) {
702: kept.add(pi.getNewName());
703: }
704: }
705: }
706:
707: comment
708: .addSetting(JDTRefactoringDescriptorComment
709: .createCompositeSetting(
710: RefactoringCoreMessages.IntroduceParameterObjectRefactoring_descriptor_fields,
711: (String[]) fields
712: .toArray(new String[0])));
713: if (!kept.isEmpty())
714: comment
715: .addSetting(JDTRefactoringDescriptorComment
716: .createCompositeSetting(
717: RefactoringCoreMessages.IntroduceParameterObjectRefactoring_descriptor_keep_parameter,
718: (String[]) kept
719: .toArray(new String[0])));
720: if (fParameterObjectFactory.isCreateGetter())
721: comment
722: .addSetting(RefactoringCoreMessages.IntroduceParameterObjectRefactoring_descriptor_create_getter);
723: if (fParameterObjectFactory.isCreateSetter())
724: comment
725: .addSetting(RefactoringCoreMessages.IntroduceParameterObjectRefactoring_descriptor_create_setter);
726: return comment;
727: }
728:
729: protected String doGetRefactoringChangeName() {
730: return getName();
731: }
732:
733: public String getParameterName() {
734: return fParameterObjectReference.getNewName();
735: }
736:
737: public RefactoringStatus initialize(RefactoringArguments arguments) {
738: RefactoringStatus refactoringStatus = new RefactoringStatus();
739: // this refactoring is initialized using the descriptor from constructor
740: return refactoringStatus;
741: }
742:
743: public boolean isCreateGetter() {
744: return fParameterObjectFactory.isCreateGetter();
745: }
746:
747: public boolean isCreateSetter() {
748: return fParameterObjectFactory.isCreateSetter();
749: }
750:
751: public boolean isCreateAsTopLevel() {
752: return fCreateAsTopLevel;
753: }
754:
755: /**
756: * Checks if the given parameter info has been selected for field creation
757: *
758: * @param pi parameter info
759: * @return true if the given parameter info has been selected for field
760: * creation
761: */
762: private boolean isValidField(ParameterInfo pi) {
763: return pi.isCreateField() & !pi.isAdded();
764: }
765:
766: private RefactoringStatus mappingErrorFound(
767: RefactoringStatus result, ASTNode node) {
768: if (node != null && (node.getFlags() & ASTNode.MALFORMED) != 0
769: && processCompilerError(result, node))
770: return result;
771: result.addFatalError(getMappingErrorMessage());
772: return result;
773: }
774:
775: public void moveFieldDown(ParameterInfo selected) {
776: fParameterObjectFactory.moveDown(selected);
777: }
778:
779: public void moveFieldUp(ParameterInfo selected) {
780: fParameterObjectFactory.moveUp(selected);
781: }
782:
783: private boolean processCompilerError(RefactoringStatus result,
784: ASTNode node) {
785: Message[] messages = ASTNodes.getMessages(node,
786: ASTNodes.INCLUDE_ALL_PARENTS);
787: if (messages.length == 0)
788: return false;
789: result
790: .addFatalError(Messages
791: .format(
792: RefactoringCoreMessages.IntroduceParameterObjectRefactoring_cannotanalysemethod_compilererror,
793: new String[] { messages[0].getMessage() }));
794: return true;
795: }
796:
797: public void setClassName(String className) {
798: fParameterObjectFactory.setClassName(className);
799: updateReferenceType();
800: }
801:
802: private void updateReferenceType() {
803: if (fCreateAsTopLevel)
804: fParameterObjectReference.setNewTypeName(JavaModelUtil
805: .concatenateName(fParameterObjectFactory
806: .getPackage(), fParameterObjectFactory
807: .getClassName()));
808: else
809: fParameterObjectReference.setNewTypeName(JavaModelUtil
810: .concatenateName(fParameterObjectFactory
811: .getEnclosingType(),
812: fParameterObjectFactory.getClassName()));
813: }
814:
815: public void setCreateGetter(boolean createGetter) {
816: fParameterObjectFactory.setCreateGetter(createGetter);
817: }
818:
819: public void setCreateSetter(boolean createSetter) {
820: fParameterObjectFactory.setCreateSetter(createSetter);
821: }
822:
823: public void setPackageName(String packageName) {
824: fParameterObjectFactory.setPackage(packageName);
825: updateReferenceType();
826: }
827:
828: public void setParameterName(String paramName) {
829: this .fParameterObjectReference.setNewName(paramName);
830: }
831:
832: public void setCreateAsTopLevel(boolean topLevel) {
833: this .fCreateAsTopLevel = topLevel;
834: updateReferenceType();
835: }
836:
837: public void updateParameterPosition() {
838: fParameterObjectFactory
839: .updateParameterPosition(fParameterObjectReference);
840: }
841:
842: private void createParameterClass(
843: MethodDeclaration methodDeclaration,
844: CompilationUnitRewrite cuRewrite) throws CoreException {
845: if (fCreateAsTopLevel) {
846: IPackageFragmentRoot root = (IPackageFragmentRoot) cuRewrite
847: .getCu().getAncestor(
848: IJavaElement.PACKAGE_FRAGMENT_ROOT);
849: fOtherChanges.addAll(fParameterObjectFactory
850: .createTopLevelParameterObject(root));
851: } else {
852: ASTRewrite rewriter = cuRewrite.getASTRewrite();
853: TypeDeclaration enclosingType = (TypeDeclaration) methodDeclaration
854: .getParent();
855: ListRewrite bodyRewrite = rewriter.getListRewrite(
856: enclosingType,
857: TypeDeclaration.BODY_DECLARATIONS_PROPERTY);
858: String fqn = enclosingType.getName()
859: .getFullyQualifiedName();
860: TypeDeclaration classDeclaration = fParameterObjectFactory
861: .createClassDeclaration(fqn, cuRewrite, null);
862: classDeclaration.modifiers().add(
863: rewriter.getAST().newModifier(
864: ModifierKeyword.PUBLIC_KEYWORD));
865: classDeclaration.modifiers().add(
866: rewriter.getAST().newModifier(
867: ModifierKeyword.STATIC_KEYWORD));
868: bodyRewrite.insertBefore(classDeclaration,
869: methodDeclaration, null);
870: }
871: }
872:
873: public String getPackage() {
874: return fParameterObjectFactory.getPackage();
875: }
876:
877: public void setPackage(String typeQualifier) {
878: fParameterObjectFactory.setPackage(typeQualifier);
879: }
880:
881: private String getNameInScope(ParameterInfo pi,
882: List enclosingMethodParameters) {
883: Assert.isNotNull(enclosingMethodParameters);
884: boolean emptyVararg = pi.getOldIndex() >= enclosingMethodParameters
885: .size();
886: if (!emptyVararg) {
887: SingleVariableDeclaration svd = (SingleVariableDeclaration) enclosingMethodParameters
888: .get(pi.getOldIndex());
889: return svd.getName().getIdentifier();
890: }
891: return null;
892: }
893:
894: public String getNewTypeName() {
895: return fParameterObjectReference.getNewTypeName();
896: }
897:
898: public ICompilationUnit getCompilationUnit() {
899: return getBaseCuRewrite().getCu();
900: }
901:
902: protected int getDescriptorFlags() {
903: return super.getDescriptorFlags()
904: | JavaRefactoringDescriptor.JAR_SOURCE_ATTACHMENT;
905: }
906:
907: }
|