EA-32658 - initialize field in method while introduce field

This commit is contained in:
Maxim.Medvedev
2012-01-31 17:23:12 +04:00
parent 5bdca08d4e
commit 3fb647577f
13 changed files with 97 additions and 131 deletions
@@ -28,6 +28,7 @@ import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrStatement;
*/
public interface GrStatementOwner extends GroovyPsiElement {
@NotNull
GrStatement addStatementBefore(@NotNull GrStatement statement, @Nullable GrStatement anchor) throws IncorrectOperationException;
void removeElements(PsiElement[] elements) throws IncorrectOperationException;
@@ -187,6 +187,7 @@ public abstract class GroovyFileBaseImpl extends PsiFileBase implements GroovyFi
return findChildrenByClass(GrStatement.class);
}
@NotNull
public GrStatement addStatementBefore(@NotNull GrStatement statement, @Nullable GrStatement anchor) throws IncorrectOperationException {
final PsiElement result = addBefore(statement, anchor);
if (anchor != null) {
@@ -144,6 +144,7 @@ public abstract class GrBlockImpl extends LazyParseablePsiElement implements GrC
return result.toArray(new GrStatement[result.size()]);
}
@NotNull
public GrStatement addStatementBefore(@NotNull GrStatement element, @Nullable GrStatement anchor) throws IncorrectOperationException {
if (anchor == null && getRBrace() == null) {
throw new IncorrectOperationException();
@@ -74,6 +74,7 @@ public class GrCaseSectionImpl extends GroovyPsiElementImpl implements GrCaseSec
return findChildrenByClass(GrStatement.class);
}
@NotNull
public GrStatement addStatementBefore(@NotNull GrStatement element, @Nullable GrStatement anchor) throws IncorrectOperationException {
ASTNode elemNode = element.copy().getNode();
assert elemNode != null;
@@ -26,7 +26,6 @@ declare.final=Declare final
press.escape.to.remove.the.highlighting=Press Escape to remove the highlighting
specify.the.type.explicitly=Specify the type explicitly
variable.of.type=Variable of type:
name.prompt=Name:
selected.expression.has.void.type=Selected expression has void type
selected.expression.in.command.expression=Selected expression is part of command expression
introduced.variable.conflicts.with.parameter.0=Introduced variable will conflict with parameter {0}
@@ -44,14 +43,12 @@ cannot.find.a.single.definition.to.inline.field=No initializer present for the f
inline.local.command=Inline Variable
local.varaible.is.lvalue=Variable to be inlined has occurrence as lvalue in assignment
inline.local.variable.prompt.0.1=Inline local variable ''{0}''?
inline.field.prompt=Inline field ''{0}''?
########################################################################################################################
# Extract method
########################################################################################################################
extract.method.title=Extract Method
selected.block.should.represent.a.statement.set=Selected block should represent a set of statements or an expression
cannot.perform.analysis=Code analysis cannot be performed
multiple.output.values=There are multiple output values for the selected code fragment
selected.block.contains.invocation.of.another.class.constructor=Selected block contains invocation of another class constructor
specify.type.label=Specify return &type explicitly
@@ -84,7 +81,6 @@ refactoring.is.not.supported.when.return.statement.interrupts.the.execution.flow
refactoring.is.not.supported.for.recursive.methods=Refactoring is not supported for recursive methods
refactoring.cannot.be.applied.to.constructors=Refactoring cannot be applied to constructors
refactoring.is.not.supported.in.parameter.initializers=Refactoring is not supported in parameter initializers
multiple.method.inline.is.not.suppored=Multiple method inline is not supported
inline.method.prompt.0=Inline method ''{0}'' invocation?
refactoring.is.available.only.for.method.calls=Refactoring is available only for method calls
method.is.not.accessible.form.context.0=Method {0} used in inlined method is not accessible from call site
@@ -127,7 +123,7 @@ refactored.method.will.cover.closure.property=Refactored method will override cl
changeSignature.not.throwable.type=Wrong type: ''{0}'' for exception, should extend java.lang.Throwable
changeSignature.wrong.type.for.exception=Wrong type: ''{0}'' for exception
changeSignature.no.type.for.exception=Specify a type for exception
no.occurences.found=No occurences found
no.occurrences.found=No occurrences found
expression.is.not.constant=Selected expression is not a constant
class.does.not.exists=Class {0} does not exists
class.does.not.exist.in.the.module=Class does not exists in the module. Do you want to create it?
@@ -35,7 +35,7 @@ import com.intellij.psi.impl.source.tree.LeafPsiElement;
import com.intellij.psi.tree.IElementType;
import com.intellij.psi.util.MethodSignature;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.psi.util.PsiUtilBase;
import com.intellij.psi.util.PsiUtilCore;
import com.intellij.util.ArrayUtil;
import com.intellij.util.IncorrectOperationException;
import com.intellij.util.ReflectionCache;
@@ -131,10 +131,6 @@ public abstract class GroovyRefactoringUtil {
}
public static PsiElement[] getExpressionOccurrences(@NotNull PsiElement expr, @NotNull PsiElement scope) {
return getExpressionOccurrences(expr, scope, false);
}
public static PsiElement[] getExpressionOccurrences(@NotNull PsiElement expr, @NotNull PsiElement scope, boolean gotoInner) {
ArrayList<PsiElement> occurrences = new ArrayList<PsiElement>();
Comparator<PsiElement> comparator = new Comparator<PsiElement>() {
public int compare(PsiElement element1, PsiElement element2) {
@@ -144,9 +140,7 @@ public abstract class GroovyRefactoringUtil {
element2 instanceof GrParameter) {
final String name1 = ((GrParameter) element1).getName();
final String name2 = ((GrParameter) element2).getName();
if (name1 != null && name2 != null) {
return name1.compareTo(name2);
}
return name1.compareTo(name2);
}
return 1;
}
@@ -162,7 +156,7 @@ public abstract class GroovyRefactoringUtil {
} else {
collectOccurrences(expr, scope, occurrences, comparator, scope instanceof GrTypeDefinition || scope instanceof GroovyFileBase);
}
return PsiUtilBase.toPsiElementArray(occurrences);
return PsiUtilCore.toPsiElementArray(occurrences);
}
@@ -192,8 +186,8 @@ public abstract class GroovyRefactoringUtil {
tempContainer instanceof GrIfStatement;
}
public static void sortOccurrences(PsiElement[] occurences) {
Arrays.sort(occurences, new Comparator<PsiElement>() {
public static void sortOccurrences(PsiElement[] occurrences) {
Arrays.sort(occurrences, new Comparator<PsiElement>() {
public int compare(PsiElement elem1, PsiElement elem2) {
final int offset1 = elem1.getTextRange().getStartOffset();
final int offset2 = elem2.getTextRange().getStartOffset();
@@ -302,7 +296,7 @@ public abstract class GroovyRefactoringUtil {
return new PsiElement[]{parent.getParent()};
}
// calcualte children
// calculate children
PsiElement[] children = PsiElement.EMPTY_ARRAY;
PsiElement psiChild = parent.getFirstChild();
if (psiChild != null) {
@@ -311,7 +305,7 @@ public abstract class GroovyRefactoringUtil {
result.add(psiChild);
psiChild = psiChild.getNextSibling();
}
children = PsiUtilBase.toPsiElementArray(result);
children = PsiUtilCore.toPsiElementArray(result);
}
@@ -338,7 +332,7 @@ public abstract class GroovyRefactoringUtil {
}
}
return PsiUtilBase.toPsiElementArray(possibleStatements);
return PsiUtilCore.toPsiElementArray(possibleStatements);
}
public static boolean isSuperOrThisCall(GrStatement statement, boolean testForSuper, boolean testForThis) {
@@ -365,7 +359,7 @@ public abstract class GroovyRefactoringUtil {
}
}
public static boolean haswrongContinueStatements(PsiElement element) {
public static boolean hasWrongContinueStatements(PsiElement element) {
ArrayList<GrContinueStatement> vector = new ArrayList<GrContinueStatement>();
addContinueStatements(element, vector);
return !vector.isEmpty();
@@ -457,70 +451,6 @@ public abstract class GroovyRefactoringUtil {
return id;
}
public static GrExpression convertJavaExpr2GroovyExpr(PsiElement expr) {
final GroovyPsiElementFactory factory = GroovyPsiElementFactory.getInstance(expr.getProject());
final List<PsiLocalVariable> localVariables = new ArrayList<PsiLocalVariable>();
final List<PsiField> fields = new ArrayList<PsiField>();
final List<PsiParameter> parameters = new ArrayList<PsiParameter>();
expr.accept(new JavaRecursiveElementVisitor() {
@Override
public void visitReferenceExpression(PsiReferenceExpression expression) {
final PsiExpression qualifierExpression = expression.getQualifierExpression();
if (qualifierExpression != null && !(qualifierExpression instanceof PsiThisExpression)) return;
PsiElement el = expression.resolve();
if (el instanceof PsiField) {
fields.add((PsiField)el);
}
else if (el instanceof PsiParameter) {
parameters.add((PsiParameter)el);
}
else if (el instanceof PsiLocalVariable) {
localVariables.add((PsiLocalVariable)el);
}
super.visitReferenceExpression(expression);
}
});
PsiJavaFile file = (PsiJavaFile)expr.getContainingFile();
StringBuilder cf = new StringBuilder();
final PsiPackageStatement packageStatement = file.getPackageStatement();
if (packageStatement != null) cf.append(packageStatement.getText());
final PsiImportList importList = file.getImportList();
if (importList != null) cf.append(importList.getText());
cf.append("class A{");
for (PsiField field : fields) {
cf.append(field.getText());
}
cf.append("void foo(");
for (int i = 0, parametersSize = parameters.size() - 1; i < parametersSize; i++) {
PsiParameter parameter = parameters.get(i);
cf.append(parameter.getText()).append(',');
}
if (parameters.size() > 0) {
cf.append(parameters.get(parameters.size() - 1).getText());
}
cf.append("){");
for (PsiLocalVariable localVariable : localVariables) {
cf.append(localVariable.getText());
}
cf.append("Object _________________ooooooo_______________=");
cf.append(expr.getText());
cf.append(";}}");
final GroovyFile grFile = factory.createGroovyFile(cf.toString(), false, expr);
final GrMethod method = (GrMethod)grFile.getClasses()[0].getMethods()[0];
final GrVariableDeclaration variableDeclaration = (GrVariableDeclaration)method.getBlock().getStatements()[0];
return variableDeclaration.getVariables()[0].getInitializerGroovy();
}
public static int verifySafeCopyExpression(GrExpression expression) {
return verifySafeCopyExpressionSubElement(expression);
}
@@ -649,19 +579,20 @@ public abstract class GroovyRefactoringUtil {
}
/**
* adds block statement in parent of expr if needed. For Example:
* adds block statement in parent of statement if needed. For Example:
* while (true) a=foo()
* will be replaced with
* while(true) {a=foo()}
* @param expr
* @return corresponding expr inside block if it has been created or expr itself.
* @param statement
* @return corresponding statement inside block if it has been created or statement itself.
* @throws com.intellij.util.IncorrectOperationException
*/
public static GrExpression addBlockIntoParent(GrExpression expr) throws IncorrectOperationException {
@NotNull
public static <Type extends PsiElement> Type addBlockIntoParent(@NotNull Type statement) throws IncorrectOperationException {
PsiElement parent = expr.getParent();
PsiElement child = expr;
PsiElement parent = statement.getParent();
PsiElement child = statement;
while (!(parent instanceof GrLoopStatement) &&
!(parent instanceof GrIfStatement) &&
!(parent instanceof GrVariableDeclarationOwner) &&
@@ -675,11 +606,11 @@ public abstract class GroovyRefactoringUtil {
}
assert parent != null;
if (parent instanceof GrVariableDeclarationOwner) {
return expr;
return statement;
}
GroovyPsiElementFactory factory = GroovyPsiElementFactory.getInstance(expr.getProject());
PsiElement tempStmt = expr;
GroovyPsiElementFactory factory = GroovyPsiElementFactory.getInstance(statement.getProject());
PsiElement tempStmt = statement;
while (parent != tempStmt.getParent()) {
tempStmt = tempStmt.getParent();
}
@@ -697,14 +628,17 @@ public abstract class GroovyRefactoringUtil {
ifStatement.replaceElseBranch(blockStatement);
}
}
GrStatement statement = blockStatement.getBlock().addStatementBefore(toAdd, null);
if (statement instanceof GrReturnStatement) {
expr = ((GrReturnStatement)statement).getReturnValue();
GrStatement result = blockStatement.getBlock().addStatementBefore(toAdd, null);
if (result instanceof GrReturnStatement) {
//noinspection ConstantConditions,unchecked
statement = (Type)((GrReturnStatement)result).getReturnValue();
}
else {
expr = (GrExpression)statement;
//noinspection unchecked
statement = (Type)result;
}
return expr;
return statement;
}
public static boolean isDiamondNewOperator(GrExpression expression) {
@@ -143,7 +143,7 @@ public abstract class ExtractHandlerBase implements RefactoringActionHandler {
for (GrStatement statement : statements) {
hasInterruptingStatements =
GroovyRefactoringUtil.hasWrongBreakStatements(statement) || GroovyRefactoringUtil.haswrongContinueStatements(statement);
GroovyRefactoringUtil.hasWrongBreakStatements(statement) || GroovyRefactoringUtil.hasWrongContinueStatements(statement);
if (hasInterruptingStatements) break;
}
@@ -54,7 +54,6 @@ import org.jetbrains.plugins.groovy.lang.psi.util.PsiUtil;
import org.jetbrains.plugins.groovy.refactoring.GroovyRefactoringBundle;
import org.jetbrains.plugins.groovy.refactoring.GroovyRefactoringUtil;
import org.jetbrains.plugins.groovy.refactoring.NameValidator;
import org.jetbrains.plugins.groovy.refactoring.introduce.field.GrIntroduceFieldHandler;
import java.util.ArrayList;
import java.util.Collections;
@@ -203,7 +202,7 @@ public abstract class GrIntroduceHandlerBase<Settings extends GrIntroduceSetting
final PsiElement scope = findScope(expression, variable);
if (variable == null) {
final PsiElement[] occurences = findOccurences(expression, scope);
final PsiElement[] occurences = findOccurrences(expression, scope);
return new GrIntroduceContext(project, editor, expression, occurences, scope, variable);
}
@@ -224,10 +223,10 @@ public abstract class GrIntroduceHandlerBase<Settings extends GrIntroduceSetting
}
}
protected PsiElement[] findOccurences(GrExpression expression, PsiElement scope) {
protected PsiElement[] findOccurrences(GrExpression expression, PsiElement scope) {
final PsiElement[] occurrences = GroovyRefactoringUtil.getExpressionOccurrences(PsiUtil.skipParentheses(expression, false), scope);
if (occurrences == null || occurrences.length == 0) {
throw new GrIntroduceRefactoringError(GroovyRefactoringBundle.message("no.occurences.found"));
throw new GrIntroduceRefactoringError(GroovyRefactoringBundle.message("no.occurrences.found"));
}
return occurrences;
}
@@ -399,7 +398,8 @@ public abstract class GrIntroduceHandlerBase<Settings extends GrIntroduceSetting
}
protected static void deleteLocalVar(GrIntroduceContext context) {
final GrVariable resolved = GrIntroduceFieldHandler.resolveLocalVar(context);
final GrVariable resolved = resolveLocalVar(context);
final PsiElement parent = resolved.getParent();
if (parent instanceof GrTupleDeclaration) {
if (((GrTupleDeclaration)parent).getVariables().length == 1) {
@@ -29,7 +29,6 @@ import org.jetbrains.plugins.groovy.lang.psi.GrQualifiedReference;
import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElementFactory;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.*;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.blocks.GrCodeBlock;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.blocks.GrOpenBlock;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrAssignmentExpression;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpression;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrReferenceExpression;
@@ -102,7 +101,7 @@ public class GrIntroduceFieldHandler extends GrIntroduceHandlerBase<GrIntroduceF
@Override
protected void checkOccurrences(PsiElement[] occurrences) {
//notning to do
//nothing to do
}
@Override
@@ -138,6 +137,8 @@ public class GrIntroduceFieldHandler extends GrIntroduceHandlerBase<GrIntroduceF
}
GrReferenceAdjuster.shortenReferences(added);
//var can be invalid if it was removed while initialization
if (settings.removeLocalVar()) {
deleteLocalVar(context);
}
@@ -145,7 +146,7 @@ public class GrIntroduceFieldHandler extends GrIntroduceHandlerBase<GrIntroduceF
if (settings.replaceAllOccurrences()) {
GroovyRefactoringUtil.sortOccurrences(context.occurrences);
for (PsiElement occurrence : context.occurrences) {
replaceOccurence(field, occurrence);
replaceOccurrence(field, occurrence);
}
}
else {
@@ -153,22 +154,22 @@ public class GrIntroduceFieldHandler extends GrIntroduceHandlerBase<GrIntroduceF
context.expression.delete();
}
else {
replaceOccurence(field, context.expression);
replaceOccurrence(field, context.expression);
}
}
return field;
}
@Override
protected PsiElement[] findOccurences(GrExpression expression, PsiElement scope) {
final PsiElement[] occurences = super.findOccurences(expression, scope);
protected PsiElement[] findOccurrences(GrExpression expression, PsiElement scope) {
final PsiElement[] occurrences = super.findOccurrences(expression, scope);
GrTypeDefinition clazz = (GrTypeDefinition)scope;
if (shouldBeStatic(expression, clazz)) return occurences;
if (shouldBeStatic(expression, clazz)) return occurrences;
List<PsiElement> filtered = new ArrayList<PsiElement>();
for (PsiElement occurence : occurences) {
if (!shouldBeStatic(occurence, clazz)) {
filtered.add(occurence);
for (PsiElement occurrence : occurrences) {
if (!shouldBeStatic(occurrence, clazz)) {
filtered.add(occurrence);
}
}
return ContainerUtil.toArray(filtered, new PsiElement[filtered.size()]);
@@ -180,18 +181,17 @@ public class GrIntroduceFieldHandler extends GrIntroduceHandlerBase<GrIntroduceF
final GrTypeDefinition scope = (GrTypeDefinition)context.scope;
final GrMethod method = getContainingMethod(expression, scope);
LOG.assertTrue(method != null);
final GrOpenBlock block = method.getBlock();
LOG.assertTrue(block != null);
final GrStatement anchor;
if (settings.removeLocalVar()) {
final GrVariable variable = resolveLocalVar(context);
GrVariable variable = resolveLocalVar(context);
anchor = PsiTreeUtil.getParentOfType(variable, GrStatement.class);
}
else {
anchor = (GrStatement)findAnchor(context, settings, context.occurrences, block);
anchor = (GrStatement)findAnchor(context, settings, context.occurrences, method.getBlock());
}
generateAssignment(context, settings, field, anchor, block);
generateAssignment(context, settings, field, anchor, method.getBlock());
}
private static void initializeInConstructor(GrIntroduceContext context, GrIntroduceFieldSettings settings, GrField field) {
@@ -233,8 +233,8 @@ public class GrIntroduceFieldHandler extends GrIntroduceHandlerBase<GrIntroduceF
private static void generateAssignment(GrIntroduceContext context,
GrIntroduceFieldSettings settings,
GrField field,
GrStatement anchor,
final GrOpenBlock block) {
@Nullable GrStatement anchor,
GrCodeBlock defaultContainer) {
final GrExpression initializer;
if (settings.removeLocalVar()) {
initializer = extractVarInitializer(context);
@@ -242,10 +242,20 @@ public class GrIntroduceFieldHandler extends GrIntroduceHandlerBase<GrIntroduceF
else {
initializer = context.expression;
}
GrAssignmentExpression init = ((GrAssignmentExpression)GroovyPsiElementFactory.getInstance(context.project)
.createExpressionFromText(settings.getName() + " = " + initializer.getText()));
GrAssignmentExpression init = (GrAssignmentExpression)GroovyPsiElementFactory.getInstance(context.project)
.createExpressionFromText(settings.getName() + " = " + initializer.getText());
GrCodeBlock block;
if (anchor != null) {
anchor = GroovyRefactoringUtil.addBlockIntoParent(anchor);
LOG.assertTrue(anchor.getParent() instanceof GrCodeBlock);
block = (GrCodeBlock)anchor.getParent();
}
else {
block = defaultContainer;
}
init = (GrAssignmentExpression)block.addStatementBefore(init, anchor);
replaceOccurence(field, init.getLValue());
replaceOccurrence(field, init.getLValue());
}
private static GrExpression extractVarInitializer(GrIntroduceContext context) {
@@ -268,13 +278,13 @@ public class GrIntroduceFieldHandler extends GrIntroduceHandlerBase<GrIntroduceF
return findAnchor(context, settings, ContainerUtil.toArray(elements, new PsiElement[elements.size()]), block);
}
private static void replaceOccurence(GrField field, PsiElement occurence) {
final GrReferenceExpression newExpr = createRefExpression(field, occurence);
private static void replaceOccurrence(GrField field, PsiElement occurrence) {
final GrReferenceExpression newExpr = createRefExpression(field, occurrence);
final PsiElement replaced;
if (occurence instanceof GrExpression) {
replaced = ((GrExpression)occurence).replaceWithExpression(newExpr, false);
if (occurrence instanceof GrExpression) {
replaced = ((GrExpression)occurrence).replaceWithExpression(newExpr, false);
} else {
replaced = occurence.replace(newExpr);
replaced = occurrence.replace(newExpr);
}
if (replaced instanceof GrQualifiedReference) {
GrReferenceAdjuster.shortenReference((GrQualifiedReference)replaced);
@@ -221,9 +221,9 @@ public class GrIntroduceParameterHandler implements RefactoringActionHandler, Me
final PsiElement expr = PsiUtil.skipParentheses(expression, false);
if (expr == null) return PsiElement.EMPTY_ARRAY;
final PsiElement[] occurrences = GroovyRefactoringUtil.getExpressionOccurrences(expr, scope, true);
final PsiElement[] occurrences = GroovyRefactoringUtil.getExpressionOccurrences(expr, scope);
if (occurrences == null || occurrences.length == 0) {
throw new GrIntroduceRefactoringError(GroovyRefactoringBundle.message("no.occurences.found"));
throw new GrIntroduceRefactoringError(GroovyRefactoringBundle.message("no.occurrences.found"));
}
return occurrences;
}
@@ -81,6 +81,10 @@ public class GrIntroduceFieldTest extends LightCodeInsightFixtureTestCase {
public void testAnonymous3() {
doTest(false, false, false, CONSTRUCTOR, false, null);
}
public void testInitializeInCurrentMethod() {
doTest(false, true, true, CUR_METHOD, false, null);
}
private void doTest(final boolean isStatic,
final boolean removeLocal,
@@ -0,0 +1,8 @@
class X {
def foo() {
if (true) {
String i = "5"
ptint <selection>i</selection>
}
}
}
@@ -0,0 +1,10 @@
class X {
final def f
def foo() {
if (true) {
f = "5"
ptint <selection>f</selection>
}
}
}