diff --git a/java/java-analysis-impl/src/com/siyeh/ig/psiutils/InstanceOfUtils.java b/java/java-analysis-impl/src/com/siyeh/ig/psiutils/InstanceOfUtils.java index 647d21e01206..7c538731da12 100644 --- a/java/java-analysis-impl/src/com/siyeh/ig/psiutils/InstanceOfUtils.java +++ b/java/java-analysis-impl/src/com/siyeh/ig/psiutils/InstanceOfUtils.java @@ -469,14 +469,13 @@ public final class InstanceOfUtils { PsiElement block = PsiUtil.getVariableCodeBlock(variable, null); if (block == null) return false; for (PsiReferenceExpression reference : VariableAccessUtils.getVariableReferences(variable, block)) { - if (!isVariableTypeChangeSafeForReference(cast, castType, reference)) return false; + if (PsiTreeUtil.isAncestor(cast, reference, true)) continue; + if (!isVariableTypeChangeSafeForReference(castType, reference)) return false; } return true; } - private static boolean isVariableTypeChangeSafeForReference(@NotNull PsiTypeCastExpression cast, - @NotNull PsiType targetType, - @NotNull PsiReferenceExpression reference) { + static boolean isVariableTypeChangeSafeForReference(@NotNull PsiType targetType, @NotNull PsiReferenceExpression reference) { PsiElement parent = PsiUtil.skipParenthesizedExprUp(reference.getParent()); if (PsiUtil.isAccessedForWriting(reference)) { PsiAssignmentExpression assignmentExpression = tryCast(parent, PsiAssignmentExpression.class); @@ -496,11 +495,11 @@ public final class InstanceOfUtils { // Could be always false instanceof which will become compilation error after fix return TypeConversionUtil.areTypesConvertible(targetType, checkType); } - if (parent instanceof PsiTypeCastExpression parentCast && parent != cast) { + if (parent instanceof PsiTypeCastExpression parentCast) { PsiTypeElement castTypeElement = parentCast.getCastType(); if (castTypeElement == null) return false; PsiType castType = castTypeElement.getType(); - // Another cast could become invalid due to this change + // Another replacement could become invalid due to this change return TypeConversionUtil.areTypesConvertible(targetType, castType); } // Some method call can be mis-resolved after update, check this @@ -513,16 +512,18 @@ public final class InstanceOfUtils { PsiTreeUtil.releaseMark(reference, mark); PsiElement refCopy = PsiTreeUtil.releaseMark(callCopy, mark); if (refCopy == null) return false; - PsiTypeCastExpression insertedCast = (PsiTypeCastExpression)refCopy.replace(cast); - Objects.requireNonNull(insertedCast.getCastType()) - .replace(JavaPsiFacade.getElementFactory(call.getProject()).createTypeElement(targetType)); + PsiElementFactory factory = JavaPsiFacade.getElementFactory(call.getProject()); + PsiTypeCastExpression insertedCast = (PsiTypeCastExpression)refCopy.replace( + factory.createExpressionFromText("(a)"+reference.getReferenceName(), refCopy)); + Objects.requireNonNull(insertedCast.getCastType()).replace(factory.createTypeElement(targetType)); return callCopy.resolveMethod() == method; } - if (parent instanceof PsiReferenceExpression && parent.getParent() instanceof PsiMethodCallExpression call) { - PsiMethod method = call.resolveMethod(); - if (method == null) return false; - // private method cannot be called on a subtype qualifier - return !method.hasModifierProperty(PsiModifier.PRIVATE); + if (parent instanceof PsiReferenceExpression) { + final PsiElement resolve = ((PsiReferenceExpression)parent).resolve(); + // private member cannot be accessed on a subtype qualifier + if (resolve instanceof PsiMember member && member.hasModifierProperty(PsiModifier.PRIVATE)) { + return false; + } } return true; } diff --git a/java/java-analysis-impl/src/com/siyeh/ig/psiutils/VariableAccessUtils.java b/java/java-analysis-impl/src/com/siyeh/ig/psiutils/VariableAccessUtils.java index 2b0a554179dc..9c8e49db9bf7 100644 --- a/java/java-analysis-impl/src/com/siyeh/ig/psiutils/VariableAccessUtils.java +++ b/java/java-analysis-impl/src/com/siyeh/ig/psiutils/VariableAccessUtils.java @@ -19,7 +19,6 @@ import com.intellij.codeInsight.daemon.impl.analysis.HighlightControlFlowUtil; import com.intellij.openapi.util.Comparing; import com.intellij.pom.java.JavaFeature; import com.intellij.psi.*; -import com.intellij.psi.search.LocalSearchScope; import com.intellij.psi.search.searches.ReferencesSearch; import com.intellij.psi.tree.IElementType; import com.intellij.psi.util.PsiTreeUtil; @@ -493,8 +492,7 @@ public final class VariableAccessUtils { final PsiType variableType = variable.getType(); final PsiType initializationType = initialization.getType(); final boolean sameType = Comparing.equal(variableType, initializationType); - for (PsiReference ref : ReferencesSearch.search(variable, new LocalSearchScope(containingScope))) { - final PsiElement refElement = ref.getElement(); + for (PsiReferenceExpression refElement : getVariableReferences(variable)) { if (finalVariableIntroduction || canCaptureThis) { final PsiElement element = PsiTreeUtil.getParentOfType(refElement, PsiClass.class, PsiLambdaExpression.class); if (element != null && PsiTreeUtil.isAncestor(containingScope, element, true)) { @@ -506,15 +504,8 @@ public final class VariableAccessUtils { return false; } - if (!sameType) { - final PsiElement parent = refElement.getParent(); - if (parent instanceof PsiReferenceExpression) { - final PsiElement resolve = ((PsiReferenceExpression)parent).resolve(); - if (resolve instanceof PsiMember && - ((PsiMember)resolve).hasModifierProperty(PsiModifier.PRIVATE)) { - return false; - } - } + if (!sameType && !InstanceOfUtils.isVariableTypeChangeSafeForReference(initializationType, refElement)) { + return false; } } diff --git a/java/java-tests/testData/ig/com/siyeh/igfixes/inline/CastForOverloads.after.java b/java/java-tests/testData/ig/com/siyeh/igfixes/inline/CastForOverloads.after.java deleted file mode 100644 index 7c59f7423f96..000000000000 --- a/java/java-tests/testData/ig/com/siyeh/igfixes/inline/CastForOverloads.after.java +++ /dev/null @@ -1,10 +0,0 @@ -class Base { - { - Descendant descendant = new Descendant(); - consume((Base) descendant); - } - - private static void consume(Base value) {} - private static void consume(Descendant value) {} -} -class Descendant extends Base {} \ No newline at end of file diff --git a/java/java-tests/testData/ig/com/siyeh/igtest/dataflow/unnecessary_local_variable/CastNecessary.java b/java/java-tests/testData/ig/com/siyeh/igtest/dataflow/unnecessary_local_variable/CastNecessary.java new file mode 100644 index 000000000000..661aa1e240b4 --- /dev/null +++ b/java/java-tests/testData/ig/com/siyeh/igtest/dataflow/unnecessary_local_variable/CastNecessary.java @@ -0,0 +1,15 @@ +class Scratch { + public static void main(String... arguments) { + String s = arguments[0]; + Object o = s; + use(o); + } + + private static void use(Object objectionable) { + System.out.println("Objection!"); + } + + private static void use(String s) { + System.out.println("Strings are like ropes. Threads are like fibers"); + } +} \ No newline at end of file diff --git a/java/java-tests/testSrc/com/siyeh/ig/dataflow/UnnecessaryLocalVariableInspectionTest.java b/java/java-tests/testSrc/com/siyeh/ig/dataflow/UnnecessaryLocalVariableInspectionTest.java index f83e174ad849..39883b6ba754 100644 --- a/java/java-tests/testSrc/com/siyeh/ig/dataflow/UnnecessaryLocalVariableInspectionTest.java +++ b/java/java-tests/testSrc/com/siyeh/ig/dataflow/UnnecessaryLocalVariableInspectionTest.java @@ -11,6 +11,8 @@ public class UnnecessaryLocalVariableInspectionTest extends LightJavaInspectionT } public void testUnnecessaryLocalVariable() { doTest(); } + + public void testCastNecessary() { doTest(); } public void testTree() { doTest(); } diff --git a/java/java-tests/testSrc/com/siyeh/ig/fixes/InlineVariableFixTest.java b/java/java-tests/testSrc/com/siyeh/ig/fixes/InlineVariableFixTest.java index d0b68eaab4d1..10b9c85e93d5 100644 --- a/java/java-tests/testSrc/com/siyeh/ig/fixes/InlineVariableFixTest.java +++ b/java/java-tests/testSrc/com/siyeh/ig/fixes/InlineVariableFixTest.java @@ -19,6 +19,6 @@ public class InlineVariableFixTest extends IGQuickFixesTestCase { public void testSingleResourceVar() { doTest(); } public void testCastNeeded() { doTest(); } public void testArrayInitializer() { doTest(); } - public void testCastForOverloads() { doTest(); } + public void testCastForOverloads() { assertQuickfixNotAvailable(); } public void testComment() { doTest(); } }