java inline field: check if initializer depends on context (IDEA-247851)

additional checks for local classes & initializer components IJ-CR-2759

GitOrigin-RevId: 84402b253396ef60c33d3468bcc6fdc65c4e3176
This commit is contained in:
Anna Kozlova
2020-08-19 07:02:25 +00:00
committed by intellij-monorepo-bot
parent ac33fff3e6
commit d880e86a3a
6 changed files with 64 additions and 9 deletions
@@ -227,16 +227,18 @@ public class InlineConstantFieldProcessor extends BaseRefactoringProcessor {
initializer.accept(collector);
HashSet<PsiMember> referencedWithVisibility = collector.myReferencedMembers;
boolean dependsOnContext = false;
if (!myField.hasInitializer()) {
boolean dependsOnContext;
PsiMethod[] constructors = Objects.requireNonNull(myField.getContainingClass()).getConstructors();
if (constructors.length == 1) {
Ref<PsiElement> reference = new Ref<>();
dependsOnContext = !PsiTreeUtil.processElements(initializer, element -> {
if (element instanceof PsiReferenceExpression &&
((PsiReferenceExpression)element).getQualifierExpression() == null) {
PsiElement resolve = ((PsiReferenceExpression)element).resolve();
if (resolve == null ||
PsiTreeUtil.isAncestor(constructors[0], resolve, true)) {
if (element instanceof PsiJavaCodeReferenceElement) {
PsiElement resolve = ((PsiJavaCodeReferenceElement)element).resolve();
if (resolve != null &&
PsiTreeUtil.isAncestor(constructors[0], resolve, true) &&
!PsiTreeUtil.isAncestor(initializer, resolve, true)) {
reference.set(resolve);
return false;
}
}
@@ -247,6 +249,7 @@ public class InlineConstantFieldProcessor extends BaseRefactoringProcessor {
PsiElement element = usageInfo.getElement();
if (element != null && !PsiTreeUtil.isAncestor(constructors[0], element, true)) {
conflicts.putValue(element, JavaRefactoringBundle.message("inline.field.initializer.is.not.accessible",
RefactoringUIUtil.getDescription(reference.get(), false),
RefactoringUIUtil.getDescription(ConflictsUtil.getContainer(element), true)));
}
}
@@ -0,0 +1,12 @@
class Test {
private final int <caret>myA;
Test() {
class Local {}
myA = new Local().hashCode();
}
void test() {
System.out.println(myA);
}
}
@@ -0,0 +1,17 @@
interface Consumer<T> {
void accept(T t);
}
class Test {
class X {
final Consumer<String> myCon<caret>sumer;
X() {
myConsumer = s -> System.out.println(s);
}
void test() {
myConsumer.accept("1");
}
}
}
@@ -0,0 +1,15 @@
interface Consumer<T> {
void accept(T t);
}
class Test {
class X {
X() {
}
void test() {
((Consumer<String>) s -> System.out.println(s)).accept("1");
}
}
}
@@ -88,7 +88,11 @@ public class InlineConstantFieldTest extends LightRefactoringTestCase {
}
public void testFieldInitializedWithParameter() {
doTestConflict("Field initializer is not accessible in method <b><code>Test.test()</code></b>");
doTestConflict("Field initializer refers to parameter <b><code>a</code></b> which is not accessible in method <b><code>Test.test()</code></b>");
}
public void testFieldInitializedLocalClass() {
doTestConflict("Field initializer refers to class <b><code>Local</code></b> which is not accessible in method <b><code>Test.test()</code></b>");
}
public void testFieldInitializedWithParameter1() {
@@ -99,6 +103,10 @@ public class InlineConstantFieldTest extends LightRefactoringTestCase {
doTest();
}
public void testFieldInitializedWithLambda() {
doTest();
}
public void testFieldUsedInJavadoc() {
doTestConflict("Inlined field is used in javadoc");
}
@@ -291,6 +291,7 @@ inline.field.title=Inline Field
inline.field.used.in.javadoc=Inlined field is used in javadoc
inline.field.used.in.reflection=Inlined field is used reflectively
inline.field.view.occurrences=Press {0} to go through {1} inlined occurrences
inline.field.initializer.is.not.accessible=Field initializer refers to {0} which is not accessible in {1}
inline.local.unable.try.catch.warning.message=Unable to inline outside try/catch statement
inline.local.used.as.resource.cannot.refactor.message=Variable is used as resource reference
inline.local.variable.declared.outside.cannot.refactor.message=Variable is declared outside a code block
@@ -776,5 +777,4 @@ replace.constructor.builder.error.selected.class.was.not.found=Selected class wa
replace.constructor.factory.error.invalid.factory.method.name=''{0}'' is invalid factory method name
replace.constructor.factory.error.factory.method.already.exists=Factory method {0} already exists and will be used instead of newly created.
java.safe.delete.empty.callee.text=Callee text would be shown here
java.safe.delete.caller.text=Caller text with highlighted callee would be shown here
inline.field.initializer.is.not.accessible=Field initializer is not accessible in {0}
java.safe.delete.caller.text=Caller text with highlighted callee would be shown here