mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
Java inspections: Created "Move return to computation" inspection, added a few tests (IDEA-121153)
This commit is contained in:
+467
@@ -0,0 +1,467 @@
|
||||
/*
|
||||
* Copyright 2000-2016 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.intermediaryVariable;
|
||||
|
||||
import com.intellij.codeInspection.*;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.controlFlow.*;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.refactoring.util.RefactoringUtil;
|
||||
import com.siyeh.ig.psiutils.ControlFlowUtils;
|
||||
import com.siyeh.ig.psiutils.ExpressionUtils;
|
||||
import gnu.trove.THashMap;
|
||||
import gnu.trove.THashSet;
|
||||
import org.jetbrains.annotations.Nls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* @author Pavel.Dolgov
|
||||
*/
|
||||
public class ReturnSeparatedFromComputationInspection extends BaseJavaBatchLocalInspectionTool {
|
||||
private static final Logger LOG = Logger.getInstance("#" + ReturnSeparatedFromComputationInspection.class.getName());
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public PsiElementVisitor buildVisitor(@NotNull ProblemsHolder holder, boolean isOnTheFly) {
|
||||
return new JavaElementVisitor() {
|
||||
@Override
|
||||
public void visitReturnStatement(PsiReturnStatement returnStatement) {
|
||||
super.visitReturnStatement(returnStatement);
|
||||
final ReturnContext context = createReturnContext(returnStatement);
|
||||
if (context != null && isApplicable(context)) {
|
||||
registerProblem(holder, returnStatement, context.returnedVariable);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private static ReturnContext createReturnContext(PsiReturnStatement returnStatement) {
|
||||
final PsiElement returnParent = returnStatement.getParent();
|
||||
if (returnParent instanceof PsiCodeBlock) {
|
||||
final PsiCodeBlock returnScope = (PsiCodeBlock)returnParent;
|
||||
final PsiStatement[] statements = returnScope.getStatements();
|
||||
if (statements.length != 0 && statements[statements.length - 1] == returnStatement) {
|
||||
PsiStatement refactoredStatement = getPrevNonEmptyStatement(returnStatement, new THashSet<>());
|
||||
if (refactoredStatement != null) {
|
||||
final PsiExpression returnValue = returnStatement.getReturnValue();
|
||||
if (returnValue instanceof PsiReferenceExpression) {
|
||||
final PsiElement resolved = ((PsiReferenceExpression)returnValue).resolve();
|
||||
if (resolved instanceof PsiVariable) {
|
||||
final PsiVariable returnedVariable = (PsiVariable)resolved;
|
||||
final PsiCodeBlock variableScope = getVariableScopeBlock(returnedVariable);
|
||||
if (variableScope != null) {
|
||||
return new ReturnContext(returnStatement, returnScope, refactoredStatement, returnedVariable, variableScope);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static PsiCodeBlock getVariableScopeBlock(@Nullable PsiVariable variable) {
|
||||
if (variable instanceof PsiLocalVariable) {
|
||||
final PsiElement variableScope = RefactoringUtil.getVariableScope((PsiLocalVariable)variable);
|
||||
if (variableScope instanceof PsiCodeBlock) {
|
||||
return ((PsiCodeBlock)variableScope);
|
||||
}
|
||||
}
|
||||
else if (variable instanceof PsiParameter) {
|
||||
final PsiParameter parameter = (PsiParameter)variable;
|
||||
final PsiElement parameterScope = parameter.getDeclarationScope();
|
||||
if (parameterScope instanceof PsiMethod) {
|
||||
return ((PsiMethod)parameterScope).getBody();
|
||||
}
|
||||
else if (parameterScope instanceof PsiLambdaExpression) {
|
||||
final PsiElement lambdaBody = ((PsiLambdaExpression)parameterScope).getBody();
|
||||
if (lambdaBody instanceof PsiCodeBlock) {
|
||||
return (PsiCodeBlock)lambdaBody;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static boolean isApplicable(@NotNull ReturnContext context) {
|
||||
final ControlFlow flow = createControlFlow(context);
|
||||
return flow != null && isApplicable(flow, context);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static ControlFlow createControlFlow(@NotNull ReturnContext context) {
|
||||
try {
|
||||
final ControlFlowPolicy policy = new LocalsControlFlowPolicy(context.variableScope);
|
||||
return ControlFlowFactory.getInstance(context.variableScope.getProject()).getControlFlow(context.variableScope, policy);
|
||||
}
|
||||
catch (AnalysisCanceledException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean isApplicable(@NotNull ControlFlow flow, @NotNull ReturnContext context) {
|
||||
final int flowStart = flow.getStartOffset(context.returnScope);
|
||||
final int flowEnd = flow.getEndOffset(context.returnScope);
|
||||
if (flowStart < 0 || flowEnd < 0) return false;
|
||||
|
||||
final int returnStartOffset = flow.getStartOffset(context.returnStatement);
|
||||
final int returnEndOffset = flow.getEndOffset(context.returnStatement);
|
||||
if (returnStartOffset < 0 || returnEndOffset < 0) return false;
|
||||
|
||||
if (context.returnScope != context.variableScope &&
|
||||
ControlFlowUtil.hasObservableThrowExitPoints(flow, flowStart, flowEnd,
|
||||
new PsiElement[]{context.refactoredStatement}, context.variableScope)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Mover mover = new Mover(flow, context.refactoredStatement, context.returnedVariable);
|
||||
mover.moveTo(context.refactoredStatement);
|
||||
return !mover.isEmpty();
|
||||
}
|
||||
|
||||
private static void doApply(PsiReturnStatement returnStatement) {
|
||||
ReturnContext context = createReturnContext(returnStatement);
|
||||
if (context != null) {
|
||||
ControlFlow flow = createControlFlow(context);
|
||||
if (flow != null) {
|
||||
Mover mover = new Mover(flow, context.refactoredStatement, context.returnedVariable);
|
||||
boolean removeReturn = mover.moveTo(context.refactoredStatement);
|
||||
if (!mover.isEmpty()) {
|
||||
applyChanges(mover, context, removeReturn);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void applyChanges(@NotNull Mover mover, @NotNull ReturnContext context, boolean removeReturn) {
|
||||
mover.insertAfter.forEach(e -> e.getParent().addAfter(context.returnStatement, e));
|
||||
mover.insertBefore.forEach(e -> e.getParent().addBefore(context.returnStatement, e));
|
||||
mover.replaceInline.forEach(e -> {
|
||||
if (e instanceof PsiBreakStatement) e.replace(context.returnStatement);
|
||||
if (e instanceof PsiAssignmentExpression) inlineAssignment((PsiAssignmentExpression)e, context.returnStatement);
|
||||
});
|
||||
mover.removeCompletely.forEach(PsiElement::delete);
|
||||
|
||||
if (removeReturn) {
|
||||
Set<PsiElement> skippedEmptyStatements = new THashSet<>();
|
||||
getPrevNonEmptyStatement(context.returnStatement, skippedEmptyStatements);
|
||||
skippedEmptyStatements.forEach(PsiElement::delete);
|
||||
context.returnStatement.delete();
|
||||
}
|
||||
}
|
||||
|
||||
private static void inlineAssignment(PsiAssignmentExpression assignmentExpression, PsiReturnStatement returnStatement) {
|
||||
PsiElement assignmentParent = assignmentExpression.getParent();
|
||||
LOG.assertTrue(assignmentParent instanceof PsiExpressionStatement, "PsiExpressionStatement");
|
||||
PsiReturnStatement returnStatementCopy = (PsiReturnStatement)returnStatement.copy();
|
||||
PsiExpression rExpression = assignmentExpression.getRExpression();
|
||||
PsiExpression returnValue = returnStatementCopy.getReturnValue();
|
||||
if (rExpression != null && returnValue!=null) {
|
||||
returnValue.replace(rExpression);
|
||||
assignmentParent.replace(returnStatementCopy);
|
||||
}
|
||||
}
|
||||
|
||||
private static class Mover {
|
||||
final ControlFlow flow;
|
||||
final PsiStatement enclosingStatement;
|
||||
final PsiVariable resultVariable;
|
||||
final Set<PsiElement> insertBefore = new THashSet<>();
|
||||
final Set<PsiElement> insertAfter = new THashSet<>();
|
||||
final Set<PsiElement> replaceInline = new THashSet<>();
|
||||
final Set<PsiElement> removeCompletely = new THashSet<>();
|
||||
|
||||
private Map<PsiStatement, Set<PsiBreakStatement>> breakStatements;
|
||||
|
||||
private Mover(@NotNull ControlFlow flow, @NotNull PsiStatement enclosingStatement, @NotNull PsiVariable resultVariable) {
|
||||
this.flow = flow;
|
||||
this.enclosingStatement = enclosingStatement;
|
||||
this.resultVariable = resultVariable;
|
||||
}
|
||||
|
||||
boolean isEmpty() {
|
||||
return insertBefore.isEmpty() && insertAfter.isEmpty() && replaceInline.isEmpty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the targetStatement will always exit via return/throw/etc after the transformation,
|
||||
* so if the next statement is a return or a break it can be removed safely.
|
||||
*/
|
||||
boolean moveTo(PsiStatement targetStatement) {
|
||||
if (targetStatement instanceof PsiBlockStatement) {
|
||||
return moveToBlock((PsiBlockStatement)targetStatement);
|
||||
}
|
||||
if (targetStatement instanceof PsiIfStatement) {
|
||||
return moveToIf((PsiIfStatement)targetStatement);
|
||||
}
|
||||
if (targetStatement instanceof PsiForStatement) {
|
||||
return moveToFor((PsiForStatement)targetStatement);
|
||||
}
|
||||
if (targetStatement instanceof PsiWhileStatement) {
|
||||
return moveToWhile((PsiWhileStatement)targetStatement);
|
||||
}
|
||||
if (targetStatement instanceof PsiDoWhileStatement) {
|
||||
return moveToDoWhile((PsiDoWhileStatement)targetStatement);
|
||||
}
|
||||
if (targetStatement instanceof PsiForeachStatement) {
|
||||
return moveToForeach((PsiForeachStatement)targetStatement);
|
||||
}
|
||||
if (targetStatement instanceof PsiTryStatement) {
|
||||
return moveToTry(((PsiTryStatement)targetStatement));
|
||||
}
|
||||
if (targetStatement instanceof PsiLabeledStatement) {
|
||||
return moveToLabeled(((PsiLabeledStatement)targetStatement));
|
||||
}
|
||||
if (targetStatement instanceof PsiExpressionStatement) {
|
||||
return inlineExpression(((PsiExpressionStatement)targetStatement));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean moveToBlock(PsiBlockStatement targetStatement) {
|
||||
return moveToBlock(targetStatement.getCodeBlock());
|
||||
}
|
||||
|
||||
private boolean moveToBlock(@NotNull PsiCodeBlock codeBlock) {
|
||||
PsiJavaToken rBrace = codeBlock.getRBrace();
|
||||
if (rBrace != null) {
|
||||
PsiStatement lastNonEmptyStatement = getPrevNonEmptyStatement(rBrace, removeCompletely);
|
||||
if (lastNonEmptyStatement == null || !moveTo(lastNonEmptyStatement)) {
|
||||
insertBefore.add(rBrace);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean moveToIf(PsiIfStatement targetStatement) {
|
||||
PsiStatement thenBranch = targetStatement.getThenBranch();
|
||||
PsiStatement elseBranch = targetStatement.getElseBranch();
|
||||
|
||||
boolean thenPart = thenBranch != null && moveTo(thenBranch);
|
||||
boolean elsePart = elseBranch != null && moveTo(elseBranch);
|
||||
return thenPart && elsePart;
|
||||
}
|
||||
|
||||
private boolean moveToFor(PsiForStatement targetStatement) {
|
||||
moveToBreaks(targetStatement);
|
||||
return isAlwaysTrue(targetStatement.getCondition(), true);
|
||||
}
|
||||
|
||||
private boolean moveToDoWhile(PsiDoWhileStatement targetStatement) {
|
||||
moveToBreaks(targetStatement);
|
||||
return isAlwaysTrue(targetStatement.getCondition(), false);
|
||||
}
|
||||
|
||||
private boolean moveToWhile(PsiWhileStatement targetStatement) {
|
||||
moveToBreaks(targetStatement);
|
||||
return isAlwaysTrue(targetStatement.getCondition(), false);
|
||||
}
|
||||
private boolean moveToForeach(PsiForeachStatement targetStatement) {
|
||||
moveToBreaks(targetStatement);
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean moveToTry(PsiTryStatement targetStatement) {
|
||||
PsiCodeBlock tryBlock = targetStatement.getTryBlock();
|
||||
if (tryBlock == null) {
|
||||
return false;
|
||||
}
|
||||
PsiCodeBlock finallyBlock = targetStatement.getFinallyBlock();
|
||||
if (finallyBlock != null && ControlFlowUtils.codeBlockMayCompleteNormally(finallyBlock) && writesVariable(finallyBlock)) {
|
||||
return false;
|
||||
}
|
||||
PsiCatchSection[] catchSections = targetStatement.getCatchSections();
|
||||
for (PsiCatchSection catchSection : catchSections) {
|
||||
PsiCodeBlock catchBlock = catchSection.getCatchBlock();
|
||||
if (catchBlock != null && ControlFlowUtils.codeBlockMayCompleteNormally(catchBlock) && writesVariable(finallyBlock)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return moveToBlock(tryBlock);
|
||||
}
|
||||
|
||||
private boolean moveToLabeled(PsiLabeledStatement targetStatement) {
|
||||
PsiStatement statement = targetStatement.getStatement();
|
||||
if (statement == null) {
|
||||
return false;
|
||||
}
|
||||
moveToBreaks(statement);
|
||||
return moveTo(statement);
|
||||
}
|
||||
|
||||
private boolean inlineExpression(PsiExpressionStatement statement) {
|
||||
PsiExpression expression = statement.getExpression();
|
||||
if (expression instanceof PsiAssignmentExpression) {
|
||||
PsiAssignmentExpression assignmentExpression = (PsiAssignmentExpression)expression;
|
||||
PsiExpression lExpression = assignmentExpression.getLExpression();
|
||||
if (lExpression instanceof PsiReferenceExpression) {
|
||||
PsiReferenceExpression referenceExpression = (PsiReferenceExpression)lExpression;
|
||||
if (!referenceExpression.isQualified() && referenceExpression.resolve() == resultVariable) {
|
||||
if (assignmentExpression.getOperationTokenType() == JavaTokenType.EQ) {
|
||||
replaceInline.add(assignmentExpression);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private void moveToBreaks(Set<PsiBreakStatement> breaks) {
|
||||
for (PsiBreakStatement breakStatement : breaks) {
|
||||
PsiStatement prevNonEmptyStatement = getPrevNonEmptyStatement(breakStatement, removeCompletely);
|
||||
if (prevNonEmptyStatement == null || !moveTo(prevNonEmptyStatement)) {
|
||||
replaceInline.add(breakStatement);
|
||||
}
|
||||
else {
|
||||
removeCompletely.add(breakStatement);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void moveToBreaks(PsiStatement targetStatement) {
|
||||
Set<PsiBreakStatement> breaks = getBreaks(targetStatement);
|
||||
moveToBreaks(breaks);
|
||||
}
|
||||
|
||||
private boolean writesVariable(PsiElement element) {
|
||||
int startOffset = flow.getStartOffset(element);
|
||||
int endOffset = flow.getEndOffset(element);
|
||||
if (startOffset < 0 || endOffset < 0) {
|
||||
return true;
|
||||
}
|
||||
List<Instruction> instructions = flow.getInstructions();
|
||||
for (int i = startOffset; i < endOffset; i++) {
|
||||
Instruction instruction = instructions.get(i);
|
||||
if (instruction instanceof WriteVariableInstruction && ((WriteVariableInstruction)instruction).variable == resultVariable) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static boolean isAlwaysTrue(@Nullable PsiExpression condition, boolean nullIsTrue) {
|
||||
if(condition == null) return nullIsTrue;
|
||||
return ExpressionUtils.computeConstantExpression(condition) == Boolean.TRUE;
|
||||
}
|
||||
|
||||
private Set<PsiBreakStatement> getBreaks(PsiStatement targetStatement) {
|
||||
if (breakStatements == null) {
|
||||
breakStatements = new THashMap<>();
|
||||
List<Instruction> instructions = flow.getInstructions();
|
||||
for (int i = 0; i < instructions.size(); i++) {
|
||||
PsiElement element = flow.getElement(i);
|
||||
PsiStatement statement = getNearestEnclosingStatement(element);
|
||||
if (statement instanceof PsiBreakStatement) {
|
||||
PsiStatement exitedStatement = ((PsiBreakStatement)statement).findExitedStatement();
|
||||
if (exitedStatement != null) {
|
||||
breakStatements.computeIfAbsent(exitedStatement, unused -> new THashSet<>()).add((PsiBreakStatement)statement);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Set<PsiBreakStatement> breaks = breakStatements.get(targetStatement);
|
||||
return breaks != null ? breaks : Collections.emptySet();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static PsiStatement getNearestEnclosingStatement(PsiElement element) {
|
||||
return element instanceof PsiStatement ? (PsiStatement)element : PsiTreeUtil.getParentOfType(element, PsiStatement.class);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static PsiStatement getPrevNonEmptyStatement(PsiElement psiElement, Set<PsiElement> skippedEmptyStatements) {
|
||||
PsiStatement prevStatement = PsiTreeUtil.getPrevSiblingOfType(psiElement, PsiStatement.class);
|
||||
List<PsiStatement> skipped = new ArrayList<>();
|
||||
while (prevStatement instanceof PsiEmptyStatement) {
|
||||
skipped.add(prevStatement);
|
||||
prevStatement = PsiTreeUtil.getPrevSiblingOfType(prevStatement, PsiStatement.class);
|
||||
}
|
||||
if (prevStatement != null) {
|
||||
skippedEmptyStatements.addAll(skipped);
|
||||
}
|
||||
return prevStatement;
|
||||
}
|
||||
|
||||
private static void registerProblem(@NotNull ProblemsHolder holder,
|
||||
@NotNull PsiReturnStatement returnStatement,
|
||||
@NotNull PsiVariable variable) {
|
||||
String name = variable.getName();
|
||||
holder.registerProblem(returnStatement, InspectionsBundle.message("inspection.return.separated.from.computation.descriptor", name),
|
||||
new VariableFix(name, variable instanceof PsiParameter));
|
||||
}
|
||||
|
||||
private static class VariableFix implements LocalQuickFix {
|
||||
private String myName;
|
||||
private boolean myIsParameter;
|
||||
|
||||
public VariableFix(String name, boolean isParameter) {
|
||||
myName = name;
|
||||
myIsParameter = isParameter;
|
||||
}
|
||||
|
||||
@Nls
|
||||
@NotNull
|
||||
@Override
|
||||
public String getName() {
|
||||
return InspectionsBundle.message("inspection.return.separated.from.computation.quickfix", myName);
|
||||
}
|
||||
|
||||
@Nls
|
||||
@NotNull
|
||||
@Override
|
||||
public String getFamilyName() {
|
||||
return InspectionsBundle.message("inspection.return.separated.from.computation.family.quickfix");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) {
|
||||
PsiElement element = descriptor.getPsiElement();
|
||||
if (element instanceof PsiReturnStatement) {
|
||||
doApply(((PsiReturnStatement)element));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static class ReturnContext {
|
||||
private final PsiReturnStatement returnStatement;
|
||||
private final PsiCodeBlock returnScope;
|
||||
private final PsiStatement refactoredStatement;
|
||||
private final PsiVariable returnedVariable;
|
||||
private final PsiCodeBlock variableScope;
|
||||
|
||||
private ReturnContext(@NotNull PsiReturnStatement returnStatement,
|
||||
@NotNull PsiCodeBlock returnScope,
|
||||
@NotNull PsiStatement refactoredStatement,
|
||||
@NotNull PsiVariable returnedVariable,
|
||||
@NotNull PsiCodeBlock variableScope) {
|
||||
|
||||
this.returnStatement = returnStatement;
|
||||
this.returnScope = returnScope;
|
||||
this.refactoredStatement = refactoredStatement;
|
||||
this.returnedVariable = returnedVariable;
|
||||
this.variableScope = variableScope;
|
||||
}
|
||||
}
|
||||
}
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
class T {
|
||||
int f(int[] a) {
|
||||
int n = -1;
|
||||
myLabel:
|
||||
for (int i = 0; i < a.length; i++) {
|
||||
if (a[0] == 0) {
|
||||
n = i;
|
||||
break myLabel;
|
||||
}
|
||||
}
|
||||
<warning descr="Return separated from computation of value of 'n'">return n;</warning>
|
||||
}
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
class T {
|
||||
int f(int[] a) {
|
||||
int n = -1;
|
||||
myLabel:
|
||||
for (int i = 0; i < a.length; i++) {
|
||||
n = i;
|
||||
if (a[0] == 0) break myLabel;
|
||||
}
|
||||
<warning descr="Return separated from computation of value of 'n'">return n;</warning>
|
||||
}
|
||||
}
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
class T {
|
||||
int f(boolean b) {
|
||||
int n = 0;
|
||||
myLabel:
|
||||
if (b) n = 1;
|
||||
else break myLabel;
|
||||
<warning descr="Return separated from computation of value of 'n'">return n;</warning>
|
||||
}
|
||||
}
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
class T {
|
||||
int f() {
|
||||
int n;
|
||||
{
|
||||
n = 1;
|
||||
}
|
||||
<warning descr="Return separated from computation of value of 'n'">return n;</warning>
|
||||
}
|
||||
}
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
class T {
|
||||
int f() {
|
||||
int n;
|
||||
{
|
||||
n = 1;
|
||||
System.out.println();
|
||||
}
|
||||
<warning descr="Return separated from computation of value of 'n'">return n;</warning>
|
||||
}
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
class T {
|
||||
int f(boolean a, boolean b) {
|
||||
int n = -1;
|
||||
if (a) {
|
||||
if (b) {
|
||||
n = 1;
|
||||
}
|
||||
}
|
||||
return n;
|
||||
}
|
||||
}
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
class T {
|
||||
int f(boolean a, boolean b) {
|
||||
int n = -1;
|
||||
if (a) {
|
||||
if (b) n = 1;
|
||||
else n = 2;
|
||||
}
|
||||
return n;
|
||||
}
|
||||
}
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
class T {
|
||||
int f(boolean a, boolean b) {
|
||||
int n = -1;
|
||||
if (a) {
|
||||
if (b) n = 1;
|
||||
}
|
||||
else n = 2;
|
||||
return n;
|
||||
}
|
||||
}
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
import java.io.*;
|
||||
|
||||
class T {
|
||||
private static String getString() throws IOException {
|
||||
String s;
|
||||
try (BufferedReader r = open()) {
|
||||
s = r.readLine();
|
||||
}
|
||||
<warning descr="Return separated from computation of value of 's'">return s;</warning>
|
||||
}
|
||||
|
||||
private static BufferedReader open() throws FileNotFoundException {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
class T {
|
||||
String f(String a) {
|
||||
String r = "";
|
||||
int i = 0;
|
||||
do {
|
||||
int j = a.indexOf(",", i);
|
||||
String s = j > i ? a.substring(i, j) : a.substring(i);
|
||||
if (s.startsWith("@")) {
|
||||
r = s;
|
||||
break;
|
||||
}
|
||||
i = j + 1;
|
||||
}
|
||||
while (i >= 0);
|
||||
<warning descr="Return separated from computation of value of 'r'">return r;</warning>
|
||||
}
|
||||
|
||||
boolean hasNext() {
|
||||
return true;
|
||||
}
|
||||
|
||||
String next() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
class T {
|
||||
int f(int[] a, int b) {
|
||||
int n = -1;
|
||||
for (int i = 0; i < a.length; i++) {
|
||||
if (a[i] == b) {
|
||||
n = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
<warning descr="Return separated from computation of value of 'n'">return n;</warning>
|
||||
}
|
||||
}
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
class T {
|
||||
String f(String[] a) {
|
||||
String r = "";
|
||||
for (String s : a) {
|
||||
if (s != null && s.contains("@")) {
|
||||
r = s + ":" + s.length();
|
||||
break;
|
||||
}
|
||||
}
|
||||
<warning descr="Return separated from computation of value of 'r'">return r;</warning>
|
||||
}
|
||||
}
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
class T {
|
||||
int f(boolean b) {
|
||||
int n = 0;
|
||||
if (b) n = 1;
|
||||
<warning descr="Return separated from computation of value of 'n'">return n;</warning>
|
||||
}
|
||||
}
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
class T {
|
||||
String f() {
|
||||
String r = "";
|
||||
while (hasNext()) {
|
||||
String s = next();
|
||||
if (s != null) {
|
||||
r = s;
|
||||
break;
|
||||
}
|
||||
}
|
||||
<warning descr="Return separated from computation of value of 'r'">return r;</warning>
|
||||
}
|
||||
|
||||
boolean hasNext() {
|
||||
return true;
|
||||
}
|
||||
|
||||
String next() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
// "Move 'return' to computation of the value of 's'" "true"
|
||||
import java.io.*;
|
||||
|
||||
class T {
|
||||
private static String getString() throws IOException {
|
||||
String s;
|
||||
try (BufferedReader reader = open()) {
|
||||
while (true) {
|
||||
s = reader.readLine();
|
||||
if (s == null || s.startsWith("$")) {
|
||||
return s;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
private static BufferedReader open() throws FileNotFoundException {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
// "Move 'return' to computation of the value of 'r'" "true"
|
||||
class T {
|
||||
String f() {
|
||||
String r = "";
|
||||
do {
|
||||
if (!hasNext()) return r;
|
||||
String s = next();
|
||||
if (s != null) {
|
||||
return s;
|
||||
}
|
||||
} while (true);
|
||||
}
|
||||
|
||||
boolean hasNext() {
|
||||
return true;
|
||||
}
|
||||
|
||||
String next() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
// "Move 'return' to computation of the value of 'n'" "true"
|
||||
class T {
|
||||
int f() {
|
||||
int n = -1;
|
||||
for(int i=0;; i++) {
|
||||
if (i % 127 == 0 && i % 129 == 0) {
|
||||
return i + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
// "Move 'return' to computation of the value of 'n'" "true"
|
||||
class T {
|
||||
int f(boolean b) {
|
||||
int n = 0;
|
||||
if (b) return 1;
|
||||
else return 2;
|
||||
}
|
||||
}
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
// "Move 'return' to computation of the value of 'n'" "true"
|
||||
class T {
|
||||
int f(boolean b) {
|
||||
int n = 0;
|
||||
if (b) System.out.println("yes");
|
||||
else return 2;
|
||||
return n;
|
||||
}
|
||||
}
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
// "Move 'return' to computation of the value of 'n'" "true"
|
||||
class T {
|
||||
int f(boolean b) {
|
||||
int n = 0;
|
||||
if (b) return 1;
|
||||
else System.out.println("no");
|
||||
return n;
|
||||
}
|
||||
}
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
// "Move 'return' to computation of the value of 'n'" "true"
|
||||
class T {
|
||||
int f(boolean b) {
|
||||
int n;
|
||||
myLabel:
|
||||
{
|
||||
n = 1;
|
||||
if (b) return n;
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
// "Move 'return' to computation of the value of 'r'" "true"
|
||||
class T {
|
||||
long f() {
|
||||
long r;
|
||||
long s = System.currentTimeMillis();
|
||||
long t = s;
|
||||
while (true) {
|
||||
t = System.currentTimeMillis();
|
||||
if (t - s > 100) {
|
||||
return t;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
// "Move 'return' to computation of the value of 'n'" "false"
|
||||
class T {
|
||||
int f(int a) {
|
||||
int n = a;
|
||||
assert n != 0;
|
||||
r<caret>eturn n;
|
||||
}
|
||||
}
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
// "Move 'return' to computation of the value of 's'" "true"
|
||||
import java.io.*;
|
||||
|
||||
class T {
|
||||
private static String getString() throws IOException {
|
||||
String s;
|
||||
try (BufferedReader reader = open()) {
|
||||
while (true) {
|
||||
s = reader.readLine();
|
||||
if (s == null || s.startsWith("$")) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
r<caret>eturn s;
|
||||
}
|
||||
private static BufferedReader open() throws FileNotFoundException {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
// "Move 'return' to computation of the value of 'r'" "true"
|
||||
class T {
|
||||
String f() {
|
||||
String r = "";
|
||||
do {
|
||||
if (!hasNext()) break;
|
||||
String s = next();
|
||||
if (s != null) {
|
||||
r = s;
|
||||
break;
|
||||
}
|
||||
} while (true);
|
||||
<caret>return r;
|
||||
}
|
||||
|
||||
boolean hasNext() {
|
||||
return true;
|
||||
}
|
||||
|
||||
String next() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
// "Move 'return' to computation of the value of 'n'" "true"
|
||||
class T {
|
||||
int f() {
|
||||
int n = -1;
|
||||
for(int i=0;; i++) {
|
||||
if (i % 127 == 0 && i % 129 == 0) {
|
||||
n = i + 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
r<caret>eturn n;
|
||||
}
|
||||
}
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
// "Move 'return' to computation of the value of 'n'" "false"
|
||||
class T {
|
||||
int f(boolean b) {
|
||||
int n = 0;
|
||||
if (b) System.out.println("yes");
|
||||
else System.out.println("no");
|
||||
ret<caret>urn n;
|
||||
}
|
||||
}
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
// "Move 'return' to computation of the value of 'n'" "true"
|
||||
class T {
|
||||
int f(boolean b) {
|
||||
int n = 0;
|
||||
if (b) n = 1;
|
||||
else n = 2;
|
||||
r<caret>eturn n;
|
||||
}
|
||||
}
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
// "Move 'return' to computation of the value of 'n'" "true"
|
||||
class T {
|
||||
int f(boolean b) {
|
||||
int n = 0;
|
||||
if (b) System.out.println("yes");
|
||||
else n = 2;
|
||||
r<caret>eturn n;
|
||||
}
|
||||
}
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
// "Move 'return' to computation of the value of 'n'" "true"
|
||||
class T {
|
||||
int f(boolean b) {
|
||||
int n = 0;
|
||||
if (b) n = 1;
|
||||
else System.out.println("no");
|
||||
ret<caret>urn n;
|
||||
}
|
||||
}
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
// "Move 'return' to computation of the value of 'n'" "true"
|
||||
class T {
|
||||
int f(boolean b) {
|
||||
int n;
|
||||
myLabel:
|
||||
{
|
||||
n = 1;
|
||||
if (b) break myLabel;
|
||||
n = 2;
|
||||
}
|
||||
ret<caret>urn n;
|
||||
}
|
||||
}
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
// "Move 'return' to computation of the value of 'r'" "true"
|
||||
class T {
|
||||
long f() {
|
||||
long r;
|
||||
long s = System.currentTimeMillis();
|
||||
long t = s;
|
||||
while (true) {
|
||||
t = System.currentTimeMillis();
|
||||
if (t - s > 100) {
|
||||
r = t;
|
||||
break;
|
||||
}
|
||||
}
|
||||
retu<caret>rn r;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
class T {
|
||||
int f(int a) {
|
||||
int n = a;
|
||||
assert n != 0;
|
||||
return n;
|
||||
}
|
||||
}
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
import java.io.*;
|
||||
|
||||
class T {
|
||||
private static String getString() throws IOException {
|
||||
String s;
|
||||
try (BufferedReader reader = open()) {
|
||||
while (true) {
|
||||
s = reader.readLine();
|
||||
if (s == null || s.startsWith("$")) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
<warning descr="Return separated from computation of value of 's'">return s;</warning>
|
||||
}
|
||||
private static BufferedReader open() throws FileNotFoundException {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
class T {
|
||||
String f() {
|
||||
String r = "";
|
||||
do {
|
||||
if (!hasNext()) break;
|
||||
String s = next();
|
||||
if (s != null) {
|
||||
r = s;
|
||||
break;
|
||||
}
|
||||
} while (true);
|
||||
<warning descr="Return separated from computation of value of 'r'">return r;</warning>
|
||||
}
|
||||
|
||||
boolean hasNext() {
|
||||
return true;
|
||||
}
|
||||
|
||||
String next() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
class T {
|
||||
int f() {
|
||||
int n = -1;
|
||||
for(int i=0;; i++) {
|
||||
if (i % 127 == 0 && i % 129 == 0) {
|
||||
n = i + 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
<warning descr="Return separated from computation of value of 'n'">return n;</warning>
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
class T {
|
||||
int f(boolean b) {
|
||||
int n = 0;
|
||||
if (b) System.out.println("yes");
|
||||
else System.out.println("no");
|
||||
return n;
|
||||
}
|
||||
}
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
class T {
|
||||
int f(boolean b) {
|
||||
int n = 0;
|
||||
if (b) n = 1;
|
||||
else n = 2;
|
||||
<warning descr="Return separated from computation of value of 'n'">return n;</warning>
|
||||
}
|
||||
}
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
class T {
|
||||
int f(boolean b) {
|
||||
int n = 0;
|
||||
if (b) System.out.println("yes");
|
||||
else n = 2;
|
||||
<warning descr="Return separated from computation of value of 'n'">return n;</warning>
|
||||
}
|
||||
}
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
class T {
|
||||
int f(boolean b) {
|
||||
int n = 0;
|
||||
if (b) n = 1;
|
||||
else System.out.println("no");
|
||||
<warning descr="Return separated from computation of value of 'n'">return n;</warning>
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
class T {
|
||||
int f(boolean b) {
|
||||
int n;
|
||||
myLabel:
|
||||
{
|
||||
n = 1;
|
||||
if (b) break myLabel;
|
||||
n = 2;
|
||||
}
|
||||
<warning descr="Return separated from computation of value of 'n'">return n;</warning>
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
class T {
|
||||
int f(int[] a) {
|
||||
int n = -1;
|
||||
myLabel:
|
||||
for (int i = 0; i < a.length; i++) {
|
||||
if (a[0] == 0) {
|
||||
n = i;
|
||||
break myLabel;
|
||||
}
|
||||
}
|
||||
<warning descr="Return separated from computation of value of 'n'">return n;</warning>
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
class T {
|
||||
int f(int[] a) {
|
||||
int n = -1;
|
||||
myLabel:
|
||||
for (int i = 0; i < a.length; i++) {
|
||||
n = i;
|
||||
if (a[0] == 0) break myLabel;
|
||||
}
|
||||
<warning descr="Return separated from computation of value of 'n'">return n;</warning>
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
class T {
|
||||
int f(boolean b) {
|
||||
int n = 0;
|
||||
myLabel:
|
||||
if (b) n = 1;
|
||||
else break myLabel;
|
||||
<warning descr="Return separated from computation of value of 'n'">return n;</warning>
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
class T {
|
||||
int f() {
|
||||
int n;
|
||||
{
|
||||
n = 1;
|
||||
}
|
||||
<warning descr="Return separated from computation of value of 'n'">return n;</warning>
|
||||
}
|
||||
}
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
class T {
|
||||
int f() {
|
||||
int n;
|
||||
{
|
||||
n = 1;
|
||||
System.out.println();
|
||||
}
|
||||
<warning descr="Return separated from computation of value of 'n'">return n;</warning>
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
class T {
|
||||
int f(boolean a, boolean b) {
|
||||
int n = -1;
|
||||
if (a) {
|
||||
if (b) {
|
||||
n = 1;
|
||||
}
|
||||
}
|
||||
<warning descr="Return separated from computation of value of 'n'">return n;</warning>
|
||||
}
|
||||
}
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
class T {
|
||||
int f(boolean a, boolean b) {
|
||||
int n = -1;
|
||||
if (a) {
|
||||
if (b) n = 1;
|
||||
else n = 2;
|
||||
}
|
||||
<warning descr="Return separated from computation of value of 'n'">return n;</warning>
|
||||
}
|
||||
}
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
class T {
|
||||
int f(boolean a, boolean b) {
|
||||
int n = -1;
|
||||
if (a) {
|
||||
if (b) n = 1;
|
||||
}
|
||||
else n = 2;
|
||||
<warning descr="Return separated from computation of value of 'n'">return n;</warning>
|
||||
}
|
||||
}
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
import java.io.*;
|
||||
|
||||
class T {
|
||||
private static String getString() throws IOException {
|
||||
String s;
|
||||
try (BufferedReader r = open()) {
|
||||
s = r.readLine();
|
||||
}
|
||||
<warning descr="Return separated from computation of value of 's'">return s;</warning>
|
||||
}
|
||||
|
||||
private static BufferedReader open() throws FileNotFoundException {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
class T {
|
||||
int[] f(boolean b) {
|
||||
int[] r = new int[]{-1};
|
||||
if (b) {
|
||||
r[0] = 1;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
class T {
|
||||
String f(String a) {
|
||||
String r = "";
|
||||
int i = 0;
|
||||
do {
|
||||
int j = a.indexOf(",", i);
|
||||
String s = j > i ? a.substring(i, j) : a.substring(i);
|
||||
if (s.startsWith("@")) {
|
||||
r = s;
|
||||
break;
|
||||
}
|
||||
i = j + 1;
|
||||
}
|
||||
while (i >= 0);
|
||||
<warning descr="Return separated from computation of value of 'r'">return r;</warning>
|
||||
}
|
||||
|
||||
boolean hasNext() {
|
||||
return true;
|
||||
}
|
||||
|
||||
String next() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
class T {
|
||||
int f(int[] a, int b) {
|
||||
int n = -1;
|
||||
for (int i = 0; i < a.length; i++) {
|
||||
if (a[i] == b) {
|
||||
n = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
<warning descr="Return separated from computation of value of 'n'">return n;</warning>
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
class T {
|
||||
String f(String[] a) {
|
||||
String r = "";
|
||||
for (String s : a) {
|
||||
if (s != null && s.contains("@")) {
|
||||
r = s + ":" + s.length();
|
||||
break;
|
||||
}
|
||||
}
|
||||
<warning descr="Return separated from computation of value of 'r'">return r;</warning>
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
class T {
|
||||
int f(boolean b) {
|
||||
int n = 0;
|
||||
if (b) n = 1;
|
||||
<warning descr="Return separated from computation of value of 'n'">return n;</warning>
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
class T {
|
||||
String f() {
|
||||
String r = "";
|
||||
while (hasNext()) {
|
||||
String s = next();
|
||||
if (s != null) {
|
||||
r = s;
|
||||
break;
|
||||
}
|
||||
}
|
||||
<warning descr="Return separated from computation of value of 'r'">return r;</warning>
|
||||
}
|
||||
|
||||
boolean hasNext() {
|
||||
return true;
|
||||
}
|
||||
|
||||
String next() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
class T {
|
||||
long f() {
|
||||
long r;
|
||||
long s = System.currentTimeMillis();
|
||||
long t = s;
|
||||
while (true) {
|
||||
t = System.currentTimeMillis();
|
||||
if (t - s > 100) {
|
||||
r = t;
|
||||
break;
|
||||
}
|
||||
}
|
||||
<warning descr="Return separated from computation of value of 'r'">return r;</warning>
|
||||
}
|
||||
}
|
||||
+48
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright 2000-2016 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.codeInsight.daemon.quickFix;
|
||||
|
||||
import com.intellij.codeInspection.LocalInspectionTool;
|
||||
import com.intellij.codeInspection.intermediaryVariable.ReturnSeparatedFromComputationInspection;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* @author Pavel.Dolgov
|
||||
*/
|
||||
public class ReturnSeparatedFromComputationFix2Test extends LightQuickFixTestCase {
|
||||
@NotNull
|
||||
@Override
|
||||
protected LocalInspectionTool[] configureLocalInspectionTools() {
|
||||
return new LocalInspectionTool[]{new ReturnSeparatedFromComputationInspection()};
|
||||
}
|
||||
|
||||
public void testAssert() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testBreakFromLoopInTryWithResources() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
private void doTest() {
|
||||
doSingleTest(getTestName(false) +".java");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getBasePath() {
|
||||
return "/codeInsight/daemonCodeAnalyzer/quickFix/returnSeparatedFromComputation";
|
||||
}
|
||||
}
|
||||
+40
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright 2000-2016 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.codeInsight.daemon.quickFix;
|
||||
|
||||
import com.intellij.codeInspection.LocalInspectionTool;
|
||||
import com.intellij.codeInspection.intermediaryVariable.ReturnSeparatedFromComputationInspection;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* @author Pavel.Dolgov
|
||||
*/
|
||||
public class ReturnSeparatedFromComputationFixTest extends LightQuickFixParameterizedTestCase {
|
||||
@NotNull
|
||||
@Override
|
||||
protected LocalInspectionTool[] configureLocalInspectionTools() {
|
||||
return new LocalInspectionTool[]{new ReturnSeparatedFromComputationInspection()};
|
||||
}
|
||||
|
||||
public void test() throws Exception {
|
||||
doAllTests();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getBasePath() {
|
||||
return "/codeInsight/daemonCodeAnalyzer/quickFix/returnSeparatedFromComputation";
|
||||
}
|
||||
}
|
||||
+136
@@ -0,0 +1,136 @@
|
||||
/*
|
||||
* Copyright 2000-2016 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;
|
||||
|
||||
import com.intellij.JavaTestUtil;
|
||||
import com.intellij.codeInspection.intermediaryVariable.ReturnSeparatedFromComputationInspection;
|
||||
import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase;
|
||||
|
||||
/**
|
||||
* @author Pavel.Dolgov
|
||||
*/
|
||||
public class ReturnSeparatedFromComputationTest extends LightCodeInsightFixtureTestCase {
|
||||
@Override
|
||||
protected String getBasePath() {
|
||||
return JavaTestUtil.getRelativeJavaTestDataPath() + "/inspection/returnSeparatedFromComputation";
|
||||
}
|
||||
|
||||
public void testReturnOutsideTryWithResources() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testBreakFromLoopInTryWithResources() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testSimpleIf() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testSimpleFor() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testIfElseWriteInBoth() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testIfElseWriteInIf() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testIfElseWriteInElse() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testIfElseNoWrite() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testNestedIf() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testNestedIfInnerElse() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testNestedIfOuterElse() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testNestedBlock() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testNestedBlockSideEffect() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testAssert() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testLabeledBlock() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testLabeledFor() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testLabeledFor2() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testLabeledIf() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testWhileTrue() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testSimpleWhile() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testForWithoutCondition() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testSimpleForeach() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testDoWhileTrue() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testSimpleDoWhile() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testSideEffectInIf() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
|
||||
private void doTest() {
|
||||
myFixture.enableInspections(new ReturnSeparatedFromComputationInspection());
|
||||
myFixture.testHighlighting(getTestName(false) + ".java");
|
||||
}
|
||||
}
|
||||
@@ -136,6 +136,11 @@ inspection.local.can.be.final.option3=Report foreach parameters
|
||||
inspection.can.be.local.parameter.problem.descriptor=Parameter <code>#ref</code> can have <code>final</code> modifier
|
||||
inspection.can.be.local.variable.problem.descriptor=Variable <code>#ref</code> can have <code>final</code> modifier
|
||||
|
||||
inspection.return.separated.from.computation.name=Return separated from computation of result
|
||||
inspection.return.separated.from.computation.descriptor=Return separated from computation of value of ''{0}''
|
||||
inspection.return.separated.from.computation.quickfix=Move ''return'' to computation of the value of ''{0}''
|
||||
inspection.return.separated.from.computation.family.quickfix=Move ''return'' to computation of the result
|
||||
|
||||
inspection.nullable.problems.display.name=@NotNull/@Nullable problems
|
||||
#check box options
|
||||
inspection.nullable.problems.method.overrides.notnull.option=<html>Report @NotNull ¶meters overriding @Nullable and <br>@Nullable methods overriding @NotNull</html>
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
<html>
|
||||
<body>
|
||||
This inspection detects <code>return</code> statements which return a local variable, where the value of the variable is computed
|
||||
somewhere else within the same code block with the <code>return</code> statement.
|
||||
<p>The quick fix inlines the returned variable by moving the return statement to the location where the value of the variable is computed.
|
||||
For example, the code below could be simplified:
|
||||
<pre><code>int n = -1;
|
||||
if (condition) n = compute();
|
||||
return n;</code></pre>
|
||||
After the quick fix it becomes the following:
|
||||
<pre><code>if (condition) return compute();
|
||||
return -1;</code></pre>
|
||||
</body>
|
||||
</html>
|
||||
@@ -647,6 +647,10 @@
|
||||
<localInspection groupPath="Java" language="JAVA" shortName="LocalCanBeFinal" bundle="messages.InspectionsBundle" key="inspection.local.can.be.final.display.name"
|
||||
groupKey="group.names.code.style.issues" enabledByDefault="false" level="WARNING"
|
||||
implementationClass="com.intellij.codeInspection.localCanBeFinal.LocalCanBeFinal"/>
|
||||
<localInspection groupPath="Java" language="JAVA" shortName="ReturnSeparatedFromComputation" bundle="messages.InspectionsBundle"
|
||||
key="inspection.return.separated.from.computation.name" groupKey="group.names.code.style.issues"
|
||||
enabledByDefault="true" level="WARNING"
|
||||
implementationClass="com.intellij.codeInspection.intermediaryVariable.ReturnSeparatedFromComputationInspection"/>
|
||||
|
||||
<localInspection groupPath="Java" language="JAVA" shortName="JavaDoc" bundle="messages.InspectionsBundle" key="inspection.javadoc.display.name"
|
||||
groupKey="group.names.javadoc.issues" enabledByDefault="true" level="WARNING"
|
||||
|
||||
Reference in New Issue
Block a user