mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-03-22 15:19:59 +07:00
IDEA-305934 Handle widening at declaration & assignment
closes https://github.com/JetBrains/intellij-community/pull/2226 GitOrigin-RevId: 88280737af72157554bfa036132ac1fb3914e972
This commit is contained in:
committed by
intellij-monorepo-bot
parent
f52c2e22d0
commit
74d1b45ef4
@@ -72,6 +72,7 @@ public class CastCanBeReplacedWithVariableInspection extends AbstractBaseJavaLoc
|
||||
final PsiCodeBlock methodBody = method.getBody();
|
||||
if (methodBody == null) return null;
|
||||
final TextRange expressionTextRange = expression.getTextRange();
|
||||
if (expressionTextRange == null) return null;
|
||||
PsiExpression operand = PsiUtil.skipParenthesizedExprDown(expression.getOperand());
|
||||
if (operand == null) return null;
|
||||
PsiType castType = expressionCastType.getType();
|
||||
@@ -86,11 +87,7 @@ public class CastCanBeReplacedWithVariableInspection extends AbstractBaseJavaLoc
|
||||
.toList();
|
||||
PsiResolveHelper resolveHelper = PsiResolveHelper.getInstance(method.getProject());
|
||||
for (PsiTypeCastExpression occurrence : found) {
|
||||
ProgressIndicatorProvider.checkCanceled();
|
||||
final TextRange occurrenceTextRange = occurrence.getTextRange();
|
||||
if (occurrence == expression || occurrenceTextRange.getEndOffset() >= expressionTextRange.getStartOffset()) {
|
||||
continue;
|
||||
}
|
||||
if (!isAtRightLocation(expression, expressionTextRange, occurrence)) continue;
|
||||
|
||||
final PsiLocalVariable variable = getVariable(occurrence);
|
||||
|
||||
@@ -113,7 +110,53 @@ public class CastCanBeReplacedWithVariableInspection extends AbstractBaseJavaLoc
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
List<PsiAssignmentExpression> narrowVariables =
|
||||
SyntaxTraverser.psiTraverser(method)
|
||||
.filter(PsiAssignmentExpression.class)
|
||||
.filter(assignment -> EquivalenceChecker.getCanonicalPsiEquivalence().expressionsAreEquivalent(assignment.getLExpression(), operand))
|
||||
.filter(assignment -> {
|
||||
PsiExpression narrowVariable = assignment.getRExpression();
|
||||
return narrowVariable != null && narrowVariable.getType() != null && InstanceOfUtils.typeCompatible(narrowVariable.getType(), castType, operand);
|
||||
})
|
||||
.toList();
|
||||
for (PsiAssignmentExpression narrowVariable : narrowVariables) {
|
||||
if (!isAtRightLocation(expression, expressionTextRange, narrowVariable)) continue;
|
||||
|
||||
final PsiLocalVariable declaration = getVariable(narrowVariable);
|
||||
|
||||
if (declaration != null &&
|
||||
resolveHelper.resolveReferencedVariable(declaration.getName(), expression) == declaration &&
|
||||
!isChangedBetween(castedVar, methodBody, narrowVariable, expression) &&
|
||||
!isChangedBetween(declaration, methodBody, narrowVariable, expression)) {
|
||||
return declaration;
|
||||
}
|
||||
}
|
||||
|
||||
if (!(operand instanceof PsiReferenceExpression wideReferenceExpression)
|
||||
|| !(wideReferenceExpression.resolve() instanceof PsiLocalVariable wideVariable)) return null;
|
||||
|
||||
PsiExpression narrowExpression = wideVariable.getInitializer();
|
||||
if (!(narrowExpression instanceof PsiReferenceExpression narrowReferenceExpression)
|
||||
|| !(narrowReferenceExpression.resolve() instanceof PsiVariable narrowVariable)
|
||||
|| narrowExpression.getType() == null
|
||||
|| !InstanceOfUtils.typeCompatible(narrowExpression.getType(), castType, operand)) return null;
|
||||
|
||||
if (!isAtRightLocation(expression, expressionTextRange, narrowExpression)) return null;
|
||||
|
||||
if (narrowVariable.getName() == null
|
||||
|| resolveHelper.resolveReferencedVariable(narrowVariable.getName(), expression) != narrowVariable
|
||||
|| isChangedBetween(castedVar, methodBody, narrowExpression, expression)
|
||||
|| isChangedBetween(narrowVariable, methodBody, narrowExpression, expression)) return null;
|
||||
|
||||
return narrowVariable;
|
||||
}
|
||||
|
||||
private static boolean isAtRightLocation(@NotNull PsiTypeCastExpression expression,
|
||||
@NotNull TextRange expressionTextRange,
|
||||
@NotNull PsiExpression occurrence) {
|
||||
ProgressIndicatorProvider.checkCanceled();
|
||||
final TextRange occurrenceTextRange = occurrence.getTextRange();
|
||||
return occurrence != expression && occurrenceTextRange.getEndOffset() < expressionTextRange.getStartOffset();
|
||||
}
|
||||
|
||||
private static boolean isChangedBetween(@NotNull final PsiVariable variable,
|
||||
@@ -163,7 +206,7 @@ public class CastCanBeReplacedWithVariableInspection extends AbstractBaseJavaLoc
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static PsiLocalVariable getVariable(@NotNull PsiExpression occurrence) {
|
||||
private static PsiLocalVariable getVariable(@NotNull PsiTypeCastExpression occurrence) {
|
||||
final PsiElement parent = PsiUtil.skipParenthesizedExprUp(occurrence.getParent());
|
||||
|
||||
if (parent instanceof PsiLocalVariable localVariable) {
|
||||
@@ -179,6 +222,16 @@ public class CastCanBeReplacedWithVariableInspection extends AbstractBaseJavaLoc
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static PsiLocalVariable getVariable(@NotNull PsiAssignmentExpression occurrence) {
|
||||
if (PsiUtil.skipParenthesizedExprDown(occurrence.getRExpression()) instanceof PsiReferenceExpression referenceExpression &&
|
||||
referenceExpression.resolve() instanceof PsiLocalVariable localVariable) {
|
||||
return localVariable;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private static class ReplaceCastWithVariableFix implements LocalQuickFix {
|
||||
private final @NotNull String myText;
|
||||
private final @NotNull String myVariableName;
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
// "Replace '(String) aText' with 'anActualText'" "true"
|
||||
|
||||
class FooBar {
|
||||
void method() {
|
||||
String anActualText = "Hello World! ";
|
||||
Object aText;
|
||||
aText = (anActualText);
|
||||
System.out.println(anActualText.trim());
|
||||
aText = Integer.MAX_VALUE;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
// "Replace '(String) aText' with 'anActualText'" "true"
|
||||
|
||||
class FooBar {
|
||||
void method() {
|
||||
String anActualText = "Hello World! ";
|
||||
Object aText;
|
||||
aText = anActualText;
|
||||
System.out.println(anActualText.trim());
|
||||
aText = Integer.MAX_VALUE;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
// "Replace '(String) aText' with 'anActualText'" "true"
|
||||
|
||||
class FooBar {
|
||||
void method() {
|
||||
String anActualText = "Hello World! ";
|
||||
Object aText = anActualText;
|
||||
System.out.println(anActualText.trim());
|
||||
aText = Integer.MAX_VALUE;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
// "Replace '(String) aText' with 'anActualText'" "true"
|
||||
|
||||
class FooBar {
|
||||
void method() {
|
||||
String anActualText = "Hello World! ";
|
||||
Object aText;
|
||||
aText = (anActualText);
|
||||
System.out.println(((String<caret>) aText).trim());
|
||||
aText = Integer.MAX_VALUE;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
// "Replace '(String) aText' with 'anActualText'" "true"
|
||||
|
||||
class FooBar {
|
||||
void method() {
|
||||
String anActualText = "Hello World! ";
|
||||
Object aText;
|
||||
aText = anActualText;
|
||||
System.out.println(((String<caret>) aText).trim());
|
||||
aText = Integer.MAX_VALUE;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
// "Replace '(String) aText' with 'anActualText'" "true"
|
||||
|
||||
class FooBar {
|
||||
void method() {
|
||||
String anActualText = "Hello World! ";
|
||||
Object aText = anActualText;
|
||||
System.out.println(((String<caret>) aText).trim());
|
||||
aText = Integer.MAX_VALUE;
|
||||
}
|
||||
}
|
||||
@@ -8,7 +8,7 @@ import com.intellij.testFramework.LightProjectDescriptor;
|
||||
import com.intellij.testFramework.fixtures.LightJavaCodeInsightFixtureTestCase;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class CastCanBeReplacedWithVariableInspectionTest extends LightQuickFixParameterizedTestCase {
|
||||
public class CastCanBeReplacedWithVariableFixTest extends LightQuickFixParameterizedTestCase {
|
||||
@Override
|
||||
protected LocalInspectionTool @NotNull [] configureLocalInspectionTools() {
|
||||
return new LocalInspectionTool[]{new CastCanBeReplacedWithVariableInspection()};
|
||||
Reference in New Issue
Block a user