Cleanup: NotNull/Nullable
[idea/community.git] / java / java-psi-impl / src / com / intellij / psi / impl / source / resolve / graphInference / PsiGraphInferenceHelper.java
1 // Copyright 2000-2017 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.psi.impl.source.resolve.graphInference;
3
4 import com.intellij.pom.java.LanguageLevel;
5 import com.intellij.psi.*;
6 import com.intellij.psi.impl.source.resolve.ParameterTypeInferencePolicy;
7 import com.intellij.psi.util.PsiUtil;
8 import org.jetbrains.annotations.NotNull;
9 import org.jetbrains.annotations.Nullable;
10
11 public class PsiGraphInferenceHelper implements PsiInferenceHelper {
12   private final PsiManager myManager;
13
14   public PsiGraphInferenceHelper(PsiManager manager) {
15     myManager = manager;
16   }
17
18   @Override
19   public PsiType inferTypeForMethodTypeParameter(@NotNull PsiTypeParameter typeParameter,
20                                                  @NotNull PsiParameter[] parameters,
21                                                  @NotNull PsiExpression[] arguments,
22                                                  @NotNull PsiSubstitutor partialSubstitutor,
23                                                  @Nullable PsiElement parent,
24                                                  @NotNull ParameterTypeInferencePolicy policy) {
25     final PsiSubstitutor substitutor;
26     if (parent != null) {
27       substitutor = inferTypeArguments(new PsiTypeParameter[]{typeParameter}, 
28                                        parameters, 
29                                        arguments, 
30                                        partialSubstitutor, 
31                                        parent, 
32                                        policy, 
33                                        PsiUtil.getLanguageLevel(parent));
34     }
35     else {
36       final InferenceSession inferenceSession = new InferenceSession(new PsiTypeParameter[]{typeParameter}, partialSubstitutor, myManager, null);
37       inferenceSession.initExpressionConstraints(parameters, arguments, null);
38       substitutor = inferenceSession.infer();
39     }
40     return substitutor.substitute(typeParameter);
41   }
42
43   @NotNull
44   @Override
45   public PsiSubstitutor inferTypeArguments(@NotNull PsiTypeParameter[] typeParameters,
46                                            @NotNull PsiParameter[] parameters,
47                                            @NotNull PsiExpression[] arguments,
48                                            @NotNull PsiSubstitutor partialSubstitutor,
49                                            @NotNull PsiElement parent,
50                                            @NotNull ParameterTypeInferencePolicy policy,
51                                            @NotNull LanguageLevel languageLevel) {
52     if (typeParameters.length == 0) return partialSubstitutor;
53
54     return InferenceSessionContainer.infer(typeParameters, parameters, arguments, partialSubstitutor, parent, policy);
55   }
56
57   @NotNull
58   @Override
59   public PsiSubstitutor inferTypeArguments(@NotNull PsiTypeParameter[] typeParameters,
60                                            @NotNull PsiType[] leftTypes,
61                                            @NotNull PsiType[] rightTypes,
62                                            @NotNull LanguageLevel languageLevel) {
63     return inferTypeArguments(typeParameters, leftTypes, rightTypes, PsiSubstitutor.EMPTY, languageLevel);
64   }
65
66   @NotNull
67   @Override
68   public PsiSubstitutor inferTypeArguments(@NotNull PsiTypeParameter[] typeParameters,
69                                            @NotNull PsiType[] leftTypes,
70                                            @NotNull PsiType[] rightTypes,
71                                            @NotNull PsiSubstitutor partialSubstitutor,
72                                            @NotNull LanguageLevel languageLevel) {
73     if (typeParameters.length == 0) return PsiSubstitutor.EMPTY;
74     InferenceSession session = new InferenceSession(typeParameters, leftTypes, rightTypes, partialSubstitutor, myManager, null);
75     for (PsiType leftType : leftTypes) {
76       if (!session.isProperType(session.substituteWithInferenceVariables(leftType))) {
77         return session.infer();
78       }
79     }
80     for (PsiType rightType : rightTypes) {
81       if (!session.isProperType(session.substituteWithInferenceVariables(rightType))) {
82         return session.infer();
83       }
84     }
85     return PsiSubstitutor.EMPTY;
86   }
87
88   @Override
89   public PsiType getSubstitutionForTypeParameter(PsiTypeParameter typeParam,
90                                                  PsiType param,
91                                                  PsiType arg,
92                                                  boolean isContraVariantPosition,
93                                                  LanguageLevel languageLevel) {
94     if (PsiType.VOID.equals(arg) || PsiType.VOID.equals(param)) return PsiType.NULL;
95     if (param instanceof PsiArrayType && arg instanceof PsiArrayType) {
96       return getSubstitutionForTypeParameter(typeParam, ((PsiArrayType)param).getComponentType(), ((PsiArrayType)arg).getComponentType(), isContraVariantPosition, languageLevel);
97     } 
98
99     if (!(param instanceof PsiClassType)) return PsiType.NULL;
100     if (arg == null) {
101       return PsiType.NULL;
102     }
103     final PsiType[] leftTypes;
104     final PsiType[] rightTypes;
105     if (isContraVariantPosition) {
106       leftTypes = new PsiType[] {param};
107       rightTypes = new PsiType[]{arg};
108     }
109     else {
110       leftTypes = new PsiType[] {arg};
111       rightTypes = new PsiType[]{param};
112     }
113     final PsiTypeParameterListOwner owner = typeParam.getOwner();
114     final PsiTypeParameter[] typeParams = owner != null ? owner.getTypeParameters() : new PsiTypeParameter[] {typeParam};
115     final InferenceSession inferenceSession = new InferenceSession(typeParams, leftTypes, rightTypes, PsiSubstitutor.EMPTY, myManager, null);
116     if (inferenceSession.isProperType(inferenceSession.substituteWithInferenceVariables(param)) &&
117         inferenceSession.isProperType(inferenceSession.substituteWithInferenceVariables(arg))) {
118       boolean proceed = false;
119       for (PsiClassType classType : typeParam.getExtendsListTypes()) {
120         if (!inferenceSession.isProperType(inferenceSession.substituteWithInferenceVariables(classType))) {
121           proceed = true;
122           break;
123         }
124       }
125       if (!proceed) {
126         return PsiType.NULL;
127       }
128     }
129     final PsiSubstitutor substitutor = inferenceSession.infer();
130     return substitutor.substitute(typeParam);
131   }
132 }