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