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