mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
Minor fixes after merging no-unknowns
This commit is contained in:
+8
-1
@@ -115,7 +115,14 @@ class StateQueue {
|
||||
}
|
||||
|
||||
private static List<DfaMemoryStateImpl> squash(List<DfaMemoryStateImpl> states) {
|
||||
return states.stream().filter(left -> states.stream().noneMatch(right -> right != left && right.isSuperStateOf(left))).collect(Collectors.toList());
|
||||
// Sometimes a.isSuperStateOf(b) && b.isSuperStateOf(a) does not imply a.equals(b) which is unpleasant hole in the abstraction
|
||||
// and requires special care here: we leave only one of such states in this case
|
||||
for (int i = 0; i < states.size(); i++) {
|
||||
DfaMemoryStateImpl left = states.get(i);
|
||||
states.subList(i + 1, states.size()).removeIf(right -> left.isSuperStateOf(right) && right.isSuperStateOf(left));
|
||||
}
|
||||
return states.stream().filter(left -> states.stream().noneMatch(right -> right != left && right.isSuperStateOf(left)))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
static List<DfaMemoryStateImpl> mergeGroup(List<DfaMemoryStateImpl> group) {
|
||||
|
||||
+7
-19
@@ -41,6 +41,7 @@ import org.jetbrains.annotations.Nullable;
|
||||
import java.util.*;
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
|
||||
public class DfaMemoryStateImpl implements DfaMemoryState {
|
||||
@@ -1170,7 +1171,7 @@ public class DfaMemoryStateImpl implements DfaMemoryState {
|
||||
}
|
||||
}
|
||||
for (DfaVariableValue value : vars) {
|
||||
if (!value.isFlushableByCalls()) continue;
|
||||
if (value.isNegated() || !value.isFlushableByCalls()) continue;
|
||||
DfaVariableValue qualifier = value.getQualifier();
|
||||
if (qualifier != null) {
|
||||
if (getValueFact(qualifier, DfaFactType.MUTABILITY) == Mutability.UNMODIFIABLE ||
|
||||
@@ -1184,22 +1185,7 @@ public class DfaMemoryStateImpl implements DfaMemoryState {
|
||||
|
||||
private boolean shouldMarkFlushed(@NotNull DfaVariableValue value) {
|
||||
if (value.getInherentNullability() != Nullability.NULLABLE) return false;
|
||||
if (getVariableState(value).getFact(DfaFactType.NULLABILITY) == DfaNullability.FLUSHED) return true;
|
||||
int eqClassIndex = getEqClassIndex(value);
|
||||
if (eqClassIndex < 0) return false;
|
||||
|
||||
EqClass eqClass = myEqClasses.get(eqClassIndex);
|
||||
if (eqClass == null) return false;
|
||||
DfaConstValue nullConst = myFactory.getConstFactory().getNull();
|
||||
if (eqClass.findConstant(true) == nullConst) return true;
|
||||
|
||||
for (DistinctPairSet.DistinctPair pair : getDistinctClassPairs()) {
|
||||
EqClass otherClass = pair.getOtherClass(eqClassIndex);
|
||||
if (otherClass != null && otherClass.findConstant(true) == nullConst) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
return getVariableState(value).getFact(DfaFactType.NULLABILITY) == DfaNullability.FLUSHED || isNull(value) || isNotNull(value);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@@ -1231,8 +1217,10 @@ public class DfaMemoryStateImpl implements DfaMemoryState {
|
||||
DfaVariableValue qualifier = variable.getQualifier();
|
||||
if (psiVariable instanceof PsiField && qualifier != null) {
|
||||
// Flush method results on field write
|
||||
qualifier.getDependentVariables().stream().filter(DfaVariableValue::containsCalls)
|
||||
.forEach(val -> doFlush(val, shouldMarkFlushed(val)));
|
||||
List<DfaVariableValue> toFlush =
|
||||
qualifier.getDependentVariables().stream().filter(DfaVariableValue::containsCalls)
|
||||
.filter(var -> !var.isNegated()).collect(Collectors.toList());
|
||||
toFlush.forEach(val -> doFlush(val, shouldMarkFlushed(val)));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -89,7 +89,7 @@ public class DfaValueFactory {
|
||||
public DfaValue createExactTypeValue(@Nullable PsiType type) {
|
||||
if (type == null) return DfaUnknownValue.getInstance();
|
||||
DfaFactMap facts = DfaFactMap.EMPTY.with(DfaFactType.TYPE_CONSTRAINT, TypeConstraint.exact(createDfaType(type)))
|
||||
.with(DfaFactType.CAN_BE_NULL, false);
|
||||
.with(DfaFactType.NULLABILITY, DfaNullability.NOT_NULL);
|
||||
return getFactFactory().createValue(facts);
|
||||
}
|
||||
|
||||
|
||||
@@ -1204,7 +1204,9 @@ public class TypeConversionUtil {
|
||||
PsiType[] types = Stream.of(extendsList).map(PsiClassType::resolve).filter(Objects::nonNull)
|
||||
.map(psiClass -> getClassErasedType(psiClass, visited, beforeSubstitutor, typeParameter, true))
|
||||
.toArray(PsiType[]::new);
|
||||
return PsiIntersectionType.createIntersection(true, types);
|
||||
return types.length == 0 ?
|
||||
PsiType.getJavaLangObject(typeParameter.getManager(), typeParameter.getResolveScope()) :
|
||||
PsiIntersectionType.createIntersection(true, types);
|
||||
}
|
||||
return getClassErasedType(extendsList[0].resolve(), visited, beforeSubstitutor, typeParameter, false);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
class Test {
|
||||
private static void test(@NotNull IfStmt ifStatement) {
|
||||
IfStmt currentIf = ifStatement;
|
||||
boolean flag = false;
|
||||
while (true) {
|
||||
if (currentIf.getElseBranch() != null) return;
|
||||
if(currentIf.getCondition() != null && checkCondition(currentIf.getCondition())) {
|
||||
flag = true;
|
||||
}
|
||||
Stmt sibling = currentIf;
|
||||
do {
|
||||
sibling = getNext(sibling);
|
||||
}
|
||||
while (sibling != null);
|
||||
|
||||
IfStmt enclosingIf = getEnclosing(currentIf);
|
||||
if (enclosingIf == null) break;
|
||||
currentIf = enclosingIf;
|
||||
}
|
||||
if(flag) {
|
||||
System.out.println("not always");
|
||||
}
|
||||
}
|
||||
|
||||
interface Stmt {}
|
||||
|
||||
interface IfStmt extends Stmt {
|
||||
@Nullable Object getElseBranch();
|
||||
@Nullable Object getCondition();
|
||||
}
|
||||
|
||||
static native @Nullable Stmt getNext(Stmt cur);
|
||||
static native IfStmt getEnclosing(Stmt cur);
|
||||
static native boolean checkCondition(Object condition);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
class GetUnknownTest {
|
||||
private void test(Message message, boolean isApplicable) {
|
||||
if (message == null && field == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (message != null) {
|
||||
field = message.getHeader();
|
||||
doSomething();
|
||||
}
|
||||
|
||||
if (isApplicable) {
|
||||
// Dubious warning: message.getHeader() is not annotated, but assigned to nullable field; should we consider the result as nullable?
|
||||
System.out.println(field.<warning descr="Method invocation 'hashCode' may produce 'java.lang.NullPointerException'">hashCode</warning>());
|
||||
}
|
||||
}
|
||||
|
||||
interface Message {
|
||||
Object getHeader();
|
||||
}
|
||||
|
||||
@Nullable Object field;
|
||||
|
||||
native void doSomething();
|
||||
}
|
||||
class BooleanTest {
|
||||
native private Object getSomething();
|
||||
private @Nullable Boolean field;
|
||||
|
||||
private boolean test(Object x) {
|
||||
if (field == null) {
|
||||
field = x != null;
|
||||
|
||||
if (getSomething() != null) {
|
||||
field = true;
|
||||
}
|
||||
}
|
||||
|
||||
return field.booleanValue();
|
||||
}
|
||||
}
|
||||
@@ -622,4 +622,6 @@ public class DataFlowInspectionTest extends DataFlowInspectionTestCase {
|
||||
public void testPolyadicEquality() { doTest(); }
|
||||
public void testBoxUnboxArrayElement() { doTest(); }
|
||||
public void testExactInstanceOf() { doTest(); }
|
||||
public void testNullFlushed() { doTest(); }
|
||||
public void testBooleanMergeInLoop() { doTest(); }
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user