mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
Convert 'ReplaceCastWithVariableAction' to 'CastCanBeReplacedWithVariableInspection' and support pattern variables
IDEA-302310 GitOrigin-RevId: 2b364e79c3b2f43fe4729677491c3676ba39d493
This commit is contained in:
committed by
intellij-monorepo-bot
parent
8909ecc23b
commit
6ace002822
+187
@@ -0,0 +1,187 @@
|
||||
// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.codeInspection;
|
||||
|
||||
import com.intellij.openapi.progress.ProgressIndicatorProvider;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.controlFlow.*;
|
||||
import com.intellij.psi.util.JavaPsiPatternUtil;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.psi.util.PsiUtil;
|
||||
import com.siyeh.InspectionGadgetsBundle;
|
||||
import com.siyeh.ig.psiutils.CommentTracker;
|
||||
import com.siyeh.ig.psiutils.EquivalenceChecker;
|
||||
import com.siyeh.ig.psiutils.InstanceOfUtils;
|
||||
import org.jetbrains.annotations.Nls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* @author Danila Ponomarenko
|
||||
*/
|
||||
public class CastCanBeReplacedWithVariableInspection extends AbstractBaseJavaLocalInspectionTool
|
||||
implements CleanupLocalInspectionTool {
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public PsiElementVisitor buildVisitor(@NotNull ProblemsHolder holder, boolean isOnTheFly) {
|
||||
return new JavaElementVisitor() {
|
||||
@Override
|
||||
public void visitTypeCastExpression(@NotNull PsiTypeCastExpression typeCastExpression) {
|
||||
final PsiMethod method = PsiTreeUtil.getParentOfType(typeCastExpression, PsiMethod.class);
|
||||
|
||||
if (method == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
final PsiExpression operand = PsiUtil.skipParenthesizedExprDown(typeCastExpression.getOperand());
|
||||
if (!(operand instanceof PsiReferenceExpression operandReference)) {
|
||||
return;
|
||||
}
|
||||
|
||||
final PsiElement resolved = operandReference.resolve();
|
||||
if (!(resolved instanceof PsiParameter) && !(resolved instanceof PsiLocalVariable)) {
|
||||
return;
|
||||
}
|
||||
|
||||
final PsiVariable replacement = findReplacement(method, (PsiVariable)resolved, typeCastExpression);
|
||||
if (replacement == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
final String variableName = replacement.getName();
|
||||
final String castExpressionText = typeCastExpression.getText();
|
||||
final LocalQuickFix fix = new ReplaceCastWithVariableFix(castExpressionText, replacement);
|
||||
holder.registerProblem(typeCastExpression,
|
||||
InspectionGadgetsBundle.message("inspection.cast.can.be.replaced.with.variable.message",
|
||||
variableName, castExpressionText), fix);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static PsiVariable findReplacement(@NotNull PsiMethod method,
|
||||
@NotNull PsiVariable castedVar,
|
||||
@NotNull PsiTypeCastExpression expression) {
|
||||
final TextRange expressionTextRange = expression.getTextRange();
|
||||
if (InstanceOfUtils.isUncheckedCast(expression)) return null;
|
||||
PsiExpression operand = Objects.requireNonNull(PsiUtil.skipParenthesizedExprDown(expression.getOperand()));
|
||||
PsiType castType = Objects.requireNonNull(expression.getCastType()).getType();
|
||||
List<PsiTypeCastExpression> found =
|
||||
SyntaxTraverser.psiTraverser(method)
|
||||
.filter(PsiTypeCastExpression.class)
|
||||
.filter(cast -> EquivalenceChecker.getCanonicalPsiEquivalence().expressionsAreEquivalent(cast.getOperand(), operand))
|
||||
.filter(cast -> {
|
||||
PsiTypeElement typeElement = cast.getCastType();
|
||||
return typeElement != null && InstanceOfUtils.typeCompatible(typeElement.getType(), castType, operand);
|
||||
})
|
||||
.toList();
|
||||
PsiResolveHelper resolveHelper = PsiResolveHelper.getInstance(method.getProject());
|
||||
final PsiCodeBlock methodBody = method.getBody();
|
||||
if (methodBody == null) return null;
|
||||
for (PsiTypeCastExpression occurrence : found) {
|
||||
ProgressIndicatorProvider.checkCanceled();
|
||||
final TextRange occurrenceTextRange = occurrence.getTextRange();
|
||||
if (occurrence == expression || occurrenceTextRange.getEndOffset() >= expressionTextRange.getStartOffset()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
final PsiLocalVariable variable = getVariable(occurrence);
|
||||
|
||||
if (variable != null &&
|
||||
resolveHelper.resolveReferencedVariable(variable.getName(), expression) == variable &&
|
||||
!isChangedBetween(castedVar, methodBody, occurrence, expression) &&
|
||||
!isChangedBetween(variable, methodBody, occurrence, expression)) {
|
||||
return variable;
|
||||
}
|
||||
}
|
||||
|
||||
PsiInstanceOfExpression instanceOf = InstanceOfUtils.findPatternCandidate(expression);
|
||||
if (instanceOf != null) {
|
||||
PsiPattern pattern = instanceOf.getPattern();
|
||||
PsiPatternVariable patternVariable = JavaPsiPatternUtil.getPatternVariable(pattern);
|
||||
if (patternVariable != null &&
|
||||
!isChangedBetween(castedVar, methodBody, instanceOf, expression) &&
|
||||
!isChangedBetween(patternVariable, methodBody, instanceOf, expression)) {
|
||||
return patternVariable;
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
ControlFlow controlFlow;
|
||||
try {
|
||||
controlFlow = ControlFlowFactory.getInstance(variable.getProject()).getControlFlow(scope, new LocalsControlFlowPolicy(scope), true);
|
||||
}
|
||||
catch (AnalysisCanceledException ignored) {
|
||||
controlFlow = ControlFlow.EMPTY;
|
||||
}
|
||||
int startOffset = controlFlow.getEndOffset(start) + 1;
|
||||
int endOffset = controlFlow.getEndOffset(end);
|
||||
return ControlFlowUtil.getWrittenVariables(controlFlow, startOffset, endOffset, true).contains(variable);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static PsiLocalVariable getVariable(@NotNull PsiExpression occurrence) {
|
||||
final PsiElement parent = PsiUtil.skipParenthesizedExprUp(occurrence.getParent());
|
||||
|
||||
if (parent instanceof PsiLocalVariable localVariable) {
|
||||
return localVariable;
|
||||
}
|
||||
|
||||
if (parent instanceof PsiAssignmentExpression assignmentExpression &&
|
||||
assignmentExpression.getLExpression() 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;
|
||||
|
||||
private ReplaceCastWithVariableFix(@NotNull String text, @NotNull PsiVariable variable) {
|
||||
myText = text;
|
||||
myVariableName = Objects.requireNonNull(variable.getName());
|
||||
}
|
||||
|
||||
@Nls(capitalization = Nls.Capitalization.Sentence)
|
||||
@NotNull
|
||||
@Override
|
||||
public String getName() {
|
||||
return CommonQuickFixBundle.message("fix.replace.x.with.y", myText, myVariableName);
|
||||
}
|
||||
|
||||
@Nls(capitalization = Nls.Capitalization.Sentence)
|
||||
@NotNull
|
||||
@Override
|
||||
public String getFamilyName() {
|
||||
return InspectionGadgetsBundle.message("inspection.cast.can.be.replaced.with.variable.family.name");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) {
|
||||
final PsiElement element = descriptor.getPsiElement();
|
||||
if (element instanceof PsiTypeCastExpression typeCastExpression) {
|
||||
final PsiElement toReplace =
|
||||
typeCastExpression.getParent() instanceof PsiParenthesizedExpression ? typeCastExpression.getParent() : typeCastExpression;
|
||||
new CommentTracker().replaceAndRestoreComments(toReplace, myVariableName);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1952,12 +1952,6 @@
|
||||
<bundleName>messages.JavaBundle</bundleName>
|
||||
<categoryKey>intention.category.strings</categoryKey>
|
||||
</intentionAction>
|
||||
<intentionAction>
|
||||
<language>JAVA</language>
|
||||
<className>com.intellij.codeInsight.intention.impl.ReplaceCastWithVariableAction</className>
|
||||
<bundleName>messages.JavaBundle</bundleName>
|
||||
<categoryKey>intention.category.declaration</categoryKey>
|
||||
</intentionAction>
|
||||
<intentionAction>
|
||||
<language>JAVA</language>
|
||||
<className>com.intellij.codeInsight.intention.impl.SortContentAction</className>
|
||||
|
||||
-176
@@ -1,176 +0,0 @@
|
||||
// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.codeInsight.intention.impl;
|
||||
|
||||
import com.intellij.codeInsight.intention.PsiElementBaseIntentionAction;
|
||||
import com.intellij.java.JavaBundle;
|
||||
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.psi.util.PsiUtil;
|
||||
import com.intellij.util.IncorrectOperationException;
|
||||
import com.siyeh.ig.psiutils.CommentTracker;
|
||||
import com.siyeh.ig.psiutils.EquivalenceChecker;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @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 = PsiUtil.skipParenthesizedExprDown(typeCastExpression.getOperand());
|
||||
if (!(operand instanceof PsiReferenceExpression)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
final PsiReferenceExpression operandReference = (PsiReferenceExpression)operand;
|
||||
final PsiElement resolved = operandReference.resolve();
|
||||
if (!(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(JavaBundle.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);
|
||||
new CommentTracker().replaceAndRestoreComments(toReplace, factory.createExpressionFromText(myReplaceVariableName, toReplace));
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static PsiLocalVariable findReplacement(@NotNull PsiMethod method,
|
||||
@NotNull PsiVariable castedVar,
|
||||
@NotNull PsiTypeCastExpression expression) {
|
||||
final TextRange expressionTextRange = expression.getTextRange();
|
||||
PsiExpression operand = PsiUtil.skipParenthesizedExprDown(expression.getOperand());
|
||||
List<PsiTypeCastExpression> found =
|
||||
SyntaxTraverser.psiTraverser(method)
|
||||
.filter(PsiTypeCastExpression.class)
|
||||
.filter(cast -> EquivalenceChecker.getCanonicalPsiEquivalence().expressionsAreEquivalent(cast.getOperand(), operand))
|
||||
.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;
|
||||
}
|
||||
|
||||
final PsiLocalVariable variable = getVariable(occurrence);
|
||||
|
||||
final PsiCodeBlock methodBody = method.getBody();
|
||||
if (variable != null && methodBody != null &&
|
||||
resolveHelper.resolveReferencedVariable(variable.getName(), expression) == variable &&
|
||||
!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<>();
|
||||
|
||||
scope.accept(
|
||||
new JavaRecursiveElementWalkingVisitor() {
|
||||
private boolean inScope;
|
||||
|
||||
@Override
|
||||
public void visitElement(@NotNull PsiElement element) {
|
||||
if (element == start) {
|
||||
inScope = true;
|
||||
}
|
||||
if (element == end) {
|
||||
inScope = false;
|
||||
stopWalking();
|
||||
}
|
||||
super.visitElement(element);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitAssignmentExpression(@NotNull 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 = PsiUtil.skipParenthesizedExprUp(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 JavaBundle.message("intention.replace.cast.with.var.family");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
<html>
|
||||
<body>
|
||||
Reports type cast operations that can be replaced with existing local or pattern variables with the same value.
|
||||
<p>Example:</p>
|
||||
<pre><code>
|
||||
void foo(Object obj) {
|
||||
String s = (String) obj;
|
||||
System.out.println(((String) obj).trim());
|
||||
}
|
||||
</code></pre>
|
||||
<p>After the quick-fix is applied:</p>
|
||||
<pre><code>
|
||||
void foo(Object obj) {
|
||||
String s = (String) obj;
|
||||
System.out.println(s.trim());
|
||||
}
|
||||
</code></pre>
|
||||
<!-- tooltip end -->
|
||||
<p><small>New in 2022.3</small></p>
|
||||
</body>
|
||||
</html>
|
||||
-2
@@ -1,2 +0,0 @@
|
||||
FooBar foobar = (FooBar) foo;
|
||||
return foobar.baz;
|
||||
-2
@@ -1,2 +0,0 @@
|
||||
FooBar foobar = (FooBar) foo;
|
||||
return <spot>((FooBar) foo)</spot>.baz;
|
||||
-5
@@ -1,5 +0,0 @@
|
||||
<html>
|
||||
<body>
|
||||
Replaces a type cast expression with an existing local variable with the same value.
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,8 @@
|
||||
// "Replace '(String) obj' with 's'" "true-preview"
|
||||
|
||||
class X {
|
||||
void foo(Object obj) {
|
||||
String s = (String) obj;
|
||||
System.out.println(s.trim());
|
||||
}
|
||||
}
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
// "Replace '(String) o' with 's1'" "true-preview"
|
||||
|
||||
class C {
|
||||
void foo(Object o) {
|
||||
String s1 = (String) o;
|
||||
if (Math.random() > 0.5) {
|
||||
o = null;
|
||||
return;
|
||||
}
|
||||
String s2 = s1;
|
||||
}
|
||||
}
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
// "Replace '(String) o' with 's1'" "true-preview"
|
||||
|
||||
class C {
|
||||
void foo(Object o) {
|
||||
String s1 = (String) o;
|
||||
if (Math.random() > 0.5) {
|
||||
s1 = null;
|
||||
return;
|
||||
}
|
||||
String s2 = s1;
|
||||
}
|
||||
}
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
// "Replace '(String) obj' with 's1'" "false"
|
||||
|
||||
class X {
|
||||
void test(Object obj) {
|
||||
String s1 = (String) obj, s2 = s1 = "blah blah blah";
|
||||
String s3 = (String) ob<caret>j;
|
||||
}
|
||||
}
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
// "Replace '(String) obj' with 's1'" "false"
|
||||
|
||||
class X {
|
||||
void test(Object obj, String s) {
|
||||
if (obj instanceof String s1 && (s1 = "blah blah blah").equals(s)) {
|
||||
String s2 = (String) ob<caret>j;
|
||||
}
|
||||
}
|
||||
}
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
// "Replace '(Integer) obj' with 's'" "false"
|
||||
|
||||
class X {
|
||||
void test(Object obj) {
|
||||
String s = (String) obj;
|
||||
Integer i = ((Integer) ob<caret>j).intValue();
|
||||
}
|
||||
}
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
// "Replace '(String) obj' with 's'" "true-preview"
|
||||
|
||||
class X {
|
||||
void foo(Object obj) {
|
||||
String s = (String) obj;
|
||||
System.out.println(((String) ob<caret>j).trim());
|
||||
}
|
||||
}
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
// "Replace '(String) o' with 's1'" "true-preview"
|
||||
|
||||
class C {
|
||||
void foo(Object o) {
|
||||
String s1 = (String) o;
|
||||
if (Math.random() > 0.5) {
|
||||
o = null;
|
||||
return;
|
||||
}
|
||||
String s2 = (String) o<caret>;
|
||||
}
|
||||
}
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
// "Replace '(String) o' with 's1'" "true-preview"
|
||||
|
||||
class C {
|
||||
void foo(Object o) {
|
||||
String s1 = (String) o;
|
||||
if (Math.random() > 0.5) {
|
||||
s1 = null;
|
||||
return;
|
||||
}
|
||||
String s2 = (String) o<caret>;
|
||||
}
|
||||
}
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
// "Replace '(ArrayList<Integer>) obj' with 'arrayList'" "false"
|
||||
|
||||
import java.util.*;
|
||||
|
||||
class X {
|
||||
void test(List obj) {
|
||||
ArrayList arrayList = (ArrayList) obj;
|
||||
Integer list = ((ArrayList<Integer>) ob<caret>j).get(0);
|
||||
}
|
||||
}
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.java.codeInspection;
|
||||
|
||||
import com.intellij.codeInsight.daemon.quickFix.LightQuickFixParameterizedTestCase;
|
||||
import com.intellij.codeInspection.CastCanBeReplacedWithVariableInspection;
|
||||
import com.intellij.codeInspection.LocalInspectionTool;
|
||||
import com.intellij.testFramework.LightProjectDescriptor;
|
||||
import com.intellij.testFramework.fixtures.LightJavaCodeInsightFixtureTestCase;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class CastCanBeReplacedWithVariableInspectionTest extends LightQuickFixParameterizedTestCase {
|
||||
@Override
|
||||
protected LocalInspectionTool @NotNull [] configureLocalInspectionTools() {
|
||||
return new LocalInspectionTool[]{new CastCanBeReplacedWithVariableInspection()};
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getBasePath() {
|
||||
return "/inspection/castCanBeReplacedWithVariable";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected @NotNull LightProjectDescriptor getProjectDescriptor() {
|
||||
return LightJavaCodeInsightFixtureTestCase.JAVA_16;
|
||||
}
|
||||
}
|
||||
@@ -859,8 +859,6 @@ intention.move.field.assignment.to.declaration=Move assignment to field declarat
|
||||
intention.move.initializer.to.constructor=Move initializer to constructor
|
||||
intention.move.initializer.to.set.up=Move initializer to setUp method
|
||||
intention.override.method.text=Override method ''{0}''
|
||||
intention.replace.cast.with.var.family=Replace cast with variable
|
||||
intention.replace.cast.with.var.text=Replace ''{0}'' with ''{1}''
|
||||
intention.replace.concatenation.with.formatted.output.family=Replace concatenation with formatted output
|
||||
intention.replace.concatenation.with.formatted.output.text=Replace '+' with 'java.text.MessageFormat.format()'
|
||||
intention.split.declaration.assignment.text=Split into declaration and assignment
|
||||
|
||||
+4
@@ -2303,6 +2303,10 @@ inspection.pattern.variable.can.be.used.existing.message=Existing pattern variab
|
||||
inspection.pattern.variable.can.be.used.existing.fix.family.name=Replace with existing pattern variable
|
||||
inspection.pattern.variable.can.be.used.existing.fix.name=Replace ''{0}'' with existing pattern variable ''{1}''
|
||||
|
||||
inspection.cast.can.be.replaced.with.variable.display.name=Cast can be replaced with variable
|
||||
inspection.cast.can.be.replaced.with.variable.message=Variable ''{0}'' can be used instead of ''{1}''
|
||||
inspection.cast.can.be.replaced.with.variable.family.name=Replace cast with variable
|
||||
|
||||
array.hash.code.fix.family.name=Replace with 'Arrays.hashCode()' call
|
||||
objects.hash.fix.family.name=Wrap with 'Arrays.hashCode()'
|
||||
unqualified.static.access.fix.family.name=Qualify static access
|
||||
|
||||
+12
-8
@@ -183,16 +183,20 @@ public final class InstanceOfUtils {
|
||||
*/
|
||||
@Nullable
|
||||
public static PsiInstanceOfExpression findPatternCandidate(@NotNull PsiTypeCastExpression cast) {
|
||||
PsiTypeElement castType = cast.getCastType();
|
||||
if (castType == null) return null;
|
||||
PsiExpression castOperand = cast.getOperand();
|
||||
if (castOperand == null) return null;
|
||||
PsiType type = castOperand.getType();
|
||||
if (type == null) return null;
|
||||
if (JavaGenericsUtil.isUncheckedCast(castType.getType(), type)) return null;
|
||||
if (isUncheckedCast(cast)) return null;
|
||||
return findCorrespondingInstanceOf(cast);
|
||||
}
|
||||
|
||||
public static boolean isUncheckedCast(@NotNull PsiTypeCastExpression cast) {
|
||||
PsiTypeElement castType = cast.getCastType();
|
||||
if (castType == null) return true;
|
||||
PsiExpression castOperand = cast.getOperand();
|
||||
if (castOperand == null) return true;
|
||||
PsiType type = castOperand.getType();
|
||||
if (type == null) return true;
|
||||
return JavaGenericsUtil.isUncheckedCast(castType.getType(), type);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param cast a cast expression to find parent instanceof for
|
||||
* @return an instanceof expression that checks for the same raw type as the cast.
|
||||
@@ -376,7 +380,7 @@ public final class InstanceOfUtils {
|
||||
return null;
|
||||
}
|
||||
|
||||
private static boolean typeCompatible(@NotNull PsiType instanceOfType, @NotNull PsiType castType, @NotNull PsiExpression castOperand) {
|
||||
public static boolean typeCompatible(@NotNull PsiType instanceOfType, @NotNull PsiType castType, @NotNull PsiExpression castOperand) {
|
||||
if (instanceOfType.equals(castType)) return true;
|
||||
if (castType instanceof PsiClassType) {
|
||||
PsiClassType rawType = ((PsiClassType)castType).rawType();
|
||||
|
||||
@@ -2769,6 +2769,10 @@
|
||||
bundle="messages.InspectionGadgetsBundle" key="inspection.pattern.variable.can.be.used.display.name"
|
||||
groupBundle="messages.InspectionsBundle" groupKey="group.names.language.level.specific.issues.and.migration.aids16"
|
||||
implementationClass="com.intellij.codeInspection.PatternVariableCanBeUsedInspection" cleanupTool="true"/>
|
||||
<localInspection groupPath="Java" language="JAVA" shortName="CastCanBeReplacedWithVariable" enabledByDefault="true" level="WARNING"
|
||||
bundle="messages.InspectionGadgetsBundle" key="inspection.cast.can.be.replaced.with.variable.display.name"
|
||||
groupBundle="messages.InspectionsBundle" groupKey="group.names.verbose.or.redundant.code.constructs"
|
||||
implementationClass="com.intellij.codeInspection.CastCanBeReplacedWithVariableInspection" cleanupTool="true"/>
|
||||
<localInspection groupPathKey="group.path.names.java.language.level.specific.issues.and.migration.aids" language="JAVA" shortName="VariableTypeCanBeExplicit" enabledByDefault="true" level="INFORMATION"
|
||||
bundle="messages.InspectionGadgetsBundle" key="variable.type.can.be.explicit.display.name"
|
||||
groupBundle="messages.InspectionsBundle" groupKey="group.names.language.level.specific.issues.and.migration.aids10"
|
||||
|
||||
Reference in New Issue
Block a user