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