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.builtins.KotlinBuiltIns; 022 import org.jetbrains.kotlin.codegen.state.JetTypeMapper; 023 import org.jetbrains.kotlin.descriptors.*; 024 import org.jetbrains.kotlin.descriptors.annotations.Annotated; 025 import org.jetbrains.kotlin.descriptors.annotations.AnnotationArgumentVisitor; 026 import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor; 027 import org.jetbrains.kotlin.load.java.JvmAnnotationNames; 028 import org.jetbrains.kotlin.name.FqName; 029 import org.jetbrains.kotlin.resolve.constants.*; 030 import org.jetbrains.kotlin.resolve.constants.StringValue; 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.Retention; 038 import java.lang.annotation.RetentionPolicy; 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 annotated.getAnnotations().findAnnotation(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 ); 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 if (annotated == null) { 087 return; 088 } 089 090 if (!(annotated instanceof DeclarationDescriptor)) { 091 return; 092 } 093 094 Set<String> annotationDescriptorsAlreadyPresent = new HashSet<String>(); 095 096 for (AnnotationDescriptor annotation : annotated.getAnnotations()) { 097 String descriptor = genAnnotation(annotation); 098 if (descriptor != null) { 099 annotationDescriptorsAlreadyPresent.add(descriptor); 100 } 101 } 102 103 generateAdditionalAnnotations(annotated, returnType, annotationDescriptorsAlreadyPresent); 104 } 105 106 private void generateAdditionalAnnotations( 107 @NotNull Annotated annotated, 108 @Nullable Type returnType, 109 @NotNull Set<String> annotationDescriptorsAlreadyPresent 110 ) { 111 if (annotated instanceof CallableDescriptor) { 112 CallableDescriptor descriptor = (CallableDescriptor) annotated; 113 114 // No need to annotate privates, synthetic accessors and their parameters 115 if (isInvisibleFromTheOutside(descriptor)) return; 116 if (descriptor instanceof ValueParameterDescriptor && isInvisibleFromTheOutside(descriptor.getContainingDeclaration())) return; 117 118 if (returnType != null && !AsmUtil.isPrimitive(returnType)) { 119 generateNullabilityAnnotation(descriptor.getReturnType(), annotationDescriptorsAlreadyPresent); 120 } 121 } 122 } 123 124 private static boolean isInvisibleFromTheOutside(@Nullable DeclarationDescriptor descriptor) { 125 if (descriptor instanceof CallableMemberDescriptor && JetTypeMapper.isAccessor((CallableMemberDescriptor) descriptor)) return false; 126 if (descriptor instanceof MemberDescriptor) { 127 return AsmUtil.getVisibilityAccessFlag((MemberDescriptor) descriptor) == Opcodes.ACC_PRIVATE; 128 } 129 return false; 130 } 131 132 private void generateNullabilityAnnotation(@Nullable JetType type, @NotNull Set<String> annotationDescriptorsAlreadyPresent) { 133 if (type == null) return; 134 135 if (isBareTypeParameterWithNullableUpperBound(type)) { 136 // This is to account for the case of, say 137 // class Function<R> { fun invoke(): R } 138 // it would be a shame to put @Nullable on the return type of the function, and force all callers to check for null, 139 // so we put no annotations 140 return; 141 } 142 143 if (TypesPackage.isFlexible(type)) { 144 // A flexible type whose lower bound in not-null and upper bound is nullable, should not be annotated 145 Flexibility flexibility = TypesPackage.flexibility(type); 146 147 if (!TypeUtils.isNullableType(flexibility.getLowerBound()) && TypeUtils.isNullableType(flexibility.getUpperBound())) { 148 AnnotationDescriptor notNull = type.getAnnotations().findAnnotation(JvmAnnotationNames.JETBRAINS_NOT_NULL_ANNOTATION); 149 if (notNull != null) { 150 generateAnnotationIfNotPresent(annotationDescriptorsAlreadyPresent, NotNull.class); 151 } 152 return; 153 } 154 } 155 156 boolean isNullableType = TypeUtils.isNullableType(type); 157 158 Class<?> annotationClass = isNullableType ? Nullable.class : NotNull.class; 159 160 generateAnnotationIfNotPresent(annotationDescriptorsAlreadyPresent, annotationClass); 161 } 162 163 private void generateAnnotationIfNotPresent(Set<String> annotationDescriptorsAlreadyPresent, Class<?> annotationClass) { 164 String descriptor = Type.getType(annotationClass).getDescriptor(); 165 if (!annotationDescriptorsAlreadyPresent.contains(descriptor)) { 166 visitAnnotation(descriptor, false).visitEnd(); 167 } 168 } 169 170 private static boolean isBareTypeParameterWithNullableUpperBound(@NotNull JetType type) { 171 ClassifierDescriptor classifier = type.getConstructor().getDeclarationDescriptor(); 172 return !type.isMarkedNullable() && classifier instanceof TypeParameterDescriptor && TypeUtils.hasNullableSuperType(type); 173 } 174 175 public void generateAnnotationDefaultValue(@NotNull CompileTimeConstant value, @NotNull JetType expectedType) { 176 AnnotationVisitor visitor = visitAnnotation(null, false); // Parameters are unimportant 177 genCompileTimeValue(null, value, expectedType, visitor); 178 visitor.visitEnd(); 179 } 180 181 @Nullable 182 private String genAnnotation(@NotNull AnnotationDescriptor annotationDescriptor) { 183 ClassifierDescriptor classifierDescriptor = annotationDescriptor.getType().getConstructor().getDeclarationDescriptor(); 184 assert classifierDescriptor != null : "Annotation descriptor has no class: " + annotationDescriptor; 185 RetentionPolicy rp = getRetentionPolicy(classifierDescriptor); 186 if (rp == RetentionPolicy.SOURCE && typeMapper.getClassBuilderMode() != ClassBuilderMode.LIGHT_CLASSES) { 187 return null; 188 } 189 190 String descriptor = typeMapper.mapType(annotationDescriptor.getType()).getDescriptor(); 191 AnnotationVisitor annotationVisitor = visitAnnotation(descriptor, rp == RetentionPolicy.RUNTIME); 192 193 genAnnotationArguments(annotationDescriptor, annotationVisitor); 194 annotationVisitor.visitEnd(); 195 196 return descriptor; 197 } 198 199 private void genAnnotationArguments(AnnotationDescriptor annotationDescriptor, AnnotationVisitor annotationVisitor) { 200 for (Map.Entry<ValueParameterDescriptor, CompileTimeConstant<?>> entry : annotationDescriptor.getAllValueArguments().entrySet()) { 201 ValueParameterDescriptor descriptor = entry.getKey(); 202 String name = descriptor.getName().asString(); 203 genCompileTimeValue(name, entry.getValue(), descriptor.getType(), annotationVisitor); 204 } 205 } 206 207 private void genCompileTimeValue( 208 @Nullable final String name, 209 @NotNull CompileTimeConstant<?> value, 210 @NotNull final JetType expectedType, 211 @NotNull final AnnotationVisitor annotationVisitor 212 ) { 213 AnnotationArgumentVisitor argumentVisitor = new AnnotationArgumentVisitor<Void, Void>() { 214 @Override 215 public Void visitLongValue(@NotNull LongValue value, Void data) { 216 return visitSimpleValue(value); 217 } 218 219 @Override 220 public Void visitIntValue(IntValue value, Void data) { 221 return visitSimpleValue(value); 222 } 223 224 @Override 225 public Void visitShortValue(ShortValue value, Void data) { 226 return visitSimpleValue(value); 227 } 228 229 @Override 230 public Void visitByteValue(ByteValue value, Void data) { 231 return visitSimpleValue(value); 232 } 233 234 @Override 235 public Void visitDoubleValue(DoubleValue value, Void data) { 236 return visitSimpleValue(value); 237 } 238 239 @Override 240 public Void visitFloatValue(FloatValue value, Void data) { 241 return visitSimpleValue(value); 242 } 243 244 @Override 245 public Void visitBooleanValue(BooleanValue value, Void data) { 246 return visitSimpleValue(value); 247 } 248 249 @Override 250 public Void visitCharValue(CharValue value, Void data) { 251 return visitSimpleValue(value); 252 } 253 254 @Override 255 public Void visitStringValue(StringValue value, Void data) { 256 return visitSimpleValue(value); 257 } 258 259 @Override 260 public Void visitEnumValue(EnumValue value, Void data) { 261 String propertyName = value.getValue().getName().asString(); 262 annotationVisitor.visitEnum(name, typeMapper.mapType(value.getType(KotlinBuiltIns.getInstance())).getDescriptor(), propertyName); 263 return null; 264 } 265 266 @Override 267 public Void visitArrayValue(ArrayValue value, Void data) { 268 AnnotationVisitor visitor = annotationVisitor.visitArray(name); 269 for (CompileTimeConstant<?> argument : value.getValue()) { 270 genCompileTimeValue(null, argument, value.getType(KotlinBuiltIns.getInstance()), visitor); 271 } 272 visitor.visitEnd(); 273 return null; 274 } 275 276 @Override 277 public Void visitAnnotationValue(AnnotationValue value, Void data) { 278 String internalAnnName = typeMapper.mapType(value.getValue().getType()).getDescriptor(); 279 AnnotationVisitor visitor = annotationVisitor.visitAnnotation(name, internalAnnName); 280 genAnnotationArguments(value.getValue(), visitor); 281 visitor.visitEnd(); 282 return null; 283 } 284 285 @Override 286 public Void visitJavaClassValue(JavaClassValue value, Void data) { 287 return visitClassOfType(value.getValue()); 288 } 289 290 @Override 291 public Void visitKClassValue(KClassValue value, Void data) { 292 return visitClassOfType(value.getValue()); 293 } 294 295 private Void visitClassOfType(@NotNull JetType type) { 296 annotationVisitor.visit(name, typeMapper.mapType(type)); 297 return null; 298 } 299 300 @Override 301 public Void visitNumberTypeValue(IntegerValueTypeConstant value, Void data) { 302 Object numberType = value.getValue(expectedType); 303 annotationVisitor.visit(name, numberType); 304 return null; 305 } 306 307 private Void visitSimpleValue(CompileTimeConstant value) { 308 annotationVisitor.visit(name, value.getValue()); 309 return null; 310 } 311 312 @Override 313 public Void visitErrorValue(ErrorValue value, Void data) { 314 return visitUnsupportedValue(value); 315 } 316 317 @Override 318 public Void visitNullValue(NullValue value, Void data) { 319 return visitUnsupportedValue(value); 320 } 321 322 private Void visitUnsupportedValue(CompileTimeConstant value) { 323 throw new IllegalStateException("Don't know how to compile annotation value " + value); 324 } 325 }; 326 327 value.accept(argumentVisitor, null); 328 } 329 330 @NotNull 331 private RetentionPolicy getRetentionPolicy(@NotNull Annotated descriptor) { 332 AnnotationDescriptor retentionAnnotation = descriptor.getAnnotations().findAnnotation(new FqName(Retention.class.getName())); 333 if (retentionAnnotation != null) { 334 Collection<CompileTimeConstant<?>> valueArguments = retentionAnnotation.getAllValueArguments().values(); 335 if (!valueArguments.isEmpty()) { 336 CompileTimeConstant<?> compileTimeConstant = valueArguments.iterator().next(); 337 if (compileTimeConstant instanceof EnumValue) { 338 ClassDescriptor enumEntry = ((EnumValue) compileTimeConstant).getValue(); 339 JetType classObjectType = getClassObjectType(enumEntry); 340 if (classObjectType != null) { 341 if ("java/lang/annotation/RetentionPolicy".equals(typeMapper.mapType(classObjectType).getInternalName())) { 342 return RetentionPolicy.valueOf(enumEntry.getName().asString()); 343 } 344 } 345 } 346 } 347 } 348 349 return RetentionPolicy.CLASS; 350 } 351 352 @NotNull 353 abstract AnnotationVisitor visitAnnotation(String descr, boolean visible); 354 355 public static AnnotationCodegen forClass(final ClassVisitor cv, JetTypeMapper mapper) { 356 return new AnnotationCodegen(mapper) { 357 @NotNull 358 @Override 359 AnnotationVisitor visitAnnotation(String descr, boolean visible) { 360 return safe(cv.visitAnnotation(descr, visible)); 361 } 362 }; 363 } 364 365 public static AnnotationCodegen forMethod(final MethodVisitor mv, JetTypeMapper mapper) { 366 return new AnnotationCodegen(mapper) { 367 @NotNull 368 @Override 369 AnnotationVisitor visitAnnotation(String descr, boolean visible) { 370 return safe(mv.visitAnnotation(descr, visible)); 371 } 372 }; 373 } 374 375 public static AnnotationCodegen forField(final FieldVisitor fv, JetTypeMapper mapper) { 376 return new AnnotationCodegen(mapper) { 377 @NotNull 378 @Override 379 AnnotationVisitor visitAnnotation(String descr, boolean visible) { 380 return safe(fv.visitAnnotation(descr, visible)); 381 } 382 }; 383 } 384 385 public static AnnotationCodegen forParameter(final int parameter, final MethodVisitor mv, JetTypeMapper mapper) { 386 return new AnnotationCodegen(mapper) { 387 @NotNull 388 @Override 389 AnnotationVisitor visitAnnotation(String descr, boolean visible) { 390 return safe(mv.visitParameterAnnotation(parameter, descr, visible)); 391 } 392 }; 393 } 394 395 public static AnnotationCodegen forAnnotationDefaultValue(final MethodVisitor mv, JetTypeMapper mapper) { 396 return new AnnotationCodegen(mapper) { 397 @NotNull 398 @Override 399 AnnotationVisitor visitAnnotation(String descr, boolean visible) { 400 return safe(mv.visitAnnotationDefault()); 401 } 402 }; 403 } 404 405 @NotNull 406 private static AnnotationVisitor safe(@Nullable AnnotationVisitor av) { 407 return av == null ? NO_ANNOTATION_VISITOR : av; 408 } 409 }