IDEA-211005 Automatically fix "Not a statement" problem in inline method

This commit is contained in:
Tagir Valeev
2019-04-14 10:22:52 +03:00
parent 823bf31091
commit c70df8b9e9
6 changed files with 106 additions and 20 deletions

View File

@@ -48,6 +48,7 @@ import com.intellij.util.ObjectUtils;
import com.intellij.util.containers.MultiMap;
import com.siyeh.ig.psiutils.CommentTracker;
import com.siyeh.ig.psiutils.SideEffectChecker;
import com.siyeh.ig.psiutils.StatementExtractor;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -239,24 +240,6 @@ public class InlineMethodProcessor extends BaseRefactoringProcessor {
}
}, conflicts, JavaLanguage.INSTANCE);
final PsiReturnStatement[] returnStatements = PsiUtil.findReturnStatements(myMethod);
for (PsiReturnStatement statement : returnStatements) {
PsiExpression value = statement.getReturnValue();
if (value != null && !(value instanceof PsiCallExpression) &&
RemoveUnusedVariableUtil.checkSideEffects(value, null, new ArrayList<>())) {
for (UsageInfo info : usagesIn) {
PsiReference reference = info.getReference();
if (reference != null) {
InlineUtil.TailCallType type = InlineUtil.getTailCallType(reference);
if (type == InlineUtil.TailCallType.Simple) {
conflicts.putValue(statement, "Inlined result would contain parse errors");
break;
}
}
}
}
}
addInaccessibleMemberConflicts(myMethod, usagesIn, new ReferencedElementsCollector(), conflicts);
addInaccessibleSuperCallsConflicts(usagesIn, conflicts);
@@ -916,7 +899,18 @@ public class InlineMethodProcessor extends BaseRefactoringProcessor {
RemoveUnusedVariableUtil.checkSideEffects(returnValue, null, new ArrayList<>())) {
PsiExpressionStatement exprStatement = (PsiExpressionStatement) myFactory.createStatementFromText("a;", null);
exprStatement.getExpression().replace(returnValue);
returnStatement.getParent().addBefore(exprStatement, returnStatement);
PsiElement returnParent = returnStatement.getParent();
exprStatement = (PsiExpressionStatement)returnParent.addBefore(exprStatement, returnStatement);
if (!PsiUtil.isStatement(exprStatement)) {
PsiExpression expression = exprStatement.getExpression();
List<PsiExpression> sideEffects = SideEffectChecker.extractSideEffectExpressions(expression);
CommentTracker ct = new CommentTracker();
sideEffects.forEach(ct::markUnchanged);
for (PsiStatement sideEffect : StatementExtractor.generateStatements(sideEffects, expression)) {
returnParent.addBefore(sideEffect, exprStatement);
}
ct.deleteAndRestoreComments(exprStatement);
}
statement = myFactory.createStatementFromText("return;", null);
} else {
statement = (PsiStatement)returnStatement.copy();

View File

@@ -0,0 +1,41 @@
// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package com.intellij.refactoring.inline;
import com.intellij.psi.PsiCodeBlock;
import com.intellij.psi.PsiMethod;
import com.intellij.psi.PsiReference;
import com.intellij.refactoring.util.InlineUtil;
public abstract class InlineTransformer {
public abstract boolean isMethodAccepted(PsiMethod method);
public abstract boolean isReferenceAccepted(PsiReference reference);
public PsiCodeBlock transformBody(PsiCodeBlock body, PsiReference reference) {
return body;
}
static class NormalTransformer extends InlineTransformer {
@Override
public boolean isMethodAccepted(PsiMethod method) {
return !InlineMethodProcessor.checkBadReturns(method);
}
@Override
public boolean isReferenceAccepted(PsiReference reference) {
return true;
}
}
static class TailCallTransformer extends InlineTransformer {
@Override
public boolean isMethodAccepted(PsiMethod method) {
return true;
}
@Override
public boolean isReferenceAccepted(PsiReference reference) {
return InlineUtil.getTailCallType(reference) != InlineUtil.TailCallType.None;
}
}
}

View File

@@ -0,0 +1,23 @@
class AAA {
void fff(Project myProject) {
final String[] strings = new String[1];
ensureFilesWritable(strings).hasReadonlyFiles();
}
private Status ensureFilesWritable(final String[] strings) {
return new Status(strings);
}
class Status {
public Status(final String[] strings) {
}
boolean hasReadonlyFiles() {
return true;
}
}
class Project {
}
}

View File

@@ -0,0 +1,13 @@
import java.util.*;
class AAA {
boolean addIntoTwoSets(Set<String> set1, Set<String> set2, String value) {
return set1.add(value) && set2.add(value);
}
void usage() {
Set<String> s1 = new HashSet<>();
Set<String> s2 = new HashSet<>();
<caret>addIntoTwoSets(s1, s2, "foo");
}
}

View File

@@ -0,0 +1,12 @@
import java.util.*;
class AAA {
void usage() {
Set<String> s1 = new HashSet<>();
Set<String> s2 = new HashSet<>();
if (s1.add("foo")) {
s2.add("foo");
}
}
}

View File

@@ -234,9 +234,12 @@ public class InlineMethodTest extends LightRefactoringTestCase {
}
public void testNotAStatement() {
doTestConflict("Inlined result would contain parse errors");
doTest();
}
public void testNotAStatement2() {
doTest();
}
public void testInSuperCall() {
doTestConflict("Inline cannot be applied to multiline method in constructor call");