From 12b1c5a4e00b23b3e174a77c6a071fe05d04be21 Mon Sep 17 00:00:00 2001 From: Tagir Valeev Date: Fri, 7 Sep 2018 16:32:43 +0700 Subject: [PATCH] Inline field/method: check for reflective usages Fixes EA-126479 - CCE: InlineConstantFieldProcessor.inlineExpressionUsage --- .../inline/InlineConstantFieldProcessor.java | 10 ++++++++++ .../inline/InlineMethodProcessor.java | 6 ++++++ .../FieldUsedInJavadoc.java | 10 ++++++++++ .../FieldUsedReflectively.java | 8 ++++++++ .../inlineMethod/MethodUsedReflectively.java | 7 +++++++ .../inline/InlineConstantFieldTest.java | 19 +++++++++++++++++++ .../refactoring/inline/InlineMethodTest.java | 4 ++++ 7 files changed, 64 insertions(+) create mode 100644 java/java-tests/testData/refactoring/inlineConstantField/FieldUsedInJavadoc.java create mode 100644 java/java-tests/testData/refactoring/inlineConstantField/FieldUsedReflectively.java create mode 100644 java/java-tests/testData/refactoring/inlineMethod/MethodUsedReflectively.java diff --git a/java/java-impl/src/com/intellij/refactoring/inline/InlineConstantFieldProcessor.java b/java/java-impl/src/com/intellij/refactoring/inline/InlineConstantFieldProcessor.java index c0f046734a35..132eff511bb3 100644 --- a/java/java-impl/src/com/intellij/refactoring/inline/InlineConstantFieldProcessor.java +++ b/java/java-impl/src/com/intellij/refactoring/inline/InlineConstantFieldProcessor.java @@ -24,6 +24,7 @@ import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Ref; import com.intellij.psi.*; import com.intellij.psi.impl.source.javadoc.PsiDocMethodOrFieldRef; +import com.intellij.psi.impl.source.resolve.reference.impl.JavaLangClassMemberReference; import com.intellij.psi.search.GlobalSearchScope; import com.intellij.psi.search.searches.ReferencesSearch; import com.intellij.psi.util.PsiTreeUtil; @@ -42,6 +43,7 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.*; +import java.util.stream.Stream; /** * @author ven @@ -201,6 +203,10 @@ public class InlineConstantFieldProcessor extends BaseRefactoringProcessor { private void inlineExpressionUsage(PsiExpression expr, PsiExpression initializer1, Set assignments) throws IncorrectOperationException { + if (expr instanceof PsiLiteralExpression) { + // Possible reflective usage + return; + } if (myField.isWritable()) { myField.normalizeDeclaration(); } @@ -268,6 +274,10 @@ public class InlineConstantFieldProcessor extends BaseRefactoringProcessor { conflicts.putValue(element, "Inlined field is used in javadoc"); } } + if (element instanceof PsiLiteralExpression && + Stream.of(element.getReferences()).anyMatch(JavaLangClassMemberReference.class::isInstance)) { + conflicts.putValue(element, "Inlined field is used reflectively"); + } } } diff --git a/java/java-impl/src/com/intellij/refactoring/inline/InlineMethodProcessor.java b/java/java-impl/src/com/intellij/refactoring/inline/InlineMethodProcessor.java index a1b371f5dcbb..fe2d64da1062 100644 --- a/java/java-impl/src/com/intellij/refactoring/inline/InlineMethodProcessor.java +++ b/java/java-impl/src/com/intellij/refactoring/inline/InlineMethodProcessor.java @@ -25,6 +25,7 @@ import com.intellij.psi.codeStyle.VariableKind; import com.intellij.psi.controlFlow.*; import com.intellij.psi.impl.source.codeStyle.CodeEditUtil; import com.intellij.psi.impl.source.javadoc.PsiDocMethodOrFieldRef; +import com.intellij.psi.impl.source.resolve.reference.impl.JavaLangClassMemberReference; import com.intellij.psi.infos.MethodCandidateInfo; import com.intellij.psi.search.GlobalSearchScope; import com.intellij.psi.search.LocalSearchScope; @@ -53,6 +54,7 @@ import org.jetbrains.annotations.Nullable; import java.util.*; import java.util.function.Predicate; +import java.util.stream.Stream; public class InlineMethodProcessor extends BaseRefactoringProcessor { private static final Logger LOG = Logger.getInstance("#com.intellij.refactoring.inline.InlineMethodProcessor"); @@ -210,6 +212,10 @@ public class InlineMethodProcessor extends BaseRefactoringProcessor { if (element instanceof PsiDocMethodOrFieldRef && !PsiTreeUtil.isAncestor(myMethod, element, false)) { conflicts.putValue(element, "Inlined method is used in javadoc"); } + if (element instanceof PsiLiteralExpression && + Stream.of(element.getReferences()).anyMatch(JavaLangClassMemberReference.class::isInstance)) { + conflicts.putValue(element, "Inlined method is used reflectively"); + } if (element instanceof PsiMethodReferenceExpression) { final PsiExpression qualifierExpression = ((PsiMethodReferenceExpression)element).getQualifierExpression(); if (qualifierExpression != null) { diff --git a/java/java-tests/testData/refactoring/inlineConstantField/FieldUsedInJavadoc.java b/java/java-tests/testData/refactoring/inlineConstantField/FieldUsedInJavadoc.java new file mode 100644 index 000000000000..1a0b26906624 --- /dev/null +++ b/java/java-tests/testData/refactoring/inlineConstantField/FieldUsedInJavadoc.java @@ -0,0 +1,10 @@ +class Test { + private static final int FIELD = 5; + + /** + * Prints the value of {@link Test#FIELD} + */ + void test() { + System.out.println(FIELD); + } +} \ No newline at end of file diff --git a/java/java-tests/testData/refactoring/inlineConstantField/FieldUsedReflectively.java b/java/java-tests/testData/refactoring/inlineConstantField/FieldUsedReflectively.java new file mode 100644 index 000000000000..e9281f5a8840 --- /dev/null +++ b/java/java-tests/testData/refactoring/inlineConstantField/FieldUsedReflectively.java @@ -0,0 +1,8 @@ +class Test { + private static final int FIELD = 5; + + void test() { + System.out.println(FIELD); + System.out.println(Test.class.getDeclaredField("FIELD")); + } +} \ No newline at end of file diff --git a/java/java-tests/testData/refactoring/inlineMethod/MethodUsedReflectively.java b/java/java-tests/testData/refactoring/inlineMethod/MethodUsedReflectively.java new file mode 100644 index 000000000000..1d2a259142ef --- /dev/null +++ b/java/java-tests/testData/refactoring/inlineMethod/MethodUsedReflectively.java @@ -0,0 +1,7 @@ +class InlineMethodTest { + public void foo(){} + + void test() throws Exception { + System.out.println(InlineMethodTest.class.getDeclaredMethod("foo")); + } +} diff --git a/java/java-tests/testSrc/com/intellij/java/refactoring/inline/InlineConstantFieldTest.java b/java/java-tests/testSrc/com/intellij/java/refactoring/inline/InlineConstantFieldTest.java index 7b94edccbb07..b871e470ce57 100644 --- a/java/java-tests/testSrc/com/intellij/java/refactoring/inline/InlineConstantFieldTest.java +++ b/java/java-tests/testSrc/com/intellij/java/refactoring/inline/InlineConstantFieldTest.java @@ -20,6 +20,7 @@ import com.intellij.codeInsight.TargetElementUtil; import com.intellij.java.refactoring.LightRefactoringTestCase; import com.intellij.openapi.projectRoots.Sdk; import com.intellij.psi.*; +import com.intellij.refactoring.BaseRefactoringProcessor; import com.intellij.refactoring.inline.InlineConstantFieldHandler; import com.intellij.refactoring.inline.InlineConstantFieldProcessor; import com.intellij.testFramework.IdeaTestUtil; @@ -82,6 +83,14 @@ public class InlineConstantFieldTest extends LightRefactoringTestCase { doTest(); } + public void testFieldUsedReflectively() { + doTestConflict("Inlined field is used reflectively"); + } + + public void testFieldUsedInJavadoc() { + doTestConflict("Inlined field is used in javadoc"); + } + public void testMultipleInitializers() { configureByFile("/refactoring/inlineConstantField/" + getTestName(false) + ".java"); PsiElement element = TargetElementUtil @@ -107,4 +116,14 @@ public class InlineConstantFieldTest extends LightRefactoringTestCase { new InlineConstantFieldProcessor(field, getProject(), refExpr, inlineThisOnly || element instanceof PsiCompiledElement).run(); checkResultByFile(fileName + ".after"); } + + private void doTestConflict(final String conflict) { + try { + doTest(); + fail("Conflict was not detected"); + } + catch (BaseRefactoringProcessor.ConflictsInTestsException e) { + assertEquals(conflict, e.getMessage()); + } + } } \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/java/refactoring/inline/InlineMethodTest.java b/java/java-tests/testSrc/com/intellij/java/refactoring/inline/InlineMethodTest.java index ac03438791ca..73c746f364d5 100644 --- a/java/java-tests/testSrc/com/intellij/java/refactoring/inline/InlineMethodTest.java +++ b/java/java-tests/testSrc/com/intellij/java/refactoring/inline/InlineMethodTest.java @@ -231,6 +231,10 @@ public class InlineMethodTest extends LightRefactoringTestCase { doTestConflict("Inlined method is used in javadoc"); } + public void testMethodUsedReflectively() { + doTestConflict("Inlined method is used reflectively"); + } + public void testNotAStatement() { doTestConflict("Inlined result would contain parse errors"); }