inline chained calls: ensure qualifiers with side effects are preserved (IDEA-199990; IDEA-147989)

This commit is contained in:
Anna.Kozlova
2018-10-08 18:57:16 +02:00
parent 291c5cb03b
commit 15ed2e8384
8 changed files with 150 additions and 6 deletions
@@ -54,9 +54,9 @@ public class RemoveUnusedVariableUtil {
return !writes.isEmpty();
}
static PsiElement replaceElementWithExpression(PsiExpression expression,
PsiElementFactory factory,
PsiElement element) throws IncorrectOperationException {
public static PsiElement replaceElementWithExpression(PsiExpression expression,
PsiElementFactory factory,
PsiElement element) throws IncorrectOperationException {
PsiElement elementToReplace = element;
PsiElement expressionToReplaceWith = expression;
if (element.getParent() instanceof PsiExpressionStatement) {
@@ -1026,8 +1026,14 @@ public class InlineMethodProcessor extends BaseRefactoringProcessor {
private void inlineParmOrThisVariable(PsiLocalVariable variable, boolean strictlyFinal) throws IncorrectOperationException {
PsiReference firstRef = ReferencesSearch.search(variable).findFirst();
PsiExpression initializer = variable.getInitializer();
if (firstRef == null) {
variable.getParent().delete(); //Q: side effects?
if (initializer != null && SideEffectChecker.mayHaveSideEffects(initializer)) {
RemoveUnusedVariableUtil.replaceElementWithExpression(initializer, PsiElementFactory.SERVICE.getInstance(myProject), variable);
}
else {
variable.getParent().delete();
}
return;
}
@@ -1043,7 +1049,6 @@ public class InlineMethodProcessor extends BaseRefactoringProcessor {
}
}
PsiExpression initializer = variable.getInitializer();
boolean shouldBeFinal = variable.hasModifierProperty(PsiModifier.FINAL) && strictlyFinal;
if (canInlineParmOrThisVariable(initializer, shouldBeFinal, strictlyFinal, refs.size(), isAccessedForWriting)) {
if (shouldBeFinal) {
@@ -1153,7 +1158,7 @@ public class InlineMethodProcessor extends BaseRefactoringProcessor {
return false;
}
else if (initializer instanceof PsiCallExpression) {
if (accessCount > 1) return false;
if (accessCount != 1) return false;//don't allow deleting probable side effects or multiply those side effects
if (initializer instanceof PsiNewExpression) {
final PsiArrayInitializerExpression arrayInitializer = ((PsiNewExpression)initializer).getArrayInitializer();
if (arrayInitializer != null) {
@@ -0,0 +1,42 @@
class MyObjBuilder {
private NewType memberVar1;
public NewType convertToNewType(LegacyType arg) {
return new NewType();
}
public MyObjBuilder memberVar1(LegacyType arg) {
memberVar1(convertToNewType(arg));
return this;
}
public MyObjBuilder memberVar1(NewType arg) {
this.memberVar1 = arg;
return this;
}
public MyObj memberVar2() {
return new MyObj();
}
}
class Main {
public static void main(String[] args) {
LegacyType lt = new LegacyType();
MyObj obj = MyObj.builder()
.mem<caret>berVar1(lt)
.memberVar2();
}
}
class NewType {
}
class MyObj {
public static MyObjBuilder builder() {
return new MyObjBuilder();
}
}
class LegacyType {}
@@ -0,0 +1,38 @@
class MyObjBuilder {
private NewType memberVar1;
public NewType convertToNewType(LegacyType arg) {
return new NewType();
}
public MyObjBuilder memberVar1(NewType arg) {
this.memberVar1 = arg;
return this;
}
public MyObj memberVar2() {
return new MyObj();
}
}
class Main {
public static void main(String[] args) {
LegacyType lt = new LegacyType();
MyObjBuilder myObjBuilder = MyObj.builder();
myObjBuilder.memberVar1(myObjBuilder.convertToNewType(lt));
MyObj obj = myObjBuilder
.memberVar2();
}
}
class NewType {
}
class MyObj {
public static MyObjBuilder builder() {
return new MyObjBuilder();
}
}
class LegacyType {}
@@ -4,6 +4,7 @@ import java.util.function.Function;
class B<T> {
void foo(B<? extends CharSequence> sequences){
sequences.bar(t -> t);
Object t1 = null;
}
@@ -0,0 +1,26 @@
class Outer {
public void checkIt() {
Inner inner = new Inner();
inner.step1().step2().st<caret>ep3();
System.out.println(" INNER.I = " + inner.i);
}
class Inner {
int i = 3;
public Inner step1() {
return this;
}
public Inner step2() {
i = 2;
return this;
}
public void step3() {
}
}
}
@@ -0,0 +1,24 @@
class Outer {
public void checkIt() {
Inner inner = new Inner();
inner.step1().step2();
System.out.println(" INNER.I = " + inner.i);
}
class Inner {
int i = 3;
public Inner step1() {
return this;
}
public Inner step2() {
i = 2;
return this;
}
}
}
@@ -416,6 +416,14 @@ public class InlineMethodTest extends LightRefactoringTestCase {
doTest();
}
public void testChainedBuilderCall() {
doTest();
}
public void testMissedQualifierWithSideEffectsOnInliningEmptyMethod() {
doTest();
}
public void testNotTailCallInsideIf() {
doTestAssertBadReturn();
}