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.jet.codegen.state.JetTypeMapper;
023    import org.jetbrains.jet.descriptors.serialization.descriptors.DeserializedCallableMemberDescriptor;
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.java.JvmAnnotationNames;
037    import org.jetbrains.jet.lang.resolve.name.FqName;
038    import org.jetbrains.jet.lang.types.Flexibility;
039    import org.jetbrains.jet.lang.types.JetType;
040    import org.jetbrains.jet.lang.types.TypeUtils;
041    import org.jetbrains.jet.lang.types.TypesPackage;
042    import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
043    import org.jetbrains.org.objectweb.asm.*;
044    
045    import java.lang.annotation.Retention;
046    import java.lang.annotation.RetentionPolicy;
047    import java.util.*;
048    
049    import static org.jetbrains.jet.lang.descriptors.CallableMemberDescriptor.Kind.DELEGATION;
050    import static org.jetbrains.jet.lang.resolve.DescriptorToSourceUtils.descriptorToDeclaration;
051    import static org.jetbrains.jet.lang.resolve.calls.callUtil.CallUtilPackage.getResolvedCall;
052    
053    public abstract class AnnotationCodegen {
054    
055        public static final class JvmFlagAnnotation {
056            private final FqName fqName;
057            private final int jvmFlag;
058    
059            public JvmFlagAnnotation(@NotNull String fqName, int jvmFlag) {
060                this.fqName = new FqName(fqName);
061                this.jvmFlag = jvmFlag;
062            }
063    
064            public boolean hasAnnotation(@NotNull Annotated annotated) {
065                return annotated.getAnnotations().findAnnotation(fqName) != null;
066            }
067    
068            public int getJvmFlag() {
069                return jvmFlag;
070            }
071        }
072    
073        public static final List<JvmFlagAnnotation> FIELD_FLAGS = Arrays.asList(
074                new JvmFlagAnnotation("kotlin.jvm.volatile", Opcodes.ACC_VOLATILE),
075                new JvmFlagAnnotation("kotlin.jvm.transient", Opcodes.ACC_TRANSIENT)
076        );
077    
078        public static final List<JvmFlagAnnotation> METHOD_FLAGS = Arrays.asList(
079                new JvmFlagAnnotation("kotlin.jvm.strictfp", Opcodes.ACC_STRICT),
080                new JvmFlagAnnotation("kotlin.jvm.synchronized", Opcodes.ACC_SYNCHRONIZED),
081                new JvmFlagAnnotation("kotlin.jvm.native", Opcodes.ACC_NATIVE)
082        );
083    
084        private static final AnnotationVisitor NO_ANNOTATION_VISITOR = new AnnotationVisitor(Opcodes.ASM5) {};
085    
086        private final JetTypeMapper typeMapper;
087        private final BindingContext bindingContext;
088    
089        private AnnotationCodegen(JetTypeMapper mapper) {
090            typeMapper = mapper;
091            bindingContext = typeMapper.getBindingContext();
092        }
093    
094        /**
095         * @param returnType can be null if not applicable (e.g. {@code annotated} is a class)
096         */
097        public void genAnnotations(@Nullable Annotated annotated, @Nullable Type returnType) {
098            if (annotated == null) {
099                return;
100            }
101    
102            if (!(annotated instanceof DeclarationDescriptor)) {
103                return;
104            }
105    
106            PsiElement psiElement;
107            if (annotated instanceof CallableMemberDescriptor && ((CallableMemberDescriptor) annotated).getKind() == DELEGATION) {
108                psiElement = null;
109            }
110            else {
111                psiElement = descriptorToDeclaration((DeclarationDescriptor) annotated);
112            }
113    
114            JetModifierList modifierList = null;
115            if (annotated instanceof ConstructorDescriptor && psiElement instanceof JetClass) {
116                modifierList = ((JetClass) psiElement).getPrimaryConstructorModifierList();
117            }
118            else if (psiElement instanceof JetModifierListOwner) {
119                modifierList = ((JetModifierListOwner) psiElement).getModifierList();
120            }
121    
122            Set<String> annotationDescriptorsAlreadyPresent = new HashSet<String>();
123    
124            if (modifierList == null) {
125                if (annotated instanceof CallableMemberDescriptor &&
126                    JvmCodegenUtil.getDirectMember((CallableMemberDescriptor) annotated) instanceof DeserializedCallableMemberDescriptor) {
127                    for (AnnotationDescriptor annotation : annotated.getAnnotations()) {
128                        String descriptor = genAnnotation(annotation);
129                        if (descriptor != null) {
130                            annotationDescriptorsAlreadyPresent.add(descriptor);
131                        }
132                    }
133                }
134            }
135            else {
136                List<JetAnnotationEntry> annotationEntries = modifierList.getAnnotationEntries();
137                for (JetAnnotationEntry annotationEntry : annotationEntries) {
138                    ResolvedCall<?> resolvedCall = getResolvedCall(annotationEntry, bindingContext);
139                    if (resolvedCall == null) continue; // Skipping annotations if they are not resolved. Needed for JetLightClass generation
140    
141                    AnnotationDescriptor annotationDescriptor = bindingContext.get(BindingContext.ANNOTATION, annotationEntry);
142                    if (annotationDescriptor == null) continue; // Skipping annotations if they are not resolved. Needed for JetLightClass generation
143    
144                    String descriptor = genAnnotation(annotationDescriptor);
145                    if (descriptor != null) {
146                        annotationDescriptorsAlreadyPresent.add(descriptor);
147                    }
148                }
149            }
150    
151            generateAdditionalAnnotations(annotated, returnType, annotationDescriptorsAlreadyPresent);
152        }
153    
154        private void generateAdditionalAnnotations(
155                @NotNull Annotated annotated,
156                @Nullable Type returnType,
157                @NotNull Set<String> annotationDescriptorsAlreadyPresent
158        ) {
159            if (annotated instanceof CallableDescriptor) {
160                CallableDescriptor descriptor = (CallableDescriptor) annotated;
161    
162                // No need to annotate privates, synthetic accessors and their parameters
163                if (isInvisibleFromTheOutside(descriptor)) return;
164                if (descriptor instanceof ValueParameterDescriptor && isInvisibleFromTheOutside(descriptor.getContainingDeclaration())) return;
165    
166                if (returnType != null && !AsmUtil.isPrimitive(returnType)) {
167                    generateNullabilityAnnotation(descriptor.getReturnType(), annotationDescriptorsAlreadyPresent);
168                }
169            }
170        }
171    
172        private static boolean isInvisibleFromTheOutside(@Nullable DeclarationDescriptor descriptor) {
173            if (descriptor instanceof CallableMemberDescriptor && JetTypeMapper.isAccessor((CallableMemberDescriptor) descriptor)) return false;
174            if (descriptor instanceof MemberDescriptor) {
175                return AsmUtil.getVisibilityAccessFlag((MemberDescriptor) descriptor) == Opcodes.ACC_PRIVATE;
176            }
177            return false;
178        }
179    
180        private void generateNullabilityAnnotation(@Nullable JetType type, @NotNull Set<String> annotationDescriptorsAlreadyPresent) {
181            if (type == null) return;
182    
183            if (isBareTypeParameterWithNullableUpperBound(type)) {
184                // This is to account for the case of, say
185                //   class Function<R> { fun invoke(): R }
186                // it would be a shame to put @Nullable on the return type of the function, and force all callers to check for null,
187                // so we put no annotations
188                return;
189            }
190    
191            if (TypesPackage.isFlexible(type)) {
192                // A flexible type whose lower bound in not-null and upper bound is nullable, should not be annotated
193                Flexibility flexibility = TypesPackage.flexibility(type);
194    
195                if (!TypeUtils.isNullableType(flexibility.getLowerBound()) && TypeUtils.isNullableType(flexibility.getUpperBound())) {
196                    AnnotationDescriptor notNull = type.getAnnotations().findAnnotation(JvmAnnotationNames.JETBRAINS_NOT_NULL_ANNOTATION);
197                    if (notNull != null) {
198                        generateAnnotationIfNotPresent(annotationDescriptorsAlreadyPresent, NotNull.class);
199                    }
200                    return;
201                }
202            }
203    
204            boolean isNullableType = TypeUtils.isNullableType(type);
205    
206            Class<?> annotationClass = isNullableType ? Nullable.class : NotNull.class;
207    
208            generateAnnotationIfNotPresent(annotationDescriptorsAlreadyPresent, annotationClass);
209        }
210    
211        private void generateAnnotationIfNotPresent(Set<String> annotationDescriptorsAlreadyPresent, Class<?> annotationClass) {
212            String descriptor = Type.getType(annotationClass).getDescriptor();
213            if (!annotationDescriptorsAlreadyPresent.contains(descriptor)) {
214                visitAnnotation(descriptor, false).visitEnd();
215            }
216        }
217    
218        private static boolean isBareTypeParameterWithNullableUpperBound(@NotNull JetType type) {
219            ClassifierDescriptor classifier = type.getConstructor().getDeclarationDescriptor();
220            return !type.isMarkedNullable() && classifier instanceof TypeParameterDescriptor && TypeUtils.hasNullableSuperType(type);
221        }
222    
223        public void generateAnnotationDefaultValue(@NotNull CompileTimeConstant value, @NotNull JetType expectedType) {
224            AnnotationVisitor visitor = visitAnnotation(null, false);  // Parameters are unimportant
225            genCompileTimeValue(null, value, expectedType, visitor);
226            visitor.visitEnd();
227        }
228    
229        @Nullable
230        private String genAnnotation(@NotNull AnnotationDescriptor annotationDescriptor) {
231            ClassifierDescriptor classifierDescriptor = annotationDescriptor.getType().getConstructor().getDeclarationDescriptor();
232            assert classifierDescriptor != null : "Annotation descriptor has no class: " + annotationDescriptor;
233            RetentionPolicy rp = getRetentionPolicy(classifierDescriptor);
234            if (rp == RetentionPolicy.SOURCE) {
235                return null;
236            }
237    
238            String descriptor = typeMapper.mapType(annotationDescriptor.getType()).getDescriptor();
239            AnnotationVisitor annotationVisitor = visitAnnotation(descriptor, rp == RetentionPolicy.RUNTIME);
240    
241            genAnnotationArguments(annotationDescriptor, annotationVisitor);
242            annotationVisitor.visitEnd();
243    
244            return descriptor;
245        }
246    
247        private void genAnnotationArguments(AnnotationDescriptor annotationDescriptor, AnnotationVisitor annotationVisitor) {
248            for (Map.Entry<ValueParameterDescriptor, CompileTimeConstant<?>> entry : annotationDescriptor.getAllValueArguments().entrySet()) {
249                ValueParameterDescriptor descriptor = entry.getKey();
250                String name = descriptor.getName().asString();
251                genCompileTimeValue(name, entry.getValue(), descriptor.getType(), annotationVisitor);
252            }
253        }
254    
255        private void genCompileTimeValue(
256                @Nullable final String name,
257                @NotNull CompileTimeConstant<?> value,
258                @NotNull final JetType expectedType,
259                @NotNull final AnnotationVisitor annotationVisitor
260        ) {
261            AnnotationArgumentVisitor argumentVisitor = new AnnotationArgumentVisitor<Void, Void>() {
262                @Override
263                public Void visitLongValue(@NotNull LongValue value, Void data) {
264                    return visitSimpleValue(value);
265                }
266    
267                @Override
268                public Void visitIntValue(IntValue value, Void data) {
269                    return visitSimpleValue(value);
270                }
271    
272                @Override
273                public Void visitShortValue(ShortValue value, Void data) {
274                    return visitSimpleValue(value);
275                }
276    
277                @Override
278                public Void visitByteValue(ByteValue value, Void data) {
279                    return visitSimpleValue(value);
280                }
281    
282                @Override
283                public Void visitDoubleValue(DoubleValue value, Void data) {
284                    return visitSimpleValue(value);
285                }
286    
287                @Override
288                public Void visitFloatValue(FloatValue value, Void data) {
289                    return visitSimpleValue(value);
290                }
291    
292                @Override
293                public Void visitBooleanValue(BooleanValue value, Void data) {
294                    return visitSimpleValue(value);
295                }
296    
297                @Override
298                public Void visitCharValue(CharValue value, Void data) {
299                    return visitSimpleValue(value);
300                }
301    
302                @Override
303                public Void visitStringValue(StringValue value, Void data) {
304                    return visitSimpleValue(value);
305                }
306    
307                @Override
308                public Void visitEnumValue(EnumValue value, Void data) {
309                    String propertyName = value.getValue().getName().asString();
310                    annotationVisitor.visitEnum(name, typeMapper.mapType(value.getType(KotlinBuiltIns.getInstance())).getDescriptor(), propertyName);
311                    return null;
312                }
313    
314                @Override
315                public Void visitArrayValue(ArrayValue value, Void data) {
316                    AnnotationVisitor visitor = annotationVisitor.visitArray(name);
317                    for (CompileTimeConstant<?> argument : value.getValue()) {
318                        genCompileTimeValue(null, argument, value.getType(KotlinBuiltIns.getInstance()), visitor);
319                    }
320                    visitor.visitEnd();
321                    return null;
322                }
323    
324                @Override
325                public Void visitAnnotationValue(AnnotationValue value, Void data) {
326                    String internalAnnName = typeMapper.mapType(value.getValue().getType()).getDescriptor();
327                    AnnotationVisitor visitor = annotationVisitor.visitAnnotation(name, internalAnnName);
328                    genAnnotationArguments(value.getValue(), visitor);
329                    visitor.visitEnd();
330                    return null;
331                }
332    
333                @Override
334                public Void visitJavaClassValue(JavaClassValue value, Void data) {
335                    annotationVisitor.visit(name, typeMapper.mapType(value.getValue()));
336                    return null;
337                }
338    
339                @Override
340                public Void visitNumberTypeValue(IntegerValueTypeConstant value, Void data) {
341                    Object numberType = value.getValue(expectedType);
342                    annotationVisitor.visit(name, numberType);
343                    return null;
344                }
345    
346                private Void visitSimpleValue(CompileTimeConstant value) {
347                    annotationVisitor.visit(name, value.getValue());
348                    return null;
349                }
350    
351                @Override
352                public Void visitErrorValue(ErrorValue value, Void data) {
353                    return visitUnsupportedValue(value);
354                }
355    
356                @Override
357                public Void visitNullValue(NullValue value, Void data) {
358                    return visitUnsupportedValue(value);
359                }
360    
361                private Void visitUnsupportedValue(CompileTimeConstant value) {
362                    throw new IllegalStateException("Don't know how to compile annotation value " + value);
363                }
364            };
365    
366            value.accept(argumentVisitor, null);
367        }
368    
369        @NotNull
370        private RetentionPolicy getRetentionPolicy(@NotNull Annotated descriptor) {
371            AnnotationDescriptor retentionAnnotation = descriptor.getAnnotations().findAnnotation(new FqName(Retention.class.getName()));
372            if (retentionAnnotation != null) {
373                Collection<CompileTimeConstant<?>> valueArguments = retentionAnnotation.getAllValueArguments().values();
374                if (!valueArguments.isEmpty()) {
375                    CompileTimeConstant<?> compileTimeConstant = valueArguments.iterator().next();
376                    if (compileTimeConstant instanceof EnumValue) {
377                        ClassDescriptor enumEntry = ((EnumValue) compileTimeConstant).getValue();
378                        JetType classObjectType = enumEntry.getClassObjectType();
379                        if (classObjectType != null) {
380                            if ("java/lang/annotation/RetentionPolicy".equals(typeMapper.mapType(classObjectType).getInternalName())) {
381                                return RetentionPolicy.valueOf(enumEntry.getName().asString());
382                            }
383                        }
384                    }
385                }
386            }
387    
388            return RetentionPolicy.CLASS;
389        }
390    
391        @NotNull
392        abstract AnnotationVisitor visitAnnotation(String descr, boolean visible);
393    
394        public static AnnotationCodegen forClass(final ClassVisitor cv, JetTypeMapper mapper) {
395            return new AnnotationCodegen(mapper) {
396                @NotNull
397                @Override
398                AnnotationVisitor visitAnnotation(String descr, boolean visible) {
399                    return safe(cv.visitAnnotation(descr, visible));
400                }
401            };
402        }
403    
404        public static AnnotationCodegen forMethod(final MethodVisitor mv, JetTypeMapper mapper) {
405            return new AnnotationCodegen(mapper) {
406                @NotNull
407                @Override
408                AnnotationVisitor visitAnnotation(String descr, boolean visible) {
409                    return safe(mv.visitAnnotation(descr, visible));
410                }
411            };
412        }
413    
414        public static AnnotationCodegen forField(final FieldVisitor fv, JetTypeMapper mapper) {
415            return new AnnotationCodegen(mapper) {
416                @NotNull
417                @Override
418                AnnotationVisitor visitAnnotation(String descr, boolean visible) {
419                    return safe(fv.visitAnnotation(descr, visible));
420                }
421            };
422        }
423    
424        public static AnnotationCodegen forParameter(final int parameter, final MethodVisitor mv, JetTypeMapper mapper) {
425            return new AnnotationCodegen(mapper) {
426                @NotNull
427                @Override
428                AnnotationVisitor visitAnnotation(String descr, boolean visible) {
429                    return safe(mv.visitParameterAnnotation(parameter, descr, visible));
430                }
431            };
432        }
433    
434        public static AnnotationCodegen forAnnotationDefaultValue(final MethodVisitor mv, JetTypeMapper mapper) {
435            return new AnnotationCodegen(mapper) {
436                @NotNull
437                @Override
438                AnnotationVisitor visitAnnotation(String descr, boolean visible) {
439                    return safe(mv.visitAnnotationDefault());
440                }
441            };
442        }
443    
444        @NotNull
445        private static AnnotationVisitor safe(@Nullable AnnotationVisitor av) {
446            return av == null ? NO_ANNOTATION_VISITOR : av;
447        }
448    }