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