IDEA-66202: Groovy Extract Method Broken: Nested Closures drop 'it' reference

This commit is contained in:
Maxim Medvedev
2011-03-06 19:33:46 +03:00
parent ca2eb3b70b
commit 9d9063bbb4
4 changed files with 66 additions and 39 deletions
@@ -48,7 +48,6 @@ import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrField;
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.expressions.*;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.literals.GrLiteral;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.path.GrMethodCallExpression;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrTypeDefinition;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrAccessorMethod;
@@ -437,8 +436,9 @@ public class GrReferenceExpressionImpl extends GrReferenceElementImpl<GrExpressi
PsiClass containingClass = method.getContainingClass();
if (containingClass != null && CommonClassNames.JAVA_LANG_OBJECT.equals(containingClass.getQualifiedName()) &&
"getClass".equals(method.getName())) {
if (seemsToBeQualifiedClassName(getQualifierExpression())) {
result = createJavaLangClassType(facade, facade.getElementFactory().createTypeFromText(getQualifier().getText(), this));
final GrExpression qualifier = getQualifier();
if (PsiUtil.seemsToBeQualifiedClassName(qualifier)) {
result = createJavaLangClassType(facade, facade.getElementFactory().createTypeFromText(qualifier.getText(), this));
}
else {
result = getTypeForObjectGetClass(facade, method);
@@ -464,7 +464,7 @@ public class GrReferenceExpressionImpl extends GrReferenceElementImpl<GrExpressi
else if (resolved == null) {
GrExpression qualifier = getQualifierExpression();
if ("class".equals(getReferenceName())) {
if (seemsToBeQualifiedClassName(qualifier)) {
if (PsiUtil.seemsToBeQualifiedClassName(qualifier)) {
assert qualifier != null;
result = createJavaLangClassType(facade, facade.getElementFactory().createTypeFromText(qualifier.getText(), this));
} else {
@@ -502,15 +502,6 @@ public class GrReferenceExpressionImpl extends GrReferenceElementImpl<GrExpressi
}
}
private static boolean seemsToBeQualifiedClassName(@Nullable GrExpression qualifier) {
if (qualifier == null) return false;
while (qualifier instanceof GrReferenceExpression) {
if (((GrReferenceExpression)qualifier).getReferenceNameElement() instanceof GrLiteral) return false;
qualifier = ((GrReferenceExpression)qualifier).getQualifierExpression();
}
return qualifier == null;
}
@Nullable
private PsiType createJavaLangClassType(JavaPsiFacade facade, @Nullable PsiType type) {
PsiType result = null;
@@ -59,6 +59,7 @@ import org.jetbrains.plugins.groovy.lang.psi.api.statements.arguments.GrArgument
import org.jetbrains.plugins.groovy.lang.psi.api.statements.arguments.GrNamedArgument;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.blocks.GrClosableBlock;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.*;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.literals.GrLiteral;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.path.GrIndexProperty;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.path.GrMethodCallExpression;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.path.GrPropertySelection;
@@ -304,41 +305,59 @@ public class PsiUtil {
public static <Qualifier extends PsiElement> boolean shortenReference(GrQualifiedReference<Qualifier> ref) {
final Qualifier qualifier = ref.getQualifier();
if (qualifier != null && !(qualifier instanceof GrSuperReferenceExpression) &&
(PsiTreeUtil.getParentOfType(ref, GrDocMemberReference.class) != null ||
PsiTreeUtil.getParentOfType(ref, GrDocComment.class) == null) &&
PsiTreeUtil.getParentOfType(ref, GrImportStatement.class) == null &&
PsiTreeUtil.getParentOfType(ref, GroovyCodeFragment.class) == null) {
final PsiElement resolved = ref.resolve();
if (resolved != null) {
ref.setQualifier(null);
if (ref.isReferenceTo(resolved)) return true;
if (qualifier == null || qualifier instanceof GrSuperReferenceExpression || cannotShortenInContext(ref)) {
return false;
}
if (!canShorten(qualifier)) return false;
if (resolved instanceof PsiClass) {
final GroovyFileBase file = (GroovyFileBase)ref.getContainingFile();
final PsiClass clazz = (PsiClass)resolved;
final String qName = clazz.getQualifiedName();
if (qName != null) {
if (mayInsertImport(ref)) {
final GrImportStatement added = file.addImportForClass(clazz);
if (!ref.isReferenceTo(resolved)) {
file.removeImport(added);
}
}
final PsiElement resolved = ref.resolve();
if (resolved == null) return false;
ref.setQualifier(null);
if (ref.isReferenceTo(resolved)) return true;
if (resolved instanceof PsiClass) {
final GroovyFileBase file = (GroovyFileBase)ref.getContainingFile();
final PsiClass clazz = (PsiClass)resolved;
final String qName = clazz.getQualifiedName();
if (qName != null) {
if (mayInsertImport(ref)) {
final GrImportStatement added = file.addImportForClass(clazz);
if (!ref.isReferenceTo(resolved)) {
file.removeImport(added);
}
}
}
}
if (!ref.isReferenceTo(resolved)) {
ref.setQualifier((Qualifier)qualifier.copy());
return false;
} else {
return true;
}
if (!ref.isReferenceTo(resolved)) {
ref.setQualifier((Qualifier)qualifier.copy());
return false;
}
else {
return true;
}
}
private static <Qualifier extends PsiElement> boolean canShorten(Qualifier qualifier) {
if (qualifier instanceof GrCodeReferenceElement) return true;
if (qualifier instanceof GrExpression) {
if (qualifier instanceof GrThisReferenceExpression) return true;
if (seemsToBeQualifiedClassName((GrExpression)qualifier)) {
final PsiElement resolved = ((GrReferenceExpression)qualifier).resolve();
if (resolved instanceof PsiClass || resolved instanceof PsiPackage) return true;
}
}
return false;
}
private static <Qualifier extends PsiElement> boolean cannotShortenInContext(GrQualifiedReference<Qualifier> ref) {
return (PsiTreeUtil.getParentOfType(ref, GrDocMemberReference.class) == null &&
PsiTreeUtil.getParentOfType(ref, GrDocComment.class) != null) ||
PsiTreeUtil.getParentOfType(ref, GrImportStatement.class) != null ||
PsiTreeUtil.getParentOfType(ref, GroovyCodeFragment.class) != null;
}
private static <Qualifier extends PsiElement> boolean mayInsertImport(GrQualifiedReference<Qualifier> ref) {
return PsiTreeUtil.getParentOfType(ref, GrDocComment.class) == null &&
!(ref.getContainingFile() instanceof GroovyCodeFragment) &&
@@ -1069,4 +1088,13 @@ public class PsiUtil {
return ((GrListOrMap)firstArg).getNamedArguments();
}
public static boolean seemsToBeQualifiedClassName(@Nullable GrExpression qualifier) {
if (qualifier == null) return false;
while (qualifier instanceof GrReferenceExpression) {
if (((GrReferenceExpression)qualifier).getReferenceNameElement() instanceof GrLiteral) return false;
qualifier = ((GrReferenceExpression)qualifier).getQualifierExpression();
}
return qualifier == null;
}
}
@@ -96,4 +96,5 @@ public class ExtractMethodTest extends LightGroovyTestCase {
public void testMultiOutput4() {doTest();}
public void testMultiOutput5() {doTest();}
public void testDontShortenRefsIncorrect() {doTest();}
}
@@ -0,0 +1,7 @@
<begin>print 1.getClass()<end>
-----
testMethod()
private def testMethod() {
print 1.getClass()
}