check lambda return values during constant&conditions (IDEA-117420)

This commit is contained in:
anna
2013-12-03 15:30:19 +01:00
parent 134c2e2bae
commit 83b6571952
10 changed files with 127 additions and 15 deletions
@@ -94,6 +94,10 @@ public class ControlFlowAnalyzer extends JavaElementVisitor {
return null;
}
PsiElement parent = codeFragment.getParent();
if (parent instanceof PsiLambdaExpression && codeFragment instanceof PsiExpression) {
addInstruction(new CheckReturnValueInstruction(codeFragment));
}
myCurrentFlow.setFields(myFields.toArray(new DfaVariableValue[myFields.size()]));
addInstruction(new ReturnInstruction(false));
@@ -528,6 +532,15 @@ public class ControlFlowAnalyzer extends JavaElementVisitor {
finishElement(statement);
}
@Override
public void visitLambdaExpression(PsiLambdaExpression expression) {
startElement(expression);
DfaValue dfaValue = myFactory.createValue(expression);
addInstruction(new PushInstruction(dfaValue, expression));
addInstruction(new LambdaInstruction(expression));
finishElement(expression);
}
@Override public void visitReturnStatement(PsiReturnStatement statement) {
startElement(statement);
@@ -538,7 +551,7 @@ public class ControlFlowAnalyzer extends JavaElementVisitor {
if (method != null) {
generateBoxingUnboxingInstructionFor(returnValue, method.getReturnType());
}
addInstruction(new CheckReturnValueInstruction(statement));
addInstruction(new CheckReturnValueInstruction(returnValue));
}
returnCheckingFinally();
@@ -479,8 +479,8 @@ public class DataFlowInspectionBase extends BaseJavaBatchLocalInspectionTool {
private static void reportNullableReturns(StandardDataFlowRunner runner, DataFlowInstructionVisitor visitor, ProblemsHolder holder, Set<PsiElement> reportedAnchors) {
for (PsiElement statement : visitor.getProblems(NullabilityProblem.nullableReturn)) {
final PsiExpression expr = ((PsiReturnStatement)statement).getReturnValue();
assert expr != null;
assert statement instanceof PsiExpression;
final PsiExpression expr = (PsiExpression)statement;
if (!reportedAnchors.add(expr)) continue;
if (runner.isInNotNullMethod()) {
@@ -226,6 +226,10 @@ public class DataFlowRunner {
}
}
}
else if (instruction instanceof LambdaInstruction) {
PsiLambdaExpression lambdaExpression = ((LambdaInstruction)instruction).getLambdaExpression();
registerNestedClosures(instructionState, lambdaExpression);
}
else if (instruction instanceof EmptyInstruction) {
PsiElement anchor = ((EmptyInstruction)instruction).getAnchor();
if (anchor instanceof PsiDeclarationStatement) {
@@ -255,6 +259,14 @@ public class DataFlowRunner {
myNestedClosures.putValue(field, createClosureState(state));
}
}
private void registerNestedClosures(DfaInstructionState instructionState, PsiLambdaExpression expr) {
DfaMemoryState state = instructionState.getMemoryState();
PsiElement body = expr.getBody();
if (body != null) {
myNestedClosures.putValue(body, createClosureState(state));
}
}
protected ControlFlowAnalyzer createControlFlowAnalyzer() {
return new ControlFlowAnalyzer(myValueFactory);
@@ -54,6 +54,10 @@ public abstract class InstructionVisitor {
return nextInstruction(instruction, runner, memState);
}
public DfaInstructionState[] visitLambdaExpression(LambdaInstruction instruction, DataFlowRunner runner, DfaMemoryState memState) {
return nextInstruction(instruction, runner, memState);
}
public DfaInstructionState[] visitConditionalGoto(ConditionalGotoInstruction instruction, DataFlowRunner runner, DfaMemoryState memState) {
DfaValue cond = memState.pop();
@@ -27,10 +27,7 @@ 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.psi.CommonClassNames;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiMethod;
import com.intellij.psi.PsiType;
import com.intellij.psi.*;
import org.jetbrains.annotations.NotNull;
import java.util.HashSet;
@@ -49,13 +46,23 @@ public class StandardDataFlowRunner extends DataFlowRunner {
@Override
protected void prepareAnalysis(@NotNull PsiElement psiBlock, Iterable<DfaMemoryState> initialStates) {
myIsInMethod = psiBlock.getParent() instanceof PsiMethod;
PsiElement parent = psiBlock.getParent();
myIsInMethod = parent instanceof PsiMethod;
if (myIsInMethod) {
PsiMethod method = (PsiMethod)psiBlock.getParent();
PsiMethod method = (PsiMethod)parent;
PsiType returnType = method.getReturnType();
myInNullableMethod = NullableNotNullManager.isNullable(method) ||
returnType != null && returnType.equalsToText(CommonClassNames.JAVA_LANG_VOID);
myInNotNullMethod = NullableNotNullManager.isNotNull(method);
} else if (parent instanceof PsiLambdaExpression) {
PsiMethod method = LambdaUtil.getFunctionalInterfaceMethod(((PsiLambdaExpression)parent).getFunctionalInterfaceType());
if (method != null) {
myIsInMethod = true;
PsiType returnType = method.getReturnType();
myInNullableMethod = NullableNotNullManager.isNullable(method) ||
returnType != null && returnType.equalsToText(CommonClassNames.JAVA_LANG_VOID);
myInNotNullMethod = NullableNotNullManager.isNotNull(method);
}
}
myCCEInstructions.clear();
@@ -19,16 +19,16 @@ import com.intellij.codeInspection.dataFlow.DataFlowRunner;
import com.intellij.codeInspection.dataFlow.DfaInstructionState;
import com.intellij.codeInspection.dataFlow.DfaMemoryState;
import com.intellij.codeInspection.dataFlow.InstructionVisitor;
import com.intellij.psi.PsiReturnStatement;
import com.intellij.psi.PsiElement;
/**
* @author max
*/
public class CheckReturnValueInstruction extends Instruction {
private final PsiReturnStatement myReturn;
private final PsiElement myReturnValue;
public CheckReturnValueInstruction(final PsiReturnStatement aReturn) {
myReturn = aReturn;
public CheckReturnValueInstruction(final PsiElement returnValue) {
myReturnValue = returnValue;
}
@Override
@@ -36,8 +36,8 @@ public class CheckReturnValueInstruction extends Instruction {
return visitor.visitCheckReturnValue(this, runner, stateBefore);
}
public PsiReturnStatement getReturn() {
return myReturn;
public PsiElement getReturn() {
return myReturnValue;
}
public String toString() {
@@ -0,0 +1,44 @@
/*
* Copyright 2000-2013 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.codeInspection.dataFlow.instructions;
import com.intellij.codeInspection.dataFlow.DataFlowRunner;
import com.intellij.codeInspection.dataFlow.DfaInstructionState;
import com.intellij.codeInspection.dataFlow.DfaMemoryState;
import com.intellij.codeInspection.dataFlow.InstructionVisitor;
import com.intellij.psi.PsiLambdaExpression;
public class LambdaInstruction extends Instruction {
private final PsiLambdaExpression myLambdaExpression;
public LambdaInstruction(PsiLambdaExpression lambdaExpression) {
myLambdaExpression = lambdaExpression;
}
public PsiLambdaExpression getLambdaExpression() {
return myLambdaExpression;
}
@Override
public DfaInstructionState[] accept(DataFlowRunner runner, DfaMemoryState stateBefore, InstructionVisitor visitor) {
return visitor.visitLambdaExpression(this, runner, stateBefore);
}
@Override
public String toString() {
return "LambdaInstruction";
}
}
@@ -0,0 +1,12 @@
import org.jetbrains.annotations.NotNull;
class Test {
interface I {
@NotNull
String get();
}
{
I i = () -> <warning descr="'null' is returned by the method declared as @NotNull">null</warning>;
}
}
@@ -0,0 +1,12 @@
import org.jetbrains.annotations.NotNull;
class Test {
interface I {
@NotNull
String get();
}
{
I i = () -> {return <warning descr="'null' is returned by the method declared as @NotNull">null</warning>;};
}
}
@@ -45,6 +45,14 @@ public class DataFlowInspection8Test extends LightCodeInsightFixtureTestCase {
doTest();
}
public void testReturnNullInLambdaExpression() throws Exception {
doTest();
}
public void testReturnNullInLambdaStatement() throws Exception {
doTest();
}
private void setupCustomAnnotations() {
myFixture.addClass("package foo;\n\nimport java.lang.annotation.*;\n\n@Target({ElementType.TYPE_USE}) public @interface Nullable { }");
myFixture.addClass("package foo;\n\nimport java.lang.annotation.*;\n\n@Target({ElementType.TYPE_USE}) public @interface NotNull { }");