[duplicates] enable duplicates analysis in PyCharm/WebStorm/PhpStorm/RubyMine
[idea/community.git] / java / java-impl / src / com / intellij / refactoring / inline / InlineMethodSpecialization.java
1 // 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.
2 package com.intellij.refactoring.inline;
3
4 import com.intellij.openapi.util.text.StringUtil;
5 import com.intellij.psi.*;
6 import com.intellij.psi.util.PsiUtil;
7 import com.intellij.util.ObjectUtils;
8 import com.siyeh.ig.callMatcher.CallMapper;
9 import com.siyeh.ig.callMatcher.CallMatcher;
10
11 import java.util.Objects;
12 import java.util.function.Supplier;
13
14 public class InlineMethodSpecialization {
15   private static final CallMatcher
16     CLASS_METHODS = CallMatcher.exactInstanceCall(CommonClassNames.JAVA_LANG_CLASS, "getName", "getSimpleName").parameterCount(0);
17
18   private static final CallMapper<Supplier<PsiCodeBlock>> SPECIALIZATIONS = new CallMapper<Supplier<PsiCodeBlock>>()
19     .register(CLASS_METHODS, (PsiMethodCallExpression call) -> {
20       PsiReferenceExpression ref = call.getMethodExpression();
21       PsiExpression qualifier = ref.getQualifierExpression();
22       PsiClassObjectAccessExpression receiver =
23         ObjectUtils.tryCast(PsiUtil.skipParenthesizedExprDown(qualifier), PsiClassObjectAccessExpression.class);
24       if (receiver != null) {
25         PsiClass psiClass = PsiUtil.resolveClassInClassTypeOnly(receiver.getOperand().getType());
26         if (psiClass != null) {
27           String name = "getSimpleName".equals(ref.getReferenceName()) ? psiClass.getName() : psiClass.getQualifiedName();
28           if (name != null) {
29             return () -> {
30               PsiElementFactory factory = JavaPsiFacade.getElementFactory(call.getProject());
31               return factory.createCodeBlockFromText("{return \"" + StringUtil.escapeStringCharacters(name) + "\";}", call);
32             };
33           }
34         }
35       }
36       return null;
37     });
38
39   static Supplier<PsiCodeBlock> forReference(PsiReference ref) {
40     if (!(ref instanceof PsiReferenceExpression)) return null;
41     PsiMethodCallExpression call = ObjectUtils.tryCast(((PsiReferenceExpression)ref).getParent(), PsiMethodCallExpression.class);
42     return SPECIALIZATIONS.mapFirst(call);
43   }
44
45   /**
46    * Replace method body with specialized implementation for some known methods
47    * @param method method to specialize
48    * @param ref method call site reference
49    * @return call-site-specific specialization of method body; or original method if there's no specialization for given method
50    */
51   static PsiMethod specialize(PsiMethod method, PsiReference ref) {
52     Supplier<PsiCodeBlock> specialization = forReference(ref);
53     if (specialization == null) return method;
54     PsiElementFactory factory = JavaPsiFacade.getElementFactory(method.getProject());
55     String parameters = method.getParameterList().getText();
56     PsiType returnType = method.getReturnType();
57     String type = returnType == null ? "" : returnType.getCanonicalText(true);
58     PsiMethod copy = factory.createMethodFromText(type + " " + method.getName() + parameters + " {}", method);
59     Objects.requireNonNull(copy.getBody()).replace(specialization.get());
60     return copy;
61   }
62 }