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