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 org.jetbrains.annotations.NotNull;
020 import org.jetbrains.annotations.Nullable;
021 import org.jetbrains.jet.lang.descriptors.ClassDescriptor;
022 import org.jetbrains.jet.lang.descriptors.PropertyDescriptor;
023 import org.jetbrains.jet.lang.descriptors.ValueParameterDescriptor;
024 import org.jetbrains.jet.lang.descriptors.VariableDescriptor;
025 import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor;
026 import org.jetbrains.jet.lang.resolve.constants.*;
027 import org.jetbrains.jet.lang.resolve.constants.StringValue;
028 import org.jetbrains.jet.lang.resolve.java.structure.*;
029 import org.jetbrains.jet.lang.resolve.name.FqName;
030 import org.jetbrains.jet.lang.resolve.name.Name;
031 import org.jetbrains.jet.lang.types.JetType;
032 import org.jetbrains.jet.lang.types.JetTypeImpl;
033 import org.jetbrains.jet.lang.types.TypeProjectionImpl;
034 import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
035
036 import javax.inject.Inject;
037 import java.util.ArrayList;
038 import java.util.Collections;
039 import java.util.List;
040
041 import static org.jetbrains.jet.lang.resolve.DescriptorUtils.getEnumEntriesScope;
042 import static org.jetbrains.jet.lang.resolve.java.DescriptorSearchRule.IGNORE_KOTLIN_SOURCES;
043 import static org.jetbrains.jet.lang.resolve.java.DescriptorSearchRule.INCLUDE_KOTLIN_SOURCES;
044
045 public final class JavaAnnotationArgumentResolver {
046 public static final FqName JL_CLASS_FQ_NAME = new FqName("java.lang.Class");
047
048 private JavaAnnotationResolver annotationResolver;
049 private JavaClassResolver classResolver;
050 private JavaTypeTransformer typeTransformer;
051
052 @Inject
053 public void setAnnotationResolver(JavaAnnotationResolver annotationResolver) {
054 this.annotationResolver = annotationResolver;
055 }
056
057 @Inject
058 public void setClassResolver(JavaClassResolver classResolver) {
059 this.classResolver = classResolver;
060 }
061
062 @Inject
063 public void setTypeTransformer(JavaTypeTransformer typeTransformer) {
064 this.typeTransformer = typeTransformer;
065 }
066
067 @Nullable
068 public CompileTimeConstant<?> resolveAnnotationArgument(
069 @NotNull FqName annotationFqName,
070 @NotNull JavaAnnotationArgument argument,
071 @NotNull PostponedTasks postponedTasks
072 ) {
073 if (argument instanceof JavaLiteralAnnotationArgument) {
074 return resolveCompileTimeConstantValue(((JavaLiteralAnnotationArgument) argument).getValue(), null);
075 }
076 // Enum
077 else if (argument instanceof JavaReferenceAnnotationArgument) {
078 return resolveFromReference(((JavaReferenceAnnotationArgument) argument).resolve(), postponedTasks);
079 }
080 // Array
081 else if (argument instanceof JavaArrayAnnotationArgument) {
082 Name argumentName = argument.getName();
083 return resolveFromArray(
084 annotationFqName,
085 argumentName == null ? JavaAnnotationResolver.DEFAULT_ANNOTATION_MEMBER_NAME : argumentName,
086 ((JavaArrayAnnotationArgument) argument).getElements(),
087 postponedTasks
088 );
089 }
090 // Annotation
091 else if (argument instanceof JavaAnnotationAsAnnotationArgument) {
092 return resolveFromAnnotation(((JavaAnnotationAsAnnotationArgument) argument).getAnnotation(), postponedTasks);
093 }
094 // Class<?>
095 else if (argument instanceof JavaClassObjectAnnotationArgument) {
096 return resolveFromJavaClassObjectType(((JavaClassObjectAnnotationArgument) argument).getReferencedType());
097 }
098
099 return null;
100 }
101
102 @Nullable
103 private CompileTimeConstant<?> resolveFromAnnotation(@NotNull JavaAnnotation value, @NotNull PostponedTasks taskList) {
104 AnnotationDescriptor descriptor = annotationResolver.resolveAnnotation(value, taskList);
105 return descriptor == null ? null : new AnnotationValue(descriptor);
106 }
107
108 @Nullable
109 private CompileTimeConstant<?> resolveFromArray(
110 @NotNull FqName annotationFqName,
111 @NotNull Name argumentName,
112 @NotNull List<JavaAnnotationArgument> elements,
113 @NotNull PostponedTasks taskList
114 ) {
115 ClassDescriptor annotationClass = classResolver.resolveClass(annotationFqName, INCLUDE_KOTLIN_SOURCES, taskList);
116 if (annotationClass == null) return null;
117
118 //TODO: nullability issues
119 ValueParameterDescriptor valueParameter = DescriptorResolverUtils.getAnnotationParameterByName(argumentName, annotationClass);
120 if (valueParameter == null) return null;
121
122 List<CompileTimeConstant<?>> values = new ArrayList<CompileTimeConstant<?>>(elements.size());
123 for (JavaAnnotationArgument argument : elements) {
124 CompileTimeConstant<?> value = resolveAnnotationArgument(annotationFqName, argument, taskList);
125 values.add(value == null ? NullValue.NULL : value);
126 }
127
128 return new ArrayValue(values, valueParameter.getType());
129 }
130
131 @Nullable
132 private CompileTimeConstant<?> resolveFromReference(@Nullable JavaElement element, @NotNull PostponedTasks taskList) {
133 if (!(element instanceof JavaField)) return null;
134
135 JavaField field = (JavaField) element;
136 if (!field.isEnumEntry()) return null;
137
138 FqName fqName = field.getContainingClass().getFqName();
139 if (fqName == null) return null;
140
141 ClassDescriptor enumClass = classResolver.resolveClass(fqName, INCLUDE_KOTLIN_SOURCES, taskList);
142 if (enumClass == null) return null;
143
144 for (VariableDescriptor variableDescriptor : getEnumEntriesScope(enumClass).getProperties(field.getName())) {
145 if (variableDescriptor.getReceiverParameter() == null) {
146 return new EnumValue((PropertyDescriptor) variableDescriptor);
147 }
148 }
149
150 return null;
151 }
152
153 @Nullable
154 private CompileTimeConstant<?> resolveFromJavaClassObjectType(@NotNull JavaType javaType) {
155 JetType type = typeTransformer.transformToType(javaType, TypeVariableResolver.EMPTY);
156
157 ClassDescriptor jlClass = classResolver.resolveClass(JL_CLASS_FQ_NAME, IGNORE_KOTLIN_SOURCES);
158 if (jlClass == null) return null;
159
160 List<TypeProjectionImpl> arguments = Collections.singletonList(new TypeProjectionImpl(type));
161 JetTypeImpl javaClassType = new JetTypeImpl(
162 jlClass.getAnnotations(),
163 jlClass.getTypeConstructor(),
164 false,
165 arguments,
166 jlClass.getMemberScope(arguments)
167 );
168
169 return new JavaClassValue(javaClassType);
170 }
171
172 @Nullable
173 public static CompileTimeConstant<?> resolveCompileTimeConstantValue(@Nullable Object value, @Nullable JetType expectedType) {
174 if (value instanceof String) {
175 return new StringValue((String) value);
176 }
177 else if (value instanceof Byte) {
178 return new ByteValue((Byte) value);
179 }
180 else if (value instanceof Short) {
181 return new ShortValue((Short) value);
182 }
183 else if (value instanceof Character) {
184 return new CharValue((Character) value);
185 }
186 else if (value instanceof Integer) {
187 KotlinBuiltIns builtIns = KotlinBuiltIns.getInstance();
188 Integer integer = (Integer) value;
189 if (builtIns.getShortType().equals(expectedType)) {
190 return new ShortValue(integer.shortValue());
191 }
192 else if (builtIns.getByteType().equals(expectedType)) {
193 return new ByteValue(integer.byteValue());
194 }
195 else if (builtIns.getCharType().equals(expectedType)) {
196 return new CharValue((char) integer.intValue());
197 }
198 return new IntValue(integer);
199 }
200 else if (value instanceof Long) {
201 return new LongValue((Long) value);
202 }
203 else if (value instanceof Float) {
204 return new FloatValue((Float) value);
205 }
206 else if (value instanceof Double) {
207 return new DoubleValue((Double) value);
208 }
209 else if (value instanceof Boolean) {
210 return BooleanValue.valueOf((Boolean) value);
211 }
212 else if (value == null) {
213 return NullValue.NULL;
214 }
215 return null;
216 }
217 }