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