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