diff --git a/java/java-impl/src/com/intellij/refactoring/inline/InlineMethodSpecialization.java b/java/java-impl/src/com/intellij/refactoring/inline/InlineMethodSpecialization.java index bb72b0d8a8da..a704158edf80 100644 --- a/java/java-impl/src/com/intellij/refactoring/inline/InlineMethodSpecialization.java +++ b/java/java-impl/src/com/intellij/refactoring/inline/InlineMethodSpecialization.java @@ -7,38 +7,72 @@ import com.intellij.psi.util.PsiUtil; import com.intellij.util.ObjectUtils; import com.siyeh.ig.callMatcher.CallMapper; import com.siyeh.ig.callMatcher.CallMatcher; +import com.siyeh.ig.psiutils.ExpressionUtils; +import org.jetbrains.annotations.Contract; +import org.jetbrains.annotations.NotNull; import java.util.Objects; import java.util.function.Supplier; +import static com.intellij.util.ObjectUtils.nullizeByCondition; +import static com.intellij.util.ObjectUtils.tryCast; + public class InlineMethodSpecialization { private static final CallMatcher CLASS_METHODS = CallMatcher.exactInstanceCall(CommonClassNames.JAVA_LANG_CLASS, "getName", "getSimpleName").parameterCount(0); + private static final CallMatcher + ENUM_NAME = CallMatcher.exactInstanceCall(CommonClassNames.JAVA_LANG_ENUM, "name").parameterCount(0); private static final CallMapper> SPECIALIZATIONS = new CallMapper>() .register(CLASS_METHODS, (PsiMethodCallExpression call) -> { PsiReferenceExpression ref = call.getMethodExpression(); PsiExpression qualifier = ref.getQualifierExpression(); PsiClassObjectAccessExpression receiver = - ObjectUtils.tryCast(PsiUtil.skipParenthesizedExprDown(qualifier), PsiClassObjectAccessExpression.class); - if (receiver != null) { - PsiClass psiClass = PsiUtil.resolveClassInClassTypeOnly(receiver.getOperand().getType()); - if (psiClass != null) { - String name = "getSimpleName".equals(ref.getReferenceName()) ? psiClass.getName() : psiClass.getQualifiedName(); - if (name != null) { - return () -> { - PsiElementFactory factory = JavaPsiFacade.getElementFactory(call.getProject()); - return factory.createCodeBlockFromText("{return \"" + StringUtil.escapeStringCharacters(name) + "\";}", call); - }; - } - } - } - return null; + tryCast(PsiUtil.skipParenthesizedExprDown(qualifier), PsiClassObjectAccessExpression.class); + if (receiver == null) return null; + PsiClass psiClass = PsiUtil.resolveClassInClassTypeOnly(receiver.getOperand().getType()); + if (psiClass == null) return null; + String name = "getSimpleName".equals(ref.getReferenceName()) ? psiClass.getName() : psiClass.getQualifiedName(); + return getStringSupplier(call, name); + }) + .register(ENUM_NAME, (PsiMethodCallExpression call) -> { + PsiReferenceExpression qualifier = + tryCast(PsiUtil.skipParenthesizedExprDown(call.getMethodExpression().getQualifierExpression()), PsiReferenceExpression.class); + if (qualifier == null) return null; + PsiEnumConstant enumConstant = tryCast(qualifier.resolve(), PsiEnumConstant.class); + if (enumConstant == null) return null; + return getStringSupplier(call, enumConstant.getName()); + }) + .register(CallMatcher.enumValueOf(), (PsiMethodCallExpression call) -> { + PsiReferenceExpression qualifier = + tryCast(PsiUtil.skipParenthesizedExprDown(call.getMethodExpression().getQualifierExpression()), PsiReferenceExpression.class); + if (qualifier == null) return null; + PsiClass cls = tryCast(qualifier.resolve(), PsiClass.class); + if (cls == null || !cls.isEnum()) return null; + PsiLiteralExpression literal = ExpressionUtils.getLiteral(call.getArgumentList().getExpressions()[0]); + if (literal == null) return null; + String name = tryCast(literal.getValue(), String.class); + if (name == null) return null; + PsiEnumConstant constant = tryCast(cls.findFieldByName(name, false), PsiEnumConstant.class); + if (constant == null) return null; + return () -> { + PsiElementFactory factory = JavaPsiFacade.getElementFactory(call.getProject()); + return factory.createCodeBlockFromText("{return " + qualifier.getText() + "." + constant.getName() + ";}", call); + }; }); + @Contract(value = "_, null -> null", pure = true) + private static Supplier getStringSupplier(PsiElement context, String name) { + if (name == null) return null; + return () -> { + PsiElementFactory factory = JavaPsiFacade.getElementFactory(context.getProject()); + return factory.createCodeBlockFromText("{return \"" + StringUtil.escapeStringCharacters(name) + "\";}", context); + }; + } + static Supplier forReference(PsiReference ref) { if (!(ref instanceof PsiReferenceExpression)) return null; - PsiMethodCallExpression call = ObjectUtils.tryCast(((PsiReferenceExpression)ref).getParent(), PsiMethodCallExpression.class); + PsiMethodCallExpression call = tryCast(((PsiReferenceExpression)ref).getParent(), PsiMethodCallExpression.class); return SPECIALIZATIONS.mapFirst(call); } diff --git a/java/java-tests/testData/refactoring/inlineMethod/SpecializeEnumName.java b/java/java-tests/testData/refactoring/inlineMethod/SpecializeEnumName.java new file mode 100644 index 000000000000..1b2a0842b29d --- /dev/null +++ b/java/java-tests/testData/refactoring/inlineMethod/SpecializeEnumName.java @@ -0,0 +1,9 @@ +package foo.bar.baz; + +class Test { + enum X {A, B, C}; + + void test() { + System.out.println(X.A.name()); + } +} \ No newline at end of file diff --git a/java/java-tests/testData/refactoring/inlineMethod/SpecializeEnumName.java.after b/java/java-tests/testData/refactoring/inlineMethod/SpecializeEnumName.java.after new file mode 100644 index 000000000000..b3c9f4ede6c0 --- /dev/null +++ b/java/java-tests/testData/refactoring/inlineMethod/SpecializeEnumName.java.after @@ -0,0 +1,9 @@ +package foo.bar.baz; + +class Test { + enum X {A, B, C}; + + void test() { + System.out.println("A"); + } +} \ No newline at end of file diff --git a/java/java-tests/testData/refactoring/inlineMethod/SpecializeEnumValueOf.java b/java/java-tests/testData/refactoring/inlineMethod/SpecializeEnumValueOf.java new file mode 100644 index 000000000000..b9445fadd52f --- /dev/null +++ b/java/java-tests/testData/refactoring/inlineMethod/SpecializeEnumValueOf.java @@ -0,0 +1,9 @@ +package foo.bar.baz; + +class Test { + enum X {A, B, C}; + + void test() { + System.out.println(X.valueOf("B")); + } +} \ No newline at end of file diff --git a/java/java-tests/testData/refactoring/inlineMethod/SpecializeEnumValueOf.java.after b/java/java-tests/testData/refactoring/inlineMethod/SpecializeEnumValueOf.java.after new file mode 100644 index 000000000000..3af2183b9304 --- /dev/null +++ b/java/java-tests/testData/refactoring/inlineMethod/SpecializeEnumValueOf.java.after @@ -0,0 +1,9 @@ +package foo.bar.baz; + +class Test { + enum X {A, B, C}; + + void test() { + System.out.println(X.B); + } +} \ 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 cc94a8d40d15..850de44cfe9b 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 @@ -491,6 +491,14 @@ public class InlineMethodTest extends LightRefactoringTestCase { doTest(); } + public void testSpecializeEnumName() { + doTest(); + } + + public void testSpecializeEnumValueOf() { + doTest(); + } + public void testBooleanModelSimple() { doTestAssertBadReturn(); }