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: * Felix Pahl (fpahl@web.de) - contributed fix for:
011: * o introduce parameter throws NPE if there are compiler errors
012: * (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=48325)
013: *******************************************************************************/package org.eclipse.jdt.internal.corext.refactoring.code;
014:
015: import java.util.Arrays;
016: import java.util.Collections;
017: import java.util.HashMap;
018: import java.util.LinkedHashSet;
019: import java.util.List;
020: import java.util.Map;
021: import java.util.StringTokenizer;
022:
023: import org.eclipse.core.runtime.Assert;
024: import org.eclipse.core.runtime.CoreException;
025: import org.eclipse.core.runtime.IProgressMonitor;
026: import org.eclipse.core.runtime.SubProgressMonitor;
027:
028: import org.eclipse.jface.text.TextSelection;
029:
030: import org.eclipse.ltk.core.refactoring.Change;
031: import org.eclipse.ltk.core.refactoring.RefactoringStatus;
032: import org.eclipse.ltk.core.refactoring.RefactoringStatusEntry;
033: import org.eclipse.ltk.core.refactoring.participants.RefactoringArguments;
034:
035: import org.eclipse.jdt.core.ICompilationUnit;
036: import org.eclipse.jdt.core.IJavaElement;
037: import org.eclipse.jdt.core.IMethod;
038: import org.eclipse.jdt.core.JavaModelException;
039: import org.eclipse.jdt.core.dom.ASTNode;
040: import org.eclipse.jdt.core.dom.ArrayInitializer;
041: import org.eclipse.jdt.core.dom.Assignment;
042: import org.eclipse.jdt.core.dom.ClassInstanceCreation;
043: import org.eclipse.jdt.core.dom.Expression;
044: import org.eclipse.jdt.core.dom.FieldAccess;
045: import org.eclipse.jdt.core.dom.IBinding;
046: import org.eclipse.jdt.core.dom.ITypeBinding;
047: import org.eclipse.jdt.core.dom.MethodDeclaration;
048: import org.eclipse.jdt.core.dom.MethodInvocation;
049: import org.eclipse.jdt.core.dom.Name;
050: import org.eclipse.jdt.core.dom.NullLiteral;
051: import org.eclipse.jdt.core.dom.QualifiedName;
052: import org.eclipse.jdt.core.dom.SimpleName;
053: import org.eclipse.jdt.core.refactoring.IJavaRefactorings;
054: import org.eclipse.jdt.core.refactoring.descriptors.ChangeMethodSignatureDescriptor;
055: import org.eclipse.jdt.core.refactoring.descriptors.IntroduceParameterDescriptor;
056:
057: import org.eclipse.jdt.internal.corext.Corext;
058: import org.eclipse.jdt.internal.corext.SourceRange;
059: import org.eclipse.jdt.internal.corext.codemanipulation.StubUtility;
060: import org.eclipse.jdt.internal.corext.dom.ASTNodes;
061: import org.eclipse.jdt.internal.corext.dom.Bindings;
062: import org.eclipse.jdt.internal.corext.dom.NodeFinder;
063: import org.eclipse.jdt.internal.corext.dom.ScopeAnalyzer;
064: import org.eclipse.jdt.internal.corext.dom.fragments.ASTFragmentFactory;
065: import org.eclipse.jdt.internal.corext.dom.fragments.IASTFragment;
066: import org.eclipse.jdt.internal.corext.dom.fragments.IExpressionFragment;
067: import org.eclipse.jdt.internal.corext.refactoring.Checks;
068: import org.eclipse.jdt.internal.corext.refactoring.JDTRefactoringDescriptorComment;
069: import org.eclipse.jdt.internal.corext.refactoring.JavaRefactoringArguments;
070: import org.eclipse.jdt.internal.corext.refactoring.JavaRefactoringDescriptorUtil;
071: import org.eclipse.jdt.internal.corext.refactoring.ParameterInfo;
072: import org.eclipse.jdt.internal.corext.refactoring.RefactoringAvailabilityTester;
073: import org.eclipse.jdt.internal.corext.refactoring.RefactoringCoreMessages;
074: import org.eclipse.jdt.internal.corext.refactoring.base.RefactoringStatusCodes;
075: import org.eclipse.jdt.internal.corext.refactoring.changes.DynamicValidationRefactoringChange;
076: import org.eclipse.jdt.internal.corext.refactoring.structure.BodyUpdater;
077: import org.eclipse.jdt.internal.corext.refactoring.structure.ChangeSignatureRefactoring;
078: import org.eclipse.jdt.internal.corext.refactoring.structure.CompilationUnitRewrite;
079: import org.eclipse.jdt.internal.corext.refactoring.tagging.IDelegateUpdating;
080: import org.eclipse.jdt.internal.corext.util.Messages;
081:
082: import org.eclipse.jdt.ui.JavaElementLabels;
083:
084: import org.eclipse.jdt.internal.ui.JavaPlugin;
085: import org.eclipse.jdt.internal.ui.actions.SelectionConverter;
086:
087: public class IntroduceParameterRefactoring extends
088: ScriptableRefactoring implements IDelegateUpdating {
089:
090: private static final String ATTRIBUTE_ARGUMENT = "argument"; //$NON-NLS-1$
091:
092: private static final String[] KNOWN_METHOD_NAME_PREFIXES = {
093: "get", "is" }; //$NON-NLS-2$ //$NON-NLS-1$
094:
095: private ICompilationUnit fSourceCU;
096: private int fSelectionStart;
097: private int fSelectionLength;
098:
099: private IMethod fMethod;
100: private ChangeSignatureRefactoring fChangeSignatureRefactoring;
101: private ParameterInfo fParameter;
102: private String fParameterName;
103: private RefactoringArguments fArguments;
104:
105: private Expression fSelectedExpression;
106: private String[] fExcludedParameterNames;
107:
108: /**
109: * Creates a new introduce parameter refactoring.
110: * @param unit the compilation unit, or <code>null</code> if invoked by scripting
111: * @param selectionStart
112: * @param selectionLength
113: */
114: public IntroduceParameterRefactoring(ICompilationUnit unit,
115: int selectionStart, int selectionLength) {
116: Assert.isTrue(selectionStart >= 0);
117: Assert.isTrue(selectionLength >= 0);
118: fSourceCU = unit;
119: fSelectionStart = selectionStart;
120: fSelectionLength = selectionLength;
121: }
122:
123: // ------------------- IDelegateUpdating ----------------------
124:
125: public boolean canEnableDelegateUpdating() {
126: return true;
127: }
128:
129: public boolean getDelegateUpdating() {
130: return (fChangeSignatureRefactoring != null) ? fChangeSignatureRefactoring
131: .getDelegateUpdating()
132: : false;
133: }
134:
135: public void setDelegateUpdating(boolean updating) {
136: if (fChangeSignatureRefactoring != null)
137: fChangeSignatureRefactoring.setDelegateUpdating(updating);
138: }
139:
140: public void setDeprecateDelegates(boolean deprecate) {
141: if (fChangeSignatureRefactoring != null)
142: fChangeSignatureRefactoring
143: .setDeprecateDelegates(deprecate);
144: }
145:
146: public boolean getDeprecateDelegates() {
147: return (fChangeSignatureRefactoring != null) ? fChangeSignatureRefactoring
148: .getDeprecateDelegates()
149: : false;
150: }
151:
152: // ------------------- /IDelegateUpdating ---------------------
153:
154: public String getName() {
155: return RefactoringCoreMessages.IntroduceParameterRefactoring_name;
156: }
157:
158: //--- checkActivation
159:
160: public RefactoringStatus checkInitialConditions(IProgressMonitor pm)
161: throws CoreException {
162: try {
163: pm.beginTask("", 7); //$NON-NLS-1$
164:
165: if (!fSourceCU.isStructureKnown())
166: return RefactoringStatus
167: .createFatalErrorStatus(RefactoringCoreMessages.IntroduceParameterRefactoring_syntax_error);
168:
169: IJavaElement enclosingElement = SelectionConverter
170: .resolveEnclosingElement(fSourceCU,
171: new TextSelection(fSelectionStart,
172: fSelectionLength));
173: if (!(enclosingElement instanceof IMethod))
174: return RefactoringStatus
175: .createFatalErrorStatus(RefactoringCoreMessages.IntroduceParameterRefactoring_expression_in_method);
176:
177: fMethod = (IMethod) enclosingElement;
178: pm.worked(1);
179:
180: RefactoringStatus result = new RefactoringStatus();
181: if (fArguments != null) {
182: // invoked by script
183: fChangeSignatureRefactoring = new ChangeSignatureRefactoring(
184: null);
185: result = fChangeSignatureRefactoring
186: .initialize(fArguments);
187: if (!result.hasFatalError()) {
188: fChangeSignatureRefactoring
189: .setValidationContext(getValidationContext());
190: result
191: .merge(fChangeSignatureRefactoring
192: .checkInitialConditions(new SubProgressMonitor(
193: pm, 2)));
194: if (result.hasFatalError())
195: return result;
196: } else {
197: pm.worked(2);
198: return result;
199: }
200: } else {
201: // first try:
202: fChangeSignatureRefactoring = RefactoringAvailabilityTester
203: .isChangeSignatureAvailable(fMethod) ? new ChangeSignatureRefactoring(
204: fMethod)
205: : null;
206: if (fChangeSignatureRefactoring == null)
207: return RefactoringStatus
208: .createFatalErrorStatus(RefactoringCoreMessages.IntroduceParameterRefactoring_expression_in_method);
209: fChangeSignatureRefactoring
210: .setValidationContext(getValidationContext());
211: result.merge(fChangeSignatureRefactoring
212: .checkInitialConditions(new SubProgressMonitor(
213: pm, 1)));
214: if (result.hasFatalError()) {
215: RefactoringStatusEntry entry = result
216: .getEntryMatchingSeverity(RefactoringStatus.FATAL);
217: if (entry.getCode() == RefactoringStatusCodes.OVERRIDES_ANOTHER_METHOD
218: || entry.getCode() == RefactoringStatusCodes.METHOD_DECLARED_IN_INTERFACE) {
219: // second try:
220: IMethod method = (IMethod) entry.getData();
221: fChangeSignatureRefactoring = RefactoringAvailabilityTester
222: .isChangeSignatureAvailable(method) ? new ChangeSignatureRefactoring(
223: method)
224: : null;
225: if (fChangeSignatureRefactoring == null) {
226: String msg = Messages
227: .format(
228: RefactoringCoreMessages.IntroduceParameterRefactoring_cannot_introduce,
229: entry.getMessage());
230: return RefactoringStatus
231: .createFatalErrorStatus(msg);
232: }
233: result = fChangeSignatureRefactoring
234: .checkInitialConditions(new SubProgressMonitor(
235: pm, 1));
236: if (result.hasFatalError())
237: return result;
238: } else {
239: return result;
240: }
241: } else {
242: pm.worked(1);
243: }
244: }
245:
246: CompilationUnitRewrite cuRewrite = fChangeSignatureRefactoring
247: .getBaseCuRewrite();
248: if (!cuRewrite.getCu().equals(fSourceCU))
249: cuRewrite = new CompilationUnitRewrite(fSourceCU); // TODO: should try to avoid throwing away this AST
250:
251: initializeSelectedExpression(cuRewrite);
252: pm.worked(1);
253:
254: result.merge(checkSelection(cuRewrite,
255: new SubProgressMonitor(pm, 3)));
256: if (result.hasFatalError())
257: return result;
258:
259: initializeExcludedParameterNames(cuRewrite);
260:
261: addParameterInfo(cuRewrite);
262:
263: fChangeSignatureRefactoring
264: .setBodyUpdater(new BodyUpdater() {
265: public void updateBody(
266: MethodDeclaration methodDeclaration,
267: CompilationUnitRewrite rewrite,
268: RefactoringStatus updaterResult) {
269: replaceSelectedExpression(rewrite);
270: }
271: });
272:
273: return result;
274: } finally {
275: pm.done();
276: if (fChangeSignatureRefactoring != null)
277: fChangeSignatureRefactoring.setValidationContext(null);
278: }
279: }
280:
281: private void addParameterInfo(CompilationUnitRewrite cuRewrite)
282: throws JavaModelException {
283: ITypeBinding typeBinding = Bindings.normalizeForDeclarationUse(
284: fSelectedExpression.resolveTypeBinding(),
285: fSelectedExpression.getAST());
286: String typeName = cuRewrite.getImportRewrite().addImport(
287: typeBinding);
288: String name = fParameterName != null ? fParameterName
289: : guessedParameterName();
290: String defaultValue = fSourceCU.getBuffer().getText(
291: fSelectedExpression.getStartPosition(),
292: fSelectedExpression.getLength());
293: fParameter = ParameterInfo.createInfoForAddedParameter(
294: typeBinding, typeName, name, defaultValue);
295: if (fArguments == null) {
296: List parameterInfos = fChangeSignatureRefactoring
297: .getParameterInfos();
298: int parametersCount = parameterInfos.size();
299: if (parametersCount > 0
300: && ((ParameterInfo) parameterInfos
301: .get(parametersCount - 1)).isOldVarargs())
302: parameterInfos.add(parametersCount - 1, fParameter);
303: else
304: parameterInfos.add(fParameter);
305: }
306: }
307:
308: private void replaceSelectedExpression(
309: CompilationUnitRewrite cuRewrite) {
310: if (!fSourceCU.equals(cuRewrite.getCu()))
311: return;
312: // TODO: do for all methodDeclarations and replace matching fragments?
313:
314: // cannot use fSelectedExpression here, since it could be from another AST (if method was replaced by overridden):
315: Expression expression = (Expression) NodeFinder.perform(
316: cuRewrite.getRoot(), fSelectedExpression
317: .getStartPosition(), fSelectedExpression
318: .getLength());
319:
320: ASTNode newExpression = cuRewrite.getRoot().getAST()
321: .newSimpleName(fParameter.getNewName());
322: String description = RefactoringCoreMessages.IntroduceParameterRefactoring_replace;
323: cuRewrite.getASTRewrite().replace(expression, newExpression,
324: cuRewrite.createGroupDescription(description));
325: }
326:
327: private void initializeSelectedExpression(
328: CompilationUnitRewrite cuRewrite) throws JavaModelException {
329: IASTFragment fragment = ASTFragmentFactory
330: .createFragmentForSourceRange(new SourceRange(
331: fSelectionStart, fSelectionLength), cuRewrite
332: .getRoot(), cuRewrite.getCu());
333:
334: if (!(fragment instanceof IExpressionFragment))
335: return;
336:
337: //TODO: doesn't handle selection of partial Expressions
338: Expression expression = ((IExpressionFragment) fragment)
339: .getAssociatedExpression();
340: if (fragment.getStartPosition() != expression
341: .getStartPosition()
342: || fragment.getLength() != expression.getLength())
343: return;
344:
345: if (Checks.isInsideJavadoc(expression))
346: return;
347: //TODO: exclude invalid selections
348: if (Checks.isEnumCase(expression.getParent()))
349: return;
350:
351: fSelectedExpression = expression;
352: }
353:
354: private RefactoringStatus checkSelection(
355: CompilationUnitRewrite cuRewrite, IProgressMonitor pm) {
356: try {
357: if (fSelectedExpression == null) {
358: String message = RefactoringCoreMessages.IntroduceParameterRefactoring_select;
359: return CodeRefactoringUtil.checkMethodSyntaxErrors(
360: fSelectionStart, fSelectionLength, cuRewrite
361: .getRoot(), message);
362: }
363:
364: MethodDeclaration methodDeclaration = (MethodDeclaration) ASTNodes
365: .getParent(fSelectedExpression,
366: MethodDeclaration.class);
367: if (methodDeclaration == null)
368: return RefactoringStatus
369: .createFatalErrorStatus(RefactoringCoreMessages.IntroduceParameterRefactoring_expression_in_method);
370: if (methodDeclaration.resolveBinding() == null)
371: return RefactoringStatus
372: .createFatalErrorStatus(RefactoringCoreMessages.IntroduceParameterRefactoring_no_binding);
373: //TODO: check for rippleMethods -> find matching fragments, consider callers of all rippleMethods
374:
375: RefactoringStatus result = new RefactoringStatus();
376: result.merge(checkExpression());
377: if (result.hasFatalError())
378: return result;
379:
380: result.merge(checkExpressionBinding());
381: if (result.hasFatalError())
382: return result;
383:
384: // if (isUsedInForInitializerOrUpdater(getSelectedExpression().getAssociatedExpression()))
385: // return RefactoringStatus.createFatalErrorStatus(RefactoringCoreMessages.getString("ExtractTempRefactoring.for_initializer_updater")); //$NON-NLS-1$
386: // pm.worked(1);
387: //
388: // if (isReferringToLocalVariableFromFor(getSelectedExpression().getAssociatedExpression()))
389: // return RefactoringStatus.createFatalErrorStatus(RefactoringCoreMessages.getString("ExtractTempRefactoring.refers_to_for_variable")); //$NON-NLS-1$
390: // pm.worked(1);
391:
392: return result;
393: } finally {
394: if (pm != null)
395: pm.done();
396: }
397: }
398:
399: private RefactoringStatus checkExpression() {
400: //TODO: adjust error messages (or generalize for all refactorings on expression-selections?)
401: Expression selectedExpression = fSelectedExpression;
402:
403: if (selectedExpression instanceof Name
404: && selectedExpression.getParent() instanceof ClassInstanceCreation)
405: return RefactoringStatus
406: .createFatalErrorStatus(RefactoringCoreMessages.ExtractTempRefactoring_name_in_new);
407: //TODO: let's just take the CIC automatically (no ambiguity -> no problem -> no dialog ;-)
408:
409: if (selectedExpression instanceof NullLiteral) {
410: return RefactoringStatus
411: .createFatalErrorStatus(RefactoringCoreMessages.ExtractTempRefactoring_null_literals);
412: } else if (selectedExpression instanceof ArrayInitializer) {
413: return RefactoringStatus
414: .createFatalErrorStatus(RefactoringCoreMessages.ExtractTempRefactoring_array_initializer);
415: } else if (selectedExpression instanceof Assignment) {
416: if (selectedExpression.getParent() instanceof Expression)
417: return RefactoringStatus
418: .createFatalErrorStatus(RefactoringCoreMessages.ExtractTempRefactoring_assignment);
419: else
420: return null;
421:
422: } else if (selectedExpression instanceof SimpleName) {
423: if ((((SimpleName) selectedExpression)).isDeclaration())
424: return RefactoringStatus
425: .createFatalErrorStatus(RefactoringCoreMessages.ExtractTempRefactoring_names_in_declarations);
426: if (selectedExpression.getParent() instanceof QualifiedName
427: && selectedExpression.getLocationInParent() == QualifiedName.NAME_PROPERTY
428: || selectedExpression.getParent() instanceof FieldAccess
429: && selectedExpression.getLocationInParent() == FieldAccess.NAME_PROPERTY)
430: return RefactoringStatus
431: .createFatalErrorStatus(RefactoringCoreMessages.ExtractTempRefactoring_select_expression);
432: }
433:
434: return null;
435: }
436:
437: private RefactoringStatus checkExpressionBinding() {
438: return checkExpressionFragmentIsRValue();
439: }
440:
441: // !! +/- same as in ExtractConstantRefactoring & ExtractTempRefactoring
442: private RefactoringStatus checkExpressionFragmentIsRValue() {
443: switch (Checks.checkExpressionIsRValue(fSelectedExpression)) {
444: case Checks.NOT_RVALUE_MISC:
445: return RefactoringStatus
446: .createStatus(
447: RefactoringStatus.FATAL,
448: RefactoringCoreMessages.IntroduceParameterRefactoring_select,
449: null,
450: Corext.getPluginId(),
451: RefactoringStatusCodes.EXPRESSION_NOT_RVALUE,
452: null);
453: case Checks.NOT_RVALUE_VOID:
454: return RefactoringStatus
455: .createStatus(
456: RefactoringStatus.FATAL,
457: RefactoringCoreMessages.IntroduceParameterRefactoring_no_void,
458: null,
459: Corext.getPluginId(),
460: RefactoringStatusCodes.EXPRESSION_NOT_RVALUE_VOID,
461: null);
462: case Checks.IS_RVALUE:
463: return new RefactoringStatus();
464: default:
465: Assert.isTrue(false);
466: return null;
467: }
468: }
469:
470: public List getParameterInfos() {
471: return fChangeSignatureRefactoring.getParameterInfos();
472: }
473:
474: public ParameterInfo getAddedParameterInfo() {
475: return fParameter;
476: }
477:
478: public String getMethodSignaturePreview() throws JavaModelException {
479: return fChangeSignatureRefactoring.getNewMethodSignature();
480: }
481:
482: //--- Input setting/validation
483:
484: public void setParameterName(String name) {
485: Assert.isNotNull(name);
486: fParameter.setNewName(name);
487: }
488:
489: /**
490: * must only be called <i>after</i> checkActivation()
491: * @return guessed parameter name
492: */
493: public String guessedParameterName() {
494: String[] proposals = guessParameterNames();
495: if (proposals.length == 0)
496: return ""; //$NON-NLS-1$
497: else
498: return proposals[0];
499: }
500:
501: // --- TODO: copied from ExtractTempRefactoring - should extract ------------------------------
502:
503: /**
504: * Must only be called <i>after</i> checkActivation().
505: * The first proposal should be used as "best guess" (if it exists).
506: * @return proposed variable names (may be empty, but not null).
507: */
508: public String[] guessParameterNames() {
509: LinkedHashSet proposals = new LinkedHashSet(); //retain ordering, but prevent duplicates
510: if (fSelectedExpression instanceof MethodInvocation) {
511: proposals.addAll(guessTempNamesFromMethodInvocation(
512: (MethodInvocation) fSelectedExpression,
513: fExcludedParameterNames));
514: }
515: proposals.addAll(guessTempNamesFromExpression(
516: fSelectedExpression, fExcludedParameterNames));
517: return (String[]) proposals
518: .toArray(new String[proposals.size()]);
519: }
520:
521: private List/*<String>*/guessTempNamesFromMethodInvocation(
522: MethodInvocation selectedMethodInvocation,
523: String[] excludedVariableNames) {
524: String methodName = selectedMethodInvocation.getName()
525: .getIdentifier();
526: for (int i = 0; i < KNOWN_METHOD_NAME_PREFIXES.length; i++) {
527: String prefix = KNOWN_METHOD_NAME_PREFIXES[i];
528: if (!methodName.startsWith(prefix))
529: continue; //not this prefix
530: if (methodName.length() == prefix.length())
531: return Collections.EMPTY_LIST; // prefix alone -> don't take method name
532: char firstAfterPrefix = methodName.charAt(prefix.length());
533: if (!Character.isUpperCase(firstAfterPrefix))
534: continue; //not uppercase after prefix
535: //found matching prefix
536: String proposal = Character.toLowerCase(firstAfterPrefix)
537: + methodName.substring(prefix.length() + 1);
538: methodName = proposal;
539: break;
540: }
541: String[] proposals = StubUtility.getLocalNameSuggestions(
542: fSourceCU.getJavaProject(), methodName, 0,
543: excludedVariableNames);
544: return Arrays.asList(proposals);
545: }
546:
547: private List/*<String>*/guessTempNamesFromExpression(
548: Expression selectedExpression, String[] excluded) {
549: ITypeBinding expressionBinding = Bindings
550: .normalizeForDeclarationUse(selectedExpression
551: .resolveTypeBinding(), selectedExpression
552: .getAST());
553: String typeName = getQualifiedName(expressionBinding);
554: if (typeName.length() == 0)
555: typeName = expressionBinding.getName();
556: if (typeName.length() == 0)
557: return Collections.EMPTY_LIST;
558: int typeParamStart = typeName.indexOf("<"); //$NON-NLS-1$
559: if (typeParamStart != -1)
560: typeName = typeName.substring(0, typeParamStart);
561: String[] proposals = StubUtility.getLocalNameSuggestions(
562: fSourceCU.getJavaProject(), typeName, expressionBinding
563: .getDimensions(), excluded);
564: return Arrays.asList(proposals);
565: }
566:
567: // ----------------------------------------------------------------------
568:
569: private static String getQualifiedName(ITypeBinding typeBinding) {
570: if (typeBinding.isAnonymous())
571: return getQualifiedName(typeBinding.getSuperclass());
572: if (!typeBinding.isArray())
573: return typeBinding.getQualifiedName();
574: else
575: return typeBinding.getElementType().getQualifiedName();
576: }
577:
578: private void initializeExcludedParameterNames(
579: CompilationUnitRewrite cuRewrite) {
580: IBinding[] bindings = new ScopeAnalyzer(cuRewrite.getRoot())
581: .getDeclarationsInScope(fSelectedExpression
582: .getStartPosition(), ScopeAnalyzer.VARIABLES);
583: fExcludedParameterNames = new String[bindings.length];
584: for (int i = 0; i < fExcludedParameterNames.length; i++) {
585: fExcludedParameterNames[i] = bindings[i].getName();
586: }
587: }
588:
589: public RefactoringStatus validateInput() {
590: return fChangeSignatureRefactoring.checkSignature();
591: }
592:
593: //--- checkInput
594:
595: public RefactoringStatus checkFinalConditions(IProgressMonitor pm)
596: throws CoreException {
597: fChangeSignatureRefactoring
598: .setValidationContext(getValidationContext());
599: try {
600: return fChangeSignatureRefactoring.checkFinalConditions(pm);
601: } finally {
602: fChangeSignatureRefactoring.setValidationContext(null);
603: }
604: }
605:
606: public Change createChange(IProgressMonitor pm)
607: throws CoreException {
608: fChangeSignatureRefactoring
609: .setValidationContext(getValidationContext());
610: try {
611: Change[] changes = fChangeSignatureRefactoring
612: .getAllChanges();
613: return new DynamicValidationRefactoringChange(
614: getRefactoringDescriptor(),
615: RefactoringCoreMessages.IntroduceParameterRefactoring_name,
616: changes);
617: } finally {
618: fChangeSignatureRefactoring.setValidationContext(null);
619: pm.done();
620: }
621: }
622:
623: private IntroduceParameterDescriptor getRefactoringDescriptor() {
624: ChangeMethodSignatureDescriptor extended = (ChangeMethodSignatureDescriptor) fChangeSignatureRefactoring
625: .createDescriptor();
626:
627: final Map arguments = new HashMap();
628: arguments.put(ATTRIBUTE_ARGUMENT, fParameter.getNewName());
629: arguments
630: .put(
631: JavaRefactoringDescriptorUtil.ATTRIBUTE_SELECTION,
632: new Integer(fSelectionStart).toString()
633: + " " + new Integer(fSelectionLength).toString()); //$NON-NLS-1$
634: arguments.putAll(extended.getArguments()); //REVIEW Is this the correct order?
635: String signature = fChangeSignatureRefactoring.getMethodName();
636: try {
637: signature = fChangeSignatureRefactoring
638: .getOldMethodSignature();
639: } catch (JavaModelException exception) {
640: JavaPlugin.log(exception);
641: }
642: final String description = Messages
643: .format(
644: RefactoringCoreMessages.IntroduceParameterRefactoring_descriptor_description_short,
645: fChangeSignatureRefactoring.getMethod()
646: .getElementName());
647: final String header = Messages
648: .format(
649: RefactoringCoreMessages.IntroduceParameterRefactoring_descriptor_description,
650: new String[] { fParameter.getNewName(),
651: signature,
652: ASTNodes.asString(fSelectedExpression) });
653: final JDTRefactoringDescriptorComment comment = new JDTRefactoringDescriptorComment(
654: extended.getProject(), this , header);
655: comment
656: .addSetting(Messages
657: .format(
658: RefactoringCoreMessages.IntroduceParameterRefactoring_original_pattern,
659: JavaElementLabels
660: .getTextLabel(
661: fChangeSignatureRefactoring
662: .getMethod(),
663: JavaElementLabels.ALL_FULLY_QUALIFIED)));
664: comment
665: .addSetting(Messages
666: .format(
667: RefactoringCoreMessages.IntroduceParameterRefactoring_expression_pattern,
668: ASTNodes.asString(fSelectedExpression)));
669: comment
670: .addSetting(Messages
671: .format(
672: RefactoringCoreMessages.IntroduceParameterRefactoring_parameter_pattern,
673: getAddedParameterInfo().getNewName()));
674: return new IntroduceParameterDescriptor(extended.getProject(),
675: description, comment.asString(), arguments, extended
676: .getFlags());
677: }
678:
679: public RefactoringStatus initialize(
680: final RefactoringArguments arguments) {
681: fArguments = arguments;
682: if (arguments instanceof JavaRefactoringArguments) {
683: final JavaRefactoringArguments extended = (JavaRefactoringArguments) arguments;
684: final String selection = extended
685: .getAttribute(JavaRefactoringDescriptorUtil.ATTRIBUTE_SELECTION);
686: if (selection != null) {
687: int offset = -1;
688: int length = -1;
689: final StringTokenizer tokenizer = new StringTokenizer(
690: selection);
691: if (tokenizer.hasMoreTokens())
692: offset = Integer.valueOf(tokenizer.nextToken())
693: .intValue();
694: if (tokenizer.hasMoreTokens())
695: length = Integer.valueOf(tokenizer.nextToken())
696: .intValue();
697: if (offset >= 0 && length >= 0) {
698: fSelectionStart = offset;
699: fSelectionLength = length;
700: } else
701: return RefactoringStatus
702: .createFatalErrorStatus(Messages
703: .format(
704: RefactoringCoreMessages.InitializableRefactoring_illegal_argument,
705: new Object[] {
706: selection,
707: JavaRefactoringDescriptorUtil.ATTRIBUTE_SELECTION }));
708: } else
709: return RefactoringStatus
710: .createFatalErrorStatus(Messages
711: .format(
712: RefactoringCoreMessages.InitializableRefactoring_argument_not_exist,
713: JavaRefactoringDescriptorUtil.ATTRIBUTE_SELECTION));
714: final String handle = extended
715: .getAttribute(JavaRefactoringDescriptorUtil.ATTRIBUTE_INPUT);
716: if (handle != null) {
717: final IJavaElement element = JavaRefactoringDescriptorUtil
718: .handleToElement(extended.getProject(), handle,
719: false);
720: if (element == null
721: || !element.exists()
722: || element.getElementType() != IJavaElement.COMPILATION_UNIT)
723: return createInputFatalStatus(element,
724: IJavaRefactorings.INTRODUCE_PARAMETER);
725: else
726: fSourceCU = ((IMethod) element)
727: .getCompilationUnit();
728: } else
729: return RefactoringStatus
730: .createFatalErrorStatus(Messages
731: .format(
732: RefactoringCoreMessages.InitializableRefactoring_argument_not_exist,
733: JavaRefactoringDescriptorUtil.ATTRIBUTE_INPUT));
734: final String name = extended
735: .getAttribute(ATTRIBUTE_ARGUMENT);
736: if (name != null && !"".equals(name)) //$NON-NLS-1$
737: fParameterName = name;
738: else
739: return RefactoringStatus
740: .createFatalErrorStatus(Messages
741: .format(
742: RefactoringCoreMessages.InitializableRefactoring_argument_not_exist,
743: ATTRIBUTE_ARGUMENT));
744: } else
745: return RefactoringStatus
746: .createFatalErrorStatus(RefactoringCoreMessages.InitializableRefactoring_inacceptable_arguments);
747: return new RefactoringStatus();
748: }
749:
750: /**
751: * {@inheritDoc}
752: */
753: public String getDelegateUpdatingTitle(boolean plural) {
754: if (plural)
755: return RefactoringCoreMessages.DelegateCreator_keep_original_changed_plural;
756: else
757: return RefactoringCoreMessages.DelegateCreator_keep_original_changed_singular;
758: }
759: }
|