mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
IDEA-85993 Nullable analysis works incorrectly with inner classes
This commit is contained in:
@@ -213,7 +213,7 @@ class ControlFlowAnalyzer extends JavaElementVisitor {
|
||||
PsiElement[] elements = statement.getDeclaredElements();
|
||||
for (PsiElement element : elements) {
|
||||
if (element instanceof PsiClass) {
|
||||
element.accept(this);
|
||||
addInstruction(new EmptyInstruction(element));
|
||||
}
|
||||
else if (element instanceof PsiVariable) {
|
||||
PsiVariable variable = (PsiVariable)element;
|
||||
@@ -306,7 +306,7 @@ class ControlFlowAnalyzer extends JavaElementVisitor {
|
||||
PsiStatement body = ((PsiForeachStatement)continuedStatement).getBody();
|
||||
offset = myPass1Flow.getEndOffset(body);
|
||||
}
|
||||
Instruction instruction = offset == -1 ? new EmptyInstruction() : new GotoInstruction(offset);
|
||||
Instruction instruction = offset == -1 ? new EmptyInstruction(null) : new GotoInstruction(offset);
|
||||
addInstruction(instruction);
|
||||
}
|
||||
finishElement(statement);
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
package com.intellij.codeInspection.dataFlow;
|
||||
|
||||
import com.intellij.codeInspection.dataFlow.instructions.BranchingInstruction;
|
||||
import com.intellij.codeInspection.dataFlow.instructions.EmptyInstruction;
|
||||
import com.intellij.codeInspection.dataFlow.instructions.Instruction;
|
||||
import com.intellij.codeInspection.dataFlow.instructions.MethodCallInstruction;
|
||||
import com.intellij.codeInspection.dataFlow.value.DfaValueFactory;
|
||||
@@ -35,6 +36,7 @@ import com.intellij.openapi.progress.ProgressManager;
|
||||
import com.intellij.openapi.util.Key;
|
||||
import com.intellij.openapi.util.Pair;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.util.PsiUtil;
|
||||
import gnu.trove.THashSet;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
@@ -71,11 +73,11 @@ public class DataFlowRunner {
|
||||
protected Collection<DfaMemoryState> createInitialStates(@NotNull PsiElement psiBlock, InstructionVisitor visitor) {
|
||||
if (psiBlock.getParent() instanceof PsiMethod) {
|
||||
final PsiClass containingClass = ((PsiMethod)psiBlock.getParent()).getContainingClass();
|
||||
if (containingClass instanceof PsiAnonymousClass) {
|
||||
final PsiElement newExpression = containingClass.getParent();
|
||||
final PsiCodeBlock block = DfaUtil.getTopmostBlockInSameClass(newExpression);
|
||||
if (newExpression instanceof PsiNewExpression && block != null) {
|
||||
final EnvironmentalInstructionVisitor envVisitor = new EnvironmentalInstructionVisitor(visitor, (PsiNewExpression)newExpression);
|
||||
if (containingClass != null && PsiUtil.isLocalOrAnonymousClass(containingClass)) {
|
||||
final PsiElement parent = containingClass.getParent();
|
||||
final PsiCodeBlock block = DfaUtil.getTopmostBlockInSameClass(parent);
|
||||
if ((parent instanceof PsiNewExpression || parent instanceof PsiDeclarationStatement) && block != null) {
|
||||
final EnvironmentalInstructionVisitor envVisitor = new EnvironmentalInstructionVisitor(visitor, parent);
|
||||
final RunnerResult result = analyzeMethod(block, envVisitor);
|
||||
if (result == RunnerResult.OK) {
|
||||
final Collection<DfaMemoryState> closureStates = envVisitor.getClosureStates();
|
||||
@@ -225,22 +227,32 @@ public class DataFlowRunner {
|
||||
}
|
||||
|
||||
private static class EnvironmentalInstructionVisitor extends DelegatingInstructionVisitor {
|
||||
private final PsiNewExpression myNewExpression;
|
||||
private final PsiElement myClassParent;
|
||||
private final Set<DfaMemoryState> myClosureStates = new THashSet<DfaMemoryState>();
|
||||
|
||||
public EnvironmentalInstructionVisitor(@NotNull InstructionVisitor delegate, @NotNull PsiNewExpression newExpression) {
|
||||
private EnvironmentalInstructionVisitor(InstructionVisitor delegate, PsiElement classParent) {
|
||||
super(delegate);
|
||||
myNewExpression = newExpression;
|
||||
myClassParent = classParent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DfaInstructionState[] visitEmptyInstruction(EmptyInstruction instruction, DataFlowRunner runner, DfaMemoryState before) {
|
||||
checkEnvironment(runner, before, instruction.getAnchor());
|
||||
return super.visitEmptyInstruction(instruction, runner, before);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DfaInstructionState[] visitMethodCall(MethodCallInstruction instruction, DataFlowRunner runner, DfaMemoryState memState) {
|
||||
if (myNewExpression == instruction.getCallExpression()) {
|
||||
checkEnvironment(runner, memState, instruction.getCallExpression());
|
||||
return super.visitMethodCall(instruction, runner, memState);
|
||||
}
|
||||
|
||||
private void checkEnvironment(DataFlowRunner runner, DfaMemoryState memState, @Nullable PsiElement anchor) {
|
||||
if (myClassParent == anchor) {
|
||||
DfaMemoryState copy = memState.createCopy();
|
||||
copy.flushFields(runner);
|
||||
myClosureStates.add(copy);
|
||||
}
|
||||
return super.visitMethodCall(instruction, runner, memState);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
|
||||
@@ -161,4 +161,7 @@ public abstract class InstructionVisitor {
|
||||
return nextInstruction(instruction, runner, memState);
|
||||
}
|
||||
|
||||
public DfaInstructionState[] visitEmptyInstruction(EmptyInstruction instruction, DataFlowRunner runner, DfaMemoryState before) {
|
||||
return nextInstruction(instruction, runner, before);
|
||||
}
|
||||
}
|
||||
|
||||
+13
-2
@@ -25,14 +25,25 @@
|
||||
package com.intellij.codeInspection.dataFlow.instructions;
|
||||
|
||||
import com.intellij.codeInspection.dataFlow.*;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
|
||||
public class EmptyInstruction extends Instruction {
|
||||
@Nullable private final PsiElement myAnchor;
|
||||
|
||||
public EmptyInstruction(@Nullable PsiElement anchor) {
|
||||
myAnchor = anchor;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public PsiElement getAnchor() {
|
||||
return myAnchor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DfaInstructionState[] accept(DataFlowRunner runner, DfaMemoryState stateBefore, InstructionVisitor visitor) {
|
||||
Instruction nextInstruction = runner.getInstruction(getIndex() + 1);
|
||||
return new DfaInstructionState[] {new DfaInstructionState(nextInstruction, stateBefore)};
|
||||
return visitor.visitEmptyInstruction(this, runner, stateBefore);
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
class Test {
|
||||
void f(@Nullable final Object x) {
|
||||
if (x != null) {
|
||||
class C {
|
||||
C(@NotNull Object x) {
|
||||
}
|
||||
|
||||
C() {
|
||||
this(x);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -47,6 +47,7 @@ public class DataFlowInspectionFixtureTest extends JavaCodeInsightFixtureTestCas
|
||||
public void testNullableAnonymousParameter() throws Throwable { doTest(); }
|
||||
public void testNullableAnonymousVolatile() throws Throwable { doTest(); }
|
||||
public void testNullableAnonymousVolatileNotNull() throws Throwable { doTest(); }
|
||||
public void testLocalClass() throws Throwable { doTest(); }
|
||||
|
||||
public void testFieldInAnonymous() throws Throwable { doTest(); }
|
||||
public void testNullableField() throws Throwable { doTest(); }
|
||||
|
||||
Reference in New Issue
Block a user