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