mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
[Java] LSP-425 Refactoring IntroduceVariableBase
- Create better structure for IntroduceVariableBase#getTempContainer - Use better return type in IntroduceVariableUtil#getIntroduceVariableCandidates GitOrigin-RevId: 3627b2928d974c977a6d89d18ad0f37792b3ba1c
This commit is contained in:
committed by
intellij-monorepo-bot
parent
ae9defa6a9
commit
888f4cc38f
+4
-3
@@ -53,10 +53,11 @@ public class IntroduceFunctionalVariableHandler extends IntroduceVariableHandler
|
||||
}
|
||||
PsiElement anchorStatement =
|
||||
elements[0] instanceof PsiComment ? elements[0] : CommonJavaRefactoringUtil.getParentStatement(elements[0], false);
|
||||
TempContainerResult result = getTempContainer(anchorStatement);
|
||||
ErrorOrContainer errorOrContainer = getTempContainer(anchorStatement);
|
||||
|
||||
if (result.errorMessage != null) {
|
||||
showErrorMessage(project, editor, result.errorMessage);
|
||||
|
||||
if (errorOrContainer instanceof ErrorOrContainer.Error(@NlsContexts.DialogMessage String message)) {
|
||||
showErrorMessage(project, editor, message);
|
||||
}
|
||||
|
||||
PsiElement[] elementsInCopy = IntroduceParameterHandler.getElementsInCopy(project, file, elements);
|
||||
|
||||
+134
-123
@@ -40,6 +40,7 @@ import com.intellij.refactoring.introduce.inplace.AbstractInplaceIntroducer;
|
||||
import com.intellij.refactoring.introduce.inplace.OccurrencesChooser;
|
||||
import com.intellij.refactoring.introduce.inplace.OccurrencesChooser.ReplaceChoice;
|
||||
import com.intellij.refactoring.introduceField.ElementToWorkOn;
|
||||
import com.intellij.refactoring.introduceVariable.IntroduceVariableBase.ErrorOrContainer.Container;
|
||||
import com.intellij.refactoring.listeners.RefactoringEventData;
|
||||
import com.intellij.refactoring.listeners.RefactoringEventListener;
|
||||
import com.intellij.refactoring.ui.TypeSelectorManagerImpl;
|
||||
@@ -64,6 +65,9 @@ import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static com.intellij.refactoring.IntroduceVariableUtil.*;
|
||||
import static com.intellij.refactoring.introduceVariable.IntroduceVariableBase.IntroduceVariableResult.Context;
|
||||
|
||||
public abstract class IntroduceVariableBase extends IntroduceHandlerBase {
|
||||
public static class JavaReplaceChoice implements OccurrencesChooser.BaseReplaceChoice {
|
||||
public static final JavaReplaceChoice NO = new JavaReplaceChoice(ReplaceChoice.NO, null, false);
|
||||
@@ -137,14 +141,15 @@ public abstract class IntroduceVariableBase extends IntroduceHandlerBase {
|
||||
final SelectionModel selectionModel = editor.getSelectionModel();
|
||||
if (!selectionModel.hasSelection()) {
|
||||
final int offset = editor.getCaretModel().getOffset();
|
||||
Pair<TextRange, List<PsiExpression>> rangeAndExpressions = getExpressionsAndSelectionRange(project, editor, file, offset);
|
||||
TextRange suggestedSelection = rangeAndExpressions.getFirst();
|
||||
IntroduceVariableCandidates
|
||||
info = getIntroduceVariableCandidates(project, editor, file, offset);
|
||||
TextRange suggestedSelection = info.bestRangeToExtractFrom();
|
||||
if (suggestedSelection != null) {
|
||||
selectionModel.setSelection(suggestedSelection.getStartOffset(), suggestedSelection.getEndOffset());
|
||||
}
|
||||
else {
|
||||
final PsiElement[] statementsInRange = IntroduceVariableUtil.findStatementsAtOffset(editor, file, offset);
|
||||
List<PsiExpression> expressions = rangeAndExpressions.getSecond();
|
||||
final PsiElement[] statementsInRange = findStatementsAtOffset(editor, file, offset);
|
||||
List<PsiExpression> expressions = info.expressions();
|
||||
IntroduceTargetChooser.showChooser(editor, expressions,
|
||||
new Pass<>() {
|
||||
@Override
|
||||
@@ -155,7 +160,7 @@ public abstract class IntroduceVariableBase extends IntroduceHandlerBase {
|
||||
},
|
||||
new PsiExpressionTrimRenderer.RenderFunction(),
|
||||
RefactoringBundle.message("introduce.target.chooser.expressions.title"),
|
||||
IntroduceVariableUtil.preferredSelection(statementsInRange, expressions), ScopeHighlighter.NATURAL_RANGER);
|
||||
preferredSelection(statementsInRange, expressions), ScopeHighlighter.NATURAL_RANGER);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -165,18 +170,25 @@ public abstract class IntroduceVariableBase extends IntroduceHandlerBase {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @deprecated use {@link IntroduceVariableUtil#getIntroduceVariableCandidates(Project, Editor, PsiFile, int)} instead.
|
||||
*/
|
||||
@Deprecated(forRemoval = true)
|
||||
public static @NotNull Pair<@Nullable TextRange, @NotNull List<PsiExpression>> getExpressionsAndSelectionRange(final @NotNull Project project,
|
||||
final Editor editor,
|
||||
final @NotNull Editor editor,
|
||||
final @NotNull PsiFile file,
|
||||
int offset) {
|
||||
return IntroduceVariableUtil.getExpressionAndSelectionRange(project, editor, file, offset);
|
||||
IntroduceVariableCandidates
|
||||
info = getIntroduceVariableCandidates(project, editor, file, offset);
|
||||
return new Pair<>(info.bestRangeToExtractFrom(), info.expressions());
|
||||
}
|
||||
|
||||
private boolean invoke(final Project project, final Editor editor, PsiFile file, int startOffset, int endOffset) {
|
||||
FeatureUsageTracker.getInstance().triggerFeatureUsed(ProductivityFeatureNames.REFACTORING_INTRODUCE_VARIABLE);
|
||||
PsiDocumentManager.getInstance(project).commitAllDocuments();
|
||||
|
||||
return invokeImpl(project, IntroduceVariableUtil.findExpressionInRange(project, file, startOffset, endOffset), editor);
|
||||
return invokeImpl(project, findExpressionInRange(project, file, startOffset, endOffset), editor);
|
||||
}
|
||||
|
||||
public @NotNull Pair<List<PsiElement>, List<PsiExpression>> getPossibleAnchorsAndOccurrences(final Project project, final PsiExpression expr) {
|
||||
@@ -203,13 +215,19 @@ public abstract class IntroduceVariableBase extends IntroduceHandlerBase {
|
||||
|
||||
private @NotNull OccurrencesInfo buildOccurrencesInfo(Project project, PsiExpression expr) {
|
||||
final PsiElement anchorStatement = getAnchor(expr);
|
||||
TempContainerResult result = getTempContainer(anchorStatement);
|
||||
ErrorOrContainer result = getTempContainer(anchorStatement);
|
||||
|
||||
if (result.errorMessage != null) {
|
||||
showErrorMessage(project, null, result.errorMessage);
|
||||
}
|
||||
final PsiElement tempContainer = switch (result) {
|
||||
case Container container -> {
|
||||
yield container.element();
|
||||
}
|
||||
case ErrorOrContainer.Error error -> {
|
||||
showErrorMessage(project, null, error.message());
|
||||
yield null;
|
||||
}
|
||||
};
|
||||
|
||||
final ExpressionOccurrenceManager occurrenceManager = createOccurrenceManager(expr, result.container);
|
||||
final ExpressionOccurrenceManager occurrenceManager = createOccurrenceManager(expr, tempContainer);
|
||||
final PsiExpression[] occurrences = occurrenceManager.getOccurrences();
|
||||
|
||||
return new OccurrencesInfo(occurrences);
|
||||
@@ -232,13 +250,13 @@ public abstract class IntroduceVariableBase extends IntroduceHandlerBase {
|
||||
@Nullable PsiElement targetContainer,
|
||||
@Nullable JavaReplaceChoice replaceChoice,
|
||||
final Editor editor) {
|
||||
Result result = getIntroduceVariableContext(project, expr, editor);
|
||||
IntroduceVariableResult introduceVariableResult = getIntroduceVariableContext(project, expr, editor);
|
||||
|
||||
switch (result) {
|
||||
switch (introduceVariableResult) {
|
||||
case Context context -> {
|
||||
return doRefactoring(project, targetContainer, replaceChoice, editor, context);
|
||||
}
|
||||
case Error error -> {
|
||||
case IntroduceVariableResult.Error error -> {
|
||||
if (error.message != null) {
|
||||
showErrorMessage(project, editor, error.message);
|
||||
}
|
||||
@@ -303,18 +321,18 @@ public abstract class IntroduceVariableBase extends IntroduceHandlerBase {
|
||||
/**
|
||||
* @return the context necessary for performing "Introduce Variable" refactoring.
|
||||
*/
|
||||
public static @NotNull Result getIntroduceVariableContext(@NotNull Project project, @Nullable PsiExpression expr, @Nullable Editor editor) {
|
||||
public static @NotNull IntroduceVariableBase.IntroduceVariableResult getIntroduceVariableContext(@NotNull Project project, @Nullable PsiExpression expr, @Nullable Editor editor) {
|
||||
if (expr != null) {
|
||||
String message = IntroduceVariableUtil.getErrorMessage(expr);
|
||||
String message = getErrorMessage(expr);
|
||||
if (message != null) {
|
||||
return new Error(message);
|
||||
return new IntroduceVariableResult.Error(message);
|
||||
}
|
||||
PsiExpression topLevelExpression = ExpressionUtils.getTopLevelExpression(expr);
|
||||
if (topLevelExpression.getParent() instanceof PsiField f) {
|
||||
PsiClass containingClass = f.getContainingClass();
|
||||
if (containingClass != null && containingClass.isInterface()) {
|
||||
message = JavaRefactoringBundle.message("introduce.variable.message.cannot.extract.variable.in.interface");
|
||||
return new Error(message);
|
||||
return new IntroduceVariableResult.Error(message);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -322,21 +340,21 @@ public abstract class IntroduceVariableBase extends IntroduceHandlerBase {
|
||||
if (expr != null && expr.getParent() instanceof PsiExpressionStatement) {
|
||||
FeatureUsageTracker.getInstance().triggerFeatureUsed("refactoring.introduceVariable.incompleteStatement");
|
||||
}
|
||||
if (IntroduceVariableUtil.LOG.isDebugEnabled()) {
|
||||
IntroduceVariableUtil.LOG.debug("expression:" + expr);
|
||||
if (LOG.isDebugEnabled()) {
|
||||
LOG.debug("expression:" + expr);
|
||||
}
|
||||
|
||||
if (expr == null || !expr.isPhysical()) {
|
||||
if (ReassignVariableUtil.reassign(editor)) return new Error(null);
|
||||
if (ReassignVariableUtil.reassign(editor)) return new IntroduceVariableResult.Error(null);
|
||||
if (expr == null) {
|
||||
String message = JavaRefactoringBundle.message("selected.block.should.represent.an.expression");
|
||||
return new Error(message);
|
||||
return new IntroduceVariableResult.Error(message);
|
||||
}
|
||||
}
|
||||
|
||||
String enumInSwitchError = RefactoringUtil.checkEnumConstantInSwitchLabel(expr);
|
||||
if (enumInSwitchError != null) {
|
||||
return new Error(enumInSwitchError);
|
||||
return new IntroduceVariableResult.Error(enumInSwitchError);
|
||||
}
|
||||
|
||||
|
||||
@@ -345,12 +363,12 @@ public abstract class IntroduceVariableBase extends IntroduceHandlerBase {
|
||||
dumbService.computeWithAlternativeResolveEnabled(() -> CommonJavaRefactoringUtil.getTypeByExpressionWithExpectedType(expr));
|
||||
if (originalType == null || LambdaUtil.notInferredType(originalType)) {
|
||||
String message = JavaRefactoringBundle.message("unknown.expression.type");
|
||||
return new Error(message);
|
||||
return new IntroduceVariableResult.Error(message);
|
||||
}
|
||||
|
||||
if (PsiTypes.voidType().equals(originalType)) {
|
||||
String message = JavaRefactoringBundle.message("selected.expression.has.void.type");
|
||||
return new Error(message);
|
||||
return new IntroduceVariableResult.Error(message);
|
||||
}
|
||||
|
||||
try {
|
||||
@@ -360,51 +378,53 @@ public abstract class IntroduceVariableBase extends IntroduceHandlerBase {
|
||||
}
|
||||
catch (IncorrectOperationException ignore) {
|
||||
String message = JavaRefactoringBundle.message("unknown.expression.type");
|
||||
return new Error(message);
|
||||
return new IntroduceVariableResult.Error(message);
|
||||
}
|
||||
|
||||
for (PsiPatternVariable variable : JavaPsiPatternUtil.getExposedPatternVariables(expr)) {
|
||||
if (ContainerUtil.exists(VariableAccessUtils.getVariableReferences(variable),
|
||||
ref -> !PsiTreeUtil.isAncestor(expr, ref, true))) {
|
||||
String message = JavaRefactoringBundle.message("selected.expression.introduces.pattern.variable", variable.getName());
|
||||
return new Error(message);
|
||||
return new IntroduceVariableResult.Error(message);
|
||||
}
|
||||
}
|
||||
|
||||
final PsiElement anchorStatement = getAnchor(expr);
|
||||
|
||||
TempContainerResult result = getTempContainer(anchorStatement);
|
||||
if (result.errorMessage != null) {
|
||||
return new Error(result.errorMessage, false);
|
||||
}
|
||||
ErrorOrContainer errorOrContainer = getTempContainer(anchorStatement);
|
||||
|
||||
final PsiElement tempContainer = Objects.requireNonNull(result.container);
|
||||
return switch (errorOrContainer) {
|
||||
case Container container -> {
|
||||
final PsiFile file = Objects.requireNonNull(anchorStatement).getContainingFile();
|
||||
LOG.assertTrue(file != null, "expr.getContainingFile() == null");
|
||||
final PsiElement nameSuggestionContext = editor == null ? null : file.findElementAt(editor.getCaretModel().getOffset());
|
||||
final RefactoringSupportProvider supportProvider = LanguageRefactoringSupport.getInstance().forContext(expr);
|
||||
final boolean isInplaceAvailableOnDataContext =
|
||||
supportProvider != null &&
|
||||
editor != null &&
|
||||
editor.getSettings().isVariableInplaceRenameEnabled() &&
|
||||
supportProvider.isInplaceIntroduceAvailable(expr, nameSuggestionContext) &&
|
||||
!isInJspHolderMethod(expr);
|
||||
|
||||
final PsiFile file = Objects.requireNonNull(anchorStatement).getContainingFile();
|
||||
IntroduceVariableUtil.LOG.assertTrue(file != null, "expr.getContainingFile() == null");
|
||||
final PsiElement nameSuggestionContext = editor == null ? null : file.findElementAt(editor.getCaretModel().getOffset());
|
||||
final RefactoringSupportProvider supportProvider = LanguageRefactoringSupport.getInstance().forContext(expr);
|
||||
final boolean isInplaceAvailableOnDataContext =
|
||||
supportProvider != null &&
|
||||
editor != null &&
|
||||
editor.getSettings().isVariableInplaceRenameEnabled() &&
|
||||
supportProvider.isInplaceIntroduceAvailable(expr, nameSuggestionContext) &&
|
||||
!isInJspHolderMethod(expr);
|
||||
if (isInplaceAvailableOnDataContext) {
|
||||
final MultiMap<PsiElement, String> conflicts = new MultiMap<>();
|
||||
checkInLoopCondition(expr, conflicts);
|
||||
if (!conflicts.isEmpty()) {
|
||||
yield new IntroduceVariableResult.Error(StringUtil.join(new TreeSet<>(conflicts.values()), "<br>"), false);
|
||||
}
|
||||
}
|
||||
|
||||
if (isInplaceAvailableOnDataContext) {
|
||||
final MultiMap<PsiElement, String> conflicts = new MultiMap<>();
|
||||
checkInLoopCondition(expr, conflicts);
|
||||
if (!conflicts.isEmpty()) {
|
||||
return new Error(StringUtil.join(new TreeSet<>(conflicts.values()), "<br>"), false);
|
||||
final ExpressionOccurrenceManager occurrenceManager = createOccurrenceManager(expr, container.element());
|
||||
final PsiExpression[] occurrences = occurrenceManager.getOccurrences();
|
||||
|
||||
OccurrencesInfo occurrencesInfo = new OccurrencesInfo(occurrences);
|
||||
|
||||
yield new Context(expr, originalType, anchorStatement, occurrenceManager, occurrencesInfo, isInplaceAvailableOnDataContext);
|
||||
}
|
||||
}
|
||||
|
||||
final ExpressionOccurrenceManager occurrenceManager = createOccurrenceManager(expr, tempContainer);
|
||||
final PsiExpression[] occurrences = occurrenceManager.getOccurrences();
|
||||
|
||||
OccurrencesInfo occurrencesInfo = new OccurrencesInfo(occurrences);
|
||||
|
||||
return new Context(expr, originalType, anchorStatement, occurrenceManager, occurrencesInfo, isInplaceAvailableOnDataContext);
|
||||
case ErrorOrContainer.Error error -> {
|
||||
yield new IntroduceVariableResult.Error(error.message(), false);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private static @Nullable PsiType getNormalizedType(PsiExpression expr) {
|
||||
@@ -458,38 +478,24 @@ public abstract class IntroduceVariableBase extends IntroduceHandlerBase {
|
||||
return physicalElement != null ? physicalElement : place;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Contract of the class: when {@code errorMessage} is not null, {@code container} must be null and vice versa.
|
||||
*/
|
||||
protected static class TempContainerResult {
|
||||
final @Nullable @NlsContexts.DialogMessage String errorMessage;
|
||||
final @Nullable PsiElement container;
|
||||
|
||||
TempContainerResult(@Nullable @NlsContexts.DialogMessage String errorMessage, @Nullable PsiElement container) {
|
||||
this.errorMessage = errorMessage;
|
||||
this.container = container;
|
||||
}
|
||||
}
|
||||
|
||||
protected static @NotNull TempContainerResult getTempContainer(@Nullable PsiElement anchorStatement) {
|
||||
protected static @NotNull ErrorOrContainer getTempContainer(@Nullable PsiElement anchorStatement) {
|
||||
if (anchorStatement == null) {
|
||||
return new TempContainerResult(
|
||||
JavaRefactoringBundle.message("refactoring.is.not.supported.in.the.current.context", getRefactoringName()), null
|
||||
return new ErrorOrContainer.Error(
|
||||
JavaRefactoringBundle.message("refactoring.is.not.supported.in.the.current.context", getRefactoringName())
|
||||
);
|
||||
}
|
||||
|
||||
String anchorMessage = getAnchorBeforeMessage(anchorStatement);
|
||||
if (anchorMessage != null) return new TempContainerResult(anchorMessage, null);
|
||||
if (anchorMessage != null) return new ErrorOrContainer.Error(anchorMessage);
|
||||
|
||||
final PsiElement tempContainer = anchorStatement.getParent();
|
||||
|
||||
if (!(tempContainer instanceof PsiCodeBlock) && !CommonJavaRefactoringUtil.isLoopOrIf(tempContainer) && !(tempContainer instanceof PsiLambdaExpression) && (tempContainer.getParent() instanceof PsiLambdaExpression)) {
|
||||
return new TempContainerResult(
|
||||
JavaRefactoringBundle.message("refactoring.is.not.supported.in.the.current.context", getRefactoringName()), null
|
||||
return new ErrorOrContainer.Error(
|
||||
JavaRefactoringBundle.message("refactoring.is.not.supported.in.the.current.context", getRefactoringName())
|
||||
);
|
||||
}
|
||||
return new TempContainerResult(null, tempContainer);
|
||||
return new Container(tempContainer);
|
||||
}
|
||||
|
||||
private static ExpressionOccurrenceManager createOccurrenceManager(PsiExpression expr, @Nullable PsiElement tempContainer) {
|
||||
@@ -845,7 +851,7 @@ public abstract class IntroduceVariableBase extends IntroduceHandlerBase {
|
||||
.map(place -> (PsiExpression)getPhysicalElement(place))
|
||||
.groupingBy(e -> PsiTreeUtil.findCommonParent(e, physical),
|
||||
() -> new TreeMap<>(treeOrder), Collectors.toList());
|
||||
IntroduceVariableUtil.LOG.assertTrue(!groupByBlock.isEmpty());
|
||||
LOG.assertTrue(!groupByBlock.isEmpty());
|
||||
List<PsiExpression> currentOccurrences = new ArrayList<>();
|
||||
Map<String, Integer> counts = new HashMap<>();
|
||||
groupByBlock.forEach((parent, occurrences) -> {
|
||||
@@ -972,7 +978,7 @@ public abstract class IntroduceVariableBase extends IntroduceHandlerBase {
|
||||
.map(Function.identity())
|
||||
.pairMap((prev, next) -> text.substring(prev.getKey(), next.getKey()) + next.getValue())
|
||||
.joining();
|
||||
IntroduceVariableUtil.LOG.error("Unable to find anchor for a new variable; selectedOccurrences.length = " + selectedOccurrences.length,
|
||||
LOG.error("Unable to find anchor for a new variable; selectedOccurrences.length = " + selectedOccurrences.length,
|
||||
new Attachment("source.java", textWithOccurrences));
|
||||
return;
|
||||
}
|
||||
@@ -1030,9 +1036,9 @@ public abstract class IntroduceVariableBase extends IntroduceHandlerBase {
|
||||
chosenAnchor instanceof PsiSwitchLabelStatementBase;
|
||||
Consumer<? super PsiElement> callback = container -> {
|
||||
PsiElement anchor = container instanceof PsiLambdaExpression ? getAnchor(container) : container;
|
||||
TempContainerResult result = getTempContainer(anchor);
|
||||
if (result.errorMessage != null) {
|
||||
showErrorMessage(project, editor, result.errorMessage);
|
||||
ErrorOrContainer errorOrContainer = getTempContainer(anchor);
|
||||
if (errorOrContainer instanceof ErrorOrContainer.Error(String message)) {
|
||||
showErrorMessage(project, editor, message);
|
||||
return;
|
||||
}
|
||||
myInplaceIntroducer = new JavaVariableInplaceIntroducer(project, settings, anchor, editor, expr,
|
||||
@@ -1052,56 +1058,61 @@ public abstract class IntroduceVariableBase extends IntroduceHandlerBase {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Represents the result of getting the necessary environment for introducing a variable.
|
||||
* @see IntroduceVariablePass#getIntroduceVariableContext(Project, PsiFile, Editor, TextRange)
|
||||
* @see IntroduceVariablePass#getIntroduceVariableContext(Project, PsiExpression, Editor)
|
||||
*/
|
||||
public sealed interface Result permits Error, Context {}
|
||||
public sealed interface IntroduceVariableResult permits IntroduceVariableResult.Error, Context {
|
||||
|
||||
/**
|
||||
* Represents a message that will be displayed in UI if there is an error during collecting the context for introduced variable.
|
||||
* @see IntroduceVariablePass#showErrorMessage(Project, Editor, String)
|
||||
*/
|
||||
public static final class Error implements Result {
|
||||
public final @NlsContexts.DialogMessage @Nullable String message;
|
||||
/**
|
||||
* Represents a message that will be displayed in UI if there is an error during collecting the context for introduced variable.
|
||||
* @see IntroduceVariablePass#showErrorMessage(Project, Editor, String)
|
||||
*/
|
||||
final class Error implements IntroduceVariableResult {
|
||||
public final @NlsContexts.DialogMessage @Nullable String message;
|
||||
|
||||
Error(@NlsContexts.DialogMessage @Nullable String message) {
|
||||
this(message, true);
|
||||
Error(@NlsContexts.DialogMessage @Nullable String message) {
|
||||
this(message, true);
|
||||
}
|
||||
|
||||
Error(@NlsContexts.DialogMessage @Nullable String message, boolean shouldWrap) {
|
||||
if (message == null) {
|
||||
this.message = null;
|
||||
}
|
||||
else if (shouldWrap) {
|
||||
this.message = RefactoringBundle.getCannotRefactorMessage(message);
|
||||
}
|
||||
else {
|
||||
this.message = message;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Error(@NlsContexts.DialogMessage @Nullable String message, boolean shouldWrap) {
|
||||
if (message == null) {
|
||||
this.message = null;
|
||||
}
|
||||
else if (shouldWrap) {
|
||||
this.message = RefactoringBundle.getCannotRefactorMessage(message);
|
||||
}
|
||||
else {
|
||||
this.message = message;
|
||||
/**
|
||||
* Represents all the data necessary to introduce the variable.
|
||||
* @param expression - element that should be extracted into the separate variable.
|
||||
* @param originalType - type of the expression that should be extracted.
|
||||
* @param anchorStatement - statement near which the declared variable will be created.
|
||||
* @param occurrenceManager - stores all occurrences of the expression that should be extracted.
|
||||
* @param occurrencesInfo - stores additional information about occurrences like whether they are valid for extraction.
|
||||
* @param isInplaceAvailableOnDataContext - indicates whether inplace refactoring is available for the current context.
|
||||
*/
|
||||
record Context(
|
||||
@NotNull PsiExpression expression,
|
||||
@NotNull PsiType originalType,
|
||||
@NotNull PsiElement anchorStatement,
|
||||
@NotNull ExpressionOccurrenceManager occurrenceManager,
|
||||
@NotNull OccurrencesInfo occurrencesInfo,
|
||||
boolean isInplaceAvailableOnDataContext
|
||||
) implements IntroduceVariableResult {
|
||||
PsiFile file() {
|
||||
return anchorStatement.getContainingFile();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents all the data necessary to introduce the variable.
|
||||
* @param expression - element that should be extracted into the separate variable.
|
||||
* @param originalType - type of the expression that should be extracted.
|
||||
* @param anchorStatement - statement near which the declared variable will be created.
|
||||
* @param occurrenceManager - stores all occurrences of the expression that should be extracted.
|
||||
* @param occurrencesInfo - stores additional information about occurrences like whether they are valid for extraction.
|
||||
* @param isInplaceAvailableOnDataContext - indicates whether inplace refactoring is available for the current context.
|
||||
*/
|
||||
public record Context(
|
||||
@NotNull PsiExpression expression,
|
||||
@NotNull PsiType originalType,
|
||||
@NotNull PsiElement anchorStatement,
|
||||
@NotNull ExpressionOccurrenceManager occurrenceManager,
|
||||
@NotNull OccurrencesInfo occurrencesInfo,
|
||||
boolean isInplaceAvailableOnDataContext
|
||||
) implements Result {
|
||||
PsiFile file() {
|
||||
return anchorStatement.getContainingFile();
|
||||
}
|
||||
protected sealed interface ErrorOrContainer permits Container, ErrorOrContainer.Error {
|
||||
record Container(@NotNull PsiElement element) implements ErrorOrContainer {}
|
||||
record Error(@NotNull @NlsContexts.DialogMessage String message) implements ErrorOrContainer {}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,7 +22,6 @@ import com.intellij.openapi.fileEditor.FileDocumentManager;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.Key;
|
||||
import com.intellij.openapi.util.NlsContexts;
|
||||
import com.intellij.openapi.util.Pair;
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
import com.intellij.openapi.util.registry.Registry;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
@@ -90,22 +89,23 @@ public final class IntroduceVariableUtil {
|
||||
}
|
||||
|
||||
/**
|
||||
* @see IntroduceVariableUtil#getExpressionAndSelectionRange(Project, Document, PsiFile, int)
|
||||
* @see IntroduceVariableUtil#getIntroduceVariableCandidates(Project, Document, PsiFile, int)
|
||||
*/
|
||||
public static @NotNull Pair<@Nullable TextRange, @NotNull List<PsiExpression>> getExpressionAndSelectionRange(
|
||||
public static @NotNull IntroduceVariableCandidates getIntroduceVariableCandidates(
|
||||
final @NotNull Project project,
|
||||
final @NotNull Editor editor,
|
||||
final @NotNull PsiFile file,
|
||||
int offset
|
||||
) {
|
||||
return getExpressionAndSelectionRange(project, editor.getDocument(), file, offset);
|
||||
return getIntroduceVariableCandidates(project, editor.getDocument(), file, offset);
|
||||
}
|
||||
|
||||
/**
|
||||
* Searches for the expressions that can be extracted into the variable near the given {@code offset}
|
||||
* @return {@link TextRange} that includes preferred expression to extract and list of {@link PsiExpression} - candidates that can be extracted as well
|
||||
* @return the expressions that can be extracted into the variable near the given {@code offset}
|
||||
* and the recommended {@link TextRange} to select the expression from (could be null).
|
||||
* @see IntroduceVariableCandidates
|
||||
*/
|
||||
public static @NotNull Pair<@Nullable TextRange, @NotNull List<PsiExpression>> getExpressionAndSelectionRange(
|
||||
public static @NotNull IntroduceVariableCandidates getIntroduceVariableCandidates(
|
||||
final @NotNull Project project,
|
||||
final @NotNull Document document,
|
||||
final @NotNull PsiFile file,
|
||||
@@ -121,7 +121,7 @@ public final class IntroduceVariableUtil {
|
||||
final PsiExpression expressionInRange =
|
||||
findExpressionInRange(project, file, lineRange.getStartOffset(), lineRange.getEndOffset());
|
||||
if (expressionInRange != null && getErrorMessage(expressionInRange) == null) {
|
||||
return Pair.create(lineRange, Collections.singletonList(expressionInRange));
|
||||
return new IntroduceVariableCandidates(lineRange, Collections.singletonList(expressionInRange));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -130,13 +130,13 @@ public final class IntroduceVariableUtil {
|
||||
CommonJavaRefactoringUtil.getParentStatement(expression, false) != null ||
|
||||
PsiTreeUtil.getParentOfType(expression, PsiField.class, true, PsiStatement.class) != null);
|
||||
if (expressions.isEmpty()) {
|
||||
return Pair.create(lineRange, Collections.emptyList());
|
||||
return new IntroduceVariableCandidates(lineRange, Collections.emptyList());
|
||||
}
|
||||
else if (!isChooserNeeded(expressions)) {
|
||||
return Pair.create(expressions.get(0).getTextRange(), expressions);
|
||||
return new IntroduceVariableCandidates(expressions.getFirst().getTextRange(), expressions);
|
||||
}
|
||||
else {
|
||||
return Pair.create(null, expressions);
|
||||
return new IntroduceVariableCandidates(null, expressions);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -144,23 +144,24 @@ public final class IntroduceVariableUtil {
|
||||
/**
|
||||
* @return single expression that can be extracted into the variable.
|
||||
*/
|
||||
public static PsiExpression findExpressionInRange(Project project, PsiFile file, int startOffset, int endOffset) {
|
||||
public static PsiExpression findExpressionInRange(@NotNull Project project, @NotNull PsiFile file, int startOffset, int endOffset) {
|
||||
PsiExpression tempExpr = CodeInsightFrontbackUtil.findExpressionInRange(file, startOffset, endOffset);
|
||||
if (tempExpr == null) {
|
||||
PsiElement[] statements = CodeInsightFrontbackUtil.findStatementsInRange(file, startOffset, endOffset);
|
||||
if (statements.length == 1) {
|
||||
if (statements[0] instanceof PsiExpressionStatement) {
|
||||
tempExpr = ((PsiExpressionStatement) statements[0]).getExpression();
|
||||
PsiElement statement = statements[0];
|
||||
if (statement instanceof PsiExpressionStatement expressionStatement) {
|
||||
tempExpr = expressionStatement.getExpression();
|
||||
}
|
||||
else if (statements[0] instanceof PsiReturnStatement) {
|
||||
tempExpr = ((PsiReturnStatement)statements[0]).getReturnValue();
|
||||
else if (statement instanceof PsiReturnStatement returnStatement) {
|
||||
tempExpr = returnStatement.getReturnValue();
|
||||
}
|
||||
else if (statements[0] instanceof PsiSwitchStatement) {
|
||||
PsiExpression expr = JavaPsiFacade.getElementFactory(project).createExpressionFromText(statements[0].getText(), statements[0]);
|
||||
TextRange range = statements[0].getTextRange();
|
||||
else if (statement instanceof PsiSwitchStatement) {
|
||||
PsiExpression expr = JavaPsiFacade.getElementFactory(project).createExpressionFromText(statement.getText(), statement);
|
||||
TextRange range = statement.getTextRange();
|
||||
final RangeMarker rangeMarker = file.getViewProvider().getDocument().createRangeMarker(range);
|
||||
expr.putUserData(ElementToWorkOn.TEXT_RANGE, rangeMarker);
|
||||
expr.putUserData(ElementToWorkOn.PARENT, statements[0]);
|
||||
expr.putUserData(ElementToWorkOn.PARENT, statement);
|
||||
return expr;
|
||||
}
|
||||
}
|
||||
@@ -586,4 +587,11 @@ public final class IntroduceVariableUtil {
|
||||
return parent.replace(createReplacement(ref.getText(), project, prefix, suffix, parent, textRange, new int[1]));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Stores information about expressions that can be extracted into the variable near the cursor position.
|
||||
* @param bestRangeToExtractFrom {@link TextRange} that includes the most appropriate expression to be extracted.
|
||||
* @param expressions list of expressions that can be extracted into variable.
|
||||
*/
|
||||
public record IntroduceVariableCandidates(@Nullable TextRange bestRangeToExtractFrom, @NotNull List<@NotNull PsiExpression> expressions) {}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user