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 e01f1cc7408c..929d70b03822 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 @@ -687,7 +687,7 @@ public class GroovyPsiElementFactoryImpl extends GroovyPsiElementFactory { text = qname + ".this"; } } - return createReferenceExpressionFromText(text); + return createReferenceExpressionFromText(text, psiClass); } @Override diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/util/PsiUtil.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/util/PsiUtil.java index b69a357824ca..415ccb837dfb 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/util/PsiUtil.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/util/PsiUtil.java @@ -491,7 +491,7 @@ public class PsiUtil { return null; } - private static boolean isInDummyFile(@NotNull PsiElement context) { + public static boolean isInDummyFile(@NotNull PsiElement context) { PsiFile file = context.getContainingFile(); if (file == null) return false; diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/convertToJava/ClosureGenerator.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/convertToJava/ClosureGenerator.java index d420e5667eee..7f04df75c424 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/convertToJava/ClosureGenerator.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/convertToJava/ClosureGenerator.java @@ -16,9 +16,7 @@ package org.jetbrains.plugins.groovy.refactoring.convertToJava; import com.intellij.openapi.diagnostic.Logger; -import com.intellij.psi.PsiModifier; -import com.intellij.psi.PsiPrimitiveType; -import com.intellij.psi.PsiType; +import com.intellij.psi.*; import com.intellij.psi.util.PsiTreeUtil; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; @@ -30,7 +28,6 @@ import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElementFactory; 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.params.GrParameter; -import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrTypeDefinition; import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrMember; import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrMethod; import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrReflectedMethod; @@ -58,11 +55,16 @@ public class ClosureGenerator { } public void generate(@NotNull GrClosableBlock closure) { - final String owner = getOwner(closure); builder.append("new "); writeTypeForNew(builder, closure.getType(), closure); builder.append('('); - builder.append(owner).append(", ").append(owner).append(") {\n"); + + final CharSequence owner = getOwner(closure); + builder.append(owner); + builder.append(", "); + builder.append(owner); + + builder.append(") {\n"); generateClosureMainMethod(closure); @@ -119,17 +121,39 @@ public class ClosureGenerator { @NonNls @NotNull - private static String getOwner(@NotNull GrClosableBlock closure) { - final GroovyPsiElement context = PsiTreeUtil.getParentOfType(closure, GrMember.class, GrClosableBlock.class, GroovyFile.class); + private CharSequence getOwner(@NotNull GrClosableBlock closure) { + final GroovyPsiElement context = PsiTreeUtil.getParentOfType(closure, GrMember.class, GroovyFile.class); LOG.assertTrue(context != null); - if (context instanceof GrTypeDefinition) { - LOG.error("closure must have member parent"); + final PsiClass contextClass; + if (context instanceof GroovyFile) { + contextClass = ((GroovyFile)context).getScriptClass(); + } + else if (context instanceof PsiClass) { + contextClass = (PsiClass)context; + } + else if (context instanceof GrMember) { + if (((GrMember)context).hasModifierProperty(PsiModifier.STATIC)) { + contextClass = null; //no context class + } + else { + contextClass = ((GrMember)context).getContainingClass(); + } + } + else { + contextClass = null; + } + + if (contextClass == null) return "null"; + + final PsiElement implicitClass = GenerationUtil.getWrappingImplicitClass(closure); + if (implicitClass == null) { return "this"; } - if (context instanceof GrMember && ((GrMember)context).hasModifierProperty(PsiModifier.STATIC)) { - return "null"; + else { + final StringBuilder buffer = new StringBuilder(); + GenerationUtil.writeThisReference(contextClass, buffer, this.context); + return buffer; } - return "this"; } } 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 787456f9ee4a..4c0ab99aed1e 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 @@ -915,12 +915,10 @@ public class ExpressionGenerator extends Generator { final GrExpression qualifier = referenceExpression.getQualifier(); final GroovyResolveResult resolveResult = referenceExpression.advancedResolve(); final PsiElement resolved = resolveResult.getElement(); + final String referenceName = referenceExpression.getReferenceName(); if (PsiUtil.isThisOrSuperRef(referenceExpression)) { - if (!context.isInAnonymousContext() && qualifier != null) { - qualifier.accept(this); - } - builder.append(referenceExpression.getReferenceName()); + writeThisOrSuperRef(referenceExpression, qualifier, referenceName); return; } @@ -939,8 +937,8 @@ public class ExpressionGenerator extends Generator { } //don't try to resolve local vars that are provided my this generator (they are listed in myUsedVarNames) - if (resolved == null && qualifier == null && context.myUsedVarNames.contains(referenceExpression.getReferenceName())) { - builder.append(referenceExpression.getReferenceName()); + if (resolved == null && qualifier == null && context.myUsedVarNames.contains(referenceName)) { + builder.append(referenceName); return; } @@ -965,7 +963,7 @@ public class ExpressionGenerator extends Generator { LOG.assertTrue(qualifier != null); builder.append("new ").append(GroovyCommonClassNames.ORG_CODEHAUS_GROOVY_RUNTIME_METHOD_CLOSURE).append('('); qualifier.accept(this); - builder.append(", \"").append(referenceExpression.getReferenceName()).append("\")"); + builder.append(", \"").append(referenceName).append("\")"); return; } @@ -1018,7 +1016,7 @@ public class ExpressionGenerator extends Generator { } else { //unresolved reference - final String refName = referenceExpression.getReferenceName(); + final String refName = referenceName; if (refName != null) { if (PsiUtil.isAccessedForWriting(referenceExpression)) { builder.append(refName); @@ -1057,6 +1055,35 @@ public class ExpressionGenerator extends Generator { } + private void writeThisOrSuperRef(GrReferenceExpression referenceExpression, GrExpression qualifier, String referenceName) { + if (!context.isInAnonymousContext() && qualifier != null) { + qualifier.accept(this); + builder.append('.'); + builder.append(referenceName); + } + else if (getWrappingImplicitClass(referenceExpression) != null) { + final PsiClass contextClass; + if ("this".equals(referenceName)) { + final PsiElement _contextClass = referenceExpression.resolve(); + if (_contextClass instanceof PsiClass) { + contextClass = (PsiClass)_contextClass; + } + else { + contextClass = null; + } + writeThisReference(contextClass, builder, context); + } + else { //super ref + //super ref is used without qualifier. So we should use context class as a qualifier + contextClass = PsiUtil.getContextClass(referenceExpression); + writeSuperReference(contextClass, builder, context); + } + } + else { + builder.append(referenceName); + } + } + private String createVarByInitializer(@NotNull GrExpression initializer) { GrExpression inner = initializer; while (inner instanceof GrParenthesizedExpression) inner = ((GrParenthesizedExpression)inner).getOperand(); 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 c20bbe560ff6..4ea1f670e587 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 @@ -27,6 +27,7 @@ import com.intellij.util.containers.hash.HashSet; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.plugins.groovy.lang.psi.GrClassSubstitutor; +import org.jetbrains.plugins.groovy.lang.psi.GroovyFile; import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElement; import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElementFactory; import org.jetbrains.plugins.groovy.lang.psi.api.GroovyResolveResult; @@ -648,4 +649,38 @@ public class GenerationUtil { static PsiType getNotNullType(PsiElement context, PsiType type) { return type != null ? type : TypesUtil.getJavaLangObject(context); } + + public static void writeThisReference(@Nullable PsiClass targetClass, StringBuilder buffer, ExpressionContext context) { + if (targetClass != null && !(targetClass instanceof PsiAnonymousClass)) { + final GrCodeReferenceElement ref = GroovyPsiElementFactory.getInstance(context.project).createCodeReferenceElementFromClass(targetClass); + writeCodeReferenceElement(buffer, ref); + buffer.append('.'); + } + buffer.append("this"); + } + + public static void writeSuperReference(@Nullable PsiClass targetClass, StringBuilder buffer, ExpressionContext context) { + if (targetClass != null && !(targetClass instanceof PsiAnonymousClass)) { + final GrCodeReferenceElement ref = GroovyPsiElementFactory.getInstance(context.project).createCodeReferenceElementFromClass(targetClass); + writeCodeReferenceElement(buffer, ref); + buffer.append('.'); + } + buffer.append("super"); + } + + @Nullable + static PsiElement getWrappingImplicitClass(@NotNull PsiElement place) { + PsiElement parent = place.getParent(); + + while (parent != null) { + if (parent instanceof PsiClass) return null; + if (parent instanceof GroovyFile && !(PsiUtil.isInDummyFile(parent))) return null; + + if (parent instanceof GrClosableBlock) return parent; + + parent = parent.getContext(); + } + + return null; + } } diff --git a/plugins/groovy/testdata/refactoring/convertGroovyToJava/codeBlock/anonymousFromMap.java b/plugins/groovy/testdata/refactoring/convertGroovyToJava/codeBlock/anonymousFromMap.java index d8ab60ca57ea..3361d6e9fab5 100644 --- a/plugins/groovy/testdata/refactoring/convertGroovyToJava/codeBlock/anonymousFromMap.java +++ b/plugins/groovy/testdata/refactoring/convertGroovyToJava/codeBlock/anonymousFromMap.java @@ -1,6 +1,6 @@ print(new java.lang.Runnable() { public void run(java.lang.Object it) { -org.codehaus.groovy.runtime.DefaultGroovyMethods.print(this, "foo}"); +org.codehaus.groovy.runtime.DefaultGroovyMethods.print(anonymousFromMap.this, "foo}"); } public void run() { this.run(null); diff --git a/plugins/groovy/testdata/refactoring/convertGroovyToJava/codeBlock/closure.java b/plugins/groovy/testdata/refactoring/convertGroovyToJava/codeBlock/closure.java index fee12b6cf1e7..15d0b91c2466 100644 --- a/plugins/groovy/testdata/refactoring/convertGroovyToJava/codeBlock/closure.java +++ b/plugins/groovy/testdata/refactoring/convertGroovyToJava/codeBlock/closure.java @@ -1,7 +1,7 @@ java.util.ArrayList list = new java.util.ArrayList(java.util.Arrays.asList(1, 2, 3)); org.codehaus.groovy.runtime.DefaultGroovyMethods.each(list, new groovy.lang.Closure(this, this) { public void doCall(java.lang.Object it) { -org.codehaus.groovy.runtime.DefaultGroovyMethods.print(this, it); +org.codehaus.groovy.runtime.DefaultGroovyMethods.print(closure.this, it); } public void doCall() { diff --git a/plugins/groovy/testdata/refactoring/convertGroovyToJava/file/closureParamInInnerClosure.java b/plugins/groovy/testdata/refactoring/convertGroovyToJava/file/closureParamInInnerClosure.java index 2e8c9cf3227c..ee262a0c24f4 100644 --- a/plugins/groovy/testdata/refactoring/convertGroovyToJava/file/closureParamInInnerClosure.java +++ b/plugins/groovy/testdata/refactoring/convertGroovyToJava/file/closureParamInInnerClosure.java @@ -8,7 +8,7 @@ this.foo = foo; private groovy.lang.Closure foo = new groovy.lang.Closure(this, this) { public java.lang.Integer doCall(int x) { final groovy.lang.Reference i1 = new groovy.lang.Reference(x); -return org.codehaus.groovy.runtime.DefaultGroovyMethods.each(1, new groovy.lang.Closure(this, this) { +return org.codehaus.groovy.runtime.DefaultGroovyMethods.each(1, new groovy.lang.Closure(X.this, X.this) { public void doCall(java.lang.Object it) { i1.set(2); int i = 3; diff --git a/plugins/groovy/testdata/refactoring/convertGroovyToJava/file/methodParamInClosureImplicitReturn.java b/plugins/groovy/testdata/refactoring/convertGroovyToJava/file/methodParamInClosureImplicitReturn.java index f99657794bc8..e772174c1cfb 100644 --- a/plugins/groovy/testdata/refactoring/convertGroovyToJava/file/methodParamInClosureImplicitReturn.java +++ b/plugins/groovy/testdata/refactoring/convertGroovyToJava/file/methodParamInClosureImplicitReturn.java @@ -12,7 +12,7 @@ public void foo(int x) { final groovy.lang.Reference i = new groovy.lang.Reference(x); org.codehaus.groovy.runtime.DefaultGroovyMethods.each(new java.util.ArrayList(java.util.Arrays.asList(1, 2, 3)), new groovy.lang.Closure(this, this) { public java.lang.Integer doCall(java.lang.Object it) { -org.codehaus.groovy.runtime.DefaultGroovyMethods.print(this, i.get()); +org.codehaus.groovy.runtime.DefaultGroovyMethods.print(methodParamInClosureImplicitReturn.this, i.get()); return setGroovyRef(i, i.get() + 1); } @@ -23,7 +23,7 @@ return doCall(null); }); org.codehaus.groovy.runtime.DefaultGroovyMethods.each(new java.util.ArrayList(java.util.Arrays.asList(1, 2, 3)), new groovy.lang.Closure(this, this) { public java.lang.Integer doCall(java.lang.Object it) { -org.codehaus.groovy.runtime.DefaultGroovyMethods.print(this, i.get()); +org.codehaus.groovy.runtime.DefaultGroovyMethods.print(methodParamInClosureImplicitReturn.this, i.get()); i.set(i.get()++); return i.get(); } diff --git a/plugins/groovy/testdata/refactoring/convertGroovyToJava/file/refInClosureInMethod.java b/plugins/groovy/testdata/refactoring/convertGroovyToJava/file/refInClosureInMethod.java index 6f49bbc1737e..3451c7a0455b 100644 --- a/plugins/groovy/testdata/refactoring/convertGroovyToJava/file/refInClosureInMethod.java +++ b/plugins/groovy/testdata/refactoring/convertGroovyToJava/file/refInClosureInMethod.java @@ -1,9 +1,9 @@ public class X { public void foo() { final groovy.lang.Reference ab = new groovy.lang.Reference(4); -org.codehaus.groovy.runtime.DefaultGroovyMethods.each(this, new groovy.lang.Closure(this, this) { -public java.lang.Object doCall(java.lang.Object it) { -return org.codehaus.groovy.runtime.DefaultGroovyMethods.each(this, new groovy.lang.Closure(this, this) { +org.codehaus.groovy.runtime.DefaultGroovyMethods.each(this, new groovy.lang.Closure(this, this) { +public X doCall(java.lang.Object it) { +return org.codehaus.groovy.runtime.DefaultGroovyMethods.each(X.this, new groovy.lang.Closure(X.this, X.this) { public java.lang.Integer doCall(java.lang.Object it) { return setGroovyRef(ab, 2); } @@ -15,7 +15,7 @@ return doCall(null); }); } -public java.lang.Object doCall() { +public X doCall() { return doCall(null); } diff --git a/plugins/groovy/testdata/refactoring/convertGroovyToJava/file/refInClosureInScript.java b/plugins/groovy/testdata/refactoring/convertGroovyToJava/file/refInClosureInScript.java index 4963dbcfdfe4..4b81506a473d 100644 --- a/plugins/groovy/testdata/refactoring/convertGroovyToJava/file/refInClosureInScript.java +++ b/plugins/groovy/testdata/refactoring/convertGroovyToJava/file/refInClosureInScript.java @@ -11,7 +11,7 @@ foo.set(foo.get()++); foo.set(foo.get() + 2); foo.set(foo.get() - 1); foo.set(4); -org.codehaus.groovy.runtime.DefaultGroovyMethods.print(this, foo.get()); +org.codehaus.groovy.runtime.DefaultGroovyMethods.print(refInClosureInScript.this, foo.get()); } public void doCall() {