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.Nullable;
022 import org.jetbrains.jet.lang.descriptors.*;
023 import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor;
024 import org.jetbrains.jet.lang.resolve.constants.*;
025 import org.jetbrains.jet.lang.resolve.constants.StringValue;
026 import org.jetbrains.jet.lang.resolve.java.DescriptorResolverUtils;
027 import org.jetbrains.jet.lang.resolve.java.DescriptorSearchRule;
028 import org.jetbrains.jet.lang.resolve.name.FqName;
029 import org.jetbrains.jet.lang.resolve.name.Name;
030 import org.jetbrains.jet.lang.resolve.scopes.JetScope;
031 import org.jetbrains.jet.lang.types.JetType;
032 import org.jetbrains.jet.lang.types.TypeProjection;
033
034 import javax.inject.Inject;
035 import java.util.ArrayList;
036 import java.util.Collection;
037 import java.util.List;
038
039 public final class JavaCompileTimeConstResolver {
040 private JavaAnnotationResolver annotationResolver;
041 private JavaClassResolver classResolver;
042
043 public JavaCompileTimeConstResolver() {
044 }
045
046 @Inject
047 public void setAnnotationResolver(JavaAnnotationResolver annotationResolver) {
048 this.annotationResolver = annotationResolver;
049 }
050
051 @Inject
052 public void setClassResolver(JavaClassResolver classResolver) {
053 this.classResolver = classResolver;
054 }
055
056 @Nullable
057 public CompileTimeConstant<?> getCompileTimeConstFromExpression(
058 FqName annotationFqName, Name parameterName,
059 PsiAnnotationMemberValue value, PostponedTasks postponedTasks
060 ) {
061 if (value instanceof PsiLiteralExpression) {
062 return getCompileTimeConstFromLiteralExpression((PsiLiteralExpression) value);
063 }
064 // Enum
065 else if (value instanceof PsiReferenceExpression) {
066 return getCompileTimeConstFromReferenceExpression((PsiReferenceExpression) value, postponedTasks);
067 }
068 // Array
069 else if (value instanceof PsiArrayInitializerMemberValue) {
070 return getCompileTimeConstFromArrayExpression(annotationFqName, parameterName, (PsiArrayInitializerMemberValue) value,
071 postponedTasks);
072 }
073 // Annotation
074 else if (value instanceof PsiAnnotation) {
075 return getCompileTimeConstFromAnnotation((PsiAnnotation) value, postponedTasks);
076 }
077 return null;
078 }
079
080 @Nullable
081 private CompileTimeConstant<?> getCompileTimeConstFromAnnotation(PsiAnnotation value, PostponedTasks taskList) {
082 AnnotationDescriptor annotationDescriptor = annotationResolver.resolveAnnotation(value, taskList);
083 if (annotationDescriptor != null) {
084 return new AnnotationValue(annotationDescriptor);
085 }
086 return null;
087 }
088
089 @Nullable
090 private CompileTimeConstant<?> getCompileTimeConstFromArrayExpression(
091 FqName annotationFqName,
092 Name valueName, PsiArrayInitializerMemberValue value,
093 PostponedTasks taskList
094 ) {
095 PsiAnnotationMemberValue[] initializers = value.getInitializers();
096 List<CompileTimeConstant<?>> values = getCompileTimeConstantForArrayValues(annotationFqName, valueName, taskList, initializers);
097
098 ClassDescriptor classDescriptor =
099 classResolver.resolveClass(annotationFqName, DescriptorSearchRule.INCLUDE_KOTLIN, taskList);
100
101 //TODO: nullability issues
102 ValueParameterDescriptor valueParameterDescriptor =
103 DescriptorResolverUtils.getValueParameterDescriptorForAnnotationParameter(valueName, classDescriptor);
104 if (valueParameterDescriptor == null) {
105 return null;
106 }
107 JetType expectedArrayType = valueParameterDescriptor.getType();
108 return new ArrayValue(values, expectedArrayType);
109 }
110
111 private List<CompileTimeConstant<?>> getCompileTimeConstantForArrayValues(
112 FqName annotationQualifiedName,
113 Name valueName,
114 PostponedTasks taskList,
115 PsiAnnotationMemberValue[] initializers
116 ) {
117 List<CompileTimeConstant<?>> values = new ArrayList<CompileTimeConstant<?>>();
118 for (PsiAnnotationMemberValue initializer : initializers) {
119 CompileTimeConstant<?> compileTimeConstant =
120 getCompileTimeConstFromExpression(annotationQualifiedName, valueName, initializer, taskList);
121 if (compileTimeConstant == null) {
122 compileTimeConstant = NullValue.NULL;
123 }
124 values.add(compileTimeConstant);
125 }
126 return values;
127 }
128
129 @Nullable
130 private CompileTimeConstant<?> getCompileTimeConstFromReferenceExpression(PsiReferenceExpression value, PostponedTasks taskList) {
131 PsiElement resolveElement = value.resolve();
132 if (resolveElement instanceof PsiEnumConstant) {
133 PsiElement psiElement = resolveElement.getParent();
134 if (psiElement instanceof PsiClass) {
135 PsiClass psiClass = (PsiClass) psiElement;
136 String fqName = psiClass.getQualifiedName();
137 if (fqName == null) {
138 return null;
139 }
140
141 JetScope scope;
142 ClassDescriptor classDescriptor = classResolver.resolveClass(new FqName(fqName), DescriptorSearchRule.INCLUDE_KOTLIN, taskList);
143 if (classDescriptor == null) {
144 return null;
145 }
146 ClassDescriptor classObjectDescriptor = classDescriptor.getClassObjectDescriptor();
147 if (classObjectDescriptor == null) {
148 return null;
149 }
150 scope = classObjectDescriptor.getMemberScope(Lists.<TypeProjection>newArrayList());
151
152 Name identifier = Name.identifier(((PsiEnumConstant) resolveElement).getName());
153 Collection<VariableDescriptor> properties = scope.getProperties(identifier);
154 for (VariableDescriptor variableDescriptor : properties) {
155 if (variableDescriptor.getReceiverParameter() == null) {
156 return new EnumValue((PropertyDescriptor) variableDescriptor);
157 }
158 }
159 return null;
160 }
161 }
162 return null;
163 }
164
165 @Nullable
166 private static CompileTimeConstant<?> getCompileTimeConstFromLiteralExpression(PsiLiteralExpression value) {
167 Object literalValue = value.getValue();
168 if (literalValue instanceof String) {
169 return new StringValue((String) literalValue);
170 }
171 else if (literalValue instanceof Byte) {
172 return new ByteValue((Byte) literalValue);
173 }
174 else if (literalValue instanceof Short) {
175 return new ShortValue((Short) literalValue);
176 }
177 else if (literalValue instanceof Character) {
178 return new CharValue((Character) literalValue);
179 }
180 else if (literalValue instanceof Integer) {
181 return new IntValue((Integer) literalValue);
182 }
183 else if (literalValue instanceof Long) {
184 return new LongValue((Long) literalValue);
185 }
186 else if (literalValue instanceof Float) {
187 return new FloatValue((Float) literalValue);
188 }
189 else if (literalValue instanceof Double) {
190 return new DoubleValue((Double) literalValue);
191 }
192 else if (literalValue == null) {
193 return NullValue.NULL;
194 }
195 return null;
196 }
197 }