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