001 /*
002 * Copyright 2010-2013 JetBrains s.r.o.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 * http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016
017 package org.jetbrains.jet.lang.resolve.java.resolver;
018
019 import com.google.common.collect.Lists;
020 import com.intellij.psi.*;
021 import org.jetbrains.annotations.NotNull;
022 import org.jetbrains.annotations.Nullable;
023 import org.jetbrains.jet.lang.descriptors.*;
024 import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor;
025 import org.jetbrains.jet.lang.resolve.constants.*;
026 import org.jetbrains.jet.lang.resolve.constants.StringValue;
027 import org.jetbrains.jet.lang.resolve.java.DescriptorResolverUtils;
028 import org.jetbrains.jet.lang.resolve.java.DescriptorSearchRule;
029 import org.jetbrains.jet.lang.resolve.name.FqName;
030 import org.jetbrains.jet.lang.resolve.name.Name;
031 import org.jetbrains.jet.lang.resolve.scopes.JetScope;
032 import org.jetbrains.jet.lang.types.JetType;
033 import org.jetbrains.jet.lang.types.TypeProjection;
034 import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
035
036 import javax.inject.Inject;
037 import java.util.ArrayList;
038 import java.util.Collection;
039 import java.util.List;
040
041 public final class JavaCompileTimeConstResolver {
042 private JavaAnnotationResolver annotationResolver;
043 private JavaClassResolver classResolver;
044
045 public JavaCompileTimeConstResolver() {
046 }
047
048 @Inject
049 public void setAnnotationResolver(JavaAnnotationResolver annotationResolver) {
050 this.annotationResolver = annotationResolver;
051 }
052
053 @Inject
054 public void setClassResolver(JavaClassResolver classResolver) {
055 this.classResolver = classResolver;
056 }
057
058 @Nullable
059 public CompileTimeConstant<?> getCompileTimeConstFromExpression(
060 FqName annotationFqName, Name parameterName,
061 PsiAnnotationMemberValue value, PostponedTasks postponedTasks
062 ) {
063 if (value instanceof PsiLiteralExpression) {
064 return getCompileTimeConstFromLiteralExpression((PsiLiteralExpression) value);
065 }
066 // Enum
067 else if (value instanceof PsiReferenceExpression) {
068 return getCompileTimeConstFromReferenceExpression((PsiReferenceExpression) value, postponedTasks);
069 }
070 // Array
071 else if (value instanceof PsiArrayInitializerMemberValue) {
072 return getCompileTimeConstFromArrayExpression(annotationFqName, parameterName, (PsiArrayInitializerMemberValue) value,
073 postponedTasks);
074 }
075 // Annotation
076 else if (value instanceof PsiAnnotation) {
077 return getCompileTimeConstFromAnnotation((PsiAnnotation) value, postponedTasks);
078 }
079 return null;
080 }
081
082 @Nullable
083 private CompileTimeConstant<?> getCompileTimeConstFromAnnotation(PsiAnnotation value, PostponedTasks taskList) {
084 AnnotationDescriptor annotationDescriptor = annotationResolver.resolveAnnotation(value, taskList);
085 if (annotationDescriptor != null) {
086 return new AnnotationValue(annotationDescriptor);
087 }
088 return null;
089 }
090
091 @Nullable
092 private CompileTimeConstant<?> getCompileTimeConstFromArrayExpression(
093 FqName annotationFqName,
094 Name valueName, PsiArrayInitializerMemberValue value,
095 PostponedTasks taskList
096 ) {
097 PsiAnnotationMemberValue[] initializers = value.getInitializers();
098 List<CompileTimeConstant<?>> values = getCompileTimeConstantForArrayValues(annotationFqName, valueName, taskList, initializers);
099
100 ClassDescriptor classDescriptor =
101 classResolver.resolveClass(annotationFqName, DescriptorSearchRule.INCLUDE_KOTLIN, taskList);
102
103 //TODO: nullability issues
104 ValueParameterDescriptor valueParameterDescriptor =
105 DescriptorResolverUtils.getValueParameterDescriptorForAnnotationParameter(valueName, classDescriptor);
106 if (valueParameterDescriptor == null) {
107 return null;
108 }
109 JetType expectedArrayType = valueParameterDescriptor.getType();
110 return new ArrayValue(values, expectedArrayType);
111 }
112
113 private List<CompileTimeConstant<?>> getCompileTimeConstantForArrayValues(
114 FqName annotationQualifiedName,
115 Name valueName,
116 PostponedTasks taskList,
117 PsiAnnotationMemberValue[] initializers
118 ) {
119 List<CompileTimeConstant<?>> values = new ArrayList<CompileTimeConstant<?>>();
120 for (PsiAnnotationMemberValue initializer : initializers) {
121 CompileTimeConstant<?> compileTimeConstant =
122 getCompileTimeConstFromExpression(annotationQualifiedName, valueName, initializer, taskList);
123 if (compileTimeConstant == null) {
124 compileTimeConstant = NullValue.NULL;
125 }
126 values.add(compileTimeConstant);
127 }
128 return values;
129 }
130
131 @Nullable
132 private CompileTimeConstant<?> getCompileTimeConstFromReferenceExpression(PsiReferenceExpression value, PostponedTasks taskList) {
133 PsiElement resolveElement = value.resolve();
134 if (resolveElement instanceof PsiEnumConstant) {
135 PsiElement psiElement = resolveElement.getParent();
136 if (psiElement instanceof PsiClass) {
137 PsiClass psiClass = (PsiClass) psiElement;
138 String fqName = psiClass.getQualifiedName();
139 if (fqName == null) {
140 return null;
141 }
142
143 JetScope scope;
144 ClassDescriptor classDescriptor = classResolver.resolveClass(new FqName(fqName), DescriptorSearchRule.INCLUDE_KOTLIN, taskList);
145 if (classDescriptor == null) {
146 return null;
147 }
148 ClassDescriptor classObjectDescriptor = classDescriptor.getClassObjectDescriptor();
149 if (classObjectDescriptor == null) {
150 return null;
151 }
152 scope = classObjectDescriptor.getMemberScope(Lists.<TypeProjection>newArrayList());
153
154 Name identifier = Name.identifier(((PsiEnumConstant) resolveElement).getName());
155 Collection<VariableDescriptor> properties = scope.getProperties(identifier);
156 for (VariableDescriptor variableDescriptor : properties) {
157 if (variableDescriptor.getReceiverParameter() == null) {
158 return new EnumValue((PropertyDescriptor) variableDescriptor);
159 }
160 }
161 return null;
162 }
163 }
164 return null;
165 }
166
167 @Nullable
168 private static CompileTimeConstant<?> getCompileTimeConstFromLiteralExpression(PsiLiteralExpression value) {
169 return getCompileTimeConstFromLiteralExpressionWithExpectedType(value, null);
170 }
171
172 @Nullable
173 public static CompileTimeConstant<?> getCompileTimeConstFromLiteralExpressionWithExpectedType(
174 @NotNull PsiLiteralExpression value,
175 @Nullable JetType expectedType
176 ) {
177 Object literalValue = value.getValue();
178 if (literalValue instanceof String) {
179 return new StringValue((String) literalValue);
180 }
181 else if (literalValue instanceof Byte) {
182 return new ByteValue((Byte) literalValue);
183 }
184 else if (literalValue instanceof Short) {
185 return new ShortValue((Short) literalValue);
186 }
187 else if (literalValue instanceof Character) {
188 return new CharValue((Character) literalValue);
189 }
190 else if (literalValue instanceof Integer) {
191 KotlinBuiltIns builtIns = KotlinBuiltIns.getInstance();
192 if (builtIns.getShortType().equals(expectedType)) {
193 return new ShortValue(((Integer) literalValue).shortValue());
194 }
195 else if (builtIns.getByteType().equals(expectedType)) {
196 return new ByteValue(((Integer) literalValue).byteValue());
197 }
198 else if (builtIns.getCharType().equals(expectedType)) {
199 return new CharValue((char) ((Integer)literalValue).intValue());
200 }
201 return new IntValue((Integer) literalValue);
202 }
203 else if (literalValue instanceof Long) {
204 return new LongValue((Long) literalValue);
205 }
206 else if (literalValue instanceof Float) {
207 return new FloatValue((Float) literalValue);
208 }
209 else if (literalValue instanceof Double) {
210 return new DoubleValue((Double) literalValue);
211 }
212 else if (literalValue instanceof Boolean) {
213 return ((Boolean) literalValue) ? BooleanValue.TRUE : BooleanValue.FALSE;
214 }
215 else if (literalValue == null) {
216 return NullValue.NULL;
217 }
218 return null;
219 }
220 }