IDEA-178890 "Inline" Foo.class.getName(), Foo.class.getSimpleName()

GitOrigin-RevId: 12c063d4e41ba8f5244a9c0609ebf016980c97c8
This commit is contained in:
Tagir Valeev
2019-04-22 12:51:38 +07:00
committed by intellij-monorepo-bot
parent 6e1e629b31
commit 505bdd1c87
6 changed files with 99 additions and 6 deletions

View File

@@ -17,6 +17,7 @@ import com.intellij.refactoring.util.InlineUtil;
import com.intellij.refactoring.util.RefactoringUtil;
import java.util.Collections;
import java.util.function.Supplier;
class InlineMethodHandler extends JavaInlineActionHandler {
private static final String REFACTORING_NAME = RefactoringBundle.message("inline.method.title");
@@ -32,7 +33,16 @@ class InlineMethodHandler extends JavaInlineActionHandler {
@Override
public void inlineElement(final Project project, Editor editor, PsiElement element) {
PsiMethod method = (PsiMethod)element.getNavigationElement();
final PsiCodeBlock methodBody = method.getBody();
PsiReference reference = editor != null ? TargetElementUtil.findReference(editor, editor.getCaretModel().getOffset()) : null;
boolean allowInlineThisOnly = false;
PsiCodeBlock methodBody = method.getBody();
Supplier<PsiCodeBlock> specialization = InlineMethodSpecialization.forReference(reference);
if (specialization != null) {
allowInlineThisOnly = true;
methodBody = specialization.get();
}
if (methodBody == null){
String message;
if (method.hasModifierProperty(PsiModifier.ABSTRACT)) {
@@ -48,7 +58,6 @@ class InlineMethodHandler extends JavaInlineActionHandler {
return;
}
PsiReference reference = editor != null ? TargetElementUtil.findReference(editor, editor.getCaretModel().getOffset()) : null;
if (reference != null) {
final PsiElement refElement = reference.getElement();
if (!isEnabledForLanguage(refElement.getLanguage())) {
@@ -73,7 +82,6 @@ class InlineMethodHandler extends JavaInlineActionHandler {
}
}
boolean allowInlineThisOnly = false;
if (method.isConstructor()) {
if (method.isVarArgs()) {
String message = RefactoringBundle.message("refactoring.cannot.be.applied.to.vararg.constructors", REFACTORING_NAME);

View File

@@ -111,8 +111,8 @@ public class InlineMethodProcessor extends BaseRefactoringProcessor {
boolean searchForTextOccurrences,
boolean isDeleteTheDeclaration) {
super(project);
myMethod = method;
myTransformerChooser = InlineTransformer.getSuitableTransformer(myMethod);
myMethod = InlineMethodSpecialization.specialize(method, reference);
myTransformerSelector = InlineTransformerSelector.forMethod(myMethod);
myReference = reference;
myEditor = editor;
myInlineThisOnly = isInlineThisOnly;
@@ -773,7 +773,10 @@ public class InlineMethodProcessor extends BaseRefactoringProcessor {
private PsiSubstitutor getCallSubstitutor(PsiMethodCallExpression methodCall) {
JavaResolveResult resolveResult = methodCall.getMethodExpression().advancedResolve(false);
LOG.assertTrue(myManager.areElementsEquivalent(resolveResult.getElement(), myMethod));
if (myMethod.isPhysical()) {
// Could be specialized
LOG.assertTrue(myManager.areElementsEquivalent(resolveResult.getElement(), myMethod));
}
if (resolveResult.getSubstitutor() != PsiSubstitutor.EMPTY) {
Iterator<PsiTypeParameter> oldTypeParameters = PsiUtil.typeParametersIterator(myMethod);
Iterator<PsiTypeParameter> newTypeParameters = PsiUtil.typeParametersIterator(myMethodCopy);

View File

@@ -0,0 +1,62 @@
// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package com.intellij.refactoring.inline;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.*;
import com.intellij.psi.util.PsiUtil;
import com.intellij.util.ObjectUtils;
import com.siyeh.ig.callMatcher.CallMapper;
import com.siyeh.ig.callMatcher.CallMatcher;
import java.util.Objects;
import java.util.function.Supplier;
public class InlineMethodSpecialization {
private static final CallMatcher
CLASS_METHODS = CallMatcher.exactInstanceCall(CommonClassNames.JAVA_LANG_CLASS, "getName", "getSimpleName").parameterCount(0);
private static final CallMapper<Supplier<PsiCodeBlock>> SPECIALIZATIONS = new CallMapper<Supplier<PsiCodeBlock>>()
.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;
});
static Supplier<PsiCodeBlock> forReference(PsiReference ref) {
if (!(ref instanceof PsiReferenceExpression)) return null;
PsiMethodCallExpression call = ObjectUtils.tryCast(((PsiReferenceExpression)ref).getParent(), PsiMethodCallExpression.class);
return SPECIALIZATIONS.mapFirst(call);
}
/**
* Replace method body with specialized implementation for some known methods
* @param method method to specialize
* @param ref method call site reference
* @return call-site-specific specialization of method body; or original method if there's no specialization for given method
*/
static PsiMethod specialize(PsiMethod method, PsiReference ref) {
Supplier<PsiCodeBlock> specialization = forReference(ref);
if (specialization == null) return method;
PsiElementFactory factory = JavaPsiFacade.getElementFactory(method.getProject());
String parameters = method.getParameterList().getText();
PsiType returnType = method.getReturnType();
String type = returnType == null ? "" : returnType.getCanonicalText(true);
PsiMethod copy = factory.createMethodFromText(type + " " + method.getName() + parameters + " {}", method);
Objects.requireNonNull(copy.getBody()).replace(specialization.get());
return copy;
}
}

View File

@@ -0,0 +1,9 @@
package foo.bar.baz;
import java.util.*;
class Test {
void test() {
String s = Test.class.get<caret>Name();
}
}

View File

@@ -0,0 +1,7 @@
package foo.bar.baz;
class Test {
void test() {
String s = "foo.bar.baz.Test";
}
}

View File

@@ -483,6 +483,10 @@ public class InlineMethodTest extends LightRefactoringTestCase {
doTest();
}
public void testSpecializeClassGetName() {
doTest();
}
@Override
protected Sdk getProjectJDK() {
return getTestName(false).contains("Src") ? IdeaTestUtil.getMockJdk17() : super.getProjectJDK();