mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-26 19:06:24 +07:00
IDEA-85758 intention to replace casted var with a var of the right type and having the same value implemented
This commit is contained in:
+177
@@ -0,0 +1,177 @@
|
||||
/*
|
||||
* Copyright 2000-2012 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.codeInsight.intention.impl;
|
||||
|
||||
import com.intellij.codeInsight.CodeInsightBundle;
|
||||
import com.intellij.codeInsight.CodeInsightUtil;
|
||||
import com.intellij.codeInsight.intention.PsiElementBaseIntentionAction;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.progress.ProgressIndicatorProvider;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.Ref;
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.util.IncorrectOperationException;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
/**
|
||||
* @author Danila Ponomarenko
|
||||
*/
|
||||
public class ReplaceCastWithVariableAction extends PsiElementBaseIntentionAction {
|
||||
private String myReplaceVariableName = "";
|
||||
|
||||
@Override
|
||||
public boolean isAvailable(@NotNull Project project, Editor editor, @NotNull PsiElement element) {
|
||||
final PsiTypeCastExpression typeCastExpression = PsiTreeUtil.getParentOfType(element, PsiTypeCastExpression.class);
|
||||
final PsiMethod method = PsiTreeUtil.getParentOfType(element, PsiMethod.class);
|
||||
|
||||
if (typeCastExpression == null || method == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
final PsiExpression operand = typeCastExpression.getOperand();
|
||||
if (!(operand instanceof PsiReferenceExpression)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
final PsiReferenceExpression operandReference = (PsiReferenceExpression)operand;
|
||||
final PsiElement resolved = operandReference.resolve();
|
||||
if (resolved == null || (!(resolved instanceof PsiParameter) && !(resolved instanceof PsiLocalVariable))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
final PsiLocalVariable replacement = findReplacement(method, (PsiVariable)resolved, typeCastExpression);
|
||||
if (replacement == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
myReplaceVariableName = replacement.getName();
|
||||
setText(CodeInsightBundle.message("intention.replace.cast.with.var.text", typeCastExpression.getText(), myReplaceVariableName));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void invoke(@NotNull Project project, Editor editor, @NotNull PsiElement element) throws IncorrectOperationException {
|
||||
final PsiTypeCastExpression typeCastExpression = PsiTreeUtil.getParentOfType(element, PsiTypeCastExpression.class);
|
||||
|
||||
if (typeCastExpression == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
final PsiElement toReplace = typeCastExpression.getParent() instanceof PsiParenthesizedExpression ? typeCastExpression.getParent() : typeCastExpression;
|
||||
final PsiElementFactory factory = JavaPsiFacade.getElementFactory(project);
|
||||
toReplace.replace(factory.createExpressionFromText(myReplaceVariableName, toReplace));
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static PsiLocalVariable findReplacement(@NotNull PsiMethod method,
|
||||
@NotNull PsiVariable castedVar,
|
||||
@NotNull PsiTypeCastExpression expression) {
|
||||
final TextRange expressionTextRange = expression.getTextRange();
|
||||
for (PsiExpression occurrence : CodeInsightUtil.findExpressionOccurrences(method,expression)){
|
||||
ProgressIndicatorProvider.checkCanceled();
|
||||
final TextRange occurrenceTextRange = occurrence.getTextRange();
|
||||
if (occurrence == expression || occurrenceTextRange.getEndOffset() >= expressionTextRange.getStartOffset()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
final PsiLocalVariable variable = getVariable(occurrence);
|
||||
|
||||
final PsiCodeBlock methodBody = method.getBody();
|
||||
if (variable != null && methodBody != null &&
|
||||
!isChangedBetween(castedVar, methodBody, occurrence, expression) && !isChangedBetween(variable, methodBody, occurrence, expression)) {
|
||||
return variable;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private static boolean isChangedBetween(@NotNull final PsiVariable variable,
|
||||
@NotNull final PsiElement scope,
|
||||
@NotNull final PsiElement start,
|
||||
@NotNull final PsiElement end) {
|
||||
if (variable.hasModifierProperty(PsiModifier.FINAL)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
final Ref<Boolean> result = new Ref<Boolean>();
|
||||
|
||||
scope.accept(
|
||||
new JavaRecursiveElementWalkingVisitor() {
|
||||
private boolean inScope = false;
|
||||
|
||||
@Override
|
||||
public void visitElement(PsiElement element) {
|
||||
if (element == start) {
|
||||
inScope = true;
|
||||
}
|
||||
if (element == end) {
|
||||
inScope = false;
|
||||
stopWalking();
|
||||
}
|
||||
super.visitElement(element);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitAssignmentExpression(PsiAssignmentExpression expression) {
|
||||
if (inScope && expression.getLExpression() instanceof PsiReferenceExpression) {
|
||||
final PsiReferenceExpression referenceExpression = (PsiReferenceExpression)expression.getLExpression();
|
||||
|
||||
if (variable.equals(referenceExpression.resolve())) {
|
||||
result.set(true);
|
||||
stopWalking();
|
||||
}
|
||||
}
|
||||
super.visitAssignmentExpression(expression);
|
||||
}
|
||||
}
|
||||
);
|
||||
return result.get() == Boolean.TRUE;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static PsiLocalVariable getVariable(@NotNull PsiExpression occurrence) {
|
||||
final PsiElement parent = occurrence.getParent();
|
||||
|
||||
if (parent instanceof PsiLocalVariable) {
|
||||
return (PsiLocalVariable)parent;
|
||||
}
|
||||
|
||||
if (parent instanceof PsiAssignmentExpression) {
|
||||
final PsiAssignmentExpression assignmentExpression = (PsiAssignmentExpression)parent;
|
||||
if (assignmentExpression.getLExpression() instanceof PsiReferenceExpression) {
|
||||
final PsiReferenceExpression referenceExpression = (PsiReferenceExpression)assignmentExpression.getLExpression();
|
||||
final PsiElement resolved = referenceExpression.resolve();
|
||||
if (resolved instanceof PsiLocalVariable) {
|
||||
return (PsiLocalVariable)resolved;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public String getFamilyName() {
|
||||
return CodeInsightBundle.message("intention.replace.cast.with.var.family");
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user