001    /*
002     * Copyright 2010-2015 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.kotlin.codegen;
018    
019    import org.jetbrains.annotations.NotNull;
020    import org.jetbrains.annotations.Nullable;
021    import org.jetbrains.kotlin.codegen.annotation.WrappedAnnotated;
022    import org.jetbrains.kotlin.codegen.state.JetTypeMapper;
023    import org.jetbrains.kotlin.descriptors.*;
024    import org.jetbrains.kotlin.descriptors.annotations.*;
025    import org.jetbrains.kotlin.load.java.JvmAnnotationNames;
026    import org.jetbrains.kotlin.name.FqName;
027    import org.jetbrains.kotlin.resolve.AnnotationChecker;
028    import org.jetbrains.kotlin.resolve.constants.*;
029    import org.jetbrains.kotlin.resolve.constants.StringValue;
030    import org.jetbrains.kotlin.resolve.descriptorUtil.DescriptorUtilPackage;
031    import org.jetbrains.kotlin.types.Flexibility;
032    import org.jetbrains.kotlin.types.JetType;
033    import org.jetbrains.kotlin.types.TypeUtils;
034    import org.jetbrains.kotlin.types.TypesPackage;
035    import org.jetbrains.org.objectweb.asm.*;
036    
037    import java.lang.annotation.*;
038    import java.util.*;
039    
040    import static org.jetbrains.kotlin.resolve.descriptorUtil.DescriptorUtilPackage.getClassObjectType;
041    
042    public abstract class AnnotationCodegen {
043    
044        public static final class JvmFlagAnnotation {
045            private final FqName fqName;
046            private final int jvmFlag;
047    
048            public JvmFlagAnnotation(@NotNull String fqName, int jvmFlag) {
049                this.fqName = new FqName(fqName);
050                this.jvmFlag = jvmFlag;
051            }
052    
053            public boolean hasAnnotation(@NotNull Annotated annotated) {
054                return Annotations.Companion.findAnyAnnotation(annotated.getAnnotations(), fqName) != null;
055            }
056    
057            public int getJvmFlag() {
058                return jvmFlag;
059            }
060        }
061    
062        public static final List<JvmFlagAnnotation> FIELD_FLAGS = Arrays.asList(
063                new JvmFlagAnnotation("kotlin.jvm.Volatile", Opcodes.ACC_VOLATILE),
064                new JvmFlagAnnotation("kotlin.jvm.Transient", Opcodes.ACC_TRANSIENT)
065        );
066    
067        public static final List<JvmFlagAnnotation> METHOD_FLAGS = Arrays.asList(
068                new JvmFlagAnnotation("kotlin.jvm.Strictfp", Opcodes.ACC_STRICT),
069                new JvmFlagAnnotation("kotlin.jvm.Synchronized", Opcodes.ACC_SYNCHRONIZED),
070                new JvmFlagAnnotation("kotlin.jvm.native", Opcodes.ACC_NATIVE),
071                new JvmFlagAnnotation("kotlin.external", Opcodes.ACC_NATIVE)
072        );
073    
074        private static final AnnotationVisitor NO_ANNOTATION_VISITOR = new AnnotationVisitor(Opcodes.ASM5) {};
075    
076        private final JetTypeMapper typeMapper;
077    
078        private AnnotationCodegen(JetTypeMapper mapper) {
079            typeMapper = mapper;
080        }
081    
082        /**
083         * @param returnType can be null if not applicable (e.g. {@code annotated} is a class)
084         */
085        public void genAnnotations(@Nullable Annotated annotated, @Nullable Type returnType) {
086            genAnnotations(annotated, returnType, null);
087        }
088    
089        public void genAnnotations(@Nullable Annotated annotated, @Nullable Type returnType, @Nullable AnnotationUseSiteTarget allowedTarget) {
090            if (annotated == null) {
091                return;
092            }
093    
094            Set<String> annotationDescriptorsAlreadyPresent = new HashSet<String>();
095    
096            Annotations annotations = annotated.getAnnotations();
097    
098            for (AnnotationWithTarget annotationWithTarget : annotations.getAllAnnotations()) {
099                AnnotationDescriptor annotation = annotationWithTarget.getAnnotation();
100                AnnotationUseSiteTarget annotationTarget = annotationWithTarget.getTarget();
101    
102                // Skip targeted annotations by default
103                if (allowedTarget == null && annotationTarget != null) continue;
104    
105                // Skip if the target is not the same
106                if (allowedTarget != null && annotationTarget != null && allowedTarget != annotationTarget) continue;
107    
108                String descriptor = genAnnotation(annotation);
109                if (descriptor != null) {
110                    annotationDescriptorsAlreadyPresent.add(descriptor);
111                }
112            }
113    
114            generateAdditionalAnnotations(annotated, returnType, annotationDescriptorsAlreadyPresent);
115        }
116    
117        private void generateAdditionalAnnotations(
118                @NotNull Annotated annotated,
119                @Nullable Type returnType,
120                @NotNull Set<String> annotationDescriptorsAlreadyPresent
121        ) {
122            Annotated unwrapped = annotated;
123            if (annotated instanceof WrappedAnnotated) {
124                unwrapped = ((WrappedAnnotated) annotated).getOriginalAnnotated();
125            }
126    
127            if (unwrapped instanceof CallableDescriptor) {
128                CallableDescriptor descriptor = (CallableDescriptor) unwrapped;
129    
130                // No need to annotate privates, synthetic accessors and their parameters
131                if (isInvisibleFromTheOutside(descriptor)) return;
132                if (descriptor instanceof ValueParameterDescriptor && isInvisibleFromTheOutside(descriptor.getContainingDeclaration())) return;
133    
134                if (returnType != null && !AsmUtil.isPrimitive(returnType)) {
135                    generateNullabilityAnnotation(descriptor.getReturnType(), annotationDescriptorsAlreadyPresent);
136                }
137            }
138            if (unwrapped instanceof ClassDescriptor) {
139                ClassDescriptor classDescriptor = (ClassDescriptor) unwrapped;
140                if (classDescriptor.getKind() == ClassKind.ANNOTATION_CLASS) {
141                    generateDocumentedAnnotation(classDescriptor, annotationDescriptorsAlreadyPresent);
142                    generateRetentionAnnotation(classDescriptor, annotationDescriptorsAlreadyPresent);
143                    generateTargetAnnotation(classDescriptor, annotationDescriptorsAlreadyPresent);
144                }
145            }
146        }
147    
148        private static boolean isInvisibleFromTheOutside(@Nullable DeclarationDescriptor descriptor) {
149            if (descriptor instanceof CallableMemberDescriptor && JetTypeMapper.isAccessor((CallableMemberDescriptor) descriptor)) return false;
150            if (descriptor instanceof MemberDescriptor) {
151                return AsmUtil.getVisibilityAccessFlag((MemberDescriptor) descriptor) == Opcodes.ACC_PRIVATE;
152            }
153            return false;
154        }
155    
156        private void generateNullabilityAnnotation(@Nullable JetType type, @NotNull Set<String> annotationDescriptorsAlreadyPresent) {
157            if (type == null) return;
158    
159            if (isBareTypeParameterWithNullableUpperBound(type)) {
160                // This is to account for the case of, say
161                //   class Function<R> { fun invoke(): R }
162                // it would be a shame to put @Nullable on the return type of the function, and force all callers to check for null,
163                // so we put no annotations
164                return;
165            }
166    
167            if (TypesPackage.isFlexible(type)) {
168                // A flexible type whose lower bound in not-null and upper bound is nullable, should not be annotated
169                Flexibility flexibility = TypesPackage.flexibility(type);
170    
171                if (!TypeUtils.isNullableType(flexibility.getLowerBound()) && TypeUtils.isNullableType(flexibility.getUpperBound())) {
172                    AnnotationDescriptor notNull = type.getAnnotations().findAnnotation(JvmAnnotationNames.JETBRAINS_NOT_NULL_ANNOTATION);
173                    if (notNull != null) {
174                        generateAnnotationIfNotPresent(annotationDescriptorsAlreadyPresent, NotNull.class);
175                    }
176                    return;
177                }
178            }
179    
180            boolean isNullableType = TypeUtils.isNullableType(type);
181    
182            Class<?> annotationClass = isNullableType ? Nullable.class : NotNull.class;
183    
184            generateAnnotationIfNotPresent(annotationDescriptorsAlreadyPresent, annotationClass);
185        }
186    
187        private static final Map<KotlinTarget, ElementType> annotationTargetMap =
188                new EnumMap<KotlinTarget, ElementType>(KotlinTarget.class);
189    
190        static {
191            annotationTargetMap.put(KotlinTarget.CLASS, ElementType.TYPE);
192            annotationTargetMap.put(KotlinTarget.ANNOTATION_CLASS, ElementType.ANNOTATION_TYPE);
193            annotationTargetMap.put(KotlinTarget.CONSTRUCTOR, ElementType.CONSTRUCTOR);
194            annotationTargetMap.put(KotlinTarget.LOCAL_VARIABLE, ElementType.LOCAL_VARIABLE);
195            annotationTargetMap.put(KotlinTarget.FUNCTION, ElementType.METHOD);
196            annotationTargetMap.put(KotlinTarget.PROPERTY_GETTER, ElementType.METHOD);
197            annotationTargetMap.put(KotlinTarget.PROPERTY_SETTER, ElementType.METHOD);
198            annotationTargetMap.put(KotlinTarget.FIELD, ElementType.FIELD);
199            annotationTargetMap.put(KotlinTarget.VALUE_PARAMETER, ElementType.PARAMETER);
200        }
201    
202        private void generateTargetAnnotation(@NotNull ClassDescriptor classDescriptor, @NotNull Set<String> annotationDescriptorsAlreadyPresent) {
203            String descriptor = Type.getType(Target.class).getDescriptor();
204            if (!annotationDescriptorsAlreadyPresent.add(descriptor)) return;
205            Set<KotlinTarget> targets = AnnotationChecker.Companion.applicableTargetSet(classDescriptor);
206            Set<ElementType> javaTargets;
207            if (targets == null) {
208                javaTargets = getJavaTargetList(classDescriptor);
209                if (javaTargets == null) return;
210            }
211            else {
212                javaTargets = EnumSet.noneOf(ElementType.class);
213                for (KotlinTarget target : targets) {
214                    if (annotationTargetMap.get(target) == null) continue;
215                    javaTargets.add(annotationTargetMap.get(target));
216                }
217            }
218            AnnotationVisitor visitor = visitAnnotation(descriptor, true);
219            AnnotationVisitor arrayVisitor = visitor.visitArray("value");
220            for (ElementType javaTarget : javaTargets) {
221                arrayVisitor.visitEnum(null, Type.getType(ElementType.class).getDescriptor(), javaTarget.name());
222            }
223            arrayVisitor.visitEnd();
224            visitor.visitEnd();
225        }
226    
227        private void generateRetentionAnnotation(@NotNull ClassDescriptor classDescriptor, @NotNull Set<String> annotationDescriptorsAlreadyPresent) {
228            RetentionPolicy policy = getRetentionPolicy(classDescriptor);
229            String descriptor = Type.getType(Retention.class).getDescriptor();
230            if (!annotationDescriptorsAlreadyPresent.add(descriptor)) return;
231            AnnotationVisitor visitor = visitAnnotation(descriptor, true);
232            visitor.visitEnum("value", Type.getType(RetentionPolicy.class).getDescriptor(), policy.name());
233            visitor.visitEnd();
234        }
235    
236        private void generateDocumentedAnnotation(@NotNull ClassDescriptor classDescriptor, @NotNull Set<String> annotationDescriptorsAlreadyPresent) {
237            boolean documented = DescriptorUtilPackage.isDocumentedAnnotation(classDescriptor);
238            if (!documented) return;
239            String descriptor = Type.getType(Documented.class).getDescriptor();
240            if (!annotationDescriptorsAlreadyPresent.add(descriptor)) return;
241            AnnotationVisitor visitor = visitAnnotation(descriptor, true);
242            visitor.visitEnd();
243        }
244    
245        private void generateAnnotationIfNotPresent(Set<String> annotationDescriptorsAlreadyPresent, Class<?> annotationClass) {
246            String descriptor = Type.getType(annotationClass).getDescriptor();
247            if (!annotationDescriptorsAlreadyPresent.contains(descriptor)) {
248                visitAnnotation(descriptor, false).visitEnd();
249            }
250        }
251    
252        private static boolean isBareTypeParameterWithNullableUpperBound(@NotNull JetType type) {
253            ClassifierDescriptor classifier = type.getConstructor().getDeclarationDescriptor();
254            return !type.isMarkedNullable() && classifier instanceof TypeParameterDescriptor && TypeUtils.hasNullableSuperType(type);
255        }
256    
257        public void generateAnnotationDefaultValue(@NotNull ConstantValue<?> value, @NotNull JetType expectedType) {
258            AnnotationVisitor visitor = visitAnnotation(null, false);  // Parameters are unimportant
259            genCompileTimeValue(null, value, visitor);
260            visitor.visitEnd();
261        }
262    
263        @Nullable
264        private String genAnnotation(@NotNull AnnotationDescriptor annotationDescriptor) {
265            ClassifierDescriptor classifierDescriptor = annotationDescriptor.getType().getConstructor().getDeclarationDescriptor();
266            assert classifierDescriptor != null : "Annotation descriptor has no class: " + annotationDescriptor;
267            RetentionPolicy rp = getRetentionPolicy(classifierDescriptor);
268            if (rp == RetentionPolicy.SOURCE && typeMapper.getClassBuilderMode() != ClassBuilderMode.LIGHT_CLASSES) {
269                return null;
270            }
271    
272            String descriptor = typeMapper.mapType(annotationDescriptor.getType()).getDescriptor();
273            AnnotationVisitor annotationVisitor = visitAnnotation(descriptor, rp == RetentionPolicy.RUNTIME);
274    
275            genAnnotationArguments(annotationDescriptor, annotationVisitor);
276            annotationVisitor.visitEnd();
277    
278            return descriptor;
279        }
280    
281        private void genAnnotationArguments(AnnotationDescriptor annotationDescriptor, AnnotationVisitor annotationVisitor) {
282            for (Map.Entry<ValueParameterDescriptor, ConstantValue<?>> entry : annotationDescriptor.getAllValueArguments().entrySet()) {
283                ValueParameterDescriptor descriptor = entry.getKey();
284                String name = descriptor.getName().asString();
285                genCompileTimeValue(name, entry.getValue(), annotationVisitor);
286            }
287        }
288    
289        private void genCompileTimeValue(
290                @Nullable final String name,
291                @NotNull ConstantValue<?> value,
292                @NotNull final AnnotationVisitor annotationVisitor
293        ) {
294            AnnotationArgumentVisitor argumentVisitor = new AnnotationArgumentVisitor<Void, Void>() {
295                @Override
296                public Void visitLongValue(@NotNull LongValue value, Void data) {
297                    return visitSimpleValue(value);
298                }
299    
300                @Override
301                public Void visitIntValue(IntValue value, Void data) {
302                    return visitSimpleValue(value);
303                }
304    
305                @Override
306                public Void visitShortValue(ShortValue value, Void data) {
307                    return visitSimpleValue(value);
308                }
309    
310                @Override
311                public Void visitByteValue(ByteValue value, Void data) {
312                    return visitSimpleValue(value);
313                }
314    
315                @Override
316                public Void visitDoubleValue(DoubleValue value, Void data) {
317                    return visitSimpleValue(value);
318                }
319    
320                @Override
321                public Void visitFloatValue(FloatValue value, Void data) {
322                    return visitSimpleValue(value);
323                }
324    
325                @Override
326                public Void visitBooleanValue(BooleanValue value, Void data) {
327                    return visitSimpleValue(value);
328                }
329    
330                @Override
331                public Void visitCharValue(CharValue value, Void data) {
332                    return visitSimpleValue(value);
333                }
334    
335                @Override
336                public Void visitStringValue(StringValue value, Void data) {
337                    return visitSimpleValue(value);
338                }
339    
340                @Override
341                public Void visitEnumValue(EnumValue value, Void data) {
342                    String propertyName = value.getValue().getName().asString();
343                    annotationVisitor.visitEnum(name, typeMapper.mapType(value.getType()).getDescriptor(), propertyName);
344                    return null;
345                }
346    
347                @Override
348                public Void visitArrayValue(ArrayValue value, Void data) {
349                    AnnotationVisitor visitor = annotationVisitor.visitArray(name);
350                    for (ConstantValue<?> argument : value.getValue()) {
351                        genCompileTimeValue(null, argument, visitor);
352                    }
353                    visitor.visitEnd();
354                    return null;
355                }
356    
357                @Override
358                public Void visitAnnotationValue(AnnotationValue value, Void data) {
359                    String internalAnnName = typeMapper.mapType(value.getValue().getType()).getDescriptor();
360                    AnnotationVisitor visitor = annotationVisitor.visitAnnotation(name, internalAnnName);
361                    genAnnotationArguments(value.getValue(), visitor);
362                    visitor.visitEnd();
363                    return null;
364                }
365    
366                @Override
367                public Void visitKClassValue(KClassValue value, Void data) {
368                    annotationVisitor.visit(name, typeMapper.mapType(value.getValue()));
369                    return null;
370                }
371    
372                private Void visitSimpleValue(ConstantValue<?> value) {
373                    annotationVisitor.visit(name, value.getValue());
374                    return null;
375                }
376    
377                @Override
378                public Void visitErrorValue(ErrorValue value, Void data) {
379                    return visitUnsupportedValue(value);
380                }
381    
382                @Override
383                public Void visitNullValue(NullValue value, Void data) {
384                    return visitUnsupportedValue(value);
385                }
386    
387                private Void visitUnsupportedValue(ConstantValue<?> value) {
388                    throw new IllegalStateException("Don't know how to compile annotation value " + value);
389                }
390            };
391    
392            value.accept(argumentVisitor, null);
393        }
394    
395        private static final Map<KotlinRetention, RetentionPolicy> annotationRetentionMap =
396                new EnumMap<KotlinRetention, RetentionPolicy>(KotlinRetention.class);
397    
398        static {
399            annotationRetentionMap.put(KotlinRetention.SOURCE, RetentionPolicy.SOURCE);
400            annotationRetentionMap.put(KotlinRetention.BINARY, RetentionPolicy.CLASS);
401            annotationRetentionMap.put(KotlinRetention.RUNTIME, RetentionPolicy.RUNTIME);
402        }
403    
404        @Nullable
405        private Set<ElementType> getJavaTargetList(ClassDescriptor descriptor) {
406            AnnotationDescriptor targetAnnotation = descriptor.getAnnotations().findAnnotation(new FqName(Target.class.getName()));
407            if (targetAnnotation != null) {
408                Collection<ConstantValue<?>> valueArguments = targetAnnotation.getAllValueArguments().values();
409                if (!valueArguments.isEmpty()) {
410                    ConstantValue<?> compileTimeConstant = valueArguments.iterator().next();
411                    if (compileTimeConstant instanceof ArrayValue) {
412                        List<? extends ConstantValue<?>> values = ((ArrayValue) compileTimeConstant).getValue();
413                        Set<ElementType> result = EnumSet.noneOf(ElementType.class);
414                        for (ConstantValue<?> value : values) {
415                            if (value instanceof EnumValue) {
416                                ClassDescriptor enumEntry = ((EnumValue) value).getValue();
417                                JetType classObjectType = getClassObjectType(enumEntry);
418                                if (classObjectType != null) {
419                                    if ("java/lang/annotation/ElementType".equals(typeMapper.mapType(classObjectType).getInternalName())) {
420                                        result.add(ElementType.valueOf(enumEntry.getName().asString()));
421                                    }
422                                }
423                            }
424                        }
425                        return result;
426                    }
427                }
428            }
429            return null;
430        }
431    
432        @NotNull
433        private RetentionPolicy getRetentionPolicy(@NotNull Annotated descriptor) {
434            KotlinRetention retention = DescriptorUtilPackage.getAnnotationRetention(descriptor);
435            if (retention != null) {
436                return annotationRetentionMap.get(retention);
437            }
438            AnnotationDescriptor retentionAnnotation = descriptor.getAnnotations().findAnnotation(new FqName(Retention.class.getName()));
439            if (retentionAnnotation != null) {
440                Collection<ConstantValue<?>> valueArguments = retentionAnnotation.getAllValueArguments().values();
441                if (!valueArguments.isEmpty()) {
442                    ConstantValue<?> compileTimeConstant = valueArguments.iterator().next();
443                    if (compileTimeConstant instanceof EnumValue) {
444                        ClassDescriptor enumEntry = ((EnumValue) compileTimeConstant).getValue();
445                        JetType classObjectType = getClassObjectType(enumEntry);
446                        if (classObjectType != null) {
447                            if ("java/lang/annotation/RetentionPolicy".equals(typeMapper.mapType(classObjectType).getInternalName())) {
448                                return RetentionPolicy.valueOf(enumEntry.getName().asString());
449                            }
450                        }
451                    }
452                }
453            }
454    
455            return RetentionPolicy.RUNTIME;
456        }
457    
458        @NotNull
459        abstract AnnotationVisitor visitAnnotation(String descr, boolean visible);
460    
461        public static AnnotationCodegen forClass(final ClassVisitor cv, JetTypeMapper mapper) {
462            return new AnnotationCodegen(mapper) {
463                @NotNull
464                @Override
465                AnnotationVisitor visitAnnotation(String descr, boolean visible) {
466                    return safe(cv.visitAnnotation(descr, visible));
467                }
468            };
469        }
470    
471        public static AnnotationCodegen forMethod(final MethodVisitor mv, JetTypeMapper mapper) {
472            return new AnnotationCodegen(mapper) {
473                @NotNull
474                @Override
475                AnnotationVisitor visitAnnotation(String descr, boolean visible) {
476                    return safe(mv.visitAnnotation(descr, visible));
477                }
478            };
479        }
480    
481        public static AnnotationCodegen forField(final FieldVisitor fv, JetTypeMapper mapper) {
482            return new AnnotationCodegen(mapper) {
483                @NotNull
484                @Override
485                AnnotationVisitor visitAnnotation(String descr, boolean visible) {
486                    return safe(fv.visitAnnotation(descr, visible));
487                }
488            };
489        }
490    
491        public static AnnotationCodegen forParameter(final int parameter, final MethodVisitor mv, JetTypeMapper mapper) {
492            return new AnnotationCodegen(mapper) {
493                @NotNull
494                @Override
495                AnnotationVisitor visitAnnotation(String descr, boolean visible) {
496                    return safe(mv.visitParameterAnnotation(parameter, descr, visible));
497                }
498            };
499        }
500    
501        public static AnnotationCodegen forAnnotationDefaultValue(final MethodVisitor mv, JetTypeMapper mapper) {
502            return new AnnotationCodegen(mapper) {
503                @NotNull
504                @Override
505                AnnotationVisitor visitAnnotation(String descr, boolean visible) {
506                    return safe(mv.visitAnnotationDefault());
507                }
508            };
509        }
510    
511        @NotNull
512        private static AnnotationVisitor safe(@Nullable AnnotationVisitor av) {
513            return av == null ? NO_ANNOTATION_VISITOR : av;
514        }
515    }