Introduce field: correct flow for introducing field from variable

This commit is contained in:
Max Medvedev
2013-11-05 09:25:59 +02:00
parent c997b3c872
commit bb97c01677
8 changed files with 259 additions and 206 deletions
@@ -32,10 +32,10 @@ import com.intellij.openapi.editor.colors.EditorColorsManager;
import com.intellij.openapi.editor.markup.RangeHighlighter;
import com.intellij.openapi.editor.markup.TextAttributes;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Pass;
import com.intellij.openapi.util.TextRange;
import com.intellij.openapi.util.*;
import com.intellij.openapi.wm.WindowManager;
import com.intellij.psi.*;
import com.intellij.psi.codeStyle.CodeStyleManager;
import com.intellij.psi.search.LocalSearchScope;
import com.intellij.psi.search.searches.ReferencesSearch;
import com.intellij.psi.util.PsiTreeUtil;
@@ -58,11 +58,13 @@ import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElementFactory;
import org.jetbrains.plugins.groovy.lang.psi.api.GroovyResolveResult;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.*;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.blocks.GrClosableBlock;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.blocks.GrCodeBlock;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.clauses.GrCaseLabel;
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.literals.GrStringInjection;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.params.GrParameter;
import org.jetbrains.plugins.groovy.lang.psi.api.util.GrDeclarationHolder;
import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.TypesUtil;
import org.jetbrains.plugins.groovy.lang.psi.util.GrStringUtil;
import org.jetbrains.plugins.groovy.lang.psi.util.PsiUtil;
@@ -120,6 +122,35 @@ public abstract class GrIntroduceHandlerBase<Settings extends GrIntroduceSetting
}
}
@NotNull
public static GrStatement getAnchor(@NotNull PsiElement[] occurrences, @NotNull PsiElement scope) {
PsiElement parent = PsiTreeUtil.findCommonParent(occurrences);
PsiElement container = getEnclosingContainer(parent);
assert container != null;
PsiElement anchor = findAnchor(occurrences, container);
assertStatement(anchor, scope);
return (GrStatement)anchor;
}
@Nullable
public static PsiElement getEnclosingContainer(PsiElement place) {
PsiElement parent = place;
while (true) {
if (parent == null) {
return null;
}
if (parent instanceof GrDeclarationHolder && !(parent instanceof GrClosableBlock && parent.getParent() instanceof GrStringInjection)) {
return parent;
}
if (parent instanceof GrLoopStatement) {
return parent;
}
parent = parent.getParent();
}
}
@NotNull
protected abstract String getRefactoringName();
@@ -300,6 +331,93 @@ public abstract class GrIntroduceHandlerBase<Settings extends GrIntroduceSetting
}
}
protected void extractStringPart(final Ref<GrIntroduceContext> ref) {
CommandProcessor.getInstance().executeCommand(ref.get().getProject(), new Runnable() {
@Override
public void run() {
ApplicationManager.getApplication().runWriteAction(new Runnable() {
@Override
public void run() {
GrIntroduceContext context = ref.get();
GrExpression expression = cutLiteral(context.getStringPart(), context.getProject());
ref.set(new GrIntroduceContextImpl(context.getProject(), context.getEditor(), expression, null, null, new PsiElement[]{expression}, context.getScope()));
}
});
}
}, getRefactoringName(), getRefactoringName());
}
protected void addBraces(@NotNull final GrStatement anchor, @NotNull final Ref<GrIntroduceContext> contextRef) {
CommandProcessor.getInstance().executeCommand(contextRef.get().getProject(), new Runnable() {
@Override
public void run() {
ApplicationManager.getApplication().runWriteAction(new Runnable() {
@Override
public void run() {
GrIntroduceContext context = contextRef.get();
SmartPointerManager pointManager = SmartPointerManager.getInstance(context.getProject());
SmartPsiElementPointer<GrExpression> expressionRef = context.getExpression() != null ? pointManager.createSmartPsiElementPointer(context.getExpression()) : null;
SmartPsiElementPointer<GrVariable> varRef = context.getVar() != null ? pointManager.createSmartPsiElementPointer(context.getVar()) : null;
SmartPsiElementPointer[] occurrencesRefs = new SmartPsiElementPointer[context.getOccurrences().length];
PsiElement[] occurrences = context.getOccurrences();
for (int i = 0; i < occurrences.length; i++) {
occurrencesRefs[i] = pointManager.createSmartPsiElementPointer(occurrences[i]);
}
PsiFile file = anchor.getContainingFile();
SmartPsiFileRange anchorPointer = pointManager.createSmartPsiFileRangePointer(file, anchor.getTextRange());
Document document = context.getEditor().getDocument();
CharSequence sequence = document.getCharsSequence();
TextRange range = anchor.getTextRange();
int end = range.getEndOffset();
document.insertString(end, "\n}");
int start = range.getStartOffset();
while (start > 0 && Character.isWhitespace(sequence.charAt(start - 1))) {
start--;
}
document.insertString(start, "{");
PsiDocumentManager.getInstance(context.getProject()).commitDocument(document);
Segment anchorSegment = anchorPointer.getRange();
PsiElement restoredAnchor = GroovyRefactoringUtil.findElementInRange(file, anchorSegment.getStartOffset(), anchorSegment.getEndOffset(), PsiElement.class);
GrCodeBlock block = (GrCodeBlock)restoredAnchor.getParent();
CodeStyleManager.getInstance(context.getProject()).reformat(block.getRBrace());
CodeStyleManager.getInstance(context.getProject()).reformat(block.getLBrace());
for (int i = 0; i < occurrencesRefs.length; i++) {
occurrences[i] = occurrencesRefs[i].getElement();
}
contextRef.set(new GrIntroduceContextImpl(context.getProject(), context.getEditor(),
expressionRef != null ? expressionRef.getElement() : null,
varRef != null ? varRef.getElement() : null,
null, occurrences, context.getScope()));
}
});
}
}, getRefactoringName(), getRefactoringName());
}
@NotNull
protected static GrStatement findAnchor(@NotNull final GrIntroduceContext context, final boolean replaceAll) {
return ApplicationManager.getApplication().runReadAction(new Computable<GrStatement>() {
@Override
public GrStatement compute() {
PsiElement[] occurrences = replaceAll ? context.getOccurrences() : new GrExpression[]{context.getExpression()};
return getAnchor(occurrences, context.getScope());
}
});
}
protected abstract void showScopeChooser(Scope[] scopes, Pass<Scope> callback, Editor editor);
public GrIntroduceContext getContext(@NotNull Project project,
@@ -613,17 +731,15 @@ public abstract class GrIntroduceHandlerBase<Settings extends GrIntroduceSetting
return candidate;
}
public static void deleteLocalVar(@NotNull GrIntroduceContext context) {
final GrVariable resolved = resolveLocalVar(context);
final PsiElement parent = resolved.getParent();
public static void deleteLocalVar(GrVariable var) {
final PsiElement parent = var.getParent();
if (((GrVariableDeclaration)parent).getVariables().length == 1) {
parent.delete();
}
else {
GrExpression initializer = resolved.getInitializerGroovy();
GrExpression initializer = var.getInitializerGroovy();
if (initializer != null) initializer.delete(); //don't special check for tuple, but this line is for the tuple case
resolved.delete();
var.delete();
}
}
@@ -73,7 +73,7 @@ public class GrIntroduceConstantProcessor {
final GrField field = (GrField)declaration.getVariables()[0];
if (context.getVar() != null) {
deleteLocalVar(context);
deleteLocalVar(context.getVar());
}
if (context.getStringPart() != null) {
@@ -16,6 +16,7 @@
package org.jetbrains.plugins.groovy.refactoring.introduce.field;
import com.intellij.codeInsight.TestFrameworks;
import com.intellij.openapi.util.Ref;
import com.intellij.psi.PsiClass;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiModifier;
@@ -103,7 +104,14 @@ public class GrIntroduceFieldHandler extends GrIntroduceFieldHandlerBase<GrIntro
@Override
protected GrAbstractInplaceIntroducer<GrIntroduceFieldSettings> getIntroducer(@NotNull GrIntroduceContext context,
OccurrencesChooser.ReplaceChoice choice) {
return new GrInplaceFieldIntroducer(context, choice);
final Ref<GrIntroduceContext> contextRef = Ref.create(context);
if (context.getStringPart() != null) {
extractStringPart(contextRef);
}
return new GrInplaceFieldIntroducer(contextRef.get(), choice);
}
static EnumSet<GrIntroduceFieldSettings.Init> getApplicableInitPlaces(GrIntroduceContext context, boolean replaceAll) {
@@ -54,6 +54,7 @@ import org.jetbrains.plugins.groovy.refactoring.introduce.GrIntroduceContext;
import org.jetbrains.plugins.groovy.refactoring.introduce.GrIntroduceHandlerBase;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
@@ -62,29 +63,39 @@ import java.util.List;
public class GrIntroduceFieldProcessor {
private static final Logger LOG = Logger.getInstance(GrIntroduceFieldProcessor.class);
private final GrIntroduceContext context;
private final GrIntroduceFieldSettings settings;
private final GrIntroduceContext myContext;
private final GrIntroduceFieldSettings mySettings;
private GrExpression myInitializer;
private GrVariable myLocalVariable;
public GrIntroduceFieldProcessor(@NotNull GrIntroduceContext context,
@NotNull GrIntroduceFieldSettings settings) {
this.context = context;
this.settings = settings;
this.myContext = context;
this.mySettings = settings;
}
@Nullable
public GrVariable run() {
PsiElement scope = context.getScope();
PsiElement scope = myContext.getScope();
final PsiClass targetClass = scope instanceof GroovyFileBase ? ((GroovyFileBase)scope).getScriptClass() : (PsiClass)scope;
if (targetClass == null) return null;
final GrVariableDeclaration declaration = insertField(targetClass);
final GrVariable field = declaration.getVariables()[0];
switch (settings.initializeIn()) {
if (mySettings.removeLocalVar()) {
myLocalVariable = GrIntroduceHandlerBase.resolveLocalVar(myContext);
}
myInitializer = (GrExpression)getInitializer().copy();
List<PsiElement> replaced = processOccurrences(targetClass, field);
switch (mySettings.initializeIn()) {
case CUR_METHOD:
initializeInMethod(field);
initializeInMethod(field, replaced);
break;
case FIELD_DECLARATION:
field.setInitializerGroovy(getInitializer());
field.setInitializerGroovy(myInitializer);
break;
case CONSTRUCTOR:
initializeInConstructor(field);
@@ -96,44 +107,46 @@ public class GrIntroduceFieldProcessor {
JavaCodeStyleManager.getInstance(declaration.getProject()).shortenClassReferences(declaration);
if (settings.removeLocalVar()) {
GrIntroduceHandlerBase.deleteLocalVar(context);
if (mySettings.removeLocalVar()) {
GrIntroduceHandlerBase.deleteLocalVar(myLocalVariable);
}
processOccurrences(targetClass, field);
return field;
}
private void processOccurrences(@NotNull PsiClass targetClass, @NotNull GrVariable field) {
if (context.getStringPart() != null) {
final GrExpression expr = GrIntroduceHandlerBase.processLiteral(field.getName(), context.getStringPart(), context.getProject());
@NotNull
private List<PsiElement> processOccurrences(@NotNull PsiClass targetClass, @NotNull GrVariable field) {
if (myContext.getStringPart() != null) {
final GrExpression expr = GrIntroduceHandlerBase.processLiteral(field.getName(), myContext.getStringPart(), myContext.getProject());
final PsiElement occurrence = replaceOccurrence(field, expr, targetClass);
updateCaretPosition(occurrence);
return Collections.singletonList(occurrence);
}
else {
if (settings.replaceAllOccurrences()) {
GroovyRefactoringUtil.sortOccurrences(context.getOccurrences());
for (PsiElement occurrence : context.getOccurrences()) {
replaceOccurrence(field, occurrence, targetClass);
if (mySettings.replaceAllOccurrences()) {
GroovyRefactoringUtil.sortOccurrences(myContext.getOccurrences());
ArrayList<PsiElement> result = ContainerUtil.newArrayList();
for (PsiElement occurrence : myContext.getOccurrences()) {
result.add(replaceOccurrence(field, occurrence, targetClass));
}
return result;
}
else {
final GrExpression expression = context.getExpression();
final GrExpression expression = myContext.getExpression();
assert expression != null;
if (PsiUtil.isExpressionStatement(expression)) {
expression.delete();
return Collections.<PsiElement>singletonList(expression);
}
else {
replaceOccurrence(field, expression, targetClass);
return Collections.singletonList(replaceOccurrence(field, expression, targetClass));
}
}
}
}
private void updateCaretPosition(PsiElement occurrence) {
context.getEditor().getCaretModel().moveToOffset(occurrence.getTextRange().getEndOffset());
context.getEditor().getSelectionModel().removeSelection();
private void updateCaretPosition(@NotNull PsiElement occurrence) {
myContext.getEditor().getCaretModel().moveToOffset(occurrence.getTextRange().getEndOffset());
myContext.getEditor().getSelectionModel().removeSelection();
}
@NotNull
@@ -172,20 +185,20 @@ public class GrIntroduceFieldProcessor {
return anchor;
}
void initializeInSetup(GrVariable field) {
final PsiMethod setUpMethod = TestFrameworks.getInstance().findOrCreateSetUpMethod(((PsiClass)context.getScope()));
void initializeInSetup(@NotNull GrVariable field) {
final PsiMethod setUpMethod = TestFrameworks.getInstance().findOrCreateSetUpMethod(((PsiClass)myContext.getScope()));
assert setUpMethod instanceof GrMethod;
final GrOpenBlock body = ((GrMethod)setUpMethod).getBlock();
final PsiElement anchor = findAnchorForAssignment(body);
generateAssignment(field, (GrStatement)anchor, body);
generateAssignment(field, (GrStatement)anchor, body, null);
}
void initializeInMethod(GrVariable field) {
final PsiElement _scope = context.getScope();
void initializeInMethod(@NotNull GrVariable field, @NotNull List<PsiElement> replaced) {
final PsiElement _scope = myContext.getScope();
final PsiElement scope = _scope instanceof GroovyScriptClass ? ((GroovyScriptClass)_scope).getContainingFile() : _scope;
final PsiElement place = context.getPlace();
final PsiElement place = replaced.get(0);
final GrMember member = GrIntroduceFieldHandler.getContainer(place, scope);
GrStatementOwner container = member instanceof GrMethod ? ((GrMethod)member).getBlock() :
@@ -195,21 +208,31 @@ public class GrIntroduceFieldProcessor {
assert container != null;
final PsiElement anchor;
if (settings.removeLocalVar()) {
GrVariable variable = GrIntroduceHandlerBase.resolveLocalVar(context);
if (mySettings.removeLocalVar()) {
GrVariable variable = myLocalVariable;
anchor = PsiTreeUtil.getParentOfType(variable, GrStatement.class);
}
else {
anchor = GrIntroduceHandlerBase.findAnchor(context.getOccurrences(), container);
GrIntroduceHandlerBase.assertStatement(anchor, context.getScope());
anchor = GrIntroduceHandlerBase.findAnchor(replaced.toArray(new PsiElement[replaced.size()]), container);
GrIntroduceHandlerBase.assertStatement(anchor, myContext.getScope());
}
generateAssignment(field, (GrStatement)anchor, container);
PsiElement occurrence = replaced.get(0);
if (!mySettings.replaceAllOccurrences() && !isRefToField(occurrence, field) && PsiUtil.isExpressionStatement(occurrence)) {
generateAssignment(field, (GrStatement)anchor, container, occurrence);
}
else {
generateAssignment(field, (GrStatement)anchor, container, null);
}
}
private static boolean isRefToField(@NotNull PsiElement occurrence, @NotNull PsiElement field) {
return occurrence instanceof GrReferenceExpression && ((GrReferenceExpression)occurrence).resolve() == field;
}
void initializeInConstructor(@NotNull GrVariable field) {
final PsiClass scope = (PsiClass)context.getScope();
final PsiClass scope = (PsiClass)myContext.getScope();
if (scope instanceof GrAnonymousClassDefinition) {
initializeInAnonymousClassInitializer(field, (GrAnonymousClassDefinition)scope);
@@ -230,7 +253,7 @@ public class GrIntroduceFieldProcessor {
if (invocation != null && invocation.isThisCall()) continue;
final PsiElement anchor = findAnchorForAssignment(((GrMethod)constructor).getBlock());
generateAssignment(field, (GrStatement)anchor, ((GrMethod)constructor).getBlock());
generateAssignment(field, (GrStatement)anchor, ((GrMethod)constructor).getBlock(), null);
}
}
@@ -238,7 +261,7 @@ public class GrIntroduceFieldProcessor {
private PsiMethod generateConstructor(@NotNull PsiClass scope) {
final String name = scope.getName();
LOG.assertTrue(name != null, scope.getText());
GroovyPsiElementFactory factory = GroovyPsiElementFactory.getInstance(context.getProject());
GroovyPsiElementFactory factory = GroovyPsiElementFactory.getInstance(myContext.getProject());
final GrMethod
constructor = factory.createConstructorFromText(name, ArrayUtil.EMPTY_STRING_ARRAY, ArrayUtil.EMPTY_STRING_ARRAY, "{}", scope);
if (scope instanceof GroovyScriptClass) constructor.getModifierList().setModifierProperty(GrModifier.DEF, true);
@@ -247,20 +270,21 @@ public class GrIntroduceFieldProcessor {
private void initializeInAnonymousClassInitializer(@NotNull GrVariable field, @NotNull GrAnonymousClassDefinition scope) {
final GrClassInitializer[] initializers = scope.getInitializers();
GroovyPsiElementFactory factory = GroovyPsiElementFactory.getInstance(context.getProject());
GroovyPsiElementFactory factory = GroovyPsiElementFactory.getInstance(myContext.getProject());
final GrClassInitializer initializer = initializers.length == 0 ? (GrClassInitializer)scope.add(factory.createClassInitializer())
: initializers[0];
final PsiElement anchor = findAnchorForAssignment(initializer.getBlock());
generateAssignment(field, (GrStatement)anchor, initializer.getBlock());
generateAssignment(field, (GrStatement)anchor, initializer.getBlock(), null);
}
private void generateAssignment(GrVariable field,
private void generateAssignment(@NotNull GrVariable field,
@Nullable GrStatement anchor,
GrStatementOwner defaultContainer) {
final GrExpression initializer = getInitializer();
GrAssignmentExpression init = (GrAssignmentExpression)GroovyPsiElementFactory.getInstance(context.getProject())
.createExpressionFromText(settings.getName() + " = " + initializer.getText());
@NotNull GrStatementOwner defaultContainer,
@Nullable PsiElement occurrenceToDelete) {
final GrExpression initializer = myInitializer;
GrAssignmentExpression init = (GrAssignmentExpression)GroovyPsiElementFactory.getInstance(myContext.getProject())
.createExpressionFromText(mySettings.getName() + " = " + initializer.getText());
GrStatementOwner block;
if (anchor != null) {
@@ -273,19 +297,24 @@ public class GrIntroduceFieldProcessor {
}
init = (GrAssignmentExpression)block.addStatementBefore(init, anchor);
replaceOccurrence(field, init.getLValue(), (PsiClass)context.getScope());
replaceOccurrence(field, init.getLValue(), (PsiClass)myContext.getScope());
if (occurrenceToDelete != null) {
occurrenceToDelete.delete();
}
}
@NotNull
private GrExpression extractVarInitializer() {
final PsiElement resolved = GrIntroduceHandlerBase.resolveLocalVar(context);
GrExpression initializer = ((GrVariable)resolved).getInitializerGroovy();
assert myLocalVariable != null;
GrExpression initializer = myLocalVariable.getInitializerGroovy();
LOG.assertTrue(initializer != null);
return initializer;
}
@Nullable
private PsiElement findAnchorForAssignment(final GrCodeBlock block) {
final List<PsiElement> elements = ContainerUtil.findAll(context.getOccurrences(), new Condition<PsiElement>() {
final List<PsiElement> elements = ContainerUtil.findAll(myContext.getOccurrences(), new Condition<PsiElement>() {
@Override
public boolean value(PsiElement element) {
return PsiTreeUtil.isAncestor(block, element, true);
@@ -295,8 +324,9 @@ public class GrIntroduceFieldProcessor {
return GrIntroduceHandlerBase.findAnchor(ContainerUtil.toArray(elements, new PsiElement[elements.size()]), block);
}
private PsiElement replaceOccurrence(GrVariable field, PsiElement occurrence, PsiClass containingClass) {
boolean isOriginal = occurrence == context.getExpression();
@NotNull
private PsiElement replaceOccurrence(@NotNull GrVariable field, @NotNull PsiElement occurrence, @NotNull PsiClass containingClass) {
boolean isOriginal = occurrence == myContext.getExpression();
final GrReferenceExpression newExpr = createRefExpression(field, occurrence, containingClass);
final PsiElement replaced;
if (occurrence instanceof GrExpression) {
@@ -315,7 +345,10 @@ public class GrIntroduceFieldProcessor {
return replaced;
}
private static GrReferenceExpression createRefExpression(GrVariable field, PsiElement place, PsiClass containingClass) {
@NotNull
private static GrReferenceExpression createRefExpression(@NotNull GrVariable field,
@NotNull PsiElement place,
@NotNull PsiClass containingClass) {
final String qname = containingClass.getQualifiedName();
final String prefix = qname != null ? qname + "." : "";
final String refText;
@@ -329,21 +362,22 @@ public class GrIntroduceFieldProcessor {
return GroovyPsiElementFactory.getInstance(place.getProject()).createReferenceExpressionFromText(refText, place);
}
private GrVariableDeclaration createField(PsiClass targetClass) {
final String name = settings.getName();
final PsiType type = settings.getSelectedType();
final String modifier = settings.getVisibilityModifier();
@NotNull
private GrVariableDeclaration createField(@NotNull PsiClass targetClass) {
final String name = mySettings.getName();
final PsiType type = mySettings.getSelectedType();
final String modifier = mySettings.getVisibilityModifier();
List<String> modifiers = new ArrayList<String>();
if (targetClass instanceof GroovyScriptClass) {
modifiers.add("@" + GroovyCommonClassNames.GROOVY_TRANSFORM_FIELD);
}
if (settings.isStatic()) modifiers.add(PsiModifier.STATIC);
if (mySettings.isStatic()) modifiers.add(PsiModifier.STATIC);
if (!PsiModifier.PACKAGE_LOCAL.equals(modifier)) modifiers.add(modifier);
if (settings.declareFinal()) modifiers.add(PsiModifier.FINAL);
if (mySettings.declareFinal()) modifiers.add(PsiModifier.FINAL);
final String[] arr_modifiers = ArrayUtil.toStringArray(modifiers);
final GroovyPsiElementFactory factory = GroovyPsiElementFactory.getInstance(context.getProject());
final GroovyPsiElementFactory factory = GroovyPsiElementFactory.getInstance(myContext.getProject());
if (targetClass instanceof GroovyScriptClass) {
return factory.createVariableDeclaration(arr_modifiers, ((GrExpression)null), type, name);
}
@@ -354,17 +388,17 @@ public class GrIntroduceFieldProcessor {
@NotNull
protected GrExpression getInitializer() {
if (settings.removeLocalVar()) {
if (mySettings.removeLocalVar()) {
return extractVarInitializer();
}
final GrExpression expression = context.getExpression();
final GrExpression expression = myContext.getExpression();
if (expression != null) {
return expression;
}
return GrIntroduceHandlerBase.generateExpressionFromStringPart(context.getStringPart(), context.getProject());
return GrIntroduceHandlerBase.generateExpressionFromStringPart(myContext.getStringPart(), myContext.getProject());
}
}
@@ -19,7 +19,6 @@ import com.intellij.openapi.diagnostic.Logger;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiReference;
import com.intellij.psi.codeStyle.JavaCodeStyleManager;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.psi.util.PsiUtilCore;
import com.intellij.refactoring.util.RefactoringUtil;
import com.intellij.util.ArrayUtilRt;
@@ -34,7 +33,6 @@ import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpres
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrReferenceExpression;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.literals.GrStringInjection;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrAccessorMethod;
import org.jetbrains.plugins.groovy.lang.psi.api.util.GrDeclarationHolder;
import org.jetbrains.plugins.groovy.lang.psi.api.util.GrStatementOwner;
import org.jetbrains.plugins.groovy.lang.psi.util.PsiUtil;
import org.jetbrains.plugins.groovy.refactoring.GroovyRefactoringUtil;
@@ -77,7 +75,7 @@ public abstract class GrIntroduceLocalVariableProcessor {
int expressionIndex = ArrayUtilRt.find(myOccurrences, myExpression);
final PsiElement[] replaced = myProcessUsages ? processOccurrences() : myOccurrences;
PsiElement replacedExpression = replaced[expressionIndex];
GrStatement anchor = getAnchor(replaced, myContext.getScope());
GrStatement anchor = GrIntroduceHandlerBase.getAnchor(replaced, myContext.getScope());
RefactoringUtil.highlightAllOccurrences(myContext.getProject(), replaced, myContext.getEditor());
@@ -193,36 +191,6 @@ public abstract class GrIntroduceLocalVariableProcessor {
return parent instanceof GrClosableBlock && parent.getParent() instanceof GrStringInjection;
}
@NotNull
static GrStatement getAnchor(@NotNull PsiElement[] occurrences, @NotNull PsiElement scope) {
PsiElement parent = PsiTreeUtil.findCommonParent(occurrences);
PsiElement container = getEnclosingContainer(parent);
assert container != null;
PsiElement anchor = GrIntroduceHandlerBase.findAnchor(occurrences, container);
GrIntroduceHandlerBase.assertStatement(anchor, scope);
return (GrStatement)anchor;
}
@Nullable
public static PsiElement getEnclosingContainer(PsiElement place) {
PsiElement parent = place;
while (true) {
if (parent == null) {
return null;
}
if (parent instanceof GrDeclarationHolder && !(parent instanceof GrClosableBlock && parent.getParent() instanceof GrStringInjection)) {
return parent;
}
if (parent instanceof GrLoopStatement) {
return parent;
}
parent = parent.getParent();
}
}
@Nullable
private static String getFieldName(@Nullable PsiElement element) {
if (element instanceof GrAccessorMethod) element = ((GrAccessorMethod)element).getProperty();
@@ -15,14 +15,12 @@
*/
package org.jetbrains.plugins.groovy.refactoring.introduce.variable;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.command.CommandProcessor;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.editor.RangeMarker;
import com.intellij.openapi.util.*;
import com.intellij.psi.*;
import com.intellij.psi.codeStyle.CodeStyleManager;
import com.intellij.openapi.util.Pass;
import com.intellij.openapi.util.Ref;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiModifier;
import com.intellij.refactoring.HelpID;
import com.intellij.refactoring.introduce.inplace.OccurrencesChooser;
import org.jetbrains.annotations.NotNull;
@@ -36,7 +34,6 @@ import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrStatement;
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.blocks.GrClosableBlock;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.blocks.GrCodeBlock;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpression;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.params.GrParameter;
import org.jetbrains.plugins.groovy.lang.psi.api.util.GrStatementOwner;
@@ -44,7 +41,6 @@ import org.jetbrains.plugins.groovy.refactoring.GrRefactoringError;
import org.jetbrains.plugins.groovy.refactoring.GroovyRefactoringBundle;
import org.jetbrains.plugins.groovy.refactoring.GroovyRefactoringUtil;
import org.jetbrains.plugins.groovy.refactoring.introduce.GrIntroduceContext;
import org.jetbrains.plugins.groovy.refactoring.introduce.GrIntroduceContextImpl;
import org.jetbrains.plugins.groovy.refactoring.introduce.GrIntroduceHandlerBase;
import org.jetbrains.plugins.groovy.refactoring.introduce.StringPartInfo;
@@ -153,9 +149,6 @@ public class GrIntroduceVariableHandler extends GrIntroduceHandlerBase<GroovyInt
addBraces(anchor, contextRef);
}
return new GrInplaceVariableIntroducer(getRefactoringName(), choice, contextRef.get()) {
@Override
protected GrVariable runRefactoring(GrIntroduceContext context, GroovyIntroduceVariableSettings settings, boolean processUsages) {
@@ -169,82 +162,6 @@ public class GrIntroduceVariableHandler extends GrIntroduceHandlerBase<GroovyInt
};
}
private static void extractStringPart(final Ref<GrIntroduceContext> ref) {
CommandProcessor.getInstance().executeCommand(ref.get().getProject(), new Runnable() {
@Override
public void run() {
ApplicationManager.getApplication().runWriteAction(new Runnable() {
@Override
public void run() {
GrIntroduceContext context = ref.get();
GrExpression expression = cutLiteral(context.getStringPart(), context.getProject());
ref.set(new GrIntroduceContextImpl(context.getProject(), context.getEditor(), expression, null, null, new PsiElement[]{expression}, context.getScope()));
}
});
}
}, REFACTORING_NAME, REFACTORING_NAME);
}
private static void addBraces(@NotNull final GrStatement anchor, @NotNull final Ref<GrIntroduceContext> contextRef) {
CommandProcessor.getInstance().executeCommand(contextRef.get().getProject(), new Runnable() {
@Override
public void run() {
ApplicationManager.getApplication().runWriteAction(new Runnable() {
@Override
public void run() {
GrIntroduceContext context = contextRef.get();
SmartPointerManager pointManager = SmartPointerManager.getInstance(context.getProject());
SmartPsiElementPointer<GrExpression> expressionRef = context.getExpression() != null ? pointManager.createSmartPsiElementPointer(context.getExpression()) : null;
SmartPsiElementPointer<GrVariable> varRef = context.getVar() != null ? pointManager.createSmartPsiElementPointer(context.getVar()) : null;
SmartPsiElementPointer[] occurrencesRefs = new SmartPsiElementPointer[context.getOccurrences().length];
PsiElement[] occurrences = context.getOccurrences();
for (int i = 0; i < occurrences.length; i++) {
occurrencesRefs[i] = pointManager.createSmartPsiElementPointer(occurrences[i]);
}
PsiFile file = anchor.getContainingFile();
SmartPsiFileRange anchorPointer = pointManager.createSmartPsiFileRangePointer(file, anchor.getTextRange());
Document document = context.getEditor().getDocument();
CharSequence sequence = document.getCharsSequence();
TextRange range = anchor.getTextRange();
int end = range.getEndOffset();
document.insertString(end, "\n}");
int start = range.getStartOffset();
while (start > 0 && Character.isWhitespace(sequence.charAt(start - 1))) {
start--;
}
document.insertString(start, "{");
PsiDocumentManager.getInstance(context.getProject()).commitDocument(document);
Segment anchorSegment = anchorPointer.getRange();
PsiElement restoredAnchor = GroovyRefactoringUtil.findElementInRange(file, anchorSegment.getStartOffset(), anchorSegment.getEndOffset(), PsiElement.class);
GrCodeBlock block = (GrCodeBlock)restoredAnchor.getParent();
CodeStyleManager.getInstance(context.getProject()).reformat(block.getRBrace());
CodeStyleManager.getInstance(context.getProject()).reformat(block.getLBrace());
for (int i = 0; i < occurrencesRefs.length; i++) {
occurrences[i] = occurrencesRefs[i].getElement();
}
contextRef.set(new GrIntroduceContextImpl(context.getProject(), context.getEditor(),
expressionRef != null ? expressionRef.getElement() : null,
varRef != null ? varRef.getElement() : null,
null, occurrences, context.getScope()));
}
});
}
}, REFACTORING_NAME, REFACTORING_NAME);
}
private static GrVariable addVariable(@NotNull GrIntroduceContext context, @NotNull GroovyIntroduceVariableSettings settings) {
GrStatement anchor = findAnchor(context, settings.replaceAllOccurrences());
PsiElement parent = anchor.getParent();
@@ -254,17 +171,6 @@ public class GrIntroduceVariableHandler extends GrIntroduceHandlerBase<GroovyInt
return ((GrVariableDeclaration)declaration).getVariables()[0];
}
@NotNull
private static GrStatement findAnchor(@NotNull final GrIntroduceContext context, final boolean replaceAll) {
return ApplicationManager.getApplication().runReadAction(new Computable<GrStatement>() {
@Override
public GrStatement compute() {
PsiElement[] occurrences = replaceAll ? context.getOccurrences() : new GrExpression[]{context.getExpression()};
return GrIntroduceLocalVariableProcessor.getAnchor(occurrences, context.getScope());
}
});
}
@Override
protected void showScopeChooser(GrControlFlowOwner[] scopes, Pass<GrControlFlowOwner> callback, Editor editor) {
//todo do nothing right now
@@ -307,6 +307,27 @@ class GroovyLightProjectDescriptor {
''', false, false, false, CUR_METHOD)
}
void testInitializeInMethodInThenBranch() {
doTest('''\
class A {
def foo() {
if (abc) print <selection>2</selection>
}
}
''', '''\
class A {
def f
def foo() {
if (abc) {
f = 2
print f
}
}
}
''', false, false, false, CUR_METHOD, false, null)
}
private void doTest(final boolean isStatic,
final boolean removeLocal,
@@ -29,7 +29,7 @@ import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpres
import org.jetbrains.plugins.groovy.lang.psi.util.PsiUtil;
import org.jetbrains.plugins.groovy.refactoring.GroovyRefactoringUtil;
import org.jetbrains.plugins.groovy.refactoring.introduce.GrIntroduceContextImpl;
import org.jetbrains.plugins.groovy.refactoring.introduce.variable.GrIntroduceLocalVariableProcessor;
import org.jetbrains.plugins.groovy.refactoring.introduce.GrIntroduceHandlerBase;
import org.jetbrains.plugins.groovy.refactoring.introduce.variable.GroovyVariableValidator;
import org.jetbrains.plugins.groovy.util.TestUtils;
@@ -84,7 +84,7 @@ public class IntroduceVariableValidatorTest extends LightCodeInsightFixtureTestC
Assert.assertNotNull("Selected expression reference points to null", selectedExpr);
final PsiElement tempContainer = GrIntroduceLocalVariableProcessor.getEnclosingContainer(selectedExpr);
final PsiElement tempContainer = GrIntroduceHandlerBase.getEnclosingContainer(selectedExpr);
Assert.assertTrue(tempContainer instanceof GroovyPsiElement);
PsiElement[] occurences = GroovyRefactoringUtil.getExpressionOccurrences(PsiUtil.skipParentheses(selectedExpr, false), tempContainer);