groovy: generated constructors should have some types on parameters (IDEA-56826) and their bodies should not have semicolons (IDEA-27066)

This commit is contained in:
peter
2010-08-04 08:12:40 +01:00
parent 8042a5c3ed
commit 11963c41c8
10 changed files with 165 additions and 83 deletions
@@ -48,6 +48,7 @@ public class LightVariableBuilder extends LightElement implements PsiVariable {
}
@Override
@NotNull
public PsiModifierList getModifierList() {
return myModifierList;
}
@@ -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<ClassMember> res = new ArrayList<ClassMember>();
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<? extends GenerationInfo> generateMemberPrototypes(PsiClass aClass, ClassMember[] members) throws IncorrectOperationException {
final List<? extends GenerationInfo> list = super.generateMemberPrototypes(aClass, members);
List<PsiGenerationInfo<GrMethod>> grConstructors = new ArrayList<PsiGenerationInfo<GrMethod>>();
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<String> parametersNames = new ArrayList<String>();
List<String> parametersTypes = new ArrayList<String>();
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<GrMethod> psiGenerationInfo = new GroovyGenerationInfo<GrMethod>(grConstructor);
grConstructors.add(psiGenerationInfo);
grConstructors.add(new GroovyGenerationInfo<GrMethod>(grConstructor));
}
return grConstructors;
@@ -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.<VirtualFile>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();
@@ -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();
}
@@ -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]);
}
@@ -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
@@ -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);
@@ -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
<caret>
}
""")
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<ClassMember> 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";
}
}
@@ -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";
}
}
@@ -24,7 +24,7 @@ class Test {<caret>}
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 {<caret>}
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 {<caret>}
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.
}
}
"""