extract method: annotate newly created method @Nullable when applicable (IDEA-76767)

This commit is contained in:
Anna Kozlova
2014-11-27 19:14:03 +01:00
parent 90456f2029
commit c28dee1968
10 changed files with 71 additions and 8 deletions
@@ -134,6 +134,21 @@ public class DataFlowInspectionBase extends BaseJavaBatchLocalInspectionTool {
};
analyzeDfaWithNestedClosures(scope, holder, dfaRunner, Arrays.asList(dfaRunner.createMemoryState()), onTheFly);
}
@Nullable
public static Collection<PsiElement> getNullableReturn(PsiMethod method) {
final StandardDataFlowRunner dfaRunner = new StandardDataFlowRunner();
final DataFlowInstructionVisitor visitor = new DataFlowInstructionVisitor(dfaRunner);
final PsiCodeBlock body = method.getBody();
if (body == null) {
return null;
}
final RunnerResult rc = dfaRunner.analyzeMethod(body, visitor);
if (rc == RunnerResult.OK) {
return visitor.getProblems(NullabilityProblem.nullableReturn);
}
return null;
}
private void analyzeDfaWithNestedClosures(PsiElement scope,
ProblemsHolder holder,
@@ -17,13 +17,17 @@ package com.intellij.refactoring.extractMethod;
import com.intellij.codeInsight.ChangeContextUtil;
import com.intellij.codeInsight.ExceptionUtil;
import com.intellij.codeInsight.NullableNotNullManager;
import com.intellij.codeInsight.daemon.impl.analysis.JavaHighlightUtil;
import com.intellij.codeInsight.daemon.impl.quickfix.AnonymousTargetClassPreselectionUtil;
import com.intellij.codeInsight.highlighting.HighlightManager;
import com.intellij.codeInsight.intention.AddAnnotationFix;
import com.intellij.codeInsight.intention.impl.AddNotNullAnnotationFix;
import com.intellij.codeInsight.intention.impl.AddNotNullAnnotationIntention;
import com.intellij.codeInsight.intention.impl.AddNullableAnnotationFix;
import com.intellij.codeInsight.intention.impl.AddNullableNotNullAnnotationFix;
import com.intellij.codeInsight.navigation.NavigationUtil;
import com.intellij.codeInspection.dataFlow.RunnerResult;
import com.intellij.codeInspection.dataFlow.StandardDataFlowRunner;
import com.intellij.codeInspection.dataFlow.StandardInstructionVisitor;
import com.intellij.codeInspection.dataFlow.*;
import com.intellij.codeInspection.dataFlow.instructions.BranchingInstruction;
import com.intellij.codeInspection.dataFlow.instructions.Instruction;
import com.intellij.ide.DataManager;
@@ -39,6 +43,7 @@ import com.intellij.openapi.editor.markup.TextAttributes;
import com.intellij.openapi.progress.ProgressManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.*;
import com.intellij.openapi.util.registry.Registry;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.wm.WindowManager;
@@ -862,6 +867,20 @@ public class ExtractMethodProcessor implements MatchProvider {
}
}
if (isNullabilityCheckApplicable() && !(newMethod.getReturnType() instanceof PsiPrimitiveType) &&
PsiUtil.isLanguageLevel5OrHigher(newMethod) && Registry.is("annotate.extracted.method.nullable.when.applicable", true)) {
final NullableNotNullManager manager = NullableNotNullManager.getInstance(myProject);
final PsiClass nullableAnnotationClass =
JavaPsiFacade.getInstance(myProject).findClass(manager.getDefaultNullable(), GlobalSearchScope.allScope(myProject));
if (nullableAnnotationClass != null) {
final Collection<PsiElement> nullableReturn = DataFlowInspectionBase.getNullableReturn(newMethod);
if (nullableReturn != null && !nullableReturn.isEmpty()) {
final AddNullableNotNullAnnotationFix annotationFix = new AddNullableAnnotationFix(newMethod);
annotationFix.invoke(myProject, myTargetClass.getContainingFile(), newMethod, newMethod);
}
}
}
myExtractedMethod = (PsiMethod)myTargetClass.addAfter(newMethod, myAnchor);
if (isNeedToChangeCallContext() && myNeedChangeContext) {
ChangeContextUtil.decodeContextInfo(myExtractedMethod, myTargetClass, RefactoringChangeUtil.createThisExpression(myManager, null));
@@ -870,7 +889,10 @@ public class ExtractMethodProcessor implements MatchProvider {
methodExpression.setQualifierExpression(RefactoringChangeUtil.createThisExpression(myManager, myTargetClass));
}
}
}
protected boolean isNullabilityCheckApplicable() {
return true;
}
protected boolean isNeedToChangeCallContext() {
@@ -657,6 +657,16 @@ public class ExtractMethodObjectProcessor extends BaseRefactoringProcessor {
return false;
}
@Override
protected boolean isNullabilityCheckApplicable() {
return false;
}
@Override
protected boolean isNeedToChangeCallContext() {
return false;
}
@Override
protected void apply(final AbstractExtractDialog dialog) {
super.apply(dialog);
@@ -741,11 +751,6 @@ public class ExtractMethodObjectProcessor extends BaseRefactoringProcessor {
return myOutputVariables;
}
@Override
protected boolean isNeedToChangeCallContext() {
return false;
}
@Override
protected void declareNecessaryVariablesAfterCall(final PsiVariable outputVariable) throws IncorrectOperationException {
if (myMultipleExitPoints) {
@@ -1,3 +1,5 @@
import org.jetbrains.annotations.Nullable;
class C {
public Object m() {
Object o = newMethod();
@@ -5,6 +7,7 @@ class C {
return null;
}
@Nullable
private Object newMethod() {
for (Object o : new ArrayList<Object>()) {
if (o != null) {
@@ -1,3 +1,5 @@
import org.jetbrains.annotations.Nullable;
class Result {
private String _message;
@@ -17,6 +19,7 @@ class Main {
return result;
}
@Nullable
private static Result newMethod(String name) {
Result result;
if (name == null) {
@@ -1,3 +1,5 @@
import org.jetbrains.annotations.Nullable;
class Test {
String foo(int i, boolean flag) {
@@ -8,6 +10,7 @@ class Test {
return null;
}
@Nullable
private String newMethod(int i, boolean flag) {
String xxx = "";
if (flag) {
@@ -1,3 +1,5 @@
import org.jetbrains.annotations.Nullable;
import java.util.List;
class Test {
@@ -11,6 +13,7 @@ class Test {
}
}
@Nullable
private Pojo newMethod() {
Pojo x = things.get(0);
@@ -1,3 +1,5 @@
import org.jetbrains.annotations.Nullable;
class Test {
void foo() {
Object o = newMethod();
@@ -5,6 +7,7 @@ class Test {
System.out.println(o);
}
@Nullable
private Object newMethod() {
Object o = "";
for (int i = 0; i < 5; i++) {
@@ -1,3 +1,5 @@
import org.jetbrains.annotations.Nullable;
class Test {
Object foo() {
Object o = newMethod();
@@ -6,6 +8,7 @@ class Test {
return o;
}
@Nullable
private Object newMethod() {
Object o = "";
for (int i = 0; i < 5; i++) {
@@ -499,3 +499,6 @@ editor.config.stop.at.project.root.description=Stops searching for .editorconfig
JDK8042508.bug.fixed=false
JDK8042508.bug.fixed.description=Disable check for type variable until javac bug is fixed
annotate.extracted.method.nullable.when.applicable=true
annotate.extracted.method.nullable.when.applicable.description=Enables @Nullable annotation on newly extracted method when applicable