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 }