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.codegen;
018
019 import com.intellij.psi.PsiElement;
020 import org.jetbrains.annotations.NotNull;
021 import org.jetbrains.annotations.Nullable;
022 import org.jetbrains.asm4.*;
023 import org.jetbrains.jet.codegen.state.JetTypeMapper;
024 import org.jetbrains.jet.lang.descriptors.*;
025 import org.jetbrains.jet.lang.descriptors.annotations.Annotated;
026 import org.jetbrains.jet.lang.descriptors.annotations.AnnotationArgumentVisitor;
027 import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor;
028 import org.jetbrains.jet.lang.psi.JetAnnotationEntry;
029 import org.jetbrains.jet.lang.psi.JetClass;
030 import org.jetbrains.jet.lang.psi.JetModifierList;
031 import org.jetbrains.jet.lang.psi.JetModifierListOwner;
032 import org.jetbrains.jet.lang.resolve.BindingContext;
033 import org.jetbrains.jet.lang.resolve.DescriptorUtils;
034 import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCall;
035 import org.jetbrains.jet.lang.resolve.constants.*;
036 import org.jetbrains.jet.lang.resolve.constants.StringValue;
037 import org.jetbrains.jet.lang.resolve.name.FqName;
038 import org.jetbrains.jet.lang.types.JetType;
039 import org.jetbrains.jet.lang.types.TypeUtils;
040 import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
041
042 import java.lang.annotation.Retention;
043 import java.lang.annotation.RetentionPolicy;
044 import java.util.*;
045
046 import static org.jetbrains.jet.lang.resolve.BindingContextUtils.descriptorToDeclaration;
047
048 public abstract class AnnotationCodegen {
049 public static final FqName VOLATILE_FQ_NAME = new FqName("kotlin.volatile");
050
051 private static final AnnotationVisitor NO_ANNOTATION_VISITOR = new AnnotationVisitor(Opcodes.ASM4) {};
052
053 private final JetTypeMapper typeMapper;
054 private final BindingContext bindingContext;
055
056 private AnnotationCodegen(JetTypeMapper mapper) {
057 typeMapper = mapper;
058 bindingContext = typeMapper.getBindingContext();
059 }
060
061 public void genAnnotations(Annotated annotated) {
062 if (annotated == null) {
063 return;
064 }
065
066 if (!(annotated instanceof DeclarationDescriptor)) {
067 return;
068 }
069
070 PsiElement psiElement = descriptorToDeclaration(bindingContext, (DeclarationDescriptor) annotated);
071
072 JetModifierList modifierList = null;
073 if (annotated instanceof ConstructorDescriptor && psiElement instanceof JetClass) {
074 modifierList = ((JetClass) psiElement).getPrimaryConstructorModifierList();
075 }
076 else if (psiElement instanceof JetModifierListOwner) {
077 modifierList = ((JetModifierListOwner) psiElement).getModifierList();
078 }
079
080 if (modifierList == null) {
081 generateAdditionalAnnotations(annotated, Collections.<String>emptySet());
082 return;
083 }
084
085 Set<String> annotationDescriptorsAlreadyPresent = new HashSet<String>();
086
087 List<JetAnnotationEntry> annotationEntries = modifierList.getAnnotationEntries();
088 for (JetAnnotationEntry annotationEntry : annotationEntries) {
089 ResolvedCall<? extends CallableDescriptor> resolvedCall =
090 bindingContext.get(BindingContext.RESOLVED_CALL, annotationEntry.getCalleeExpression());
091 if (resolvedCall == null) continue; // Skipping annotations if they are not resolved. Needed for JetLightClass generation
092
093 AnnotationDescriptor annotationDescriptor = bindingContext.get(BindingContext.ANNOTATION, annotationEntry);
094 if (annotationDescriptor == null) continue; // Skipping annotations if they are not resolved. Needed for JetLightClass generation
095 if (isVolatile(annotationDescriptor)) continue;
096
097 String descriptor = genAnnotation(annotationDescriptor);
098 if (descriptor != null) {
099 annotationDescriptorsAlreadyPresent.add(descriptor);
100 }
101 }
102
103 generateAdditionalAnnotations(annotated, annotationDescriptorsAlreadyPresent);
104 }
105
106 private void generateAdditionalAnnotations(@NotNull Annotated annotated, @NotNull Set<String> annotationDescriptorsAlreadyPresent) {
107 if (annotated instanceof CallableDescriptor) {
108 CallableDescriptor descriptor = (CallableDescriptor) annotated;
109
110 // No need to annotate privates, synthetic accessors and their parameters
111 if (isInvisibleFromTheOutside(descriptor)) return;
112 if (descriptor instanceof ValueParameterDescriptor && isInvisibleFromTheOutside(descriptor.getContainingDeclaration())) return;
113
114 generateNullabilityAnnotation(descriptor.getReturnType(), annotationDescriptorsAlreadyPresent);
115 }
116 }
117
118 private static boolean isInvisibleFromTheOutside(@Nullable DeclarationDescriptor descriptor) {
119 if (descriptor instanceof CallableMemberDescriptor && JetTypeMapper.isAccessor((CallableMemberDescriptor) descriptor)) return false;
120 if (descriptor instanceof MemberDescriptor) {
121 return AsmUtil.getVisibilityAccessFlag((MemberDescriptor) descriptor) == Opcodes.ACC_PRIVATE;
122 }
123 return false;
124 }
125
126 private void generateNullabilityAnnotation(@Nullable JetType type, @NotNull Set<String> annotationDescriptorsAlreadyPresent) {
127 if (type == null) return;
128
129 if (isBareTypeParameterWithNullableUpperBound(type)) {
130 // This is to account for the case of, say
131 // class Function<R> { fun invoke(): R }
132 // it would be a shame to put @Nullable on the return type of the function, and force all callers to check for null,
133 // so we put no annotations
134 return;
135 }
136
137 boolean isNullableType = CodegenUtil.isNullableType(type);
138 if (!isNullableType && KotlinBuiltIns.getInstance().isPrimitiveType(type)) return;
139
140 Class<?> annotationClass = isNullableType ? Nullable.class : NotNull.class;
141
142 String descriptor = Type.getType(annotationClass).getDescriptor();
143 if (!annotationDescriptorsAlreadyPresent.contains(descriptor)) {
144 visitAnnotation(descriptor, false).visitEnd();
145 }
146 }
147
148 private static boolean isBareTypeParameterWithNullableUpperBound(@NotNull JetType type) {
149 ClassifierDescriptor classifier = type.getConstructor().getDeclarationDescriptor();
150 return !type.isNullable() && classifier instanceof TypeParameterDescriptor && TypeUtils.hasNullableSuperType(type);
151 }
152
153 private static boolean isVolatile(@NotNull AnnotationDescriptor annotationDescriptor) {
154 ClassifierDescriptor classDescriptor = annotationDescriptor.getType().getConstructor().getDeclarationDescriptor();
155 return classDescriptor != null && DescriptorUtils.getFqName(classDescriptor).equals(VOLATILE_FQ_NAME.toUnsafe());
156 }
157
158 public void generateAnnotationDefaultValue(@NotNull CompileTimeConstant value, @NotNull JetType expectedType) {
159 AnnotationVisitor visitor = visitAnnotation(null, false); // Parameters are unimportant
160 genCompileTimeValue(null, value, expectedType, visitor);
161 visitor.visitEnd();
162 }
163
164 @Nullable
165 private String genAnnotation(@NotNull AnnotationDescriptor annotationDescriptor) {
166 ClassifierDescriptor classifierDescriptor = annotationDescriptor.getType().getConstructor().getDeclarationDescriptor();
167 assert classifierDescriptor != null : "Annotation descriptor has no class: " + annotationDescriptor;
168 RetentionPolicy rp = getRetentionPolicy(classifierDescriptor);
169 if (rp == RetentionPolicy.SOURCE) {
170 return null;
171 }
172
173 String descriptor = typeMapper.mapType(annotationDescriptor.getType()).getDescriptor();
174 AnnotationVisitor annotationVisitor = visitAnnotation(descriptor, rp == RetentionPolicy.RUNTIME);
175
176 genAnnotationArguments(annotationDescriptor, annotationVisitor);
177 annotationVisitor.visitEnd();
178
179 return descriptor;
180 }
181
182 private void genAnnotationArguments(AnnotationDescriptor annotationDescriptor, AnnotationVisitor annotationVisitor) {
183 for (Map.Entry<ValueParameterDescriptor, CompileTimeConstant<?>> entry : annotationDescriptor.getAllValueArguments().entrySet()) {
184 ValueParameterDescriptor descriptor = entry.getKey();
185 String name = descriptor.getName().asString();
186 genCompileTimeValue(name, entry.getValue(), descriptor.getType(), annotationVisitor);
187 }
188 }
189
190 private void genCompileTimeValue(
191 @Nullable final String name,
192 @NotNull CompileTimeConstant<?> value,
193 @NotNull final JetType expectedType,
194 @NotNull final AnnotationVisitor annotationVisitor
195 ) {
196 AnnotationArgumentVisitor argumentVisitor = new AnnotationArgumentVisitor<Void, Void>() {
197 @Override
198 public Void visitLongValue(@NotNull LongValue value, Void data) {
199 return visitSimpleValue(value);
200 }
201
202 @Override
203 public Void visitIntValue(IntValue value, Void data) {
204 return visitSimpleValue(value);
205 }
206
207 @Override
208 public Void visitShortValue(ShortValue value, Void data) {
209 return visitSimpleValue(value);
210 }
211
212 @Override
213 public Void visitByteValue(ByteValue value, Void data) {
214 return visitSimpleValue(value);
215 }
216
217 @Override
218 public Void visitDoubleValue(DoubleValue value, Void data) {
219 return visitSimpleValue(value);
220 }
221
222 @Override
223 public Void visitFloatValue(FloatValue value, Void data) {
224 return visitSimpleValue(value);
225 }
226
227 @Override
228 public Void visitBooleanValue(BooleanValue value, Void data) {
229 return visitSimpleValue(value);
230 }
231
232 @Override
233 public Void visitCharValue(CharValue value, Void data) {
234 return visitSimpleValue(value);
235 }
236
237 @Override
238 public Void visitStringValue(StringValue value, Void data) {
239 return visitSimpleValue(value);
240 }
241
242 @Override
243 public Void visitEnumValue(EnumValue value, Void data) {
244 String propertyName = value.getValue().getName().asString();
245 annotationVisitor.visitEnum(name, typeMapper.mapType(value.getType(KotlinBuiltIns.getInstance())).getDescriptor(), propertyName);
246 return null;
247 }
248
249 @Override
250 public Void visitArrayValue(ArrayValue value, Void data) {
251 AnnotationVisitor visitor = annotationVisitor.visitArray(name);
252 for (CompileTimeConstant<?> argument : value.getValue()) {
253 genCompileTimeValue(null, argument, value.getType(KotlinBuiltIns.getInstance()), visitor);
254 }
255 visitor.visitEnd();
256 return null;
257 }
258
259 @Override
260 public Void visitAnnotationValue(AnnotationValue value, Void data) {
261 String internalAnnName = typeMapper.mapType(value.getValue().getType()).getDescriptor();
262 AnnotationVisitor visitor = annotationVisitor.visitAnnotation(name, internalAnnName);
263 genAnnotationArguments(value.getValue(), visitor);
264 visitor.visitEnd();
265 return null;
266 }
267
268 @Override
269 public Void visitJavaClassValue(JavaClassValue value, Void data) {
270 annotationVisitor.visit(name, typeMapper.mapType(value.getValue()));
271 return null;
272 }
273
274 @Override
275 public Void visitNumberTypeValue(IntegerValueTypeConstant value, Void data) {
276 Object numberType = value.getValue(expectedType);
277 annotationVisitor.visit(name, numberType);
278 return null;
279 }
280
281 private Void visitSimpleValue(CompileTimeConstant value) {
282 annotationVisitor.visit(name, value.getValue());
283 return null;
284 }
285
286 @Override
287 public Void visitErrorValue(ErrorValue value, Void data) {
288 return visitUnsupportedValue(value);
289 }
290
291 @Override
292 public Void visitNullValue(NullValue value, Void data) {
293 return visitUnsupportedValue(value);
294 }
295
296 private Void visitUnsupportedValue(CompileTimeConstant value) {
297 throw new IllegalStateException("Don't know how to compile annotation value " + value);
298 }
299 };
300
301 value.accept(argumentVisitor, null);
302 }
303
304 @NotNull
305 private RetentionPolicy getRetentionPolicy(@NotNull Annotated descriptor) {
306 AnnotationDescriptor retentionAnnotation = descriptor.getAnnotations().findAnnotation(new FqName(Retention.class.getName()));
307 if (retentionAnnotation == null) return RetentionPolicy.CLASS;
308
309 Collection<CompileTimeConstant<?>> valueArguments = retentionAnnotation.getAllValueArguments().values();
310 assert valueArguments.size() == 1 : "Retention should have an argument: " + retentionAnnotation + " on " + descriptor;
311 CompileTimeConstant<?> compileTimeConstant = valueArguments.iterator().next();
312 assert compileTimeConstant instanceof EnumValue : "Retention argument should be enum value: " + compileTimeConstant;
313 ClassDescriptor enumEntry = ((EnumValue) compileTimeConstant).getValue();
314 JetType classObjectType = enumEntry.getClassObjectType();
315 assert classObjectType != null : "Enum entry should have a class object: " + enumEntry;
316 assert "java/lang/annotation/RetentionPolicy".equals(typeMapper.mapType(classObjectType).getInternalName()) :
317 "Retention argument should be of type RetentionPolicy: " + enumEntry;
318 return RetentionPolicy.valueOf(enumEntry.getName().asString());
319 }
320
321 @NotNull
322 abstract AnnotationVisitor visitAnnotation(String descr, boolean visible);
323
324 public static AnnotationCodegen forClass(final ClassVisitor cv, JetTypeMapper mapper) {
325 return new AnnotationCodegen(mapper) {
326 @NotNull
327 @Override
328 AnnotationVisitor visitAnnotation(String descr, boolean visible) {
329 return safe(cv.visitAnnotation(descr, visible));
330 }
331 };
332 }
333
334 public static AnnotationCodegen forMethod(final MethodVisitor mv, JetTypeMapper mapper) {
335 return new AnnotationCodegen(mapper) {
336 @NotNull
337 @Override
338 AnnotationVisitor visitAnnotation(String descr, boolean visible) {
339 return safe(mv.visitAnnotation(descr, visible));
340 }
341 };
342 }
343
344 public static AnnotationCodegen forField(final FieldVisitor fv, JetTypeMapper mapper) {
345 return new AnnotationCodegen(mapper) {
346 @NotNull
347 @Override
348 AnnotationVisitor visitAnnotation(String descr, boolean visible) {
349 return safe(fv.visitAnnotation(descr, visible));
350 }
351 };
352 }
353
354 public static AnnotationCodegen forParameter(final int parameter, final MethodVisitor mv, JetTypeMapper mapper) {
355 return new AnnotationCodegen(mapper) {
356 @NotNull
357 @Override
358 AnnotationVisitor visitAnnotation(String descr, boolean visible) {
359 return safe(mv.visitParameterAnnotation(parameter, descr, visible));
360 }
361 };
362 }
363
364 public static AnnotationCodegen forAnnotationDefaultValue(final MethodVisitor mv, JetTypeMapper mapper) {
365 return new AnnotationCodegen(mapper) {
366 @NotNull
367 @Override
368 AnnotationVisitor visitAnnotation(String descr, boolean visible) {
369 return safe(mv.visitAnnotationDefault());
370 }
371 };
372 }
373
374 @NotNull
375 private static AnnotationVisitor safe(@Nullable AnnotationVisitor av) {
376 return av == null ? NO_ANNOTATION_VISITOR : av;
377 }
378 }