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