[duplicates] enable duplicates analysis in PyCharm/WebStorm/PhpStorm/RubyMine
[idea/community.git] / java / java-impl / src / com / intellij / refactoring / extractMethodObject / reflect / MethodReferenceReflectionAccessor.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.psi.*;
6 import com.intellij.refactoring.extractMethodObject.ItemToReplaceDescriptor;
7 import com.intellij.refactoring.extractMethodObject.reflect.ConstructorReflectionAccessor.ConstructorDescriptor;
8 import com.intellij.refactoring.util.LambdaRefactoringUtil;
9 import org.jetbrains.annotations.NotNull;
10 import org.jetbrains.annotations.Nullable;
11
12 import static com.intellij.refactoring.extractMethodObject.reflect.ConstructorReflectionAccessor.ConstructorDescriptor.createIfInaccessible;
13
14 /**
15  * @author Vitaliy.Bibaev
16  */
17 public class MethodReferenceReflectionAccessor
18   extends ReferenceReflectionAccessorBase<MethodReferenceReflectionAccessor.MethodReferenceDescriptor> {
19   private static final Logger LOG = Logger.getInstance(MethodReferenceReflectionAccessor.class);
20
21   private final MethodReflectionAccessor myMethodAccessor;
22   private final ConstructorReflectionAccessor myConstructorReflectionAccessor;
23   public MethodReferenceReflectionAccessor(@NotNull PsiClass psiClass,
24                                            @NotNull PsiElementFactory elementFactory) {
25     super(psiClass, elementFactory);
26     myMethodAccessor = new MethodReflectionAccessor(psiClass, elementFactory);
27     myConstructorReflectionAccessor = new ConstructorReflectionAccessor(psiClass, elementFactory);
28   }
29
30   @Nullable
31   @Override
32   protected MethodReferenceDescriptor createDescriptor(@NotNull PsiReferenceExpression expression) {
33     if (expression instanceof PsiMethodReferenceExpression) {
34       PsiElement resolvedElement = expression.resolve();
35       if (resolvedElement instanceof PsiMethod) {
36         PsiMethod method = (PsiMethod)resolvedElement;
37         if (!PsiReflectionAccessUtil.isAccessibleMember(method)) {
38           return new MethodReferenceDescriptor(method, (PsiMethodReferenceExpression)expression);
39         }
40       }
41     }
42
43     return null;
44   }
45
46   @Override
47   protected void grantAccess(@NotNull MethodReferenceDescriptor descriptor) {
48     PsiLambdaExpression lambda = LambdaRefactoringUtil.convertMethodReferenceToLambda(descriptor.expression, false, true);
49     PsiElement lambdaBody = lambda == null ? null : lambda.getBody();
50     if (lambdaBody != null) {
51       if (lambdaBody instanceof PsiNewExpression) {
52         ConstructorDescriptor constructorDescriptor = createIfInaccessible((PsiNewExpression)lambdaBody);
53         if (constructorDescriptor != null) {
54           myConstructorReflectionAccessor.grantAccess(constructorDescriptor);
55         }
56         else {
57           LOG.warn("Inaccessible constructor not found. Method reference: " + descriptor.expression.getText());
58         }
59       }
60       else if (lambdaBody instanceof PsiMethodCallExpression) {
61         PsiMethodCallExpression callExpression = (PsiMethodCallExpression)lambdaBody;
62         PsiMethod method = callExpression.resolveMethod();
63         if (method != null) {
64           myMethodAccessor.grantAccess(new MethodReflectionAccessor.MethodCallDescriptor(callExpression, method));
65         }
66         else {
67           LOG.warn("Could not resolve method from expression: " + callExpression.getText());
68         }
69       }
70       else {
71         LOG.warn("Unexpected type of lambda body: " + lambdaBody.getClass().getCanonicalName());
72       }
73     }
74     else {
75       LOG.warn("Could not replace method reference with lambda: " + descriptor.expression.getText());
76     }
77   }
78
79   public static class MethodReferenceDescriptor implements ItemToReplaceDescriptor {
80     public final PsiMethod method;
81     public final PsiMethodReferenceExpression expression;
82
83     public MethodReferenceDescriptor(@NotNull PsiMethod method, @NotNull PsiMethodReferenceExpression expression) {
84       this.method = method;
85       this.expression = expression;
86     }
87   }
88 }