mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
dfa: remove unnecessary statefulness and clarify void type checks
This commit is contained in:
+26
-7
@@ -34,6 +34,7 @@ import com.intellij.codeInspection.*;
|
||||
import com.intellij.codeInspection.dataFlow.instructions.*;
|
||||
import com.intellij.codeInspection.dataFlow.value.DfaConstValue;
|
||||
import com.intellij.codeInspection.dataFlow.value.DfaValue;
|
||||
import com.intellij.codeInspection.nullable.NullableStuffInspectionBase;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.Condition;
|
||||
@@ -168,7 +169,7 @@ public class DataFlowInspectionBase extends BaseJavaBatchLocalInspectionTool {
|
||||
final DataFlowInstructionVisitor visitor = new DataFlowInstructionVisitor(dfaRunner);
|
||||
final RunnerResult rc = dfaRunner.analyzeMethod(scope, visitor, IGNORE_ASSERT_STATEMENTS, initialStates);
|
||||
if (rc == RunnerResult.OK) {
|
||||
createDescription(dfaRunner, holder, visitor, onTheFly);
|
||||
createDescription(dfaRunner, holder, visitor, onTheFly, scope);
|
||||
|
||||
MultiMap<PsiElement,DfaMemoryState> nestedClosures = dfaRunner.getNestedClosures();
|
||||
for (PsiElement closure : nestedClosures.keySet()) {
|
||||
@@ -226,7 +227,7 @@ public class DataFlowInspectionBase extends BaseJavaBatchLocalInspectionTool {
|
||||
protected void addSurroundWithIfFix(PsiExpression qualifier, List<LocalQuickFix> fixes, boolean onTheFly) {
|
||||
}
|
||||
|
||||
private void createDescription(StandardDataFlowRunner runner, ProblemsHolder holder, DataFlowInstructionVisitor visitor, final boolean onTheFly) {
|
||||
private void createDescription(StandardDataFlowRunner runner, ProblemsHolder holder, DataFlowInstructionVisitor visitor, final boolean onTheFly, PsiElement scope) {
|
||||
Pair<Set<Instruction>, Set<Instruction>> constConditions = runner.getConstConditionalExpressions();
|
||||
Set<Instruction> trueSet = constConditions.getFirst();
|
||||
Set<Instruction> falseSet = constConditions.getSecond();
|
||||
@@ -264,9 +265,7 @@ public class DataFlowInspectionBase extends BaseJavaBatchLocalInspectionTool {
|
||||
reportNullableArguments(visitor, holder, reportedAnchors);
|
||||
reportNullableAssignments(visitor, holder, reportedAnchors);
|
||||
reportUnboxedNullables(visitor, holder, reportedAnchors);
|
||||
if (!runner.isInNullableMethod() && runner.isInMethod() && (runner.isInNotNullMethod() || SUGGEST_NULLABLE_ANNOTATIONS)) {
|
||||
reportNullableReturns(runner, visitor, holder, reportedAnchors);
|
||||
}
|
||||
reportNullableReturns(visitor, holder, reportedAnchors, getScopeMethod(scope));
|
||||
if (SUGGEST_NULLABLE_ANNOTATIONS) {
|
||||
reportNullableArgumentsPassedToNonAnnotated(visitor, holder, reportedAnchors);
|
||||
}
|
||||
@@ -497,13 +496,33 @@ public class DataFlowInspectionBase extends BaseJavaBatchLocalInspectionTool {
|
||||
}
|
||||
}
|
||||
|
||||
private static void reportNullableReturns(StandardDataFlowRunner runner, DataFlowInstructionVisitor visitor, ProblemsHolder holder, Set<PsiElement> reportedAnchors) {
|
||||
@Nullable
|
||||
private static PsiMethod getScopeMethod(PsiElement block) {
|
||||
PsiElement parent = block.getParent();
|
||||
if (parent instanceof PsiMethod) return (PsiMethod)parent;
|
||||
if (parent instanceof PsiLambdaExpression) return LambdaUtil.getFunctionalInterfaceMethod(((PsiLambdaExpression)parent).getFunctionalInterfaceType());
|
||||
return null;
|
||||
}
|
||||
|
||||
private void reportNullableReturns(DataFlowInstructionVisitor visitor,
|
||||
ProblemsHolder holder,
|
||||
Set<PsiElement> reportedAnchors,
|
||||
@Nullable PsiMethod method) {
|
||||
if (method == null || NullableStuffInspectionBase.isNullableNotInferred(method, true)) return;
|
||||
|
||||
boolean notNullRequired = NullableNotNullManager.isNotNull(method);
|
||||
if (!notNullRequired && !SUGGEST_NULLABLE_ANNOTATIONS) return;
|
||||
|
||||
PsiType returnType = method.getReturnType();
|
||||
// no warnings for Void methods (where only null can be possibly returned), or in void lambdas, where the last expression is not returned anyway
|
||||
if (returnType == null || returnType == PsiType.VOID || returnType.equalsToText(CommonClassNames.JAVA_LANG_VOID)) return;
|
||||
|
||||
for (PsiElement statement : visitor.getProblems(NullabilityProblem.nullableReturn)) {
|
||||
assert statement instanceof PsiExpression;
|
||||
final PsiExpression expr = (PsiExpression)statement;
|
||||
if (!reportedAnchors.add(expr)) continue;
|
||||
|
||||
if (runner.isInNotNullMethod()) {
|
||||
if (notNullRequired) {
|
||||
final String text = isNullLiteralExpression(expr)
|
||||
? InspectionsBundle.message("dataflow.message.return.null.from.notnull")
|
||||
: InspectionsBundle.message("dataflow.message.return.nullable.from.notnull");
|
||||
|
||||
@@ -67,9 +67,6 @@ public class DataFlowRunner {
|
||||
return myValueFactory;
|
||||
}
|
||||
|
||||
protected void prepareAnalysis(@NotNull PsiElement psiBlock, Iterable<DfaMemoryState> initialStates) {
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private Collection<DfaMemoryState> createInitialStates(@NotNull PsiElement psiBlock, InstructionVisitor visitor) {
|
||||
PsiClass containingClass = PsiTreeUtil.getParentOfType(psiBlock, PsiClass.class);
|
||||
@@ -101,8 +98,6 @@ public class DataFlowRunner {
|
||||
boolean ignoreAssertions,
|
||||
@NotNull Collection<DfaMemoryState> initialStates) {
|
||||
try {
|
||||
prepareAnalysis(psiBlock, initialStates);
|
||||
|
||||
final ControlFlow flow = createControlFlowAnalyzer().buildControlFlow(psiBlock, ignoreAssertions);
|
||||
if (flow == null) return RunnerResult.NOT_APPLICABLE;
|
||||
|
||||
|
||||
@@ -126,13 +126,6 @@ public class DfaPsiUtil {
|
||||
final PsiCodeBlock body = constructor.getBody();
|
||||
final Map<PsiField, Boolean> map = ContainerUtil.newHashMap();
|
||||
final StandardDataFlowRunner dfaRunner = new StandardDataFlowRunner(false, false) {
|
||||
boolean shouldCheck;
|
||||
|
||||
@Override
|
||||
protected void prepareAnalysis(@NotNull PsiElement psiBlock, Iterable<DfaMemoryState> initialStates) {
|
||||
super.prepareAnalysis(psiBlock, initialStates);
|
||||
shouldCheck = psiBlock == body;
|
||||
}
|
||||
|
||||
private boolean isCallExposingNonInitializedFields(Instruction instruction) {
|
||||
if (!(instruction instanceof MethodCallInstruction) ||
|
||||
@@ -160,19 +153,17 @@ public class DfaPsiUtil {
|
||||
|
||||
@Override
|
||||
protected DfaInstructionState[] acceptInstruction(InstructionVisitor visitor, DfaInstructionState instructionState) {
|
||||
if (shouldCheck) {
|
||||
Instruction instruction = instructionState.getInstruction();
|
||||
if (isCallExposingNonInitializedFields(instruction) ||
|
||||
instruction instanceof ReturnInstruction && !((ReturnInstruction)instruction).isViaException()) {
|
||||
for (PsiField field : containingClass.getFields()) {
|
||||
if (!instructionState.getMemoryState().isNotNull(getFactory().getVarFactory().createVariableValue(field, false))) {
|
||||
map.put(field, false);
|
||||
} else if (!map.containsKey(field)) {
|
||||
map.put(field, true);
|
||||
}
|
||||
Instruction instruction = instructionState.getInstruction();
|
||||
if (isCallExposingNonInitializedFields(instruction) ||
|
||||
instruction instanceof ReturnInstruction && !((ReturnInstruction)instruction).isViaException()) {
|
||||
for (PsiField field : containingClass.getFields()) {
|
||||
if (!instructionState.getMemoryState().isNotNull(getFactory().getVarFactory().createVariableValue(field, false))) {
|
||||
map.put(field, false);
|
||||
} else if (!map.containsKey(field)) {
|
||||
map.put(field, true);
|
||||
}
|
||||
return DfaInstructionState.EMPTY_ARRAY;
|
||||
}
|
||||
return DfaInstructionState.EMPTY_ARRAY;
|
||||
}
|
||||
return super.acceptInstruction(visitor, instructionState);
|
||||
}
|
||||
|
||||
-48
@@ -24,11 +24,8 @@
|
||||
*/
|
||||
package com.intellij.codeInspection.dataFlow;
|
||||
|
||||
import com.intellij.codeInsight.NullableNotNullManager;
|
||||
import com.intellij.codeInspection.dataFlow.instructions.InstanceofInstruction;
|
||||
import com.intellij.codeInspection.dataFlow.instructions.Instruction;
|
||||
import com.intellij.codeInspection.nullable.NullableStuffInspectionBase;
|
||||
import com.intellij.psi.*;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.HashSet;
|
||||
@@ -37,10 +34,6 @@ import java.util.Set;
|
||||
public class StandardDataFlowRunner extends DataFlowRunner {
|
||||
private final Set<Instruction> myCCEInstructions = new HashSet<Instruction>();
|
||||
|
||||
private boolean myInNullableMethod = false;
|
||||
private boolean myInNotNullMethod = false;
|
||||
private boolean myIsInMethod = false;
|
||||
|
||||
public StandardDataFlowRunner() {
|
||||
this(false, true);
|
||||
}
|
||||
@@ -48,35 +41,6 @@ public class StandardDataFlowRunner extends DataFlowRunner {
|
||||
super(unknownMembersAreNullable, honorFieldInitializers);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void prepareAnalysis(@NotNull PsiElement psiBlock, Iterable<DfaMemoryState> initialStates) {
|
||||
PsiElement parent = psiBlock.getParent();
|
||||
myIsInMethod = parent instanceof PsiMethod;
|
||||
if (myIsInMethod) {
|
||||
PsiMethod method = (PsiMethod)parent;
|
||||
myInNullableMethod = isTreatedAsNullable(method);
|
||||
myInNotNullMethod = NullableNotNullManager.isNotNull(method);
|
||||
} else if (parent instanceof PsiLambdaExpression) {
|
||||
PsiMethod method = LambdaUtil.getFunctionalInterfaceMethod(((PsiLambdaExpression)parent).getFunctionalInterfaceType());
|
||||
if (method != null) {
|
||||
myIsInMethod = true;
|
||||
myInNullableMethod = isTreatedAsNullable(method);
|
||||
myInNotNullMethod = NullableNotNullManager.isNotNull(method);
|
||||
}
|
||||
}
|
||||
|
||||
myCCEInstructions.clear();
|
||||
}
|
||||
|
||||
private static boolean isTreatedAsNullable(PsiMethod method) {
|
||||
if (NullableStuffInspectionBase.isNullableNotInferred(method, true)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
PsiType returnType = method.getReturnType();
|
||||
return returnType != null && (returnType == PsiType.VOID || returnType.equalsToText(CommonClassNames.JAVA_LANG_VOID));
|
||||
}
|
||||
|
||||
public void onInstructionProducesCCE(Instruction instruction) {
|
||||
myCCEInstructions.add(instruction);
|
||||
}
|
||||
@@ -85,18 +49,6 @@ public class StandardDataFlowRunner extends DataFlowRunner {
|
||||
return myCCEInstructions;
|
||||
}
|
||||
|
||||
public boolean isInNotNullMethod() {
|
||||
return myInNotNullMethod;
|
||||
}
|
||||
|
||||
public boolean isInNullableMethod() {
|
||||
return myInNullableMethod;
|
||||
}
|
||||
|
||||
public boolean isInMethod() {
|
||||
return myIsInMethod;
|
||||
}
|
||||
|
||||
@NotNull public static Set<Instruction> getRedundantInstanceofs(final DataFlowRunner runner, StandardInstructionVisitor visitor) {
|
||||
HashSet<Instruction> result = new HashSet<Instruction>(1);
|
||||
for (Instruction instruction : runner.getInstructions()) {
|
||||
|
||||
Reference in New Issue
Block a user