From 11963c41c8bf4d98a501c103405fc85a89202270 Mon Sep 17 00:00:00 2001 From: peter Date: Wed, 4 Aug 2010 08:10:15 +0100 Subject: [PATCH] groovy: generated constructors should have some types on parameters (IDEA-56826) and their bodies should not have semicolons (IDEA-27066) --- .../psi/impl/light/LightVariableBuilder.java | 1 + .../ConstructorGenerateHandler.java | 63 ++++++------ .../generator/GroovyToJavaGenerator.java | 17 ++++ .../api/statements/params/GrParameter.java | 5 + .../psi/impl/GroovyPsiElementFactoryImpl.java | 8 +- .../statements/params/GrParameterImpl.java | 4 +- .../GroovyOverrideImplementUtil.java | 3 +- .../generate/GroovyGenerateMembersTest.groovy | 97 +++++++++++++++++++ .../generate/GroovyGenerateMembersTest.java | 44 --------- .../GroovyOverrideImplementTest.groovy | 6 +- 10 files changed, 165 insertions(+), 83 deletions(-) create mode 100644 plugins/groovy/test/org/jetbrains/plugins/groovy/lang/actions/generate/GroovyGenerateMembersTest.groovy delete mode 100644 plugins/groovy/test/org/jetbrains/plugins/groovy/lang/actions/generate/GroovyGenerateMembersTest.java diff --git a/java/java-impl/src/com/intellij/psi/impl/light/LightVariableBuilder.java b/java/java-impl/src/com/intellij/psi/impl/light/LightVariableBuilder.java index 94bb7ea3e64a..6932cb320c0e 100644 --- a/java/java-impl/src/com/intellij/psi/impl/light/LightVariableBuilder.java +++ b/java/java-impl/src/com/intellij/psi/impl/light/LightVariableBuilder.java @@ -48,6 +48,7 @@ public class LightVariableBuilder extends LightElement implements PsiVariable { } @Override + @NotNull public PsiModifierList getModifierList() { return myModifierList; } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/actions/generate/constructors/ConstructorGenerateHandler.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/actions/generate/constructors/ConstructorGenerateHandler.java index 45dd61030793..ca7f92f6df4d 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/actions/generate/constructors/ConstructorGenerateHandler.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/actions/generate/constructors/ConstructorGenerateHandler.java @@ -17,12 +17,16 @@ package org.jetbrains.plugins.groovy.actions.generate.constructors; import com.intellij.codeInsight.generation.*; import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.*; import com.intellij.util.ArrayUtil; import com.intellij.util.IncorrectOperationException; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.jetbrains.plugins.groovy.compiler.generator.GroovyToJavaGenerator; import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElementFactory; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrField; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.params.GrParameter; import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrMethod; import org.jetbrains.plugins.groovy.lang.psi.util.PsiUtil; @@ -35,55 +39,50 @@ import java.util.List; */ public class ConstructorGenerateHandler extends GenerateConstructorHandler { + private static final String DEF_PSEUDO_ANNO = "_____intellij_idea_rulez_def_"; + @Nullable protected ClassMember[] chooseOriginalMembers(PsiClass aClass, Project project) { - final ClassMember[] classMembers = super.chooseOriginalMembers(aClass, project); - + final ClassMember[] classMembers = chooseOriginalMembersImpl(aClass, project); if (classMembers == null) return null; List res = new ArrayList(); final PsiElementFactory factory = JavaPsiFacade.getInstance(aClass.getProject()).getElementFactory(); - String text; - for (ClassMember classMember : classMembers) { - if (classMember instanceof PsiMethodMember) { - PsiMethod constructorImpl; - final PsiMethod method = ((PsiMethodMember) classMember).getElement(); - - //TODO: rewrite it like fine java method - text = method.getText(); - try { - constructorImpl = factory.createMethodFromText(text, aClass); - res.add(new PsiMethodMember(constructorImpl)); - } catch (IncorrectOperationException e) { - e.printStackTrace(); + final PsiMethod method = ((PsiMethodMember)classMember).getElement(); + final PsiMethod copy = (PsiMethod)method.copy(); + if (copy instanceof GrMethod) { + for (GrParameter parameter : ((GrMethod)copy).getParameterList().getParameters()) { + if (parameter.getTypeElementGroovy() == null) { + parameter.setName(DEF_PSEUDO_ANNO + parameter.getName()); + } + } } + res.add(new PsiMethodMember(factory.createMethodFromText(GroovyToJavaGenerator.generateMethodStub(copy), aClass))); } else if (classMember instanceof PsiFieldMember) { - final PsiFieldMember fieldMember = (PsiFieldMember) classMember; - PsiField fieldImpl; + final PsiField field = ((PsiFieldMember) classMember).getElement(); - final PsiField field = fieldMember.getElement(); - try { - fieldImpl = factory.createFieldFromText(field.getType().getCanonicalText() + " " + field.getName(), aClass); - res.add(new PsiFieldMember(fieldImpl)); - } catch (IncorrectOperationException e) { - e.printStackTrace(); - } + String prefix = field instanceof GrField && ((GrField)field).getTypeElementGroovy() == null ? DEF_PSEUDO_ANNO : ""; + res.add(new PsiFieldMember(factory.createFieldFromText(field.getType().getCanonicalText() + " " + prefix + field.getName(), aClass))); } } return res.toArray(new ClassMember[res.size()]); } + @Nullable + protected ClassMember[] chooseOriginalMembersImpl(PsiClass aClass, Project project) { + return super.chooseOriginalMembers(aClass, project); + } + @NotNull protected List generateMemberPrototypes(PsiClass aClass, ClassMember[] members) throws IncorrectOperationException { final List list = super.generateMemberPrototypes(aClass, members); List> grConstructors = new ArrayList>(); - GrMethod grConstructor; for (GenerationInfo generationInfo : list) { final PsiMember constructorMember = generationInfo.getPsiMember(); assert constructorMember instanceof PsiMethod; @@ -93,22 +92,26 @@ public class ConstructorGenerateHandler extends GenerateConstructorHandler { assert block != null; final String constructorName = aClass.getName(); - final String body = block.getText(); + final String body = StringUtil.replace(StringUtil.replace(block.getText(), DEF_PSEUDO_ANNO, ""), ";", ""); final PsiParameterList list1 = constructor.getParameterList(); List parametersNames = new ArrayList(); + List parametersTypes = new ArrayList(); for (PsiParameter parameter : list1.getParameters()) { - parametersNames.add(parameter.getName()); + final String fullName = parameter.getName(); + parametersNames.add(StringUtil.trimStart(fullName, DEF_PSEUDO_ANNO)); + parametersTypes.add(fullName.startsWith(DEF_PSEUDO_ANNO) ? null : parameter.getType().getCanonicalText()); } final String[] paramNames = ArrayUtil.toStringArray(parametersNames); + final String[] paramTypes = ArrayUtil.toStringArray(parametersTypes); assert constructorName != null; - grConstructor = GroovyPsiElementFactory.getInstance(aClass.getProject()).createConstructorFromText(constructorName, null, paramNames, body); + GrMethod grConstructor = + GroovyPsiElementFactory.getInstance(aClass.getProject()).createConstructorFromText(constructorName, paramTypes, paramNames, body); PsiUtil.shortenReferences(grConstructor); - final PsiGenerationInfo psiGenerationInfo = new GroovyGenerationInfo(grConstructor); - grConstructors.add(psiGenerationInfo); + grConstructors.add(new GroovyGenerationInfo(grConstructor)); } return grConstructors; diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/compiler/generator/GroovyToJavaGenerator.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/compiler/generator/GroovyToJavaGenerator.java index b4c3bcf20071..8191bd68cd05 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/compiler/generator/GroovyToJavaGenerator.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/compiler/generator/GroovyToJavaGenerator.java @@ -50,6 +50,7 @@ import org.jetbrains.plugins.groovy.compiler.GroovyCompilerConfiguration; import org.jetbrains.plugins.groovy.lang.psi.GrClassSubstitutor; import org.jetbrains.plugins.groovy.lang.psi.GroovyFile; import org.jetbrains.plugins.groovy.lang.psi.GroovyFileBase; +import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElement; import org.jetbrains.plugins.groovy.lang.psi.api.GroovyResolveResult; import org.jetbrains.plugins.groovy.lang.psi.api.auxiliary.modifiers.GrModifierList; import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrConstructorInvocation; @@ -697,6 +698,22 @@ public class GroovyToJavaGenerator { } } + public static String generateMethodStub(@NotNull PsiMethod method) { + if (!(method instanceof GroovyPsiElement)) { + return method.getText(); + } + + final GroovyToJavaGenerator generator = new GroovyToJavaGenerator(method.getProject(), null, Collections.emptyList()); + final StringBuffer buffer = new StringBuffer(); + if (method instanceof GrConstructor) { + generator.writeConstructor(buffer, (GrConstructor)method, false); + } + else { + generator.writeMethod(buffer, method, method.getParameterList().getParameters()); + } + return buffer.toString(); + } + private void writeMethod(StringBuffer text, PsiMethod method, final PsiParameter[] parameters) { if (method == null) return; String name = method.getName(); diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/api/statements/params/GrParameter.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/api/statements/params/GrParameter.java index f695d8174b18..2d0d042f0189 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/api/statements/params/GrParameter.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/api/statements/params/GrParameter.java @@ -16,6 +16,8 @@ package org.jetbrains.plugins.groovy.lang.psi.api.statements.params; +import com.intellij.psi.PsiModifierList; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.plugins.groovy.lang.psi.api.types.GrTypeElement; import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrVariable; @@ -35,5 +37,8 @@ public interface GrParameter extends PsiParameter, GrVariable { @Nullable GrExpression getDefaultInitializer(); + @NotNull + PsiModifierList getModifierList(); + boolean isOptional(); } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/GroovyPsiElementFactoryImpl.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/GroovyPsiElementFactoryImpl.java index 5e1a9da3c021..bf538c0048d1 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/GroovyPsiElementFactoryImpl.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/GroovyPsiElementFactoryImpl.java @@ -528,12 +528,14 @@ public class GroovyPsiElementFactoryImpl extends GroovyPsiElementFactory { builder.append("("); for (int i = 0; i < paramNames.length; i++) { - String paramType = paramTypes == null ? "" : paramTypes[i]; + String paramType = paramTypes == null ? null : paramTypes[i]; if (i > 0) builder.append(", "); - builder.append(paramType); - builder.append(" "); + if (paramType != null) { + builder.append(paramType); + builder.append(" "); + } builder.append(paramNames[i]); } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/params/GrParameterImpl.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/params/GrParameterImpl.java index d3965f74fa6e..fbcad0d19794 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/params/GrParameterImpl.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/params/GrParameterImpl.java @@ -185,9 +185,9 @@ public class GrParameterImpl extends GrVariableImpl implements GrParameter { return getNameIdentifierGroovy().getTextRange().getStartOffset(); } - @Nullable + @NotNull public GrModifierList getModifierList() { - return findChildByClass(GrModifierList.class); + return findNotNullChildByClass(GrModifierList.class); } @NotNull diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/overrideImplement/GroovyOverrideImplementUtil.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/overrideImplement/GroovyOverrideImplementUtil.java index 025d5388da36..3a66ee2098a1 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/overrideImplement/GroovyOverrideImplementUtil.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/overrideImplement/GroovyOverrideImplementUtil.java @@ -27,6 +27,7 @@ import com.intellij.openapi.editor.Editor; import com.intellij.openapi.editor.ScrollType; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Condition; +import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.*; import com.intellij.psi.infos.CandidateInfo; import com.intellij.psi.util.PsiTreeUtil; @@ -314,7 +315,7 @@ public class GroovyOverrideImplementUtil { JavaTemplateUtil.setClassAndMethodNameProperties(properties, method.getContainingClass(), resultMethod); try { - String bodyText = template.getText(properties); + String bodyText = StringUtil.replace(template.getText(properties), ";", ""); final GrCodeBlock newBody = GroovyPsiElementFactory.getInstance(project).createMethodBodyFromText("\n" + bodyText + "\n"); resultMethod.setBlock(newBody); diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/actions/generate/GroovyGenerateMembersTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/actions/generate/GroovyGenerateMembersTest.groovy new file mode 100644 index 000000000000..a0d9cac99121 --- /dev/null +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/actions/generate/GroovyGenerateMembersTest.groovy @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2000-2005 by JetBrains s.r.o. All Rights Reserved. + * Use is subject to license terms. + */ +package org.jetbrains.plugins.groovy.lang.actions.generate; + + +import com.intellij.codeInsight.generation.ClassMember +import com.intellij.codeInsight.generation.PsiFieldMember +import com.intellij.openapi.application.Result +import com.intellij.openapi.application.RunResult +import com.intellij.openapi.command.WriteCommandAction +import com.intellij.openapi.project.Project +import com.intellij.psi.PsiClass +import com.intellij.psi.PsiFile +import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase +import org.jetbrains.plugins.groovy.actions.generate.constructors.ConstructorGenerateHandler +import org.jetbrains.plugins.groovy.util.TestUtils +import com.intellij.codeInsight.generation.PsiMethodMember + +/** + * @author peter + */ +public class GroovyGenerateMembersTest extends LightCodeInsightFixtureTestCase { + + public void testConstructorAtOffset() throws Throwable { + doTest(); + } + + public void testConstructorAtEnd() throws Throwable { + doTest(); + } + + public void testLonelyConstructor() throws Throwable { + doTest(); + } + + public void testExplicitArgumentTypes() throws Exception { + myFixture.configureByText("a.groovy", """ +class Super { + def Super(a, int b) {} +} + +class Foo extends Super { + int c + Object d + final e + +} +""") + generateConstructor() + myFixture.checkResult """ +class Super { + def Super(a, int b) {} +} + +class Foo extends Super { + int c + Object d + final e + + def Foo(a, int b, int c, Object d, e) { + super(a, b) + this.c = c + this.d = d + this.e = e + } +} +""" + } + + private void doTest() throws Throwable { + myFixture.configureByFile(getTestName(false) + ".groovy"); + generateConstructor(); + myFixture.checkResultByFile(getTestName(false) + "_after.groovy"); + } + + RunResult generateConstructor() { + return new WriteCommandAction(getProject(), new PsiFile[0]) { + protected void run(Result result) throws Throwable { + new ConstructorGenerateHandler() { + @Override protected ClassMember[] chooseOriginalMembersImpl(PsiClass aClass, Project project) { + List members = aClass.fields.collect { new PsiFieldMember(it) } + members << new PsiMethodMember(aClass.superClass.constructors[0]) + return members as ClassMember[] + } + + }.invoke(getProject(), myFixture.getEditor(), myFixture.getFile()); + } + }.execute() + } + + @Override + protected String getBasePath() { + return TestUtils.getTestDataPath() + "generate"; + } +} diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/actions/generate/GroovyGenerateMembersTest.java b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/actions/generate/GroovyGenerateMembersTest.java deleted file mode 100644 index c7b637905ad3..000000000000 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/actions/generate/GroovyGenerateMembersTest.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright (c) 2000-2005 by JetBrains s.r.o. All Rights Reserved. - * Use is subject to license terms. - */ -package org.jetbrains.plugins.groovy.lang.actions.generate; - -import com.intellij.openapi.application.Result; -import com.intellij.openapi.command.WriteCommandAction; -import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase; -import org.jetbrains.plugins.groovy.actions.generate.constructors.ConstructorGenerateHandler; -import org.jetbrains.plugins.groovy.util.TestUtils; - -/** - * @author peter - */ -public class GroovyGenerateMembersTest extends LightCodeInsightFixtureTestCase { - - public void testConstructorAtOffset() throws Throwable { - doTest(); - } - - public void testConstructorAtEnd() throws Throwable { - doTest(); - } - - public void testLonelyConstructor() throws Throwable { - doTest(); - } - - private void doTest() throws Throwable { - myFixture.configureByFile(getTestName(false) + ".groovy"); - new WriteCommandAction(getProject()) { - protected void run(Result result) throws Throwable { - new ConstructorGenerateHandler().invoke(getProject(), myFixture.getEditor(), myFixture.getFile()); - } - }.execute(); - myFixture.checkResultByFile(getTestName(false) + "_after.groovy"); - } - - @Override - protected String getBasePath() { - return TestUtils.getTestDataPath() + "generate"; - } -} diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/overriding/GroovyOverrideImplementTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/overriding/GroovyOverrideImplementTest.groovy index 4c2b80c599af..10887d400c7a 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/overriding/GroovyOverrideImplementTest.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/overriding/GroovyOverrideImplementTest.groovy @@ -24,7 +24,7 @@ class Test {} class Test { @Override boolean equals(Object obj) { - return super.equals(obj); //To change body of overridden methods use File | Settings | File Templates. + return super.equals(obj) //To change body of overridden methods use File | Settings | File Templates. } } """ @@ -38,7 +38,7 @@ class Test {} myFixture.checkResult """ class Test { def Test() { - super(); //To change body of overridden methods use File | Settings | File Templates. + super() //To change body of overridden methods use File | Settings | File Templates. } } """ @@ -59,7 +59,7 @@ class Test {} myFixture.checkResult """ class Test { @Override def foo() { - return super.foo(); //To change body of overridden methods use File | Settings | File Templates. + return super.foo() //To change body of overridden methods use File | Settings | File Templates. } } """