From 7a8e58a984ccc83f4397026a61989e550947a509 Mon Sep 17 00:00:00 2001 From: anna Date: Fri, 29 Jan 2010 21:02:14 +0300 Subject: [PATCH] Inline inner: rise conflict for recursive inlinement (IDEA-39353) --- .../inline/InlineToAnonymousClassHandler.java | 3 ++- .../inline/InlineToAnonymousClassProcessor.java | 29 ++++++++++++++++++++++ .../NoInlineRecursiveAccess.java | 20 +++++++++++++++ .../ParamTypeReplacement.java | 13 ++++++++++ .../ParamTypeReplacement.java.after | 11 ++++++++ .../inline/InlineToAnonymousClassTest.java | 24 +++++++++++++++--- 6 files changed, 96 insertions(+), 4 deletions(-) create mode 100644 java/java-tests/testData/refactoring/inlineToAnonymousClass/NoInlineRecursiveAccess.java create mode 100644 java/java-tests/testData/refactoring/inlineToAnonymousClass/ParamTypeReplacement.java create mode 100644 java/java-tests/testData/refactoring/inlineToAnonymousClass/ParamTypeReplacement.java.after diff --git a/java/java-impl/src/com/intellij/refactoring/inline/InlineToAnonymousClassHandler.java b/java/java-impl/src/com/intellij/refactoring/inline/InlineToAnonymousClassHandler.java index dc8ad3b3ad..9d1a6536bf 100644 --- a/java/java-impl/src/com/intellij/refactoring/inline/InlineToAnonymousClassHandler.java +++ b/java/java-impl/src/com/intellij/refactoring/inline/InlineToAnonymousClassHandler.java @@ -284,7 +284,8 @@ public class InlineToAnonymousClassHandler extends JavaInlineActionHandler { } final PsiElement parentElement = element.getParent(); if (parentElement != null) { - if (parentElement.getParent() instanceof PsiClassObjectAccessExpression) { + final PsiElement grandPa = parentElement.getParent(); + if (grandPa instanceof PsiClassObjectAccessExpression) { return "Class cannot be inlined because it has usages of its class literal"; } if (ourCatchClausePattern.accepts(parentElement)) { diff --git a/java/java-impl/src/com/intellij/refactoring/inline/InlineToAnonymousClassProcessor.java b/java/java-impl/src/com/intellij/refactoring/inline/InlineToAnonymousClassProcessor.java index 92f13b3584..1a5a1ea269 100644 --- a/java/java-impl/src/com/intellij/refactoring/inline/InlineToAnonymousClassProcessor.java +++ b/java/java-impl/src/com/intellij/refactoring/inline/InlineToAnonymousClassProcessor.java @@ -150,6 +150,35 @@ public class InlineToAnonymousClassProcessor extends BaseRefactoringProcessor { } }; InlineMethodProcessor.addInaccessibleMemberConflicts(myClass, usages, collector, result); + for (UsageInfo usage : usages) { + final PsiElement element = usage.getElement(); + if (element == null) continue; + final PsiElement parent = element.getParent(); + if (parent == null) continue; + if (parent instanceof PsiNewExpression && PsiTreeUtil.isAncestor(myClass, parent, false)) { + result.putValue(parent, "Class cannot be inlined because a call to its constructor inside body"); + } + final PsiElement grandPa = parent.getParent(); + if (grandPa instanceof PsiParameter && PsiTreeUtil.isAncestor(myClass, grandPa, false)) { + for (PsiReference psiReference : ReferencesSearch.search(grandPa)) { + final PsiElement refElement = psiReference.getElement(); + if (refElement instanceof PsiExpression) { + final PsiReferenceExpression referenceExpression = PsiTreeUtil.getParentOfType(refElement, PsiReferenceExpression.class); + if (referenceExpression != null && referenceExpression.getQualifierExpression() == refElement) { + final PsiElement resolvedMember = referenceExpression.resolve(); + if (resolvedMember != null && PsiTreeUtil.isAncestor(myClass, resolvedMember, false)) { + if (resolvedMember instanceof PsiMethod) { + if (myClass.findMethodsBySignature((PsiMethod)resolvedMember, true).length > 1) { //skip inherited methods + continue; + } + } + result.putValue(refElement, "Class cannot be inlined because a call to its member inside body"); + } + } + } + } + } + } return result; } diff --git a/java/java-tests/testData/refactoring/inlineToAnonymousClass/NoInlineRecursiveAccess.java b/java/java-tests/testData/refactoring/inlineToAnonymousClass/NoInlineRecursiveAccess.java new file mode 100644 index 0000000000..0ae807f380 --- /dev/null +++ b/java/java-tests/testData/refactoring/inlineToAnonymousClass/NoInlineRecursiveAccess.java @@ -0,0 +1,20 @@ +public class SelfParams { + private int myVar = 0; + + private int myProp = 0; + public int getProp() { + return myProp; + } + public void setProp(int prop) { + myProp = prop; + } + + public void copy(SelfParams sp) { + this.myVar = sp.myVar; + this.myProp = sp.getProp(); + } +} + +class Usage { + SelfParams s = new SelfParams(); +} \ No newline at end of file diff --git a/java/java-tests/testData/refactoring/inlineToAnonymousClass/ParamTypeReplacement.java b/java/java-tests/testData/refactoring/inlineToAnonymousClass/ParamTypeReplacement.java new file mode 100644 index 0000000000..0687e1e20e --- /dev/null +++ b/java/java-tests/testData/refactoring/inlineToAnonymousClass/ParamTypeReplacement.java @@ -0,0 +1,13 @@ +public class Simple implements Runnable{ + void foo(Simple s) { + System.out.println(s.toString()); + s.run(); + } + + public void run(){ + } +} + +class Usage { + Simple s = new Simple(); +} \ No newline at end of file diff --git a/java/java-tests/testData/refactoring/inlineToAnonymousClass/ParamTypeReplacement.java.after b/java/java-tests/testData/refactoring/inlineToAnonymousClass/ParamTypeReplacement.java.after new file mode 100644 index 0000000000..5e73698e1d --- /dev/null +++ b/java/java-tests/testData/refactoring/inlineToAnonymousClass/ParamTypeReplacement.java.after @@ -0,0 +1,11 @@ +class Usage { + Runnable s = new Runnable() { + void foo(Runnable s) { + System.out.println(s.toString()); + s.run(); + } + + public void run(){ + } + }; +} \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/refactoring/inline/InlineToAnonymousClassTest.java b/java/java-tests/testSrc/com/intellij/refactoring/inline/InlineToAnonymousClassTest.java index 61c8e144f5..9bbd231a00 100644 --- a/java/java-tests/testSrc/com/intellij/refactoring/inline/InlineToAnonymousClassTest.java +++ b/java/java-tests/testSrc/com/intellij/refactoring/inline/InlineToAnonymousClassTest.java @@ -13,6 +13,8 @@ import com.intellij.usageView.UsageInfo; import com.intellij.util.containers.MultiMap; import org.jetbrains.annotations.NonNls; +import java.util.Iterator; + /** * @author yole */ @@ -222,6 +224,10 @@ public class InlineToAnonymousClassTest extends LightCodeInsightTestCase { doTest(false, true); } + public void testParamTypeReplacement() throws Exception { + doTest(false, true); + } + public void testNoInlineAbstract() throws Exception { doTestNoInline("Abstract classes cannot be inlined"); } @@ -322,13 +328,25 @@ public class InlineToAnonymousClassTest extends LightCodeInsightTestCase { doTestPreprocessUsages("Class is never used"); } + public void testNoInlineRecursiveAccess() throws Exception { + doTestConflict("Class cannot be inlined because a call to its member inside body", "Class cannot be inlined because a call to its member inside body"); + } + public void testConflictInaccessibleOuterField() throws Exception { + doTestConflict( + "Field C2.a that is used in inlined method is not accessible from call site(s) in method C2User.test()"); + } + + public void doTestConflict(final String... expected) throws Exception { InlineToAnonymousClassProcessor processor = prepareProcessor(); UsageInfo[] usages = processor.findUsages(); MultiMap conflicts = processor.getConflicts(usages); - assertEquals(1, conflicts.size()); - assertEquals("Field C2.a that is used in inlined method is not accessible from call site(s) in method C2User.test()", - conflicts.values().iterator().next()); + assertEquals(expected.length, conflicts.size()); + final Iterator iterator = conflicts.values().iterator(); + for (String s : expected) { + assertTrue(iterator.hasNext()); + assertEquals(s, iterator.next()); + } } private void doTestNoInline(final String expectedMessage) throws Exception { -- 2.11.4.GIT