From 8daf5892fc67b563aa673f3d1bd075a09df9620e Mon Sep 17 00:00:00 2001 From: Maxim Medvedev Date: Fri, 15 Apr 2011 15:57:41 +0400 Subject: [PATCH] convert simple reference expressions --- .../convertToJava/CodeBlockGenerator.java | 26 ++--- .../convertToJava/ExpressionGenerator.java | 109 +++++++++++++----- .../convertToJava/GenerationUtil.java | 25 +++- .../CodeBlockGenerationTest.groovy | 16 +++ .../codeBlock/refExpr.groovy | 10 ++ .../codeBlock/refExpr.java | 6 + .../codeBlock/switch3.java | 6 +- .../codeBlock/switch4.java | 4 +- 8 files changed, 155 insertions(+), 47 deletions(-) create mode 100644 plugins/groovy/testdata/refactoring/convertGroovyToJava/codeBlock/refExpr.groovy create mode 100644 plugins/groovy/testdata/refactoring/convertGroovyToJava/codeBlock/refExpr.java diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/convertToJava/CodeBlockGenerator.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/convertToJava/CodeBlockGenerator.java index be909e23cc79..8f1b931b28da 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/convertToJava/CodeBlockGenerator.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/convertToJava/CodeBlockGenerator.java @@ -73,13 +73,16 @@ public class CodeBlockGenerator extends Generator { @Override public void visitOpenBlock(GrOpenBlock block) { builder.append("{\n"); - super.visitOpenBlock(block); + final GrStatement[] statements = block.getStatements(); + for (GrStatement statement : statements) { + statement.accept(this); + builder.append('\n'); + } builder.append("}\n"); } - @Override public void visitStatement(GrStatement statement) { - super.visitStatement(statement); //To change body of overridden methods use File | Settings | File Templates. + LOG.assertTrue(false, "all statements must be overloaded"); } @Override @@ -191,6 +194,7 @@ public class CodeBlockGenerator extends Generator { @Override public void visitForStatement(GrForStatement forStatement) { final StringBuilder builder = new StringBuilder(); + builder.append("for("); final GrForClause clause = forStatement.getClause(); ExpressionContext forContext = context.extend(); @@ -199,16 +203,14 @@ public class CodeBlockGenerator extends Generator { final GrVariable declaredVariable = clause.getDeclaredVariable(); LOG.assertTrue(declaredVariable != null); - builder.append("for("); writeVariableWithoutSemicolonAndInitializer(builder, declaredVariable); builder.append(" : "); if (expression != null) { final ExpressionContext context = forContext.copy(); expression.accept(new ExpressionGenerator(builder, context)); } - builder.append(")"); } - else { + else if (clause instanceof GrTraditionalForClause) { final GrTraditionalForClause cl = (GrTraditionalForClause)clause; final GrCondition initialization = cl.getInitialization(); final GrExpression condition = cl.getCondition(); @@ -244,10 +246,13 @@ public class CodeBlockGenerator extends Generator { if (update != null) { genForPart(builder, update, forContext.copy()); } - builder.append(")"); } + builder.append(")"); - forStatement.getBody().accept(new CodeBlockGenerator(builder, forContext)); + final GrStatement body = forStatement.getBody(); + if (body != null) { + body.accept(new CodeBlockGenerator(builder, forContext)); + } } private static void genForPart(StringBuilder builder, GrExpression part, final ExpressionContext context) { @@ -486,11 +491,6 @@ public class CodeBlockGenerator extends Generator { } } - private void writeVariable(GrVariable variable) { - //todo - throw new UnsupportedOperationException(); - } - private static String getTypeText(PsiType varType) { final StringBuilder builder = new StringBuilder(); GenerationUtil.writeType(builder, varType); diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/convertToJava/ExpressionGenerator.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/convertToJava/ExpressionGenerator.java index 6d1d61cfe394..babcf42555e9 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/convertToJava/ExpressionGenerator.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/convertToJava/ExpressionGenerator.java @@ -21,7 +21,6 @@ import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.*; import com.intellij.psi.search.GlobalSearchScope; import com.intellij.psi.tree.IElementType; -import com.intellij.psi.util.PsiTreeUtil; import com.intellij.util.ArrayUtil; import org.jetbrains.annotations.Nullable; import org.jetbrains.plugins.groovy.intentions.conversions.ConvertGStringToStringIntention; @@ -32,6 +31,7 @@ import org.jetbrains.plugins.groovy.lang.psi.api.GroovyResolveResult; import org.jetbrains.plugins.groovy.lang.psi.api.auxiliary.GrListOrMap; import org.jetbrains.plugins.groovy.lang.psi.api.auxiliary.modifiers.GrModifier; import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrConstructorInvocation; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrVariable; import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrVariableDeclaration; import org.jetbrains.plugins.groovy.lang.psi.api.statements.arguments.GrArgumentLabel; import org.jetbrains.plugins.groovy.lang.psi.api.statements.arguments.GrArgumentList; @@ -59,6 +59,9 @@ import org.jetbrains.plugins.groovy.lang.psi.util.GroovyCommonClassNames; import org.jetbrains.plugins.groovy.lang.psi.util.GroovyPropertyUtils; import org.jetbrains.plugins.groovy.lang.psi.util.PsiUtil; import org.jetbrains.plugins.groovy.lang.resolve.ResolveUtil; +import org.jetbrains.plugins.groovy.refactoring.GroovyRefactoringUtil; + +import static org.jetbrains.plugins.groovy.refactoring.convertToJava.GenerationUtil.*; /** * @author Maxim.Medvedev @@ -128,7 +131,7 @@ public class ExpressionGenerator extends Generator { } } - GenerationUtil.invokeMethodByName(invoked, "call", exprs, namedArgs, clArgs, this, methodCallExpression); + invokeMethodByName(invoked, "call", exprs, namedArgs, clArgs, this, methodCallExpression); } @Override @@ -140,8 +143,8 @@ public class ExpressionGenerator extends Generator { final String varName; if (hasFieldInitialization) { builder = new StringBuilder(); - varName = GenerationUtil.suggestVarName(type, newExpression, this.context); - GenerationUtil.writeType(builder, type); + varName = suggestVarName(type, newExpression, this.context); + writeType(builder, type); builder.append(" ").append(varName).append(" = "); } else { @@ -164,10 +167,10 @@ public class ExpressionGenerator extends Generator { final PsiType builtIn = typeElement.getType(); LOG.assertTrue(builtIn instanceof PsiPrimitiveType); final PsiType boxed = TypesUtil.boxPrimitiveType(builtIn, newExpression.getManager(), newExpression.getResolveScope()); - GenerationUtil.writeType(builder, boxed); + writeType(builder, boxed); } else if (referenceElement != null) { - GenerationUtil.writeCodeReferenceElement(builder, referenceElement); + writeCodeReferenceElement(builder, referenceElement); } final GrArgumentList argList = newExpression.getArgumentList(); @@ -259,7 +262,7 @@ public class ExpressionGenerator extends Generator { private static boolean hasFieldInitialization(GrNewExpression newExpression) { final GrArgumentList argumentList = newExpression.getArgumentList(); if (argumentList == null) return false; - if (argumentList.getNamedArguments().length > 0) return false; + if (argumentList.getNamedArguments().length == 0) return false; final GrCodeReferenceElement refElement = newExpression.getReferenceElement(); if (refElement == null) return false; @@ -275,7 +278,7 @@ public class ExpressionGenerator extends Generator { } private void writeTypeBody(StringBuilder builder, GrAnonymousClassDefinition anonymous) { - //todo + //todo write type body for anonymous class throw new UnsupportedOperationException(); } @@ -460,6 +463,8 @@ public class ExpressionGenerator extends Generator { else { builder.append(value); } + + //todo replace with character in some cases } @Override @@ -471,16 +476,70 @@ public class ExpressionGenerator extends Generator { @Override public void visitReferenceExpression(GrReferenceExpression referenceExpression) { - final GrExpression qualifier = referenceExpression.getQualifier(); - final PsiElement refNameElement = referenceExpression.getReferenceNameElement(); - final GroovyResolveResult resolveResult = referenceExpression.advancedResolve(); + LOG.assertTrue(!(referenceExpression.getParent() instanceof GrMethodCall)); - if (qualifier != null) { - qualifier.accept(this); - builder.append("."); + final GrExpression qualifier = referenceExpression.getQualifier(); + final GroovyResolveResult resolveResult = referenceExpression.advancedResolve(); + final PsiElement resolved = resolveResult.getElement(); + + final IElementType type = referenceExpression.getDotTokenType(); + + GrExpression qualifierToUse = qualifier; + + if (type == GroovyTokenTypes.mOPTIONAL_DOT) { + LOG.assertTrue(qualifier != null); + + String qualifierName = createVarByInitializer(qualifier); + builder.append(qualifierName).append(" == null ? null : "); + + qualifierToUse = factory.createReferenceExpressionFromText(qualifierName, referenceExpression); } - builder.append(referenceExpression.getReferenceName()); - //todo make reference expression + + + if (resolveResult.isInvokedOnProperty()) { + LOG.assertTrue(resolved instanceof PsiMethod); + invokeMethodOn( + ((PsiMethod)resolved), + qualifierToUse, + GrExpression.EMPTY_ARRAY, + GrNamedArgument.EMPTY_ARRAY, + GrClosableBlock.EMPTY_ARRAY, + resolveResult.getSubstitutor(), + referenceExpression + ); + } + else { + if (qualifierToUse != null) { + qualifierToUse.accept(this); + builder.append('.'); + } + final String refName = + resolved instanceof PsiNamedElement ? ((PsiNamedElement)resolved).getName() : referenceExpression.getReferenceName(); + builder.append(refName); + } + } + + private String createVarByInitializer(GrExpression initializer) { + if (initializer instanceof GrReferenceExpression) { + final GrExpression qualifier = ((GrReferenceExpression)initializer).getQualifier(); + if (qualifier == null) { + final PsiElement resolved = ((GrReferenceExpression)initializer).resolve(); + if (resolved instanceof GrVariable && GroovyRefactoringUtil.isLocalVariable((GrVariable)resolved)) { + + //don't create new var. it is already exists + return ((GrVariable)resolved).getName(); + } + } + } + final String name = suggestVarName(initializer, context); + final StringBuilder builder = new StringBuilder(); + builder.append("final "); + writeType(builder, initializer.getType()); + builder.append(' ').append(name).append(" = "); + initializer.accept(new ExpressionGenerator(builder, context)); + builder.append(';'); + context.myStatements.add(builder.toString()); + return name; } @Override @@ -490,14 +549,8 @@ public class ExpressionGenerator extends Generator { final PsiElement resolved = expr.resolve(); LOG.assertTrue(resolved instanceof PsiClass); - final PsiElement firstContainingClass = PsiTreeUtil.getParentOfType(expr, GrClosableBlock.class, PsiClass.class); - if (expr.getManager().areElementsEquivalent(firstContainingClass, resolved)) { - builder.append(expr.getReferenceName()); - } - else { - builder.append(((PsiClass)resolved).getQualifiedName()).append(".").append(expr.getReferenceName()); - } + builder.append(((PsiClass)resolved).getQualifiedName()).append(".").append(expr.getReferenceName()); } @Override @@ -611,8 +664,8 @@ public class ExpressionGenerator extends Generator { } final GroovyResolveResult candidate = PsiImplUtil.getIndexPropertyMethodCandidate(thisType, argTypes, expression); - GenerationUtil.invokeMethodByResolveResult( - selectedExpression, candidate, "getAt", exprArgs, namedArgs, GrClosableBlock.EMPTY_ARRAY, this,expression + invokeMethodByResolveResult( + selectedExpression, candidate, "getAt", exprArgs, namedArgs, GrClosableBlock.EMPTY_ARRAY, this, expression ); } @@ -716,10 +769,10 @@ public class ExpressionGenerator extends Generator { private String generateListOrMapVariableDeclaration(GrListOrMap listOrMap, PsiType type) { StringBuilder declaration = new StringBuilder(); - GenerationUtil.writeType(declaration, type); - final String varName = GenerationUtil.suggestVarName(type, listOrMap, this.context); + writeType(declaration, type); + final String varName = suggestVarName(type, listOrMap, this.context); declaration.append(" ").append(varName).append(" = new "); - GenerationUtil.writeType(declaration, type); + writeType(declaration, type); declaration.append("("); //insert count of elements in list or map diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/convertToJava/GenerationUtil.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/convertToJava/GenerationUtil.java index 901c0c185492..237b6c058524 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/convertToJava/GenerationUtil.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/convertToJava/GenerationUtil.java @@ -70,6 +70,16 @@ public class GenerationUtil { builder.replace(builder.length() - 2, builder.length(), ">"); } + static String suggestVarName(GrExpression expr, ExpressionContext expressionContext) { + final DefaultGroovyVariableNameValidator nameValidator = + new DefaultGroovyVariableNameValidator(expr, expressionContext.myUsedVarNames, true); + final String[] varNames = GroovyNameSuggestionUtil.suggestVariableNames(expr, nameValidator); + + LOG.assertTrue(varNames.length > 0); + expressionContext.myUsedVarNames.add(varNames[0]); + return varNames[0]; + } + static String suggestVarName(PsiType type, GroovyPsiElement context, ExpressionContext expressionContext) { final DefaultGroovyVariableNameValidator nameValidator = new DefaultGroovyVariableNameValidator(context, expressionContext.myUsedVarNames, true); @@ -85,7 +95,20 @@ public class GenerationUtil { } public static void writeCodeReferenceElement(StringBuilder builder, GrCodeReferenceElement referenceElement) { - builder.append(referenceElement.getText()); + final GroovyResolveResult resolveResult = referenceElement.advancedResolve(); + final PsiElement resolved = resolveResult.getElement(); + if (resolved == null) { + builder.append(referenceElement.getText()); + return; + } + LOG.assertTrue(resolved instanceof PsiClass || resolved instanceof PsiPackage); + if (resolved instanceof PsiClass) { + builder.append(((PsiClass)resolved).getQualifiedName()); + } + else { + builder.append(((PsiPackage)resolved).getQualifiedName()); + } + writeTypeParameters(builder, referenceElement.getTypeArguments()); } public static void invokeMethodByName(GrExpression caller, diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/refactoring/convertToJava/CodeBlockGenerationTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/refactoring/convertToJava/CodeBlockGenerationTest.groovy index 532604d641b8..669155ccc9ed 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/refactoring/convertToJava/CodeBlockGenerationTest.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/refactoring/convertToJava/CodeBlockGenerationTest.groovy @@ -88,4 +88,20 @@ public class CodeBlockGenerationTest extends LightCodeInsightFixtureTestCase { void _testWhile2() {doTest()} void _testWhile3() {doTest()} + void testRefExpr() { + myFixture.addFileToProject "Bar.groovy", """ +class Bar { + def foo = 2 + + def getBar() {3} +} +class MyCat { + static getAbc(Bar b) { + return 4 + } +} +""" + + doTest() + } } diff --git a/plugins/groovy/testdata/refactoring/convertGroovyToJava/codeBlock/refExpr.groovy b/plugins/groovy/testdata/refactoring/convertGroovyToJava/codeBlock/refExpr.groovy new file mode 100644 index 000000000000..44f74c60eddf --- /dev/null +++ b/plugins/groovy/testdata/refactoring/convertGroovyToJava/codeBlock/refExpr.groovy @@ -0,0 +1,10 @@ +print new Bar().foo +print new Bar().bar + +def bar = new Bar() + +print bar?.foo + +def file = new File("") +print file.text + diff --git a/plugins/groovy/testdata/refactoring/convertGroovyToJava/codeBlock/refExpr.java b/plugins/groovy/testdata/refactoring/convertGroovyToJava/codeBlock/refExpr.java new file mode 100644 index 000000000000..15b1127bbadb --- /dev/null +++ b/plugins/groovy/testdata/refactoring/convertGroovyToJava/codeBlock/refExpr.java @@ -0,0 +1,6 @@ +print(new Bar().getFoo()); +print(new Bar().getBar()); +Bar bar = new Bar(); +print(bar == null ? null : bar.getFoo()); +java.io.File file = new java.io.File(""); +print(org.codehaus.groovy.runtime.DefaultGroovyMethods.getText(file)); diff --git a/plugins/groovy/testdata/refactoring/convertGroovyToJava/codeBlock/switch3.java b/plugins/groovy/testdata/refactoring/convertGroovyToJava/codeBlock/switch3.java index ab6d5cf98598..b1f9dc5ded69 100644 --- a/plugins/groovy/testdata/refactoring/convertGroovyToJava/codeBlock/switch3.java +++ b/plugins/groovy/testdata/refactoring/convertGroovyToJava/codeBlock/switch3.java @@ -1,9 +1,9 @@ -java.util.Date date = new Date(2011, 4, 9); -if (org.codehaus.groovy.runtime.DefaultGroovyMethods.isCase(new Date(20, 11, 23), date)) { +java.util.Date date = new java.util.Date(2011, 4, 9); +if (org.codehaus.groovy.runtime.DefaultGroovyMethods.isCase(new java.util.Date(20, 11, 23), date)) { print("aaa"); print("bbb"); } -else if (org.codehaus.groovy.runtime.DefaultGroovyMethods.isCase(new Date(45, 1, 2), date)) { +else if (org.codehaus.groovy.runtime.DefaultGroovyMethods.isCase(new java.util.Date(45, 1, 2), date)) { print("bbb"); } else print("ccc"); diff --git a/plugins/groovy/testdata/refactoring/convertGroovyToJava/codeBlock/switch4.java b/plugins/groovy/testdata/refactoring/convertGroovyToJava/codeBlock/switch4.java index feadc641f3e2..60b25a0e977d 100644 --- a/plugins/groovy/testdata/refactoring/convertGroovyToJava/codeBlock/switch4.java +++ b/plugins/groovy/testdata/refactoring/convertGroovyToJava/codeBlock/switch4.java @@ -1,5 +1,5 @@ -java.util.Date date = new Date(2011, 4, 9); -if (org.codehaus.groovy.runtime.DefaultGroovyMethods.isCase(new Date(20, 11, 23), date)) { +java.util.Date date = new java.util.Date(2011, 4, 9); +if (org.codehaus.groovy.runtime.DefaultGroovyMethods.isCase(new java.util.Date(20, 11, 23), date)) { print("aaa"); print("bbb"); }