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