mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
Extract variable to chained method call
This commit is contained in:
+2
-3
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2000-2016 JetBrains s.r.o.
|
||||
* Copyright 2000-2017 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -21,7 +21,6 @@ import com.intellij.openapi.project.Project;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiExpression;
|
||||
import com.intellij.psi.PsiType;
|
||||
import com.intellij.refactoring.introduce.inplace.OccurrencesChooser;
|
||||
import com.intellij.refactoring.introduceVariable.InputValidator;
|
||||
import com.intellij.refactoring.introduceVariable.IntroduceVariableHandler;
|
||||
import com.intellij.refactoring.introduceVariable.IntroduceVariableSettings;
|
||||
@@ -53,7 +52,7 @@ public class IntroduceVariablePostfixTemplate extends PostfixTemplateWithExpress
|
||||
public final IntroduceVariableSettings getSettings(Project project, Editor editor, final PsiExpression expr,
|
||||
PsiExpression[] occurrences, TypeSelectorManagerImpl typeSelectorManager,
|
||||
boolean declareFinalIfAll, boolean anyAssignmentLHS, InputValidator validator,
|
||||
PsiElement anchor, OccurrencesChooser.ReplaceChoice replaceChoice) {
|
||||
PsiElement anchor, JavaReplaceChoice replaceChoice) {
|
||||
return new IntroduceVariableSettings() {
|
||||
@Override
|
||||
public String getEnteredName() {
|
||||
|
||||
+85
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
* Copyright 2000-2017 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.intellij.refactoring.introduceVariable;
|
||||
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.Computable;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.refactoring.chainCall.ChainCallExtractor;
|
||||
import com.intellij.refactoring.ui.TypeSelectorManagerImpl;
|
||||
import com.intellij.util.ArrayUtil;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
/**
|
||||
* @author Tagir Valeev
|
||||
*/
|
||||
public class ChainCallInplaceIntroducer extends JavaVariableInplaceIntroducer {
|
||||
private PsiParameter myParameter;
|
||||
private PsiMethodCallExpression myCall;
|
||||
|
||||
public ChainCallInplaceIntroducer(Project project,
|
||||
IntroduceVariableSettings settings,
|
||||
PsiElement chosenAnchor,
|
||||
Editor editor,
|
||||
PsiExpression expr,
|
||||
PsiExpression[] occurrences,
|
||||
TypeSelectorManagerImpl selectorManager,
|
||||
String title) {
|
||||
super(project, settings, chosenAnchor, editor, expr, true, occurrences, selectorManager, title);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
protected PsiVariable getVariable() {
|
||||
if (myParameter != null && myParameter.isValid()) {
|
||||
return myParameter;
|
||||
}
|
||||
return super.getVariable();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
protected PsiElement checkLocalScope() {
|
||||
return myCall;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
protected PsiVariable introduceVariable() {
|
||||
PsiVariable variable = super.introduceVariable();
|
||||
if (variable instanceof PsiLocalVariable) {
|
||||
PsiLambdaExpression lambda = ApplicationManager.getApplication().runWriteAction(
|
||||
(Computable<PsiLambdaExpression>)() -> ChainCallExtractor.extractMappingStep(myProject, (PsiLocalVariable)variable));
|
||||
if (lambda != null) {
|
||||
PsiParameter parameter = ArrayUtil.getFirstElement(lambda.getParameterList().getParameters());
|
||||
myParameter = parameter;
|
||||
myCall = PsiTreeUtil.getParentOfType(lambda, PsiMethodCallExpression.class);
|
||||
myExprMarker = null;
|
||||
myExpr = null;
|
||||
setAdvertisementText(null);
|
||||
PsiDocumentManager.getInstance(myProject).doPostponedOperationsAndUnblockDocument(myEditor.getDocument());
|
||||
return parameter;
|
||||
}
|
||||
else if (!variable.isValid()) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return variable;
|
||||
}
|
||||
}
|
||||
+108
-27
@@ -54,8 +54,10 @@ import com.intellij.psi.impl.source.jsp.jspJava.JspCodeBlock;
|
||||
import com.intellij.psi.impl.source.jsp.jspJava.JspHolderMethod;
|
||||
import com.intellij.psi.impl.source.tree.injected.InjectedLanguageUtil;
|
||||
import com.intellij.psi.impl.source.tree.java.ReplaceExpressionUtil;
|
||||
import com.intellij.psi.search.searches.ReferencesSearch;
|
||||
import com.intellij.psi.util.*;
|
||||
import com.intellij.refactoring.*;
|
||||
import com.intellij.refactoring.chainCall.ChainCallExtractor;
|
||||
import com.intellij.refactoring.introduce.inplace.AbstractInplaceIntroducer;
|
||||
import com.intellij.refactoring.introduce.inplace.OccurrencesChooser;
|
||||
import com.intellij.refactoring.introduceField.ElementToWorkOn;
|
||||
@@ -70,12 +72,14 @@ import com.intellij.refactoring.util.occurrences.ExpressionOccurrenceManager;
|
||||
import com.intellij.refactoring.util.occurrences.NotInSuperCallOccurrenceFilter;
|
||||
import com.intellij.util.ArrayUtilRt;
|
||||
import com.intellij.util.IncorrectOperationException;
|
||||
import com.intellij.util.Processor;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import com.intellij.util.containers.MultiMap;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.text.MessageFormat;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
@@ -83,6 +87,37 @@ import java.util.*;
|
||||
* Date: Nov 15, 2002
|
||||
*/
|
||||
public abstract class IntroduceVariableBase extends IntroduceHandlerBase {
|
||||
public enum JavaReplaceChoice implements OccurrencesChooser.BaseReplaceChoice {
|
||||
NO("Replace this occurrence only"), NO_WRITE("Replace all occurrences but write"), ALL("Replace all {0} occurrences"),
|
||||
NO_CHAIN("Create variable inside current lambda"), CHAIN("Extract as separate step"),
|
||||
CHAIN_ALL("Replace all {0} occurrences and extract as separate step");
|
||||
|
||||
private final String myDescription;
|
||||
|
||||
JavaReplaceChoice(String description) {
|
||||
myDescription = description;
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
return myDescription;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isMultiple() {
|
||||
return this == NO_WRITE || this == ALL || this == CHAIN_ALL;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAll() {
|
||||
return this == ALL || this == CHAIN_ALL;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String formatDescription(int occurrencesCount) {
|
||||
return MessageFormat.format(getDescription(), occurrencesCount);
|
||||
}
|
||||
}
|
||||
|
||||
private static final Logger LOG = Logger.getInstance("#com.intellij.refactoring.introduceVariable.IntroduceVariableBase");
|
||||
@NonNls private static final String PREFER_STATEMENTS_OPTION = "introduce.variable.prefer.statements";
|
||||
@NonNls private static final String REFACTORING_ID = "refactoring.extractVariable";
|
||||
@@ -610,20 +645,20 @@ public abstract class IntroduceVariableBase extends IntroduceHandlerBase {
|
||||
|
||||
if (!CommonRefactoringUtil.checkReadOnlyStatus(project, file)) return false;
|
||||
|
||||
final LinkedHashMap<OccurrencesChooser.ReplaceChoice, List<PsiExpression>> occurrencesMap = occurrencesInfo.buildOccurrencesMap(expr);
|
||||
final LinkedHashMap<JavaReplaceChoice, List<PsiExpression>> occurrencesMap = occurrencesInfo.buildOccurrencesMap(expr);
|
||||
|
||||
final boolean inFinalContext = occurrenceManager.isInFinalContext();
|
||||
final InputValidator validator = new InputValidator(this, project, anchorStatementIfAll, anchorStatement, occurrenceManager);
|
||||
final TypeSelectorManagerImpl typeSelectorManager = new TypeSelectorManagerImpl(project, originalType, expr, occurrences);
|
||||
final boolean[] wasSucceed = new boolean[]{true};
|
||||
final Pass<OccurrencesChooser.ReplaceChoice> callback = new Pass<OccurrencesChooser.ReplaceChoice>() {
|
||||
final Pass<JavaReplaceChoice> callback = new Pass<JavaReplaceChoice>() {
|
||||
@Override
|
||||
public void pass(final OccurrencesChooser.ReplaceChoice choice) {
|
||||
public void pass(final JavaReplaceChoice choice) {
|
||||
boolean hasWriteAccess = occurrencesInfo.myHasWriteAccess;
|
||||
List<PsiExpression> nonWrite = occurrencesInfo.myNonWrite;
|
||||
if (choice != null) {
|
||||
final boolean noWriteChoice = choice == OccurrencesChooser.ReplaceChoice.NO_WRITE;
|
||||
final boolean allChoice = choice == OccurrencesChooser.ReplaceChoice.ALL;
|
||||
final boolean noWriteChoice = choice == JavaReplaceChoice.NO_WRITE;
|
||||
final boolean allChoice = choice.isAll();
|
||||
final boolean replaceAll = allChoice || noWriteChoice;
|
||||
typeSelectorManager.setAllOccurrences(replaceAll);
|
||||
|
||||
@@ -638,13 +673,24 @@ public abstract class IntroduceVariableBase extends IntroduceHandlerBase {
|
||||
.filter(occurrence -> !(expr.equals(occurrence) && expr.getParent() instanceof PsiExpressionStatement))
|
||||
.filter(occurrence -> allChoice || (noWriteChoice && !PsiUtil.isAccessedForWriting(occurrence)) || expr.equals(occurrence))
|
||||
.toArray(PsiExpression[]::new);
|
||||
myInplaceIntroducer = new JavaVariableInplaceIntroducer(project,
|
||||
settings,
|
||||
chosenAnchor,
|
||||
editor, expr, cantChangeFinalModifier,
|
||||
allOccurrences,
|
||||
typeSelectorManager,
|
||||
REFACTORING_NAME);
|
||||
if (choice == JavaReplaceChoice.CHAIN || choice == JavaReplaceChoice.CHAIN_ALL) {
|
||||
myInplaceIntroducer = new ChainCallInplaceIntroducer(project,
|
||||
settings,
|
||||
chosenAnchor,
|
||||
editor, expr,
|
||||
allOccurrences,
|
||||
typeSelectorManager,
|
||||
REFACTORING_NAME);
|
||||
}
|
||||
else {
|
||||
myInplaceIntroducer = new JavaVariableInplaceIntroducer(project,
|
||||
settings,
|
||||
chosenAnchor,
|
||||
editor, expr, cantChangeFinalModifier,
|
||||
allOccurrences,
|
||||
typeSelectorManager,
|
||||
REFACTORING_NAME);
|
||||
}
|
||||
if (myInplaceIntroducer.startInplaceIntroduceTemplate()) {
|
||||
return;
|
||||
}
|
||||
@@ -653,6 +699,9 @@ public abstract class IntroduceVariableBase extends IntroduceHandlerBase {
|
||||
CommandProcessor.getInstance().executeCommand(
|
||||
project,
|
||||
() -> {
|
||||
if (!anchorStatement.isValid()) {
|
||||
return;
|
||||
}
|
||||
final Editor topLevelEditor ;
|
||||
if (!InjectedLanguageManager.getInstance(project).isInjectedFragment(anchorStatement.getContainingFile())) {
|
||||
topLevelEditor = InjectedLanguageUtil.getTopLevelEditor(editor);
|
||||
@@ -694,17 +743,20 @@ public abstract class IntroduceVariableBase extends IntroduceHandlerBase {
|
||||
callback.pass(null);
|
||||
}
|
||||
else {
|
||||
OccurrencesChooser.ReplaceChoice choice = getOccurrencesChoice();
|
||||
JavaReplaceChoice choice = getOccurrencesChoice();
|
||||
if (choice != null) {
|
||||
callback.pass(choice);
|
||||
} else {
|
||||
OccurrencesChooser.<PsiExpression>simpleChooser(editor).showChooser(callback, occurrencesMap);
|
||||
String title = occurrencesInfo.myChainCallCandidate && occurrences.length == 1
|
||||
? "Lambda chain detected"
|
||||
: OccurrencesChooser.DEFAULT_CHOOSER_TITLE;
|
||||
OccurrencesChooser.<PsiExpression>simpleChooser(editor).showChooser(callback, occurrencesMap, title);
|
||||
}
|
||||
}
|
||||
return wasSucceed[0];
|
||||
}
|
||||
|
||||
protected OccurrencesChooser.ReplaceChoice getOccurrencesChoice() {
|
||||
protected JavaReplaceChoice getOccurrencesChoice() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -1096,13 +1148,12 @@ public abstract class IntroduceVariableBase extends IntroduceHandlerBase {
|
||||
boolean anyAssignmentLHS,
|
||||
final InputValidator validator,
|
||||
PsiElement anchor,
|
||||
final OccurrencesChooser.ReplaceChoice replaceChoice) {
|
||||
final boolean replaceAll =
|
||||
replaceChoice == OccurrencesChooser.ReplaceChoice.ALL || replaceChoice == OccurrencesChooser.ReplaceChoice.NO_WRITE;
|
||||
final JavaReplaceChoice replaceChoice) {
|
||||
final boolean replaceAll = replaceChoice.isMultiple();
|
||||
final SuggestedNameInfo suggestedName = getSuggestedName(typeSelectorManager.getDefaultType(), expr, anchor);
|
||||
final String variableName = suggestedName.names.length > 0 ? suggestedName.names[0] : "";
|
||||
final boolean declareFinal = replaceAll && declareFinalIfAll || !anyAssignmentLHS && createFinals(project);
|
||||
final boolean replaceWrite = anyAssignmentLHS && replaceChoice == OccurrencesChooser.ReplaceChoice.ALL;
|
||||
final boolean replaceWrite = anyAssignmentLHS && replaceChoice.isAll();
|
||||
return new IntroduceVariableSettings() {
|
||||
@Override
|
||||
public String getEnteredName() {
|
||||
@@ -1192,11 +1243,14 @@ public abstract class IntroduceVariableBase extends IntroduceHandlerBase {
|
||||
}
|
||||
|
||||
static class OccurrencesInfo {
|
||||
static final boolean CHAIN_ALLOWED = Registry.is("java.extract.variable.chaining.method");
|
||||
|
||||
List<PsiExpression> myOccurrences;
|
||||
List<PsiExpression> myNonWrite;
|
||||
boolean myCantReplaceAll;
|
||||
boolean myCantReplaceAllButWrite;
|
||||
boolean myHasWriteAccess;
|
||||
boolean myChainCallCandidate;
|
||||
|
||||
public OccurrencesInfo(PsiExpression[] occurrences) {
|
||||
myOccurrences = Arrays.asList(occurrences);
|
||||
@@ -1214,18 +1268,45 @@ public abstract class IntroduceVariableBase extends IntroduceHandlerBase {
|
||||
}
|
||||
}
|
||||
myHasWriteAccess = myOccurrences.size() > myNonWrite.size() && myOccurrences.size() > 1;
|
||||
myChainCallCandidate = CHAIN_ALLOWED && isChainCallCandidate();
|
||||
}
|
||||
|
||||
private boolean isChainCallCandidate() {
|
||||
if (myHasWriteAccess || myOccurrences.isEmpty()) return false;
|
||||
// The whole lambda body selected
|
||||
PsiExpression expression = myOccurrences.get(0);
|
||||
if (myOccurrences.size() == 1 && expression.getParent() instanceof PsiLambdaExpression) return false;
|
||||
PsiElement parent = PsiTreeUtil.findCommonParent(myOccurrences);
|
||||
if (parent == null) return false;
|
||||
PsiType type = expression.getType();
|
||||
PsiLambdaExpression lambda = PsiTreeUtil.getParentOfType(parent, PsiLambdaExpression.class, true, PsiStatement.class);
|
||||
if (ChainCallExtractor.findExtractor(lambda, expression, type) == null) return false;
|
||||
PsiParameter parameter = lambda.getParameterList().getParameters()[0];
|
||||
return ReferencesSearch.search(parameter).forEach((Processor<PsiReference>)ref ->
|
||||
myOccurrences.stream().anyMatch(expr -> PsiTreeUtil.isAncestor(expr, ref.getElement(), false)));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private LinkedHashMap<OccurrencesChooser.ReplaceChoice, List<PsiExpression>> buildOccurrencesMap(PsiExpression expr) {
|
||||
final LinkedHashMap<OccurrencesChooser.ReplaceChoice, List<PsiExpression>> occurrencesMap = ContainerUtil.newLinkedHashMap();
|
||||
occurrencesMap.put(OccurrencesChooser.ReplaceChoice.NO, Collections.singletonList(expr));
|
||||
if (myHasWriteAccess && !myCantReplaceAllButWrite) {
|
||||
occurrencesMap.put(OccurrencesChooser.ReplaceChoice.NO_WRITE, myNonWrite);
|
||||
}
|
||||
LinkedHashMap<JavaReplaceChoice, List<PsiExpression>> buildOccurrencesMap(PsiExpression expr) {
|
||||
final LinkedHashMap<JavaReplaceChoice, List<PsiExpression>> occurrencesMap = ContainerUtil.newLinkedHashMap();
|
||||
if (myChainCallCandidate) {
|
||||
if (myOccurrences.size() > 1 && !myCantReplaceAll) {
|
||||
occurrencesMap.put(JavaReplaceChoice.NO, Collections.singletonList(expr));
|
||||
occurrencesMap.put(JavaReplaceChoice.ALL, myOccurrences);
|
||||
occurrencesMap.put(JavaReplaceChoice.CHAIN_ALL, myOccurrences);
|
||||
} else {
|
||||
occurrencesMap.put(JavaReplaceChoice.NO_CHAIN, Collections.singletonList(expr));
|
||||
occurrencesMap.put(JavaReplaceChoice.CHAIN, Collections.singletonList(expr));
|
||||
}
|
||||
} else {
|
||||
occurrencesMap.put(JavaReplaceChoice.NO, Collections.singletonList(expr));
|
||||
if (myHasWriteAccess && !myCantReplaceAllButWrite) {
|
||||
occurrencesMap.put(JavaReplaceChoice.NO_WRITE, myNonWrite);
|
||||
}
|
||||
|
||||
if (myOccurrences.size() > 1 && !myCantReplaceAll) {
|
||||
occurrencesMap.put(OccurrencesChooser.ReplaceChoice.ALL, myOccurrences);
|
||||
if (myOccurrences.size() > 1 && !myCantReplaceAll) {
|
||||
occurrencesMap.put(JavaReplaceChoice.ALL, myOccurrences);
|
||||
}
|
||||
}
|
||||
return occurrencesMap;
|
||||
}
|
||||
|
||||
+3
-4
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2000-2014 JetBrains s.r.o.
|
||||
* Copyright 2000-2017 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -29,7 +29,6 @@ import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiExpression;
|
||||
import com.intellij.refactoring.HelpID;
|
||||
import com.intellij.refactoring.RefactoringBundle;
|
||||
import com.intellij.refactoring.introduce.inplace.OccurrencesChooser;
|
||||
import com.intellij.refactoring.ui.ConflictsDialog;
|
||||
import com.intellij.refactoring.ui.TypeSelectorManagerImpl;
|
||||
import com.intellij.refactoring.util.CommonRefactoringUtil;
|
||||
@@ -51,9 +50,9 @@ public class IntroduceVariableHandler extends IntroduceVariableBase {
|
||||
boolean declareFinalIfAll,
|
||||
boolean anyAssignmentLHS,
|
||||
final InputValidator validator,
|
||||
PsiElement anchor, OccurrencesChooser.ReplaceChoice replaceChoice) {
|
||||
PsiElement anchor, JavaReplaceChoice replaceChoice) {
|
||||
if (replaceChoice == null && ApplicationManager.getApplication().isUnitTestMode()) {
|
||||
replaceChoice = OccurrencesChooser.ReplaceChoice.NO;
|
||||
replaceChoice = JavaReplaceChoice.NO;
|
||||
}
|
||||
if (replaceChoice != null) {
|
||||
return super.getSettings(project, editor, expr, occurrences, typeSelectorManager, declareFinalIfAll, anyAssignmentLHS, validator,
|
||||
|
||||
+16
-7
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2000-2016 JetBrains s.r.o.
|
||||
* Copyright 2000-2017 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -396,13 +396,9 @@ public class JavaVariableInplaceIntroducer extends AbstractJavaInplaceIntroducer
|
||||
|
||||
@Override
|
||||
protected PsiVariable createFieldToStartTemplateOn(String[] names, PsiType psiType) {
|
||||
PsiVariable variable = IntroduceVariableBase.introduce(myProject, myExpr, myEditor, myChosenAnchor.getElement(), getOccurrences(), mySettings);
|
||||
final PsiDeclarationStatement declarationStatement = PsiTreeUtil.getParentOfType(variable, PsiDeclarationStatement.class);
|
||||
myPointer = declarationStatement != null ? SmartPointerManager.getInstance(myProject).createSmartPsiElementPointer(declarationStatement) : null;
|
||||
myEditor.putUserData(ReassignVariableUtil.DECLARATION_KEY, myPointer);
|
||||
setAdvertisementText(getAdvertisementText(declarationStatement, variable.getType(), myHasTypeSuggestion));
|
||||
PsiVariable variable = introduceVariable();
|
||||
|
||||
PsiDocumentManager.getInstance(myProject).doPostponedOperationsAndUnblockDocument(myEditor.getDocument());
|
||||
if (variable == null) return null;
|
||||
|
||||
final PsiVariable restoredVar = getVariable();
|
||||
if (restoredVar != null) {
|
||||
@@ -433,6 +429,19 @@ public class JavaVariableInplaceIntroducer extends AbstractJavaInplaceIntroducer
|
||||
return variable;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
protected PsiVariable introduceVariable() {
|
||||
PsiVariable variable = IntroduceVariableBase
|
||||
.introduce(myProject, myExpr, myEditor, myChosenAnchor.getElement(), getOccurrences(), mySettings);
|
||||
final PsiDeclarationStatement declarationStatement = PsiTreeUtil.getParentOfType(variable, PsiDeclarationStatement.class);
|
||||
myPointer = declarationStatement != null ? SmartPointerManager.getInstance(myProject).createSmartPsiElementPointer(declarationStatement) : null;
|
||||
myEditor.putUserData(ReassignVariableUtil.DECLARATION_KEY, myPointer);
|
||||
setAdvertisementText(getAdvertisementText(declarationStatement, variable.getType(), myHasTypeSuggestion));
|
||||
|
||||
PsiDocumentManager.getInstance(myProject).doPostponedOperationsAndUnblockDocument(myEditor.getDocument());
|
||||
return variable;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getCaretOffset() {
|
||||
final PsiVariable variable = getVariable();
|
||||
|
||||
@@ -2,7 +2,7 @@ class C {
|
||||
{
|
||||
int[] a = new int[1];
|
||||
a[1] = 42;
|
||||
int x = a[1];
|
||||
System.out.println(x);
|
||||
int i = a[1];
|
||||
System.out.println(i);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
import java.util.List;
|
||||
|
||||
public class StreamExtract {
|
||||
void test(List<String> list) {
|
||||
list.stream().forEach(s -> System.out.println(
|
||||
new StringBuilder().append(String.forma<caret>t("[%s]", s))
|
||||
.append("oops")
|
||||
.append("argh")
|
||||
));
|
||||
}
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
import java.util.List;
|
||||
|
||||
public class StreamExtract {
|
||||
void test(List<String> list) {
|
||||
list.stream().map(s -> String.format("[%s]", s)).forEach(format -> System.out.println(
|
||||
new StringBuilder().append(format)
|
||||
.append("oops")
|
||||
.append("argh")
|
||||
));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
import java.util.List;
|
||||
|
||||
public class StreamExtract {
|
||||
void test(List<String> list) {
|
||||
list.stream().mapToInt(x -> x.length() + 10 * x.l<caret>ength()).forEach(System.out::println);
|
||||
}
|
||||
}
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
import java.util.List;
|
||||
|
||||
public class StreamExtract {
|
||||
void test(List<String> list) {
|
||||
list.stream().mapToInt(String::length).map(length -> length + 10 * length).forEach(System.out::println);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
import java.util.List;
|
||||
|
||||
public class StreamExtract {
|
||||
void test(List<String> list) {
|
||||
list.stream().forEach(s -> System.out.println(s.t<caret>oLowerCase()));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
import java.util.List;
|
||||
|
||||
public class StreamExtract {
|
||||
void test(List<String> list) {
|
||||
list.stream().map(String::toLowerCase).forEach(s1 -> System.out.println(s1));
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,8 @@
|
||||
class C {
|
||||
{
|
||||
int[] a = new int[1];
|
||||
int x = a[1];
|
||||
x = 42;
|
||||
System.out.println(x);
|
||||
int i = a[1];
|
||||
i = 42;
|
||||
System.out.println(i);
|
||||
}
|
||||
}
|
||||
+2
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2000-2016 JetBrains s.r.o.
|
||||
* Copyright 2000-2017 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -54,7 +54,7 @@ public abstract class AbstractJavaInplaceIntroduceTest extends AbstractInplaceIn
|
||||
|
||||
@Override
|
||||
protected Sdk getProjectJDK() {
|
||||
return IdeaTestUtil.getMockJdk17();
|
||||
return IdeaTestUtil.getMockJdk18();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+24
-12
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2000-2014 JetBrains s.r.o.
|
||||
* Copyright 2000-2017 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -31,7 +31,7 @@ import com.intellij.psi.codeStyle.CodeStyleSettingsManager;
|
||||
import com.intellij.psi.impl.source.tree.injected.InjectedLanguageUtil;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.refactoring.introduce.inplace.AbstractInplaceIntroducer;
|
||||
import com.intellij.refactoring.introduce.inplace.OccurrencesChooser;
|
||||
import com.intellij.refactoring.introduceVariable.IntroduceVariableBase;
|
||||
import com.intellij.refactoring.introduceVariable.IntroduceVariableHandler;
|
||||
import com.intellij.testFramework.MapDataContext;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@@ -117,7 +117,7 @@ public class InplaceIntroduceVariableTest extends AbstractJavaInplaceIntroduceTe
|
||||
}
|
||||
|
||||
public void testPlaceInsideLambdaBodyMultipleOccurrences1() throws Exception {
|
||||
doTestReplaceChoice(OccurrencesChooser.ReplaceChoice.ALL, new Pass<AbstractInplaceIntroducer>() {
|
||||
doTestReplaceChoice(IntroduceVariableBase.JavaReplaceChoice.ALL, new Pass<AbstractInplaceIntroducer>() {
|
||||
@Override
|
||||
public void pass(AbstractInplaceIntroducer inplaceIntroduceFieldPopup) {
|
||||
type("expr");
|
||||
@@ -190,19 +190,31 @@ public class InplaceIntroduceVariableTest extends AbstractJavaInplaceIntroduceTe
|
||||
}
|
||||
|
||||
public void testWritable() throws Exception {
|
||||
doTestReplaceChoice(OccurrencesChooser.ReplaceChoice.ALL);
|
||||
doTestReplaceChoice(IntroduceVariableBase.JavaReplaceChoice.ALL);
|
||||
}
|
||||
|
||||
public void testNoWritable() throws Exception {
|
||||
doTestReplaceChoice(OccurrencesChooser.ReplaceChoice.NO_WRITE);
|
||||
doTestReplaceChoice(IntroduceVariableBase.JavaReplaceChoice.NO_WRITE);
|
||||
}
|
||||
|
||||
public void testAllInsertFinal() throws Exception {
|
||||
doTestReplaceChoice(OccurrencesChooser.ReplaceChoice.ALL);
|
||||
doTestReplaceChoice(IntroduceVariableBase.JavaReplaceChoice.ALL);
|
||||
}
|
||||
|
||||
public void testAllIncomplete() throws Exception {
|
||||
doTestReplaceChoice(OccurrencesChooser.ReplaceChoice.ALL);
|
||||
doTestReplaceChoice(IntroduceVariableBase.JavaReplaceChoice.ALL);
|
||||
}
|
||||
|
||||
public void testStreamSimple() throws Exception {
|
||||
doTestReplaceChoice(IntroduceVariableBase.JavaReplaceChoice.CHAIN);
|
||||
}
|
||||
|
||||
public void testStreamMultiple() throws Exception {
|
||||
doTestReplaceChoice(IntroduceVariableBase.JavaReplaceChoice.CHAIN_ALL);
|
||||
}
|
||||
|
||||
public void testStreamMultiline() throws Exception {
|
||||
doTestReplaceChoice(IntroduceVariableBase.JavaReplaceChoice.CHAIN);
|
||||
}
|
||||
|
||||
public void testBrokenFormattingWithInValidation() throws Exception {
|
||||
@@ -273,11 +285,11 @@ public class InplaceIntroduceVariableTest extends AbstractJavaInplaceIntroduceTe
|
||||
}
|
||||
}
|
||||
|
||||
private void doTestReplaceChoice(OccurrencesChooser.ReplaceChoice choice) {
|
||||
private void doTestReplaceChoice(IntroduceVariableBase.JavaReplaceChoice choice) {
|
||||
doTestReplaceChoice(choice, null);
|
||||
}
|
||||
|
||||
private void doTestReplaceChoice(OccurrencesChooser.ReplaceChoice choice, Pass<AbstractInplaceIntroducer> pass) {
|
||||
private void doTestReplaceChoice(IntroduceVariableBase.JavaReplaceChoice choice, Pass<AbstractInplaceIntroducer> pass) {
|
||||
String name = getTestName(true);
|
||||
configureByFile(getBasePath() + name + getExtension());
|
||||
final boolean enabled = getEditor().getSettings().isVariableInplaceRenameEnabled();
|
||||
@@ -318,9 +330,9 @@ public class InplaceIntroduceVariableTest extends AbstractJavaInplaceIntroduceTe
|
||||
}
|
||||
|
||||
public static class MyIntroduceVariableHandler extends IntroduceVariableHandler implements MyIntroduceHandler {
|
||||
private OccurrencesChooser.ReplaceChoice myChoice = null;
|
||||
private JavaReplaceChoice myChoice = null;
|
||||
|
||||
public void setChoice(OccurrencesChooser.ReplaceChoice choice) {
|
||||
public void setChoice(JavaReplaceChoice choice) {
|
||||
myChoice = choice;
|
||||
}
|
||||
|
||||
@@ -335,7 +347,7 @@ public class InplaceIntroduceVariableTest extends AbstractJavaInplaceIntroduceTe
|
||||
}
|
||||
|
||||
@Override
|
||||
protected OccurrencesChooser.ReplaceChoice getOccurrencesChoice() {
|
||||
protected JavaReplaceChoice getOccurrencesChoice() {
|
||||
return myChoice;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2000-2016 JetBrains s.r.o.
|
||||
* Copyright 2000-2017 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -23,7 +23,6 @@ import com.intellij.psi.CommonClassNames;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiExpression;
|
||||
import com.intellij.psi.PsiType;
|
||||
import com.intellij.refactoring.introduce.inplace.OccurrencesChooser;
|
||||
import com.intellij.refactoring.introduceVariable.InputValidator;
|
||||
import com.intellij.refactoring.introduceVariable.IntroduceVariableBase;
|
||||
import com.intellij.refactoring.introduceVariable.IntroduceVariableSettings;
|
||||
@@ -365,7 +364,7 @@ public class IntroduceVariableTest extends LightCodeInsightTestCase {
|
||||
boolean declareFinalIfAll,
|
||||
boolean anyAssignmentLHS,
|
||||
InputValidator validator,
|
||||
PsiElement anchor, final OccurrencesChooser.ReplaceChoice replaceChoice) {
|
||||
PsiElement anchor, final JavaReplaceChoice replaceChoice) {
|
||||
final PsiType type = typeSelectorManager.getDefaultType();
|
||||
assertTrue(type.getPresentableText(), type.getPresentableText().equals(expectedTypeName));
|
||||
assertEquals("path", IntroduceVariableBase.getSuggestedName(type, expr).names[0]);
|
||||
@@ -384,7 +383,7 @@ public class IntroduceVariableTest extends LightCodeInsightTestCase {
|
||||
boolean declareFinalIfAll,
|
||||
boolean anyAssignmentLHS,
|
||||
InputValidator validator,
|
||||
PsiElement anchor, final OccurrencesChooser.ReplaceChoice replaceChoice) {
|
||||
PsiElement anchor, final JavaReplaceChoice replaceChoice) {
|
||||
final PsiType type = typeSelectorManager.getDefaultType();
|
||||
assertTrue(type.getPresentableText(), type.getPresentableText().equals("B"));
|
||||
return super.getSettings(project, editor, expr, occurrences, typeSelectorManager, declareFinalIfAll, anyAssignmentLHS,
|
||||
@@ -552,7 +551,7 @@ public class IntroduceVariableTest extends LightCodeInsightTestCase {
|
||||
boolean declareFinalIfAll,
|
||||
boolean anyAssignmentLHS,
|
||||
InputValidator validator,
|
||||
PsiElement anchor, final OccurrencesChooser.ReplaceChoice replaceChoice) {
|
||||
PsiElement anchor, final JavaReplaceChoice replaceChoice) {
|
||||
final PsiType[] types = typeSelectorManager.getTypesForAll();
|
||||
assertTrue(types[0].getPresentableText(), types[0].getPresentableText().equals("B"));
|
||||
assertTrue(types[1].getPresentableText(), types[1].getPresentableText().equals("A"));
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2000-2014 JetBrains s.r.o.
|
||||
* Copyright 2000-2017 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -20,12 +20,10 @@ import com.intellij.openapi.project.Project;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiExpression;
|
||||
import com.intellij.psi.PsiType;
|
||||
import com.intellij.refactoring.introduce.inplace.OccurrencesChooser;
|
||||
import com.intellij.refactoring.introduceVariable.InputValidator;
|
||||
import com.intellij.refactoring.introduceVariable.IntroduceVariableBase;
|
||||
import com.intellij.refactoring.introduceVariable.IntroduceVariableSettings;
|
||||
import com.intellij.refactoring.ui.TypeSelectorManagerImpl;
|
||||
import com.intellij.util.containers.MultiMap;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
|
||||
import static org.junit.Assert.assertTrue;
|
||||
@@ -66,7 +64,7 @@ class MockIntroduceVariableHandler extends IntroduceVariableBase {
|
||||
final boolean declareFinalIfAll,
|
||||
boolean anyAssignmentLHS,
|
||||
InputValidator validator,
|
||||
PsiElement anchor, final OccurrencesChooser.ReplaceChoice replaceChoice) {
|
||||
PsiElement anchor, final JavaReplaceChoice replaceChoice) {
|
||||
final PsiType type = myLookForType ? findType(typeSelectorManager.getTypesForAll(), typeSelectorManager.getDefaultType())
|
||||
: typeSelectorManager.getDefaultType();
|
||||
assertTrue(type.getInternalCanonicalText(), type.getInternalCanonicalText().equals(myExpectedTypeCanonicalName));
|
||||
|
||||
+41
-14
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2000-2013 JetBrains s.r.o.
|
||||
* Copyright 2000-2017 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -44,7 +44,17 @@ import java.util.List;
|
||||
// This prevents languages with polyadic expressions or sequences
|
||||
// from reusing it, use simpleChooser instead.
|
||||
public abstract class OccurrencesChooser<T> {
|
||||
public enum ReplaceChoice {
|
||||
public static final String DEFAULT_CHOOSER_TITLE = "Multiple occurrences found";
|
||||
|
||||
public interface BaseReplaceChoice {
|
||||
boolean isMultiple();
|
||||
|
||||
boolean isAll();
|
||||
|
||||
String formatDescription(int occurrencesCount);
|
||||
}
|
||||
|
||||
public enum ReplaceChoice implements BaseReplaceChoice {
|
||||
NO("Replace this occurrence only"), NO_WRITE("Replace all occurrences but write"), ALL("Replace all {0} occurrences");
|
||||
|
||||
private final String myDescription;
|
||||
@@ -56,6 +66,21 @@ public abstract class OccurrencesChooser<T> {
|
||||
public String getDescription() {
|
||||
return myDescription;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isMultiple() {
|
||||
return this == NO_WRITE || this == ALL;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAll() {
|
||||
return this == ALL;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String formatDescription(int occurrencesCount) {
|
||||
return MessageFormat.format(getDescription(), occurrencesCount);
|
||||
}
|
||||
}
|
||||
|
||||
public static <T extends PsiElement> OccurrencesChooser<T> simpleChooser(Editor editor) {
|
||||
@@ -89,15 +114,21 @@ public abstract class OccurrencesChooser<T> {
|
||||
}
|
||||
|
||||
public void showChooser(final Pass<ReplaceChoice> callback, final Map<ReplaceChoice, List<T>> occurrencesMap) {
|
||||
showChooser(callback, occurrencesMap, DEFAULT_CHOOSER_TITLE);
|
||||
}
|
||||
|
||||
public <C extends BaseReplaceChoice> void showChooser(final Pass<C> callback,
|
||||
final Map<C, List<T>> occurrencesMap,
|
||||
String title) {
|
||||
if (occurrencesMap.size() == 1) {
|
||||
callback.pass(occurrencesMap.keySet().iterator().next());
|
||||
return;
|
||||
}
|
||||
final DefaultListModel model = new DefaultListModel();
|
||||
for (ReplaceChoice choice : occurrencesMap.keySet()) {
|
||||
final DefaultListModel<C> model = new DefaultListModel<>();
|
||||
for (C choice : occurrencesMap.keySet()) {
|
||||
model.addElement(choice);
|
||||
}
|
||||
final JList list = new JBList(model);
|
||||
final JList<C> list = new JBList<>(model);
|
||||
list.setCellRenderer(new DefaultListCellRenderer() {
|
||||
@Override
|
||||
public Component getListCellRendererComponent(final JList list,
|
||||
@@ -106,13 +137,9 @@ public abstract class OccurrencesChooser<T> {
|
||||
final boolean isSelected,
|
||||
final boolean cellHasFocus) {
|
||||
final Component rendererComponent = super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
|
||||
final ReplaceChoice choices = (ReplaceChoice)value;
|
||||
@SuppressWarnings("unchecked") final C choices = (C)value;
|
||||
if (choices != null) {
|
||||
String text = choices.getDescription();
|
||||
if (choices == ReplaceChoice.ALL) {
|
||||
text = MessageFormat.format(text, occurrencesMap.get(choices).size());
|
||||
}
|
||||
setText(text);
|
||||
setText(choices.formatDescription(occurrencesMap.get(choices).size()));
|
||||
}
|
||||
return rendererComponent;
|
||||
}
|
||||
@@ -120,7 +147,7 @@ public abstract class OccurrencesChooser<T> {
|
||||
list.addListSelectionListener(new ListSelectionListener() {
|
||||
@Override
|
||||
public void valueChanged(final ListSelectionEvent e) {
|
||||
final ReplaceChoice value = (ReplaceChoice)list.getSelectedValue();
|
||||
final C value = list.getSelectedValue();
|
||||
if (value == null) return;
|
||||
dropHighlighters();
|
||||
final MarkupModel markupModel = myEditor.getMarkupModel();
|
||||
@@ -136,11 +163,11 @@ public abstract class OccurrencesChooser<T> {
|
||||
});
|
||||
|
||||
JBPopupFactory.getInstance().createListPopupBuilder(list)
|
||||
.setTitle("Multiple occurrences found")
|
||||
.setTitle(title)
|
||||
.setMovable(true)
|
||||
.setResizable(false)
|
||||
.setRequestFocus(true)
|
||||
.setItemChoosenCallback(() -> callback.pass((ReplaceChoice)list.getSelectedValue()))
|
||||
.setItemChoosenCallback(() -> callback.pass(list.getSelectedValue()))
|
||||
.addListener(new JBPopupAdapter() {
|
||||
@Override
|
||||
public void onClosed(LightweightWindowEvent event) {
|
||||
|
||||
@@ -1046,4 +1046,8 @@ jest.debugger.use.inspect.description=Use --inspect for debugging Jest tests wit
|
||||
JavaScript.WebPack.With.JsonSchema=true
|
||||
JavaScript.WebPack.With.JsonSchema.description=Use JSON-Schema powered support for webpack config files
|
||||
ide.diagnostics.suggest.sending.all.attachments=false
|
||||
ide.diagnostics.suggest.sending.all.attachments.description=Suggest the user to send all error attachments by default
|
||||
ide.diagnostics.suggest.sending.all.attachments.description=Suggest the user to send all error attachments by default
|
||||
|
||||
java.extract.variable.chaining.method=true
|
||||
java.extract.variable.chaining.method.description=Allows "Extract variable" to create separate call chain step
|
||||
java.extract.variable.chaining.method.restartRequired=true
|
||||
|
||||
Reference in New Issue
Block a user