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