001 /*
002 * Copyright 2010-2015 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.kotlin.codegen;
018
019 import org.jetbrains.annotations.NotNull;
020 import org.jetbrains.annotations.Nullable;
021 import org.jetbrains.kotlin.codegen.annotation.WrappedAnnotated;
022 import org.jetbrains.kotlin.codegen.state.JetTypeMapper;
023 import org.jetbrains.kotlin.descriptors.*;
024 import org.jetbrains.kotlin.descriptors.annotations.*;
025 import org.jetbrains.kotlin.descriptors.impl.AnonymousFunctionDescriptor;
026 import org.jetbrains.kotlin.load.java.JvmAnnotationNames;
027 import org.jetbrains.kotlin.name.FqName;
028 import org.jetbrains.kotlin.resolve.AnnotationChecker;
029 import org.jetbrains.kotlin.resolve.constants.*;
030 import org.jetbrains.kotlin.resolve.constants.StringValue;
031 import org.jetbrains.kotlin.resolve.descriptorUtil.DescriptorUtilPackage;
032 import org.jetbrains.kotlin.types.Flexibility;
033 import org.jetbrains.kotlin.types.JetType;
034 import org.jetbrains.kotlin.types.TypeUtils;
035 import org.jetbrains.kotlin.types.TypesPackage;
036 import org.jetbrains.org.objectweb.asm.*;
037
038 import java.lang.annotation.*;
039 import java.util.*;
040
041 import static org.jetbrains.kotlin.resolve.descriptorUtil.DescriptorUtilPackage.getClassObjectType;
042
043 public abstract class AnnotationCodegen {
044
045 public static final class JvmFlagAnnotation {
046 private final FqName fqName;
047 private final int jvmFlag;
048
049 public JvmFlagAnnotation(@NotNull String fqName, int jvmFlag) {
050 this.fqName = new FqName(fqName);
051 this.jvmFlag = jvmFlag;
052 }
053
054 public boolean hasAnnotation(@NotNull Annotated annotated) {
055 return Annotations.Companion.findAnyAnnotation(annotated.getAnnotations(), fqName) != null;
056 }
057
058 public int getJvmFlag() {
059 return jvmFlag;
060 }
061 }
062
063 public static final List<JvmFlagAnnotation> FIELD_FLAGS = Arrays.asList(
064 new JvmFlagAnnotation("kotlin.jvm.Volatile", Opcodes.ACC_VOLATILE),
065 new JvmFlagAnnotation("kotlin.jvm.Transient", Opcodes.ACC_TRANSIENT)
066 );
067
068 public static final List<JvmFlagAnnotation> METHOD_FLAGS = Arrays.asList(
069 new JvmFlagAnnotation("kotlin.jvm.Strictfp", Opcodes.ACC_STRICT),
070 new JvmFlagAnnotation("kotlin.jvm.Synchronized", Opcodes.ACC_SYNCHRONIZED),
071 new JvmFlagAnnotation("kotlin.jvm.native", Opcodes.ACC_NATIVE),
072 new JvmFlagAnnotation("kotlin.external", Opcodes.ACC_NATIVE)
073 );
074
075 private static final AnnotationVisitor NO_ANNOTATION_VISITOR = new AnnotationVisitor(Opcodes.ASM5) {};
076
077 private final JetTypeMapper typeMapper;
078
079 private AnnotationCodegen(JetTypeMapper mapper) {
080 typeMapper = mapper;
081 }
082
083 /**
084 * @param returnType can be null if not applicable (e.g. {@code annotated} is a class)
085 */
086 public void genAnnotations(@Nullable Annotated annotated, @Nullable Type returnType) {
087 genAnnotations(annotated, returnType, null);
088 }
089
090 public void genAnnotations(@Nullable Annotated annotated, @Nullable Type returnType, @Nullable AnnotationUseSiteTarget allowedTarget) {
091 if (annotated == null) {
092 return;
093 }
094
095 Set<String> annotationDescriptorsAlreadyPresent = new HashSet<String>();
096
097 Annotations annotations = annotated.getAnnotations();
098
099 for (AnnotationWithTarget annotationWithTarget : annotations.getAllAnnotations()) {
100 AnnotationDescriptor annotation = annotationWithTarget.getAnnotation();
101 AnnotationUseSiteTarget annotationTarget = annotationWithTarget.getTarget();
102
103 // Skip targeted annotations by default
104 if (allowedTarget == null && annotationTarget != null) continue;
105
106 // Skip if the target is not the same
107 if (allowedTarget != null && annotationTarget != null && allowedTarget != annotationTarget) continue;
108
109 Set<KotlinTarget> applicableTargets = AnnotationChecker.applicableTargetSet(annotation);
110 if (annotated instanceof AnonymousFunctionDescriptor
111 && !applicableTargets.contains(KotlinTarget.FUNCTION)
112 && !applicableTargets.contains(KotlinTarget.PROPERTY_GETTER)
113 && !applicableTargets.contains(KotlinTarget.PROPERTY_SETTER)) {
114 assert (applicableTargets.contains(KotlinTarget.EXPRESSION)) :
115 "Inconsistent target list for lambda annotation: " + applicableTargets + " on " + annotated;
116 continue;
117 }
118
119 String descriptor = genAnnotation(annotation);
120 if (descriptor != null) {
121 annotationDescriptorsAlreadyPresent.add(descriptor);
122 }
123 }
124
125 generateAdditionalAnnotations(annotated, returnType, annotationDescriptorsAlreadyPresent);
126 }
127
128 private void generateAdditionalAnnotations(
129 @NotNull Annotated annotated,
130 @Nullable Type returnType,
131 @NotNull Set<String> annotationDescriptorsAlreadyPresent
132 ) {
133 Annotated unwrapped = annotated;
134 if (annotated instanceof WrappedAnnotated) {
135 unwrapped = ((WrappedAnnotated) annotated).getOriginalAnnotated();
136 }
137
138 if (unwrapped instanceof CallableDescriptor) {
139 CallableDescriptor descriptor = (CallableDescriptor) unwrapped;
140
141 // No need to annotate privates, synthetic accessors and their parameters
142 if (isInvisibleFromTheOutside(descriptor)) return;
143 if (descriptor instanceof ValueParameterDescriptor && isInvisibleFromTheOutside(descriptor.getContainingDeclaration())) return;
144
145 if (returnType != null && !AsmUtil.isPrimitive(returnType)) {
146 generateNullabilityAnnotation(descriptor.getReturnType(), annotationDescriptorsAlreadyPresent);
147 }
148 }
149 if (unwrapped instanceof ClassDescriptor) {
150 ClassDescriptor classDescriptor = (ClassDescriptor) unwrapped;
151 if (classDescriptor.getKind() == ClassKind.ANNOTATION_CLASS) {
152 generateDocumentedAnnotation(classDescriptor, annotationDescriptorsAlreadyPresent);
153 generateRetentionAnnotation(classDescriptor, annotationDescriptorsAlreadyPresent);
154 generateTargetAnnotation(classDescriptor, annotationDescriptorsAlreadyPresent);
155 }
156 }
157 }
158
159 private static boolean isInvisibleFromTheOutside(@Nullable DeclarationDescriptor descriptor) {
160 if (descriptor instanceof CallableMemberDescriptor && JetTypeMapper.isAccessor((CallableMemberDescriptor) descriptor)) return false;
161 if (descriptor instanceof MemberDescriptor) {
162 return AsmUtil.getVisibilityAccessFlag((MemberDescriptor) descriptor) == Opcodes.ACC_PRIVATE;
163 }
164 return false;
165 }
166
167 private void generateNullabilityAnnotation(@Nullable JetType type, @NotNull Set<String> annotationDescriptorsAlreadyPresent) {
168 if (type == null) return;
169
170 if (isBareTypeParameterWithNullableUpperBound(type)) {
171 // This is to account for the case of, say
172 // class Function<R> { fun invoke(): R }
173 // it would be a shame to put @Nullable on the return type of the function, and force all callers to check for null,
174 // so we put no annotations
175 return;
176 }
177
178 if (TypesPackage.isFlexible(type)) {
179 // A flexible type whose lower bound in not-null and upper bound is nullable, should not be annotated
180 Flexibility flexibility = TypesPackage.flexibility(type);
181
182 if (!TypeUtils.isNullableType(flexibility.getLowerBound()) && TypeUtils.isNullableType(flexibility.getUpperBound())) {
183 AnnotationDescriptor notNull = type.getAnnotations().findAnnotation(JvmAnnotationNames.JETBRAINS_NOT_NULL_ANNOTATION);
184 if (notNull != null) {
185 generateAnnotationIfNotPresent(annotationDescriptorsAlreadyPresent, NotNull.class);
186 }
187 return;
188 }
189 }
190
191 boolean isNullableType = TypeUtils.isNullableType(type);
192
193 Class<?> annotationClass = isNullableType ? Nullable.class : NotNull.class;
194
195 generateAnnotationIfNotPresent(annotationDescriptorsAlreadyPresent, annotationClass);
196 }
197
198 private static final Map<KotlinTarget, ElementType> annotationTargetMap =
199 new EnumMap<KotlinTarget, ElementType>(KotlinTarget.class);
200
201 static {
202 annotationTargetMap.put(KotlinTarget.CLASS, ElementType.TYPE);
203 annotationTargetMap.put(KotlinTarget.ANNOTATION_CLASS, ElementType.ANNOTATION_TYPE);
204 annotationTargetMap.put(KotlinTarget.CONSTRUCTOR, ElementType.CONSTRUCTOR);
205 annotationTargetMap.put(KotlinTarget.LOCAL_VARIABLE, ElementType.LOCAL_VARIABLE);
206 annotationTargetMap.put(KotlinTarget.FUNCTION, ElementType.METHOD);
207 annotationTargetMap.put(KotlinTarget.PROPERTY_GETTER, ElementType.METHOD);
208 annotationTargetMap.put(KotlinTarget.PROPERTY_SETTER, ElementType.METHOD);
209 annotationTargetMap.put(KotlinTarget.FIELD, ElementType.FIELD);
210 annotationTargetMap.put(KotlinTarget.VALUE_PARAMETER, ElementType.PARAMETER);
211 }
212
213 private void generateTargetAnnotation(@NotNull ClassDescriptor classDescriptor, @NotNull Set<String> annotationDescriptorsAlreadyPresent) {
214 String descriptor = Type.getType(Target.class).getDescriptor();
215 if (!annotationDescriptorsAlreadyPresent.add(descriptor)) return;
216 Set<KotlinTarget> targets = AnnotationChecker.Companion.applicableTargetSet(classDescriptor);
217 Set<ElementType> javaTargets;
218 if (targets == null) {
219 javaTargets = getJavaTargetList(classDescriptor);
220 if (javaTargets == null) return;
221 }
222 else {
223 javaTargets = EnumSet.noneOf(ElementType.class);
224 for (KotlinTarget target : targets) {
225 if (annotationTargetMap.get(target) == null) continue;
226 javaTargets.add(annotationTargetMap.get(target));
227 }
228 }
229 AnnotationVisitor visitor = visitAnnotation(descriptor, true);
230 AnnotationVisitor arrayVisitor = visitor.visitArray("value");
231 for (ElementType javaTarget : javaTargets) {
232 arrayVisitor.visitEnum(null, Type.getType(ElementType.class).getDescriptor(), javaTarget.name());
233 }
234 arrayVisitor.visitEnd();
235 visitor.visitEnd();
236 }
237
238 private void generateRetentionAnnotation(@NotNull ClassDescriptor classDescriptor, @NotNull Set<String> annotationDescriptorsAlreadyPresent) {
239 RetentionPolicy policy = getRetentionPolicy(classDescriptor);
240 String descriptor = Type.getType(Retention.class).getDescriptor();
241 if (!annotationDescriptorsAlreadyPresent.add(descriptor)) return;
242 AnnotationVisitor visitor = visitAnnotation(descriptor, true);
243 visitor.visitEnum("value", Type.getType(RetentionPolicy.class).getDescriptor(), policy.name());
244 visitor.visitEnd();
245 }
246
247 private void generateDocumentedAnnotation(@NotNull ClassDescriptor classDescriptor, @NotNull Set<String> annotationDescriptorsAlreadyPresent) {
248 boolean documented = DescriptorUtilPackage.isDocumentedAnnotation(classDescriptor);
249 if (!documented) return;
250 String descriptor = Type.getType(Documented.class).getDescriptor();
251 if (!annotationDescriptorsAlreadyPresent.add(descriptor)) return;
252 AnnotationVisitor visitor = visitAnnotation(descriptor, true);
253 visitor.visitEnd();
254 }
255
256 private void generateAnnotationIfNotPresent(Set<String> annotationDescriptorsAlreadyPresent, Class<?> annotationClass) {
257 String descriptor = Type.getType(annotationClass).getDescriptor();
258 if (!annotationDescriptorsAlreadyPresent.contains(descriptor)) {
259 visitAnnotation(descriptor, false).visitEnd();
260 }
261 }
262
263 private static boolean isBareTypeParameterWithNullableUpperBound(@NotNull JetType type) {
264 ClassifierDescriptor classifier = type.getConstructor().getDeclarationDescriptor();
265 return !type.isMarkedNullable() && classifier instanceof TypeParameterDescriptor && TypeUtils.hasNullableSuperType(type);
266 }
267
268 public void generateAnnotationDefaultValue(@NotNull ConstantValue<?> value, @NotNull JetType expectedType) {
269 AnnotationVisitor visitor = visitAnnotation(null, false); // Parameters are unimportant
270 genCompileTimeValue(null, value, visitor);
271 visitor.visitEnd();
272 }
273
274 @Nullable
275 private String genAnnotation(@NotNull AnnotationDescriptor annotationDescriptor) {
276 ClassifierDescriptor classifierDescriptor = annotationDescriptor.getType().getConstructor().getDeclarationDescriptor();
277 assert classifierDescriptor != null : "Annotation descriptor has no class: " + annotationDescriptor;
278 RetentionPolicy rp = getRetentionPolicy(classifierDescriptor);
279 if (rp == RetentionPolicy.SOURCE && typeMapper.getClassBuilderMode() != ClassBuilderMode.LIGHT_CLASSES) {
280 return null;
281 }
282
283 String descriptor = typeMapper.mapType(annotationDescriptor.getType()).getDescriptor();
284 AnnotationVisitor annotationVisitor = visitAnnotation(descriptor, rp == RetentionPolicy.RUNTIME);
285
286 genAnnotationArguments(annotationDescriptor, annotationVisitor);
287 annotationVisitor.visitEnd();
288
289 return descriptor;
290 }
291
292 private void genAnnotationArguments(AnnotationDescriptor annotationDescriptor, AnnotationVisitor annotationVisitor) {
293 for (Map.Entry<ValueParameterDescriptor, ConstantValue<?>> entry : annotationDescriptor.getAllValueArguments().entrySet()) {
294 ValueParameterDescriptor descriptor = entry.getKey();
295 String name = descriptor.getName().asString();
296 genCompileTimeValue(name, entry.getValue(), annotationVisitor);
297 }
298 }
299
300 private void genCompileTimeValue(
301 @Nullable final String name,
302 @NotNull ConstantValue<?> value,
303 @NotNull final AnnotationVisitor annotationVisitor
304 ) {
305 AnnotationArgumentVisitor argumentVisitor = new AnnotationArgumentVisitor<Void, Void>() {
306 @Override
307 public Void visitLongValue(@NotNull LongValue value, Void data) {
308 return visitSimpleValue(value);
309 }
310
311 @Override
312 public Void visitIntValue(IntValue value, Void data) {
313 return visitSimpleValue(value);
314 }
315
316 @Override
317 public Void visitShortValue(ShortValue value, Void data) {
318 return visitSimpleValue(value);
319 }
320
321 @Override
322 public Void visitByteValue(ByteValue value, Void data) {
323 return visitSimpleValue(value);
324 }
325
326 @Override
327 public Void visitDoubleValue(DoubleValue value, Void data) {
328 return visitSimpleValue(value);
329 }
330
331 @Override
332 public Void visitFloatValue(FloatValue value, Void data) {
333 return visitSimpleValue(value);
334 }
335
336 @Override
337 public Void visitBooleanValue(BooleanValue value, Void data) {
338 return visitSimpleValue(value);
339 }
340
341 @Override
342 public Void visitCharValue(CharValue value, Void data) {
343 return visitSimpleValue(value);
344 }
345
346 @Override
347 public Void visitStringValue(StringValue value, Void data) {
348 return visitSimpleValue(value);
349 }
350
351 @Override
352 public Void visitEnumValue(EnumValue value, Void data) {
353 String propertyName = value.getValue().getName().asString();
354 annotationVisitor.visitEnum(name, typeMapper.mapType(value.getType()).getDescriptor(), propertyName);
355 return null;
356 }
357
358 @Override
359 public Void visitArrayValue(ArrayValue value, Void data) {
360 AnnotationVisitor visitor = annotationVisitor.visitArray(name);
361 for (ConstantValue<?> argument : value.getValue()) {
362 genCompileTimeValue(null, argument, visitor);
363 }
364 visitor.visitEnd();
365 return null;
366 }
367
368 @Override
369 public Void visitAnnotationValue(AnnotationValue value, Void data) {
370 String internalAnnName = typeMapper.mapType(value.getValue().getType()).getDescriptor();
371 AnnotationVisitor visitor = annotationVisitor.visitAnnotation(name, internalAnnName);
372 genAnnotationArguments(value.getValue(), visitor);
373 visitor.visitEnd();
374 return null;
375 }
376
377 @Override
378 public Void visitKClassValue(KClassValue value, Void data) {
379 annotationVisitor.visit(name, typeMapper.mapType(value.getValue()));
380 return null;
381 }
382
383 private Void visitSimpleValue(ConstantValue<?> value) {
384 annotationVisitor.visit(name, value.getValue());
385 return null;
386 }
387
388 @Override
389 public Void visitErrorValue(ErrorValue value, Void data) {
390 return visitUnsupportedValue(value);
391 }
392
393 @Override
394 public Void visitNullValue(NullValue value, Void data) {
395 return visitUnsupportedValue(value);
396 }
397
398 private Void visitUnsupportedValue(ConstantValue<?> value) {
399 throw new IllegalStateException("Don't know how to compile annotation value " + value);
400 }
401 };
402
403 value.accept(argumentVisitor, null);
404 }
405
406 private static final Map<KotlinRetention, RetentionPolicy> annotationRetentionMap =
407 new EnumMap<KotlinRetention, RetentionPolicy>(KotlinRetention.class);
408
409 static {
410 annotationRetentionMap.put(KotlinRetention.SOURCE, RetentionPolicy.SOURCE);
411 annotationRetentionMap.put(KotlinRetention.BINARY, RetentionPolicy.CLASS);
412 annotationRetentionMap.put(KotlinRetention.RUNTIME, RetentionPolicy.RUNTIME);
413 }
414
415 @Nullable
416 private Set<ElementType> getJavaTargetList(ClassDescriptor descriptor) {
417 AnnotationDescriptor targetAnnotation = descriptor.getAnnotations().findAnnotation(new FqName(Target.class.getName()));
418 if (targetAnnotation != null) {
419 Collection<ConstantValue<?>> valueArguments = targetAnnotation.getAllValueArguments().values();
420 if (!valueArguments.isEmpty()) {
421 ConstantValue<?> compileTimeConstant = valueArguments.iterator().next();
422 if (compileTimeConstant instanceof ArrayValue) {
423 List<? extends ConstantValue<?>> values = ((ArrayValue) compileTimeConstant).getValue();
424 Set<ElementType> result = EnumSet.noneOf(ElementType.class);
425 for (ConstantValue<?> value : values) {
426 if (value instanceof EnumValue) {
427 ClassDescriptor enumEntry = ((EnumValue) value).getValue();
428 JetType classObjectType = getClassObjectType(enumEntry);
429 if (classObjectType != null) {
430 if ("java/lang/annotation/ElementType".equals(typeMapper.mapType(classObjectType).getInternalName())) {
431 result.add(ElementType.valueOf(enumEntry.getName().asString()));
432 }
433 }
434 }
435 }
436 return result;
437 }
438 }
439 }
440 return null;
441 }
442
443 @NotNull
444 private RetentionPolicy getRetentionPolicy(@NotNull Annotated descriptor) {
445 KotlinRetention retention = DescriptorUtilPackage.getAnnotationRetention(descriptor);
446 if (retention != null) {
447 return annotationRetentionMap.get(retention);
448 }
449 AnnotationDescriptor retentionAnnotation = descriptor.getAnnotations().findAnnotation(new FqName(Retention.class.getName()));
450 if (retentionAnnotation != null) {
451 Collection<ConstantValue<?>> valueArguments = retentionAnnotation.getAllValueArguments().values();
452 if (!valueArguments.isEmpty()) {
453 ConstantValue<?> compileTimeConstant = valueArguments.iterator().next();
454 if (compileTimeConstant instanceof EnumValue) {
455 ClassDescriptor enumEntry = ((EnumValue) compileTimeConstant).getValue();
456 JetType classObjectType = getClassObjectType(enumEntry);
457 if (classObjectType != null) {
458 if ("java/lang/annotation/RetentionPolicy".equals(typeMapper.mapType(classObjectType).getInternalName())) {
459 return RetentionPolicy.valueOf(enumEntry.getName().asString());
460 }
461 }
462 }
463 }
464 }
465
466 return RetentionPolicy.RUNTIME;
467 }
468
469 @NotNull
470 abstract AnnotationVisitor visitAnnotation(String descr, boolean visible);
471
472 public static AnnotationCodegen forClass(final ClassVisitor cv, JetTypeMapper mapper) {
473 return new AnnotationCodegen(mapper) {
474 @NotNull
475 @Override
476 AnnotationVisitor visitAnnotation(String descr, boolean visible) {
477 return safe(cv.visitAnnotation(descr, visible));
478 }
479 };
480 }
481
482 public static AnnotationCodegen forMethod(final MethodVisitor mv, JetTypeMapper mapper) {
483 return new AnnotationCodegen(mapper) {
484 @NotNull
485 @Override
486 AnnotationVisitor visitAnnotation(String descr, boolean visible) {
487 return safe(mv.visitAnnotation(descr, visible));
488 }
489 };
490 }
491
492 public static AnnotationCodegen forField(final FieldVisitor fv, JetTypeMapper mapper) {
493 return new AnnotationCodegen(mapper) {
494 @NotNull
495 @Override
496 AnnotationVisitor visitAnnotation(String descr, boolean visible) {
497 return safe(fv.visitAnnotation(descr, visible));
498 }
499 };
500 }
501
502 public static AnnotationCodegen forParameter(final int parameter, final MethodVisitor mv, JetTypeMapper mapper) {
503 return new AnnotationCodegen(mapper) {
504 @NotNull
505 @Override
506 AnnotationVisitor visitAnnotation(String descr, boolean visible) {
507 return safe(mv.visitParameterAnnotation(parameter, descr, visible));
508 }
509 };
510 }
511
512 public static AnnotationCodegen forAnnotationDefaultValue(final MethodVisitor mv, JetTypeMapper mapper) {
513 return new AnnotationCodegen(mapper) {
514 @NotNull
515 @Override
516 AnnotationVisitor visitAnnotation(String descr, boolean visible) {
517 return safe(mv.visitAnnotationDefault());
518 }
519 };
520 }
521
522 @NotNull
523 private static AnnotationVisitor safe(@Nullable AnnotationVisitor av) {
524 return av == null ? NO_ANNOTATION_VISITOR : av;
525 }
526 }