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