diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/inliner/MapUpdateInliner.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/inliner/MapUpdateInliner.java index 3d594b87894c..caabdc1b2699 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/inliner/MapUpdateInliner.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/inliner/MapUpdateInliner.java @@ -7,8 +7,6 @@ import com.intellij.codeInsight.Nullability; import com.intellij.codeInspection.dataFlow.CFGBuilder; import com.intellij.codeInspection.dataFlow.SpecialField; import com.intellij.codeInspection.dataFlow.types.DfTypes; -import com.intellij.codeInspection.dataFlow.value.DfaValue; -import com.intellij.codeInspection.dataFlow.value.DfaValueFactory; import com.intellij.psi.CommonClassNames; import com.intellij.psi.PsiExpression; import com.intellij.psi.PsiMethodCallExpression; @@ -36,18 +34,19 @@ public class MapUpdateInliner implements CallInliner { PsiExpression key = args[0]; PsiExpression function = args[1]; builder - .pushExpression(qualifier) - .pop(); + .pushExpression(qualifier) // stack: .. qualifier + .pushExpression(key) // stack: .. qualifier; key + .evaluateFunction(function); String name = Objects.requireNonNull(call.getMethodExpression().getReferenceName()); switch (name) { case "computeIfAbsent": - inlineComputeIfAbsent(builder, qualifier, key, function, type); + inlineComputeIfAbsent(builder, function, type); break; case "computeIfPresent": - inlineComputeIfPresent(builder, qualifier, key, function, type); + inlineComputeIfPresent(builder, function, type); break; case "compute": - inlineCompute(builder, qualifier, key, function, type); + inlineCompute(builder, function, type); break; default: throw new IllegalStateException("Unsupported name: " + name); @@ -65,78 +64,64 @@ public class MapUpdateInliner implements CallInliner { PsiExpression value = args[1]; PsiExpression function = args[2]; builder - .pushExpression(qualifier) - .pop() - .pushExpression(key) - .pop() - .pushExpression(value) + .pushExpression(qualifier) // stack: .. qualifier + .pushExpression(key) // stack: .. qualifier; key + .pop() // stack: .. qualifier + .pushExpression(value) // stack: .. qualifier; value .boxUnbox(value, ExpectedTypeUtils.findExpectedType(value, false)) .evaluateFunction(function) - .pushUnknown() - .ifNotNull() - .push(DfTypes.typedObject(type, Nullability.NOT_NULL)) - .swap() - .invokeFunction(2, function) + .pushUnknown() // stack: .. qualifier; value; get() result + .ifNotNull() // stack: .. qualifier; value + .push(DfTypes.typedObject(type, Nullability.NOT_NULL)) // stack: .. qualifier; value; get() result + .swap() // stack: .. qualifier; get() result; value + .invokeFunction(2, function) // stack: .. qualifier; mapping result .end() - .chain(b -> flushSize(qualifier, b)) + .chain(b -> flushSize(b)) .resultOf(call); return true; } return false; } - private static void flushSize(PsiExpression qualifier, CFGBuilder builder) { - DfaValueFactory factory = builder.getFactory(); - DfaValue value = factory.createValue(qualifier); - DfaValue size = SpecialField.COLLECTION_SIZE.createValue(factory, value); - builder.flush(size); + private static void flushSize(CFGBuilder builder) { + builder.swap().unwrap(SpecialField.COLLECTION_SIZE).pushUnknown().assign().pop(); } private static void inlineComputeIfAbsent(@NotNull CFGBuilder builder, - PsiExpression qualifier, - PsiExpression key, PsiExpression function, PsiType type) { builder - .pushExpression(key) // stack: .. key - .evaluateFunction(function) - .pushUnknown() // stack: .. key; get() result - .ifNull() // stack: .. key - .invokeFunction(1, function) // stack: .. mapping result - .chain(b -> flushSize(qualifier, b)) + .pushUnknown() // stack: .. qualifier; key; get() result + .ifNull() // stack: .. qualifier; key + .invokeFunction(1, function) // stack: .. qualifier; mapping_result + .chain(MapUpdateInliner::flushSize) .elseBranch() - .pop() + .splice(2) .push(DfTypes.typedObject(type, Nullability.NOT_NULL)) .end(); } private static void inlineComputeIfPresent(@NotNull CFGBuilder builder, - PsiExpression qualifier, PsiExpression key, PsiExpression function, PsiType type) { builder - .pushExpression(key) // stack: .. key - .evaluateFunction(function) - .pushUnknown() // stack: .. key; get() result - .ifNotNull() // stack: .. key + .pushUnknown() // stack: .. qualifier; key; get() result + .ifNotNull() // stack: .. qualifier; key .push(DfTypes.typedObject(type, Nullability.NOT_NULL)) - .invokeFunction(2, function) // stack: .. mapping result - .chain(b -> flushSize(qualifier, b)) + .invokeFunction(2, function) // stack: .. qualifier; mapping result + .chain(MapUpdateInliner::flushSize) .elseBranch() - .pop() + .splice(2) .pushNull() .end(); } private static void inlineCompute(@NotNull CFGBuilder builder, - PsiExpression qualifier, PsiExpression key, PsiExpression function, PsiType type) { builder - .pushExpression(key) // stack: .. key - .evaluateFunction(function) .push(DfTypes.typedObject(type, Nullability.NULLABLE)) - .invokeFunction(2, function) // stack: .. mapping result - .chain(b -> flushSize(qualifier, b)); + .invokeFunction(2, function) // stack: .. qualifier; mapping result + .chain(MapUpdateInliner::flushSize); } } diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/redundancy/redundant_operation_on_empty_container/TernaryInQualifier.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/redundancy/redundant_operation_on_empty_container/TernaryInQualifier.java new file mode 100644 index 000000000000..304250866179 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/redundancy/redundant_operation_on_empty_container/TernaryInQualifier.java @@ -0,0 +1,18 @@ +import java.util.*; + +final class Test { + + public static void main(String[] args) { + List keys = Arrays.asList(1, 2, 3, 4, 5); + + Map map1 = new HashMap<>(); + Map map2 = new HashMap<>(); + + for (Integer key : keys) { + (key % 2 == 0 ? map1 : map2).compute(key, (k, v) -> true); + } + + map1.forEach((k, v) -> System.out.println(k + ", " + v)); + map2.forEach((k, v) -> System.out.println(k + ", " + v)); + } +} \ No newline at end of file diff --git a/plugins/InspectionGadgets/testsrc/com/siyeh/ig/redundancy/RedundantOperationOnEmptyContainerInspectionTest.java b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/redundancy/RedundantOperationOnEmptyContainerInspectionTest.java index a97760d0c04d..f3a0bf800a5d 100644 --- a/plugins/InspectionGadgets/testsrc/com/siyeh/ig/redundancy/RedundantOperationOnEmptyContainerInspectionTest.java +++ b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/redundancy/RedundantOperationOnEmptyContainerInspectionTest.java @@ -26,6 +26,9 @@ public class RedundantOperationOnEmptyContainerInspectionTest extends LightJavaI public void testEmptyCollectionReturnThis() { doTest(); } + public void testTernaryInQualifier() { + doTest(); + } @Nullable @Override