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