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