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