mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-01-04 17:20:55 +07:00
IDEA-231391 Evaluate 'x.contains(x)' as 'always true'
Also, restore common known type information on state merge GitOrigin-RevId: f40b56b17c4f1f255c4533b5c8c65bfe3d0c9ebb
This commit is contained in:
committed by
intellij-monorepo-bot
parent
d14f04de7d
commit
a0a2a7dd5d
@@ -125,6 +125,9 @@ public class HardcodedContracts {
|
|||||||
singleConditionContract(
|
singleConditionContract(
|
||||||
ContractValue.argument(0).specialField(SpecialField.STRING_LENGTH), RelationType.EQ,
|
ContractValue.argument(0).specialField(SpecialField.STRING_LENGTH), RelationType.EQ,
|
||||||
ContractValue.zero(), returnTrue()),
|
ContractValue.zero(), returnTrue()),
|
||||||
|
singleConditionContract(
|
||||||
|
ContractValue.argument(0), RelationType.EQ,
|
||||||
|
ContractValue.qualifier(), returnTrue()),
|
||||||
singleConditionContract(
|
singleConditionContract(
|
||||||
ContractValue.qualifier().specialField(SpecialField.STRING_LENGTH), RelationType.LT,
|
ContractValue.qualifier().specialField(SpecialField.STRING_LENGTH), RelationType.LT,
|
||||||
ContractValue.argument(0).specialField(SpecialField.STRING_LENGTH), returnFalse())))
|
ContractValue.argument(0).specialField(SpecialField.STRING_LENGTH), returnFalse())))
|
||||||
|
|||||||
@@ -8,7 +8,6 @@ import com.intellij.codeInspection.dataFlow.value.DfaValue;
|
|||||||
import com.intellij.codeInspection.dataFlow.value.DfaValueFactory;
|
import com.intellij.codeInspection.dataFlow.value.DfaValueFactory;
|
||||||
import com.intellij.codeInspection.dataFlow.value.DfaVariableValue;
|
import com.intellij.codeInspection.dataFlow.value.DfaVariableValue;
|
||||||
import com.intellij.openapi.progress.ProgressManager;
|
import com.intellij.openapi.progress.ProgressManager;
|
||||||
import com.intellij.util.Function;
|
|
||||||
import com.intellij.util.containers.ContainerUtil;
|
import com.intellij.util.containers.ContainerUtil;
|
||||||
import com.intellij.util.containers.MultiMap;
|
import com.intellij.util.containers.MultiMap;
|
||||||
import one.util.streamex.LongStreamEx;
|
import one.util.streamex.LongStreamEx;
|
||||||
@@ -57,11 +56,7 @@ class StateMerger {
|
|||||||
|
|
||||||
final Collection<DfaMemoryStateImpl> group = ContainerUtil.newArrayList(ContainerUtil.concat(group1, group2));
|
final Collection<DfaMemoryStateImpl> group = ContainerUtil.newArrayList(ContainerUtil.concat(group1, group2));
|
||||||
|
|
||||||
replacements.stripAndMerge(group, original -> {
|
replacements.stripAndMerge(group, fact);
|
||||||
DfaMemoryStateImpl copy = original.createCopy();
|
|
||||||
fact.removeFromState(copy);
|
|
||||||
return copy;
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (replacements.hasMerges()) return replacements.getMergeResult();
|
if (replacements.hasMerges()) return replacements.getMergeResult();
|
||||||
@@ -339,6 +334,11 @@ class StateMerger {
|
|||||||
|
|
||||||
abstract void removeFromState(@NotNull DfaMemoryStateImpl state);
|
abstract void removeFromState(@NotNull DfaMemoryStateImpl state);
|
||||||
|
|
||||||
|
void restoreCommonState(DfaMemoryStateImpl stripped, Collection<DfaMemoryStateImpl> merged) {
|
||||||
|
DfType commonType = StreamEx.of(merged).map(s -> s.getDfType(myVar)).foldLeft(DfTypes.BOTTOM, DfType::join);
|
||||||
|
stripped.meetDfType(myVar, commonType);
|
||||||
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
static EqualityFact createEqualityFact(@NotNull DfaVariableValue var, @NotNull DfaValue val) {
|
static EqualityFact createEqualityFact(@NotNull DfaVariableValue var, @NotNull DfaValue val) {
|
||||||
if (val instanceof DfaVariableValue && val.getID() < var.getID()) {
|
if (val instanceof DfaVariableValue && val.getID() < var.getID()) {
|
||||||
@@ -491,22 +491,25 @@ class StateMerger {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void stripAndMerge(@NotNull Collection<DfaMemoryStateImpl> group,
|
private void stripAndMerge(@NotNull Collection<DfaMemoryStateImpl> group, @NotNull Fact fact) {
|
||||||
@NotNull Function<DfaMemoryStateImpl, DfaMemoryStateImpl> stripper) {
|
|
||||||
if (group.size() <= 1) return;
|
if (group.size() <= 1) return;
|
||||||
|
|
||||||
MultiMap<DfaMemoryStateImpl, DfaMemoryStateImpl> strippedToOriginals = MultiMap.create();
|
MultiMap<DfaMemoryStateImpl, DfaMemoryStateImpl> strippedToOriginals = MultiMap.create();
|
||||||
for (DfaMemoryStateImpl original : group) {
|
for (DfaMemoryStateImpl original : group) {
|
||||||
strippedToOriginals.putValue(stripper.fun(original), original);
|
DfaMemoryStateImpl copy = original.createCopy();
|
||||||
|
fact.removeFromState(copy);
|
||||||
|
strippedToOriginals.putValue(copy, original);
|
||||||
}
|
}
|
||||||
for (Map.Entry<DfaMemoryStateImpl, Collection<DfaMemoryStateImpl>> entry : strippedToOriginals.entrySet()) {
|
for (Map.Entry<DfaMemoryStateImpl, Collection<DfaMemoryStateImpl>> entry : strippedToOriginals.entrySet()) {
|
||||||
Collection<DfaMemoryStateImpl> merged = entry.getValue();
|
Collection<DfaMemoryStateImpl> merged = entry.getValue();
|
||||||
if (merged.size() > 1) {
|
if (merged.size() > 1) {
|
||||||
|
DfaMemoryStateImpl stripped = entry.getKey();
|
||||||
|
fact.restoreCommonState(stripped, merged);
|
||||||
for (DfaMemoryStateImpl state : merged) {
|
for (DfaMemoryStateImpl state : merged) {
|
||||||
entry.getKey().afterMerge(state);
|
stripped.afterMerge(state);
|
||||||
}
|
}
|
||||||
myRemovedStates.addAll(merged);
|
myRemovedStates.addAll(merged);
|
||||||
myMerged.add(entry.getKey());
|
myMerged.add(stripped);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,13 @@
|
|||||||
|
import org.jetbrains.annotations.*;
|
||||||
|
|
||||||
|
class Test {
|
||||||
|
public static boolean test(@Nullable String name, @NotNull String prefix) {
|
||||||
|
return name != null && name.startsWith(prefix) && name.length() > prefix.length();
|
||||||
|
}
|
||||||
|
|
||||||
|
void test1(String s1, String s2) {
|
||||||
|
if (<warning descr="Condition 's1.contains(s1)' is always 'true'">s1.contains(s1)</warning>) {}
|
||||||
|
|
||||||
|
if (s1.contains(s2) || <warning descr="Condition 's1.equals(s2)' is always 'false' when reached">s1.equals(s2)</warning>) {}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -667,4 +667,5 @@ public class DataFlowInspectionTest extends DataFlowInspectionTestCase {
|
|||||||
public void testCompareEqualObjectWithNull() { doTest(); }
|
public void testCompareEqualObjectWithNull() { doTest(); }
|
||||||
public void testNullabilityAfterCastAndInstanceOf() { doTest(); }
|
public void testNullabilityAfterCastAndInstanceOf() { doTest(); }
|
||||||
public void testInstanceOfTernary() { doTest(); }
|
public void testInstanceOfTernary() { doTest(); }
|
||||||
|
public void testStringContains() { doTest(); }
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user