From 4f47f3ad4d6b11f5daa9d032166f10a389940127 Mon Sep 17 00:00:00 2001 From: Maxim Medvedev Date: Thu, 29 Jul 2010 10:51:49 +0400 Subject: [PATCH] 'add constructor parameter' intention --- .../after.groovy.template | 7 + .../before.groovy.template | 6 + .../description.html | 5 + plugins/groovy/src/META-INF/plugin.xml | 5 + .../GroovyIntentionsBundle.properties | 8 +- .../CreateParameterForFieldIntention.java | 317 ++++++++++++++++++ .../impl/statements/blocks/GrBlockImpl.java | 2 - .../DefaultGroovyVariableNameValidator.java | 30 +- .../GroovyNameSuggestionProvider.java | 7 +- .../changeSignature/GrChangeInfoImpl.java | 6 +- .../GrChangeSignatureDialog.java | 4 + .../GrParameterTableModel.java | 6 +- .../changeSignature/GrTableParameterInfo.java | 13 + .../CreateParameterForFieldTest.java | 35 ++ .../FromConstructor.groovy | 6 + .../FromConstructor_after.groovy | 7 + .../createParameterForField/FromField.groovy | 7 + .../FromField_after.groovy | 8 + 18 files changed, 465 insertions(+), 14 deletions(-) create mode 100644 plugins/groovy/resources/intentionDescriptions/CreateParameterForFieldIntention/after.groovy.template create mode 100644 plugins/groovy/resources/intentionDescriptions/CreateParameterForFieldIntention/before.groovy.template create mode 100644 plugins/groovy/resources/intentionDescriptions/CreateParameterForFieldIntention/description.html create mode 100644 plugins/groovy/src/org/jetbrains/plugins/groovy/intentions/control/CreateParameterForFieldIntention.java create mode 100644 plugins/groovy/test/org/jetbrains/plugins/groovy/intentions/CreateParameterForFieldTest.java create mode 100644 plugins/groovy/testdata/intentions/createParameterForField/FromConstructor.groovy create mode 100644 plugins/groovy/testdata/intentions/createParameterForField/FromConstructor_after.groovy create mode 100644 plugins/groovy/testdata/intentions/createParameterForField/FromField.groovy create mode 100644 plugins/groovy/testdata/intentions/createParameterForField/FromField_after.groovy diff --git a/plugins/groovy/resources/intentionDescriptions/CreateParameterForFieldIntention/after.groovy.template b/plugins/groovy/resources/intentionDescriptions/CreateParameterForFieldIntention/after.groovy.template new file mode 100644 index 000000000000..07896cc93878 --- /dev/null +++ b/plugins/groovy/resources/intentionDescriptions/CreateParameterForFieldIntention/after.groovy.template @@ -0,0 +1,7 @@ + class Foo { + def field + + def Foo(def field) { + this.field = field + } + } diff --git a/plugins/groovy/resources/intentionDescriptions/CreateParameterForFieldIntention/before.groovy.template b/plugins/groovy/resources/intentionDescriptions/CreateParameterForFieldIntention/before.groovy.template new file mode 100644 index 000000000000..4e6acb3280a8 --- /dev/null +++ b/plugins/groovy/resources/intentionDescriptions/CreateParameterForFieldIntention/before.groovy.template @@ -0,0 +1,6 @@ +class Foo { + def field + + def Foo() { + } +} diff --git a/plugins/groovy/resources/intentionDescriptions/CreateParameterForFieldIntention/description.html b/plugins/groovy/resources/intentionDescriptions/CreateParameterForFieldIntention/description.html new file mode 100644 index 000000000000..4d855e8801ab --- /dev/null +++ b/plugins/groovy/resources/intentionDescriptions/CreateParameterForFieldIntention/description.html @@ -0,0 +1,5 @@ + + +This intention adds parameter to constructor for uninitialized field + + \ No newline at end of file diff --git a/plugins/groovy/src/META-INF/plugin.xml b/plugins/groovy/src/META-INF/plugin.xml index c072abb2eb76..27d39350f39b 100644 --- a/plugins/groovy/src/META-INF/plugin.xml +++ b/plugins/groovy/src/META-INF/plugin.xml @@ -285,6 +285,11 @@ intention.category.groovy/intention.category.control.flow org.jetbrains.plugins.groovy.intentions.control.DemorgansLawIntention + + org.jetbrains.plugins.groovy.intentions.GroovyIntentionsBundle + intention.category.groovy/intention.category.control.flow + org.jetbrains.plugins.groovy.intentions.control.CreateParameterForFieldIntention + org.jetbrains.plugins.groovy.intentions.GroovyIntentionsBundle intention.category.groovy/intention.category.control.flow diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/intentions/GroovyIntentionsBundle.properties b/plugins/groovy/src/org/jetbrains/plugins/groovy/intentions/GroovyIntentionsBundle.properties index dcdce8ab3c5b..0108a6fd38e9 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/intentions/GroovyIntentionsBundle.properties +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/intentions/GroovyIntentionsBundle.properties @@ -85,4 +85,10 @@ map.param.name=Map parameter &name: convert.param.to.map.entry=Convert parameter to map entry convert.java.style.array.intention.name=Convert java-style array creation -convert.java.style.array.intention.family.name=Convert Java-Style Array Creation to Groovy Syntax \ No newline at end of file +convert.java.style.array.intention.family.name=Convert Java-Style Array Creation to Groovy Syntax + +create.parameter.for.field.intention.name = Add constructor parameter for field +create.parameter.for.field.intention.family.name = Add constructor parameter for field +cannot.suggest.parameter.name=Cannot suggest parameter name +create.parameter.for.field=Add parameter for field ''{0}'' +create.parameter.for.fields=Add parameter for field... \ No newline at end of file diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/intentions/control/CreateParameterForFieldIntention.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/intentions/control/CreateParameterForFieldIntention.java new file mode 100644 index 000000000000..f746dc76991c --- /dev/null +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/intentions/control/CreateParameterForFieldIntention.java @@ -0,0 +1,317 @@ +/* + * Copyright 2000-2010 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jetbrains.plugins.groovy.intentions.control; + +import com.intellij.ide.util.DefaultPsiElementCellRenderer; +import com.intellij.ide.util.MethodCellRenderer; +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.command.CommandProcessor; +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.ui.popup.PopupChooserBuilder; +import com.intellij.openapi.util.Condition; +import com.intellij.openapi.util.Ref; +import com.intellij.psi.*; +import com.intellij.psi.codeStyle.JavaCodeStyleManager; +import com.intellij.psi.codeStyle.VariableKind; +import com.intellij.psi.util.PsiTreeUtil; +import com.intellij.refactoring.changeSignature.JavaThrownExceptionInfo; +import com.intellij.refactoring.changeSignature.ThrownExceptionInfo; +import com.intellij.ui.components.JBList; +import com.intellij.util.IncorrectOperationException; +import com.intellij.util.containers.ContainerUtil; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.plugins.groovy.intentions.GroovyIntentionsBundle; +import org.jetbrains.plugins.groovy.intentions.base.Intention; +import org.jetbrains.plugins.groovy.intentions.base.PsiElementPredicate; +import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElementFactory; +import org.jetbrains.plugins.groovy.lang.psi.GroovyRecursiveElementVisitor; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrField; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrStatement; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.blocks.GrClosableBlock; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.blocks.GrOpenBlock; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrAssignmentExpression; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrReferenceExpression; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.params.GrParameter; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrTypeDefinition; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrMethod; +import org.jetbrains.plugins.groovy.lang.psi.util.PsiUtil; +import org.jetbrains.plugins.groovy.refactoring.DefaultGroovyVariableNameValidator; +import org.jetbrains.plugins.groovy.refactoring.changeSignature.GrChangeInfoImpl; +import org.jetbrains.plugins.groovy.refactoring.changeSignature.GrChangeSignatureProcessor; +import org.jetbrains.plugins.groovy.refactoring.changeSignature.GrParameterInfo; + +import javax.swing.*; +import java.util.*; + +/** + * @author Maxim.Medvedev + */ +public class CreateParameterForFieldIntention extends Intention { + private static final Logger LOG = Logger.getInstance("org.jetbrains.plugins.groovy.intentions.control.CreateParameterForFieldIntention"); + + @NotNull + @Override + public String getText() { + return super.getText(); + } + + @Override + protected void processIntention(@NotNull PsiElement element, final Project project, final Editor editor) + throws IncorrectOperationException { + final List candidates = findFieldCandidates(element); + if (candidates != null) { + performForConstructor(element, project, editor, candidates); + } + else { + final List constructors = findConstructorCandidates(element); + performForField(element, project, editor, constructors); + } + } + + private static void performForField(PsiElement element, final Project project, Editor editor, List constructors) { + final GrField field = PsiTreeUtil.getParentOfType(element, GrField.class); + if (constructors.size() == 0) return; + + if (ApplicationManager.getApplication().isUnitTestMode()) { + for (GrMethod constructor : constructors) { + addParameter(field, constructor, project); + } + return; + } + + final JList list = new JBList(constructors.toArray(new GrMethod[constructors.size()])); + list.setCellRenderer(new MethodCellRenderer(true)); + + new PopupChooserBuilder(list).setTitle(GroovyIntentionsBundle.message("create.parameter.for.field.intention.name")). + setMovable(true). + setItemChoosenCallback(new Runnable() { + public void run() { + final Object[] selectedValues = list.getSelectedValues(); + Arrays.sort(selectedValues, new Comparator() { + @Override + public int compare(Object o1, Object o2) { + return ((GrMethod)o2).getParameterList().getParametersCount() - ((GrMethod)o1).getParameterList().getParametersCount(); + } + }); + CommandProcessor.getInstance().executeCommand(project, new Runnable() { + @Override + public void run() { + ApplicationManager.getApplication().runWriteAction(new Runnable() { + @Override + public void run() { + for (Object selectedValue : selectedValues) { + LOG.assertTrue(((GrMethod)selectedValue).isValid()); + addParameter(field, ((GrMethod)selectedValue), project); + } + } + }); + } + }, GroovyIntentionsBundle.message("create.parameter.for.field.intention.name"), null); + } + }).createPopup().showInBestPositionFor(editor); + + } + + private static void performForConstructor(PsiElement element, final Project project, Editor editor, List candidates) { + final GrMethod constructor = PsiTreeUtil.getParentOfType(element, GrMethod.class); + if (candidates.size() == 0) return; + if (ApplicationManager.getApplication().isUnitTestMode()) { + for (GrField candidate : candidates) { + addParameter(candidate, constructor, project); + } + return; + } + final JList list = new JBList(candidates.toArray(new GrField[candidates.size()])); + list.setCellRenderer(new DefaultPsiElementCellRenderer()); + + new PopupChooserBuilder(list).setTitle(GroovyIntentionsBundle.message("create.parameter.for.field.intention.name")). + setMovable(true). + setItemChoosenCallback(new Runnable() { + public void run() { + final Object[] selectedValues = list.getSelectedValues(); + CommandProcessor.getInstance().executeCommand(project, new Runnable() { + @Override + public void run() { + ApplicationManager.getApplication().runWriteAction(new Runnable() { + @Override + public void run() { + for (Object selectedValue : selectedValues) { + LOG.assertTrue(((GrField)selectedValue).isValid()); + addParameter(((GrField)selectedValue), constructor, project); + } + } + }); + } + }, GroovyIntentionsBundle.message("create.parameter.for.field.intention.name"), null); + } + }).createPopup().showInBestPositionFor(editor); + } + + private static void addParameter(final GrField selectedValue, final GrMethod constructor, final Project project) { + List parameters = new ArrayList(); + GrParameter[] constructorParameters = constructor.getParameters(); + for (int i = 0; i < constructorParameters.length; i++) { + parameters.add(new GrParameterInfo(constructorParameters[i], i)); + } + final String[] suggestedNames = + JavaCodeStyleManager.getInstance(project).suggestVariableName(VariableKind.PARAMETER, selectedValue.getName(), null, null).names; + + final DefaultGroovyVariableNameValidator nameValidator = + new DefaultGroovyVariableNameValidator(constructor, Collections.emptyList(), false); + String parameterName = ContainerUtil.find(suggestedNames, new Condition() { + @Override + public boolean value(String name) { + return nameValidator.validateName(name, false).length() > 0; + } + }); + + if (parameterName == null) { + parameterName = nameValidator.validateName(suggestedNames[0], true); + } + parameters.add(new GrParameterInfo(parameterName, "null", "", selectedValue.getTypeGroovy(), -1)); + + PsiClassType[] exceptionTypes = constructor.getThrowsList().getReferencedTypes(); + ThrownExceptionInfo[] thrownExceptionInfos = new ThrownExceptionInfo[exceptionTypes.length]; + for (int i = 0; i < exceptionTypes.length; i++) { + new JavaThrownExceptionInfo(i, exceptionTypes[i]); + } + + final GrChangeInfoImpl grChangeInfo = + new GrChangeInfoImpl(constructor, null, null, constructor.getName(), parameters, thrownExceptionInfos, false); + final GrChangeSignatureProcessor processor = new GrChangeSignatureProcessor(project, grChangeInfo); + final Ref success = Ref.create(Boolean.FALSE); + processor.setPrepareSuccessfulSwingThreadCallback(new Runnable() { + @Override + public void run() { + success.set(Boolean.TRUE); + } + }); + processor.run(); + + if (success.get()) { + final GrOpenBlock block = constructor.getBlock(); + LOG.assertTrue(block != null); + final GrStatement statement = block.addStatementBefore( + GroovyPsiElementFactory.getInstance(project).createStatementFromText(selectedValue.getName() + " = " + parameterName), null); + final GrReferenceExpression ref = (GrReferenceExpression)((GrAssignmentExpression)statement).getLValue(); + if (!PsiManager.getInstance(project).areElementsEquivalent(ref.resolve(), selectedValue)) { + PsiUtil.qualifyMemberReference(ref, selectedValue, selectedValue.getName()); + } + } + } + + @NotNull + @Override + protected PsiElementPredicate getElementPredicate() { + return new MyPredicate(); + } + + static class MyPredicate implements PsiElementPredicate { + @Override + public boolean satisfiedBy(PsiElement element) { + final List candidates = findFieldCandidates(element); + if (candidates != null && candidates.size() > 0) return true; + final List constructors = findConstructorCandidates(element); + return constructors != null && constructors.size() > 0; + } + } + + @Nullable + private static List findFieldCandidates(PsiElement element) { + final GrMethod constructor = PsiTreeUtil.getParentOfType(element, GrMethod.class); + if (constructor == null || !constructor.isConstructor()) return null; + if (constructor.getBlock() == null) return null; + if (PsiTreeUtil.isAncestor(constructor.getBlock(), element, false)) { + return null; + } + final PsiClass clazz = constructor.getContainingClass(); + + if (!(clazz instanceof GrTypeDefinition)) return null; + return findCandidates(constructor, (GrTypeDefinition)clazz); + } + + private static List findCandidates(GrMethod constructor, final GrTypeDefinition clazz) { + final List usedFields = new ArrayList(); + //ContainerUtil.addAll(fields, clazz.getFields()); + final GrOpenBlock block = constructor.getBlock(); + LOG.assertTrue(block != null); + + final PsiManager manager = clazz.getManager(); + block.accept(new GroovyRecursiveElementVisitor() { + @Override + public void visitReferenceExpression(GrReferenceExpression referenceExpression) { + super.visitReferenceExpression(referenceExpression); + final PsiElement resolved = referenceExpression.resolve(); + if (resolved instanceof GrField && + manager.areElementsEquivalent(((GrField)resolved).getContainingClass(), clazz) && + PsiUtil.isAccessedForWriting(referenceExpression)) { + usedFields.add((GrField)resolved); + } + } + + @Override + public void visitTypeDefinition(GrTypeDefinition typeDefinition) { + } + + @Override + public void visitClosure(GrClosableBlock closure) { + } + }); + + List fields = new ArrayList(); + for (final GrField field : clazz.getFields()) { + if (field.getInitializerGroovy() != null) continue; + if (ContainerUtil.find(usedFields, new Condition() { + @Override + public boolean value(PsiField o) { + return manager.areElementsEquivalent(o, field); + } + }) == null) { + fields.add(field); + } + } + + return fields; + } + + @Nullable + private static List findConstructorCandidates(PsiElement element) { + final GrField field = PsiTreeUtil.getParentOfType(element, GrField.class); + if (field == null) return null; + return findConstructorCandidates(field, (GrTypeDefinition)field.getContainingClass()); + } + + private static List findConstructorCandidates(final GrField field, GrTypeDefinition psiClass) { + final List result = new ArrayList(); + final PsiMethod[] constructors = psiClass.getConstructors(); + final PsiManager manager = field.getManager(); + for (PsiMethod constructor : constructors) { + final List fields = findCandidates(((GrMethod)constructor), psiClass); + if (ContainerUtil.find(fields, new Condition() { + @Override + public boolean value(GrField grField) { + return manager.areElementsEquivalent(grField, field); + } + }) != null) { + result.add((GrMethod)constructor); + } + } + return result; + } +} diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/blocks/GrBlockImpl.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/blocks/GrBlockImpl.java index c85bdd2d8468..914f25279a05 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/blocks/GrBlockImpl.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/blocks/GrBlockImpl.java @@ -105,8 +105,6 @@ public abstract class GrBlockImpl extends GroovyPsiElementImpl implements GrCode throw new IncorrectOperationException(); } - ASTNode elemNode = element.copy().getNode(); - assert elemNode != null; PsiElement actualAnchor = anchor == null ? getRBrace() : anchor; if (mayUseNewLinesAsSeparators()) { PsiElement prev = actualAnchor.getPrevSibling(); diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/DefaultGroovyVariableNameValidator.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/DefaultGroovyVariableNameValidator.java index 3c7b0b212b0d..0dc04319c953 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/DefaultGroovyVariableNameValidator.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/DefaultGroovyVariableNameValidator.java @@ -17,9 +17,15 @@ package org.jetbrains.plugins.groovy.refactoring; import com.intellij.openapi.project.Project; import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiField; import com.intellij.psi.PsiNamedElement; import com.intellij.util.containers.hash.HashSet; +import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElement; +import org.jetbrains.plugins.groovy.lang.psi.GroovyRecursiveElementVisitor; import org.jetbrains.plugins.groovy.lang.psi.api.GroovyResolveResult; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrVariable; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.blocks.GrClosableBlock; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrTypeDefinition; import org.jetbrains.plugins.groovy.lang.resolve.ResolveUtil; import org.jetbrains.plugins.groovy.lang.resolve.processors.PropertyResolverProcessor; @@ -28,18 +34,21 @@ import java.util.Collections; import java.util.Set; /** - * checks for only upper declared names * @author Maxim.Medvedev */ public class DefaultGroovyVariableNameValidator implements NameValidator { private final PsiElement myContext; private final Set mySet = new HashSet(); - public DefaultGroovyVariableNameValidator(PsiElement context) { + public DefaultGroovyVariableNameValidator(GroovyPsiElement context) { this(context, Collections.emptyList()); } - public DefaultGroovyVariableNameValidator(PsiElement context, Collection restrictedNames) { + public DefaultGroovyVariableNameValidator(GroovyPsiElement context, Collection restrictedNames) { + this(context, restrictedNames, true); + } + + public DefaultGroovyVariableNameValidator(GroovyPsiElement context, Collection restrictedNames, boolean includeFields) { myContext = context; mySet.addAll(restrictedNames); PropertyResolverProcessor processor = new PropertyResolverProcessor(null, myContext); @@ -47,10 +56,23 @@ public class DefaultGroovyVariableNameValidator implements NameValidator { final GroovyResolveResult[] results = processor.getCandidates(); for (GroovyResolveResult result : results) { final PsiElement element = result.getElement(); - if (element instanceof PsiNamedElement) { + if (element instanceof PsiNamedElement && (includeFields || !(element instanceof PsiField))) { mySet.add(((PsiNamedElement)element).getName()); } } + + context.accept(new GroovyRecursiveElementVisitor(){ + @Override + public void visitVariable(GrVariable variable) { + mySet.add(variable.getName()); + } + + @Override + public void visitClosure(GrClosableBlock closure) {} + + @Override + public void visitTypeDefinition(GrTypeDefinition typeDefinition) {} + }); } public String validateName(String name, boolean increaseNumber) { diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/GroovyNameSuggestionProvider.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/GroovyNameSuggestionProvider.java index 79d2b7cc642c..0c69566ba662 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/GroovyNameSuggestionProvider.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/GroovyNameSuggestionProvider.java @@ -23,6 +23,7 @@ import com.intellij.psi.codeStyle.SuggestedNameInfo; import com.intellij.psi.statistics.JavaStatisticsManager; import com.intellij.refactoring.rename.NameSuggestionProvider; import org.jetbrains.annotations.Nullable; +import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElement; import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrVariable; import java.util.Arrays; @@ -36,11 +37,11 @@ public class GroovyNameSuggestionProvider implements NameSuggestionProvider { @Override public SuggestedNameInfo getSuggestedNames(final PsiElement element, @Nullable PsiElement nameSuggestionContext, Set result) { if (nameSuggestionContext == null) nameSuggestionContext = element; - if (element instanceof GrVariable) { + if (element instanceof GrVariable && nameSuggestionContext instanceof GroovyPsiElement) { final PsiType type = ((GrVariable)element).getTypeGroovy(); if (type != null) { - final String[] names = - GroovyNameSuggestionUtil.suggestVariableNameByType(type, new DefaultGroovyVariableNameValidator(nameSuggestionContext)); + final String[] names = GroovyNameSuggestionUtil + .suggestVariableNameByType(type, new DefaultGroovyVariableNameValidator((GroovyPsiElement)nameSuggestionContext)); result.addAll(Arrays.asList(names)); return new SuggestedNameInfo(names) { @Override diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/changeSignature/GrChangeInfoImpl.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/changeSignature/GrChangeInfoImpl.java index a7ab92d8f41a..2508abbbb7df 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/changeSignature/GrChangeInfoImpl.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/changeSignature/GrChangeInfoImpl.java @@ -34,7 +34,7 @@ import java.util.List; /** * @author Maxim.Medvedev */ -class GrChangeInfoImpl implements JavaChangeInfo { +public class GrChangeInfoImpl implements JavaChangeInfo { GrMethod method; final String newName; @Nullable final CanonicalTypes.Type returnType; @@ -61,7 +61,7 @@ class GrChangeInfoImpl implements JavaChangeInfo { private String[] myOldParameterTypes; public GrChangeInfoImpl(GrMethod method, - String visibilityModifier, + @Nullable String visibilityModifier, @Nullable CanonicalTypes.Type returnType, String newName, List parameters, ThrownExceptionInfo[] exceptions, boolean generateDelegate) { @@ -77,7 +77,7 @@ class GrChangeInfoImpl implements JavaChangeInfo { myIsNameChanged = true; } - myIsVisibilityChanged = !method.hasModifierProperty(visibilityModifier); + myIsVisibilityChanged = visibilityModifier != null && !method.hasModifierProperty(visibilityModifier); if (!method.isConstructor()) { PsiType oldReturnType = null; diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/changeSignature/GrChangeSignatureDialog.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/changeSignature/GrChangeSignatureDialog.java index 356be9639c63..e0652277fa30 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/changeSignature/GrChangeSignatureDialog.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/changeSignature/GrChangeSignatureDialog.java @@ -407,4 +407,8 @@ public class GrChangeSignatureDialog extends RefactoringDialog { return true; //Groovy accepts methods and parameters without explicit type } } + + public GrParameterTableModel getParameterModel() { + return myParameterModel; + } } \ No newline at end of file diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/changeSignature/GrParameterTableModel.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/changeSignature/GrParameterTableModel.java index 81a4c9d08865..7a8fbfbdacdf 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/changeSignature/GrParameterTableModel.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/changeSignature/GrParameterTableModel.java @@ -50,8 +50,12 @@ public class GrParameterTableModel extends AbstractTableModel implements RowEdit } public void addRow() { + addRow(new GrTableParameterInfo(myProject, myMethod)); + } + + public void addRow(GrTableParameterInfo info) { final int row = infos.size(); - infos.add(new GrTableParameterInfo(myProject, myMethod)); + infos.add(info); fireTableRowsInserted(row, row); } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/changeSignature/GrTableParameterInfo.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/changeSignature/GrTableParameterInfo.java index ff5d2fe96b43..b9834cf3cd9d 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/changeSignature/GrTableParameterInfo.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/changeSignature/GrTableParameterInfo.java @@ -65,6 +65,19 @@ public class GrTableParameterInfo { myDefaultInitializer = new GroovyCodeFragment(project, ""); } + public GrTableParameterInfo(Project project, + PsiElement context, + String name, + String type, + String defaultValue, + String defaultInitializer) { + this.myPosition = -1; + myName = new GroovyCodeFragment(project, name); + myDefaultValue = new GroovyCodeFragment(project, defaultValue); + myType = JavaPsiFacade.getElementFactory(project).createTypeCodeFragment(type, context, true, true); + myDefaultInitializer = new GroovyCodeFragment(project, defaultInitializer); + } + public GroovyCodeFragment getNameFragment() { return myName; } diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/intentions/CreateParameterForFieldTest.java b/plugins/groovy/test/org/jetbrains/plugins/groovy/intentions/CreateParameterForFieldTest.java new file mode 100644 index 000000000000..9301d51e333e --- /dev/null +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/intentions/CreateParameterForFieldTest.java @@ -0,0 +1,35 @@ +/* + * Copyright 2000-2010 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jetbrains.plugins.groovy.intentions; + +import org.jetbrains.plugins.groovy.util.TestUtils; + +/** + * @author Maxim.Medvedev + */ +public class CreateParameterForFieldTest extends GrIntentionTestCase { + @Override + protected String getBasePath() { + return TestUtils.getTestDataPath() + "intentions/createParameterForField/"; + } + + public void testFromConstructor() {doTest();} + public void testFromField() {doTest();} + + protected void doTest() { + doTest("Add constructor parameter for field", true); + } +} diff --git a/plugins/groovy/testdata/intentions/createParameterForField/FromConstructor.groovy b/plugins/groovy/testdata/intentions/createParameterForField/FromConstructor.groovy new file mode 100644 index 000000000000..873e4424819c --- /dev/null +++ b/plugins/groovy/testdata/intentions/createParameterForField/FromConstructor.groovy @@ -0,0 +1,6 @@ +class Foo { + def foo + def Foo() { + + } +} \ No newline at end of file diff --git a/plugins/groovy/testdata/intentions/createParameterForField/FromConstructor_after.groovy b/plugins/groovy/testdata/intentions/createParameterForField/FromConstructor_after.groovy new file mode 100644 index 000000000000..6f70aff9e9c8 --- /dev/null +++ b/plugins/groovy/testdata/intentions/createParameterForField/FromConstructor_after.groovy @@ -0,0 +1,7 @@ +class Foo { + def foo + def Foo(def foo) { + + this.foo = foo + } +} \ No newline at end of file diff --git a/plugins/groovy/testdata/intentions/createParameterForField/FromField.groovy b/plugins/groovy/testdata/intentions/createParameterForField/FromField.groovy new file mode 100644 index 000000000000..5d3848620d82 --- /dev/null +++ b/plugins/groovy/testdata/intentions/createParameterForField/FromField.groovy @@ -0,0 +1,7 @@ +class Foo { + def foo + + def Foo() { + + } +} \ No newline at end of file diff --git a/plugins/groovy/testdata/intentions/createParameterForField/FromField_after.groovy b/plugins/groovy/testdata/intentions/createParameterForField/FromField_after.groovy new file mode 100644 index 000000000000..c348f9751f6e --- /dev/null +++ b/plugins/groovy/testdata/intentions/createParameterForField/FromField_after.groovy @@ -0,0 +1,8 @@ +class Foo { + def foo + + def Foo(def foo) { + + this.foo = foo + } +} \ No newline at end of file