[java-dfa] Restrict the result of CustomMethodHandler when qualifier is restricted

Fixes EA-1080132 - ISE: MethodCallInstruction.getMethodResultValue (String.trim, Enum.name)

GitOrigin-RevId: 3ab2fe4fac1d9333d0a61198d2614eead74a173c
This commit is contained in:
Tagir Valeev
2024-06-11 18:03:40 +00:00
committed by intellij-monorepo-bot
parent 8b5e8b8f6d
commit d50f41f7ae
6 changed files with 54 additions and 5 deletions
@@ -1,10 +1,7 @@
// Copyright 2000-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package com.intellij.codeInspection.dataFlow.jvm.descriptors;
import com.intellij.codeInspection.dataFlow.DfaNullability;
import com.intellij.codeInspection.dataFlow.DfaPsiUtil;
import com.intellij.codeInspection.dataFlow.TypeConstraint;
import com.intellij.codeInspection.dataFlow.TypeConstraints;
import com.intellij.codeInspection.dataFlow.*;
import com.intellij.codeInspection.dataFlow.memory.DfaMemoryState;
import com.intellij.codeInspection.dataFlow.types.DfAntiConstantType;
import com.intellij.codeInspection.dataFlow.types.DfConstantType;
@@ -91,6 +88,20 @@ public final class GetterDescriptor extends PsiVarDescriptor {
return super.createValue(factory, qualifier);
}
@Override
public @NotNull DfType restrictFromState(@NotNull DfaVariableValue qualifier, @NotNull DfaMemoryState state) {
CustomMethodHandlers.CustomMethodHandler handler = CustomMethodHandlers.find(myGetter);
if (handler != null) {
DfaValue value = handler.getMethodResultValue(
new DfaCallArguments(qualifier, DfaValue.EMPTY_ARRAY, MutationSignature.pure()),
state, qualifier.getFactory(), myGetter);
if (value != null) {
return state.getDfType(value);
}
}
return super.restrictFromState(qualifier, state);
}
@Override
public int hashCode() {
return Objects.hashCode(myGetter.getName());
@@ -0,0 +1,19 @@
class Scratch {
void test(String codeblock) {
if (codeblock.trim().equals("{")) {
if (<warning descr="Condition 'codeblock.equals(\"}\")' is always 'false'">codeblock.equals("}")</warning>) {
System.out.println(codeblock.trim());
}
}
}
enum E {A, B, C}
void test(E e) {
if (e.name().equals("C")) {
if (<warning descr="Condition 'e == E.A' is always 'false'">e == E.A</warning>) {
System.out.println(e.name());
}
}
}
}
@@ -760,4 +760,5 @@ public class DataFlowInspectionTest extends DataFlowInspectionTestCase {
public void testInitializedViaSuperCall() { doTest(); }
public void testBoxedBooleanMethodWithCast() { doTest(); }
public void testAssignAndReturnVolatile() { doTest(); }
public void testQualifiedValueFromConstant() { doTest();}
}
@@ -2626,6 +2626,7 @@ com.intellij.codeInspection.dataFlow.value.VariableDescriptor
- isCall():Z
- isImplicitReadPossible():Z
- a:isStable():Z
- restrictFromState(com.intellij.codeInspection.dataFlow.value.DfaVariableValue,com.intellij.codeInspection.dataFlow.memory.DfaMemoryState):com.intellij.codeInspection.dataFlow.types.DfType
c:com.intellij.codeInspection.ex.ApplicationInspectionProfileManagerBase
- com.intellij.profile.codeInspection.BaseInspectionProfileManager
- sf:Companion:com.intellij.codeInspection.ex.ApplicationInspectionProfileManagerBase$Companion
@@ -19,7 +19,6 @@ import com.intellij.util.ObjectUtils;
import com.intellij.util.containers.Stack;
import it.unimi.dsi.fastutil.ints.*;
import one.util.streamex.StreamEx;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -794,6 +793,14 @@ public class DfaMemoryStateImpl implements DfaMemoryState {
return false;
}
}
for (Map.Entry<DfaVariableValue, DfType> entry : new ArrayList<>(myVariableTypes.entrySet())) {
DfaVariableValue knownVar = entry.getKey();
if (knownVar.getQualifier() == var) {
if (!meetDfType(knownVar, knownVar.getDescriptor().restrictFromState(var, this))) {
return false;
}
}
}
if (!updateDependentVariables(var, newType)) return false;
if (!correctRelatedValues(var, newType)) return false;
if (newType instanceof DfConstantType && !propagateConstant(var, (DfConstantType<?>)newType)) return false;
@@ -72,6 +72,16 @@ public interface VariableDescriptor {
@NotNull
DfType getDfType(@Nullable DfaVariableValue qualifier);
/**
* @param qualifier qualifier
* @param state memory state
* @return DfType of this value, which might be more precise than the result of {@link #getDfType(DfaVariableValue)} if the
* qualifier type is known to be more precise, and this information restricts the type of this value
*/
default @NotNull DfType restrictFromState(@NotNull DfaVariableValue qualifier, @NotNull DfaMemoryState state) {
return getDfType(qualifier);
}
/**
* Returns the DfType the value with this descriptor has at the beginning of the interpretation in a given context.
*