mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
DataFlowAnalysis: disable nested closures for impossible cases
This commit is contained in:
+15
-11
@@ -33,6 +33,7 @@ import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
public class DataFlowRunner {
|
||||
private static final Logger LOG = Logger.getInstance("#com.intellij.codeInspection.dataFlow.DataFlowRunner");
|
||||
@@ -42,7 +43,7 @@ public class DataFlowRunner {
|
||||
private final MultiMap<PsiElement, DfaMemoryState> myNestedClosures = new MultiMap<>();
|
||||
// Closures which were registered for previous instruction and can be queried by visitor
|
||||
// to adjust them somehow
|
||||
private final List<DfaMemoryState> myStackTopClosures = new ArrayList<>();
|
||||
private final Map<DfaMemoryState, PsiElement> myStackTopClosures = new HashMap<>();
|
||||
@NotNull
|
||||
private final DfaValueFactory myValueFactory;
|
||||
// Maximum allowed attempts to process instruction. Fail as too complex to process if certain instruction
|
||||
@@ -82,8 +83,12 @@ public class DataFlowRunner {
|
||||
return Collections.singletonList(createMemoryState());
|
||||
}
|
||||
|
||||
List<DfaMemoryState> getStackTopClosures() {
|
||||
return new ArrayList<>(myStackTopClosures);
|
||||
void updateStackTopClosures(Predicate<DfaMemoryState> updater) {
|
||||
myStackTopClosures.forEach((state, element) -> {
|
||||
if(!updater.test(state)) {
|
||||
myNestedClosures.remove(element, state);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@@ -293,14 +298,14 @@ public class DataFlowRunner {
|
||||
for (PsiMethod method : nestedClass.getMethods()) {
|
||||
PsiCodeBlock body = method.getBody();
|
||||
if (body != null) {
|
||||
myNestedClosures.putValue(body, createClosureState(state));
|
||||
createClosureState(body, state);
|
||||
}
|
||||
}
|
||||
for (PsiClassInitializer initializer : nestedClass.getInitializers()) {
|
||||
myNestedClosures.putValue(initializer.getBody(), createClosureState(state));
|
||||
createClosureState(initializer.getBody(), state);
|
||||
}
|
||||
for (PsiField field : nestedClass.getFields()) {
|
||||
myNestedClosures.putValue(field, createClosureState(state));
|
||||
createClosureState(field, state);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -308,15 +313,14 @@ public class DataFlowRunner {
|
||||
DfaMemoryState state = instructionState.getMemoryState();
|
||||
PsiElement body = expr.getBody();
|
||||
if (body != null) {
|
||||
myNestedClosures.putValue(body, createClosureState(state));
|
||||
createClosureState(body, state);
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private DfaMemoryState createClosureState(DfaMemoryState state) {
|
||||
private void createClosureState(PsiElement anchor, DfaMemoryState state) {
|
||||
DfaMemoryState closureState = state.createClosureState();
|
||||
myStackTopClosures.add(closureState);
|
||||
return closureState;
|
||||
myStackTopClosures.put(closureState, anchor);
|
||||
myNestedClosures.putValue(anchor, closureState);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
|
||||
+1
-4
@@ -373,7 +373,6 @@ public class StandardInstructionVisitor extends InstructionVisitor {
|
||||
if (methodName == null || !OPTIONAL_METHOD_NAMES.contains(methodName)) return Collections.emptyList();
|
||||
PsiMethod method = call.resolveMethod();
|
||||
if (method == null || !TypeUtils.isOptional(method.getContainingClass())) return Collections.emptyList();
|
||||
List<DfaMemoryState> closures = runner.getStackTopClosures();
|
||||
DfaCallArguments arguments = popCall(instruction, runner, memState, false);
|
||||
DfaValue[] argValues = arguments.myArguments;
|
||||
DfaValue result = null;
|
||||
@@ -416,9 +415,7 @@ public class StandardInstructionVisitor extends InstructionVisitor {
|
||||
case "transform": {
|
||||
DfaOptionalValue optional = factory.getOptionalFactory().getOptional(!methodName.startsWith("or"));
|
||||
DfaValue relation = factory.createCondition(arguments.myQualifier, RelationType.IS, optional);
|
||||
for (DfaMemoryState closure : closures) {
|
||||
closure.applyCondition(relation);
|
||||
}
|
||||
runner.updateStackTopClosures(state -> state.applyCondition(relation));
|
||||
break;
|
||||
}
|
||||
default:
|
||||
|
||||
@@ -371,4 +371,15 @@ class OptionalWithoutIsPresent {
|
||||
}
|
||||
String res = Optional.<String>empty().<warning descr="The call to 'orElseThrow' always fails, according to its method contracts">orElseThrow</warning>(RuntimeException::new);
|
||||
}
|
||||
|
||||
void testOrElseGet() {
|
||||
final Optional<String> a = Optional.ofNullable(Math.random() > 0.5 ? null:"");
|
||||
final Optional<String> b = Optional.ofNullable(Math.random() > 0.5 ? null:"");
|
||||
if (a.isPresent() || b.isPresent()) {
|
||||
String result = a.orElseGet(() -> b.get()); // no warning
|
||||
System.out.println(result);
|
||||
}
|
||||
String result = a.orElseGet(() -> b.<warning descr="'Optional.get()' without 'isPresent()' check">get</warning>());
|
||||
System.out.println(result);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user