756cbad9731de7e41f4f6da7314c420199b3c298
[idea/community.git] / java / java-psi-api / src / com / intellij / psi / PsiJvmConversionHelper.java
1 /*
2  * Copyright 2000-2017 JetBrains s.r.o.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package com.intellij.psi;
17
18 import com.intellij.lang.jvm.*;
19 import com.intellij.lang.jvm.types.*;
20 import com.intellij.openapi.diagnostic.Logger;
21 import com.intellij.psi.PsiClassType.ClassResolveResult;
22 import com.intellij.util.containers.ContainerUtil;
23 import org.jetbrains.annotations.NonNls;
24 import org.jetbrains.annotations.NotNull;
25 import org.jetbrains.annotations.Nullable;
26
27 import java.util.Arrays;
28 import java.util.EnumSet;
29 import java.util.Set;
30
31 public class PsiJvmConversionHelper {
32
33   private static final Logger LOG = Logger.getInstance(PsiJvmConversionHelper.class);
34
35   @NotNull
36   public static Iterable<JvmModifier> getModifiers(@NotNull PsiModifierListOwner modifierListOwner) {
37     final Set<JvmModifier> result = EnumSet.noneOf(JvmModifier.class);
38     for (@NonNls String modifier : PsiModifier.MODIFIERS) {
39       if (modifierListOwner.hasModifierProperty(modifier)) {
40         String jvmName = modifier.toUpperCase();
41         JvmModifier jvmModifier = JvmModifier.valueOf(jvmName);
42         result.add(jvmModifier);
43       }
44     }
45     return result;
46   }
47
48   @NotNull
49   public static JvmClassKind getJvmClassKind(@NotNull PsiClass psiClass) {
50     if (psiClass.isAnnotationType()) return JvmClassKind.ANNOTATION;
51     if (psiClass.isInterface()) return JvmClassKind.INTERFACE;
52     if (psiClass.isEnum()) return JvmClassKind.ENUM;
53     return JvmClassKind.CLASS;
54   }
55
56   @Nullable
57   public static JvmClassType getClassSuperType(@NotNull PsiClass psiClass) {
58     throw new RuntimeException("not implemented");
59   }
60
61   @NotNull
62   public static Iterable<JvmClassType> getClassInterfaces(@NotNull PsiClass psiClass) {
63     throw new RuntimeException("not implemented");
64   }
65
66   @NotNull
67   public static JvmType getMethodReturnType(@NotNull PsiMethod method) {
68     LOG.assertTrue(!method.isConstructor());
69     final PsiType type = method.getReturnType();
70     LOG.assertTrue(type != null);
71     return toJvmType(type);
72   }
73
74   @NotNull
75   public static Iterable<JvmParameter> getMethodParameters(@NotNull PsiMethod method) {
76     final PsiParameterList parameterList = method.getParameterList();
77     return Arrays.asList(parameterList.getParameters());
78   }
79
80   @NotNull
81   public static Iterable<JvmReferenceType> getMethodThrowsTypes(@NotNull PsiMethod method) {
82     return getReferencedTypes(method.getThrowsList());
83   }
84
85   @NotNull
86   public static Iterable<JvmReferenceType> getTypeParameterBounds(@NotNull PsiTypeParameter typeParameter) {
87     return getReferencedTypes(typeParameter.getExtendsList());
88   }
89
90   private static Iterable<JvmReferenceType> getReferencedTypes(@NotNull PsiReferenceList referenceList) {
91     return ContainerUtil.map(referenceList.getReferencedTypes(), it -> toJvmReferenceType(it));
92   }
93
94   @NotNull
95   public static JvmType toJvmType(@NotNull PsiType type) {
96     if (type instanceof PsiPrimitiveType || type instanceof PsiWildcardType || type instanceof PsiArrayType) {
97       return ((JvmType)type);
98     }
99     else if (type instanceof PsiClassType) {
100       return toJvmReferenceType(((PsiClassType)type));
101     }
102     throw new IllegalArgumentException("Unsupported type: " + type);
103   }
104
105   @NotNull
106   public static JvmReferenceType toJvmReferenceType(@NotNull PsiClassType type) {
107     if (type.hasParameters()) {
108       return new PsiJvmClassType(type);
109     }
110     else {
111       return new PsiJvmReferenceType(type);
112     }
113   }
114
115   @Nullable
116   public static JvmReferenceType toJvmReferenceTypeOrNull(@Nullable PsiType type) {
117     return type instanceof PsiClassType ? toJvmReferenceType(((PsiClassType)type)) : null;
118   }
119
120   private static class PsiJvmReferenceType implements JvmReferenceType {
121
122     protected final @NotNull PsiClassType myPsiClassType;
123
124     private PsiJvmReferenceType(@NotNull PsiClassType type) {
125       myPsiClassType = type;
126     }
127
128     @Nullable
129     @Override
130     public JvmTypeResolveResult resolveType() {
131       PsiClass clazz = myPsiClassType.resolve();
132       return clazz == null ? null : new JvmTypeResolveResult() {
133         @NotNull
134         @Override
135         public JvmTypeDeclarator getDeclarator() {
136           return clazz;
137         }
138       };
139     }
140
141     @NotNull
142     @Override
143     public JvmAnnotation[] getAnnotations() {
144       return myPsiClassType.getAnnotations();
145     }
146   }
147
148   private static class PsiJvmClassType extends PsiJvmReferenceType implements JvmClassType {
149
150     private PsiJvmClassType(@NotNull PsiClassType type) {
151       super(type);
152     }
153
154     @Nullable
155     @Override
156     public JvmGenericResolveResult resolveType() {
157       final ClassResolveResult classResolveResult = myPsiClassType.resolveGenerics();
158       final PsiClass clazz = classResolveResult.getElement();
159       if (clazz == null) return null;
160
161       final PsiSubstitutor substitutor = classResolveResult.getSubstitutor();
162       return new JvmGenericResolveResult() {
163
164         private final JvmSubstitutor mySubstitutor = new PsiJvmSubstitutor(substitutor);
165
166         @NotNull
167         @Override
168         public JvmClass getDeclarator() {
169           return clazz;
170         }
171
172         @NotNull
173         @Override
174         public JvmSubstitutor getSubstitutor() {
175           return mySubstitutor;
176         }
177       };
178     }
179
180     @NotNull
181     @Override
182     public Iterable<JvmType> getTypeArguments() {
183       return ContainerUtil.map(myPsiClassType.getParameters(), it -> toJvmType(it));
184     }
185   }
186
187
188   private static class PsiJvmSubstitutor implements JvmSubstitutor {
189
190     private final @NotNull PsiSubstitutor mySubstitutor;
191
192     private PsiJvmSubstitutor(@NotNull PsiSubstitutor substitutor) {
193       mySubstitutor = substitutor;
194     }
195
196     @Nullable
197     @Override
198     public JvmType substitute(@NotNull JvmTypeParameter typeParameter) {
199       if (!(typeParameter instanceof PsiTypeParameter)) return null;
200       PsiTypeParameter psiTypeParameter = ((PsiTypeParameter)typeParameter);
201       PsiType substituted = mySubstitutor.substitute(psiTypeParameter);
202       return substituted == null ? null : toJvmType(substituted);
203     }
204   }
205 }