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