[jvm] API draft 3 updates
[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     if (modifierListOwner.hasModifierProperty(PsiModifier.PACKAGE_LOCAL)) {
46       result.add(JvmModifier.PACKAGE_LOCAL);
47     }
48     return result;
49   }
50
51   @NotNull
52   public static JvmClassKind getJvmClassKind(@NotNull PsiClass psiClass) {
53     if (psiClass.isAnnotationType()) return JvmClassKind.ANNOTATION;
54     if (psiClass.isInterface()) return JvmClassKind.INTERFACE;
55     if (psiClass.isEnum()) return JvmClassKind.ENUM;
56     return JvmClassKind.CLASS;
57   }
58
59   @Nullable
60   public static JvmClassType getClassSuperType(@NotNull PsiClass psiClass) {
61     // TODO
62     throw new RuntimeException("not implemented");
63   }
64
65   @NotNull
66   public static Iterable<JvmClassType> getClassInterfaces(@NotNull PsiClass psiClass) {
67     // TODO
68     throw new RuntimeException("not implemented");
69   }
70
71   @NotNull
72   public static JvmType getMethodReturnType(@NotNull PsiMethod method) {
73     LOG.assertTrue(!method.isConstructor());
74     final PsiType type = method.getReturnType();
75     LOG.assertTrue(type != null);
76     return toJvmType(type);
77   }
78
79   @NotNull
80   public static Iterable<JvmParameter> getMethodParameters(@NotNull PsiMethod method) {
81     final PsiParameterList parameterList = method.getParameterList();
82     return Arrays.asList(parameterList.getParameters());
83   }
84
85   @NotNull
86   public static Iterable<JvmReferenceType> getMethodThrowsTypes(@NotNull PsiMethod method) {
87     return getReferencedTypes(method.getThrowsList());
88   }
89
90   @NotNull
91   public static Iterable<JvmReferenceType> getTypeParameterBounds(@NotNull PsiTypeParameter typeParameter) {
92     return getReferencedTypes(typeParameter.getExtendsList());
93   }
94
95   private static Iterable<JvmReferenceType> getReferencedTypes(@NotNull PsiReferenceList referenceList) {
96     return ContainerUtil.map(referenceList.getReferencedTypes(), it -> toJvmReferenceType(it));
97   }
98
99   @NotNull
100   public static JvmType toJvmType(@NotNull PsiType type) {
101     if (type instanceof PsiPrimitiveType || type instanceof PsiWildcardType || type instanceof PsiArrayType) {
102       return ((JvmType)type);
103     }
104     else if (type instanceof PsiClassType) {
105       return toJvmReferenceType(((PsiClassType)type));
106     }
107     throw new IllegalArgumentException("Unsupported type: " + type);
108   }
109
110   @NotNull
111   public static JvmReferenceType toJvmReferenceType(@NotNull PsiClassType type) {
112     if (type.hasParameters()) {
113       return new PsiJvmClassType(type);
114     }
115     else {
116       return new PsiJvmReferenceType(type);
117     }
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     @NotNull
129     @Override
130     public String getName() {
131       return myPsiClassType.getClassName();
132     }
133
134     @Nullable
135     @Override
136     public JvmTypeResolveResult resolveType() {
137       PsiClass clazz = myPsiClassType.resolve();
138       return clazz == null ? null : new JvmTypeResolveResult() {
139         @NotNull
140         @Override
141         public JvmTypeDeclarator getDeclarator() {
142           return clazz;
143         }
144       };
145     }
146
147     @NotNull
148     @Override
149     public JvmAnnotation[] getAnnotations() {
150       return myPsiClassType.getAnnotations();
151     }
152   }
153
154   private static class PsiJvmClassType extends PsiJvmReferenceType implements JvmClassType {
155
156     private PsiJvmClassType(@NotNull PsiClassType type) {
157       super(type);
158     }
159
160     @Nullable
161     @Override
162     public JvmGenericResolveResult resolveType() {
163       final ClassResolveResult classResolveResult = myPsiClassType.resolveGenerics();
164       final PsiClass clazz = classResolveResult.getElement();
165       if (clazz == null) return null;
166
167       final PsiSubstitutor substitutor = classResolveResult.getSubstitutor();
168       return new JvmGenericResolveResult() {
169
170         private final JvmSubstitutor mySubstitutor = new PsiJvmSubstitutor(substitutor);
171
172         @NotNull
173         @Override
174         public JvmClass getDeclarator() {
175           return clazz;
176         }
177
178         @NotNull
179         @Override
180         public JvmSubstitutor getSubstitutor() {
181           return mySubstitutor;
182         }
183       };
184     }
185
186     @NotNull
187     @Override
188     public Iterable<JvmType> getTypeArguments() {
189       return ContainerUtil.map(myPsiClassType.getParameters(), it -> toJvmType(it));
190     }
191   }
192
193
194   private static class PsiJvmSubstitutor implements JvmSubstitutor {
195
196     private final @NotNull PsiSubstitutor mySubstitutor;
197
198     private PsiJvmSubstitutor(@NotNull PsiSubstitutor substitutor) {
199       mySubstitutor = substitutor;
200     }
201
202     @Nullable
203     @Override
204     public JvmType substitute(@NotNull JvmTypeParameter typeParameter) {
205       if (!(typeParameter instanceof PsiTypeParameter)) return null;
206       PsiTypeParameter psiTypeParameter = ((PsiTypeParameter)typeParameter);
207       PsiType substituted = mySubstitutor.substitute(psiTypeParameter);
208       return substituted == null ? null : toJvmType(substituted);
209     }
210   }
211 }