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