get rid of intellij.build.toolbox.litegen parameter and use BuildOptions.TOOLBOX_LITE...
[idea/community.git] / java / java-impl / src / com / intellij / refactoring / extractMethodObject / reflect / MethodDescriptor.java
1 // Copyright 2000-2018 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.extractMethodObject.reflect;
3
4 import com.intellij.openapi.diagnostic.Logger;
5 import com.intellij.openapi.util.text.StringUtil;
6 import com.intellij.psi.*;
7 import com.intellij.psi.util.ClassUtil;
8 import com.intellij.refactoring.extractMethodObject.ItemToReplaceDescriptor;
9 import one.util.streamex.StreamEx;
10 import org.jetbrains.annotations.NotNull;
11 import org.jetbrains.annotations.Nullable;
12
13 import java.util.Objects;
14
15 /**
16  * @author Vitaliy.Bibaev
17  */
18 public class MethodDescriptor implements ItemToReplaceDescriptor {
19   private static final Logger LOG = Logger.getInstance(MethodDescriptor.class);
20
21   private final PsiMethodCallExpression myCallExpression;
22   private final PsiMethod myMethod;
23   private final String myAccessibleReturnType;
24
25   public MethodDescriptor(@NotNull PsiMethodCallExpression expression, @NotNull PsiMethod method) {
26     myCallExpression = expression;
27     myMethod = method;
28     String returnType = PsiReflectionAccessUtil.getAccessibleReturnType(myCallExpression, resolveMethodReturnType(expression, method));
29     if (returnType == null) {
30       LOG.warn("Could not resolve method return type. java.lang.Object will be used instead");
31       returnType = "java.lang.Object";
32     }
33     myAccessibleReturnType = returnType;
34   }
35
36   public static MethodDescriptor createIfInaccessible(@NotNull PsiClass outerClass, @NotNull PsiMethodCallExpression expression) {
37     PsiMethod method = expression.resolveMethod();
38     if (method != null && !Objects.equals(method.getContainingClass(), outerClass)) {
39       return needReplace(method, expression) ? new MethodDescriptor(expression, method) : null;
40     }
41
42     return null;
43   }
44
45   @Override
46   public void replace(@NotNull PsiClass outerClass,
47                       @NotNull PsiElementFactory elementFactory,
48                       @NotNull PsiMethodCallExpression callExpression) {
49     PsiClass containingClass = myMethod.getContainingClass();
50     String containingClassName = containingClass == null ? null : ClassUtil.getJVMClassName(containingClass);
51     String name = myMethod.getName();
52
53     if (containingClassName == null) {
54       LOG.warn("containing class for method \"" + name + "\" not found");
55       return;
56     }
57
58     String newMethodName = PsiReflectionAccessUtil.getUniqueMethodName(outerClass, "call" + StringUtil.capitalize(name));
59     ReflectionAccessMethodBuilder methodBuilder = new ReflectionAccessMethodBuilder(newMethodName);
60     PsiMethod newMethod = methodBuilder.accessedMethod(containingClassName, myMethod.getName())
61       .setStatic(outerClass.hasModifierProperty(PsiModifier.STATIC))
62       .addParameter("java.lang.Object", "object")
63       .addParameters(myMethod.getParameterList())
64       .setReturnType(myAccessibleReturnType)
65       .build(elementFactory, outerClass);
66
67     outerClass.add(newMethod);
68     String objectToCallOn = MemberQualifierUtil
69       .findObjectExpression(myCallExpression.getMethodExpression(), myMethod, outerClass, callExpression, elementFactory);
70     String args = StreamEx.of(myCallExpression.getArgumentList().getExpressions())
71       .map(x -> x.getText())
72       .prepend(objectToCallOn == null ? "null" : objectToCallOn)
73       .joining(", ", "(", ")");
74     String newMethodCallExpression = newMethod.getName() + args;
75
76     myCallExpression.replace(elementFactory.createExpressionFromText(newMethodCallExpression, myCallExpression));
77   }
78
79   private static boolean needReplace(@NotNull PsiMethod method, @NotNull PsiMethodCallExpression referenceExpression) {
80     return !PsiReflectionAccessUtil.isAccessibleMember(method) ||
81            !PsiReflectionAccessUtil.isQualifierAccessible(referenceExpression.getMethodExpression().getQualifierExpression());
82   }
83
84   @Nullable
85   private static PsiType resolveMethodReturnType(@NotNull PsiMethodCallExpression callExpression, @NotNull PsiMethod method) {
86     PsiSubstitutor substitutor = callExpression.resolveMethodGenerics().getSubstitutor();
87     return substitutor.substitute(method.getReturnType());
88   }
89 }