mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
check lambda return values during constant&conditions (IDEA-117420)
This commit is contained in:
+14
-1
@@ -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();
|
||||
|
||||
+2
-2
@@ -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);
|
||||
|
||||
+4
@@ -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();
|
||||
|
||||
|
||||
+13
-6
@@ -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();
|
||||
|
||||
+6
-6
@@ -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() {
|
||||
|
||||
+44
@@ -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";
|
||||
}
|
||||
}
|
||||
+12
@@ -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 { }");
|
||||
|
||||
Reference in New Issue
Block a user