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