From 916cc450053179d2d6378d1993e2846fe28482c9 Mon Sep 17 00:00:00 2001 From: Tagir Valeev Date: Sat, 14 Dec 2019 10:27:31 +0700 Subject: [PATCH] Constant methods: boxing support GitOrigin-RevId: 6fa28da7fe823d2e5bea0ecabe1e49e34e55d7b6 --- .../dataFlow/CustomMethodHandlers.java | 12 ++++++++++-- .../dataFlow/DfaMemoryStateImpl.java | 6 ++++++ .../dataFlow/StandardInstructionVisitor.java | 4 ++++ .../instructions/MethodCallInstruction.java | 3 ++- .../replaceWithTrivialLambda/afterMethodRef.java | 2 +- .../replaceWithTrivialLambda/beforeMethodRef.java | 2 +- .../dataFlow/fixture/ConstantMethods.java | 14 ++++++++++++++ 7 files changed, 38 insertions(+), 5 deletions(-) diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/CustomMethodHandlers.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/CustomMethodHandlers.java index 3da14dd725d5..d2aa36ac3a1c 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/CustomMethodHandlers.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/CustomMethodHandlers.java @@ -46,7 +46,15 @@ class CustomMethodHandlers { staticCall(JAVA_LANG_FLOAT, "toString", "toHexString").parameterTypes("float"), staticCall(JAVA_LANG_BYTE, "toString").parameterTypes("byte"), staticCall(JAVA_LANG_SHORT, "toString").parameterTypes("short"), - staticCall(JAVA_LANG_BOOLEAN, "parseBoolean").parameterTypes("java.lang.String") + staticCall(JAVA_LANG_BOOLEAN, "parseBoolean").parameterTypes("java.lang.String"), + exactInstanceCall(JAVA_LANG_INTEGER, "toString").parameterCount(0), + exactInstanceCall(JAVA_LANG_LONG, "toString").parameterCount(0), + exactInstanceCall(JAVA_LANG_DOUBLE, "toString").parameterCount(0), + exactInstanceCall(JAVA_LANG_FLOAT, "toString").parameterCount(0), + exactInstanceCall(JAVA_LANG_BYTE, "toString").parameterCount(0), + exactInstanceCall(JAVA_LANG_SHORT, "toString").parameterCount(0), + exactInstanceCall(JAVA_LANG_CHARACTER, "toString").parameterCount(0), + exactInstanceCall(JAVA_LANG_BOOLEAN, "toString").parameterCount(0) ); static final int MAX_STRING_CONSTANT_LENGTH_TO_TRACK = 256; @@ -352,7 +360,7 @@ class CustomMethodHandlers { } private static Object getConstantValue(DfaMemoryState memoryState, DfaValue value) { - DfType type = memoryState.getDfType(value); + DfType type = memoryState.getUnboxedDfType(value); Object constant = DfConstantType.getConstantOfType(type, Object.class); if (constant instanceof String && ((String)constant).length() > MAX_STRING_CONSTANT_LENGTH_TO_TRACK) return null; return constant; diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/DfaMemoryStateImpl.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/DfaMemoryStateImpl.java index 24d39ec1c6b3..832fd2421c64 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/DfaMemoryStateImpl.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/DfaMemoryStateImpl.java @@ -1172,6 +1172,12 @@ public class DfaMemoryStateImpl implements DfaMemoryState { if (value instanceof DfaVariableValue && TypeConversionUtil.isPrimitiveWrapper(value.getType())) { return getDfType(SpecialField.UNBOX.createValue(myFactory, value)); } + if (value instanceof DfaTypeValue) { + DfReferenceType refType = ObjectUtils.tryCast(value.getDfType(), DfReferenceType.class); + if (refType != null && refType.getSpecialField() == SpecialField.UNBOX) { + return refType.getSpecialFieldType(); + } + } return getDfType(value); } diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/StandardInstructionVisitor.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/StandardInstructionVisitor.java index 89f200336245..ed6c4348e558 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/StandardInstructionVisitor.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/StandardInstructionVisitor.java @@ -562,6 +562,10 @@ public class StandardInstructionVisitor extends InstructionVisitor { if (precalculated != null) { return getPrecalculatedResult(qualifierValue, state, factory, precalculated); } + SpecialField field = SpecialField.findSpecialField(instruction.getTargetMethod()); + if (field != null) { + return factory.fromDfType(field.getFromQualifier(state.getDfType(qualifierValue))); + } PsiType type = instruction.getResultType(); diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/instructions/MethodCallInstruction.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/instructions/MethodCallInstruction.java index 631700d0c918..698d5da6640b 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/instructions/MethodCallInstruction.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/instructions/MethodCallInstruction.java @@ -18,6 +18,7 @@ package com.intellij.codeInspection.dataFlow.instructions; import com.intellij.codeInsight.Nullability; import com.intellij.codeInspection.dataFlow.*; +import com.intellij.codeInspection.dataFlow.value.DfaTypeValue; import com.intellij.codeInspection.dataFlow.value.DfaValue; import com.intellij.psi.*; import com.intellij.util.ObjectUtils; @@ -96,7 +97,7 @@ public class MethodCallInstruction extends ExpressionPushingInstruction 0 || isPureCall()); - myPrecalculatedReturnValue = precalculatedReturnValue; + myPrecalculatedReturnValue = DfaTypeValue.isUnknown(precalculatedReturnValue) ? null : precalculatedReturnValue; myReturnNullability = call instanceof PsiNewExpression ? Nullability.NOT_NULL : DfaPsiUtil.getElementNullability(myType, myTargetMethod); } diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/replaceWithTrivialLambda/afterMethodRef.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/replaceWithTrivialLambda/afterMethodRef.java index 4e5f225c1ae3..8c829fbe3f43 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/replaceWithTrivialLambda/afterMethodRef.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/replaceWithTrivialLambda/afterMethodRef.java @@ -15,7 +15,7 @@ public class MethodReferenceConstantValue { Boolean aBoolean = opt.map(s -> false) .map(o1 -> true) .map(o -> false) - .orElse(false); + .orElse(new Random().nextBoolean()); if (opt.isPresent()) { Stream.generate(() -> true) .limit(10) diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/replaceWithTrivialLambda/beforeMethodRef.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/replaceWithTrivialLambda/beforeMethodRef.java index a245bee5dba7..dcacb593b5a2 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/replaceWithTrivialLambda/beforeMethodRef.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/replaceWithTrivialLambda/beforeMethodRef.java @@ -15,7 +15,7 @@ public class MethodReferenceConstantValue { Boolean aBoolean = opt.map(this::strangeMethod) .map(Objects::nonNull) .map(Objects::isNull) - .orElse(false); + .orElse(new Random().nextBoolean()); if (opt.isPresent()) { Stream.generate(opt::isPresent) .limit(10) diff --git a/java/java-tests/testData/inspection/dataFlow/fixture/ConstantMethods.java b/java/java-tests/testData/inspection/dataFlow/fixture/ConstantMethods.java index 6a6bc08833d6..2022a72b7e6f 100644 --- a/java/java-tests/testData/inspection/dataFlow/fixture/ConstantMethods.java +++ b/java/java-tests/testData/inspection/dataFlow/fixture/ConstantMethods.java @@ -22,4 +22,18 @@ class Test { System.out.println("Impossible"); } } + + void test4() { + boolean b1 = Boolean.valueOf(false).booleanValue(); + boolean b2 = Boolean.FALSE.booleanValue(); + boolean b3 = Boolean.parseBoolean("false"); + boolean b4 = Boolean.valueOf(false).toString().startsWith("t"); + } + + void test5(double x) { + if (x == 5 || x == 7) { + Double y = x; + System.out.println(y.toString().length() == 3); + } + } } \ No newline at end of file