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.asm4.AnnotationVisitor;
023 import org.jetbrains.asm4.ClassVisitor;
024 import org.jetbrains.asm4.FieldVisitor;
025 import org.jetbrains.asm4.MethodVisitor;
026 import org.jetbrains.jet.codegen.state.JetTypeMapper;
027 import org.jetbrains.jet.lang.descriptors.*;
028 import org.jetbrains.jet.lang.descriptors.annotations.Annotated;
029 import org.jetbrains.jet.lang.descriptors.annotations.AnnotationArgumentVisitor;
030 import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor;
031 import org.jetbrains.jet.lang.psi.JetAnnotationEntry;
032 import org.jetbrains.jet.lang.psi.JetClass;
033 import org.jetbrains.jet.lang.psi.JetModifierList;
034 import org.jetbrains.jet.lang.psi.JetModifierListOwner;
035 import org.jetbrains.jet.lang.resolve.BindingContext;
036 import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCall;
037 import org.jetbrains.jet.lang.resolve.constants.*;
038 import org.jetbrains.jet.lang.resolve.constants.StringValue;
039 import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
040
041 import java.lang.annotation.RetentionPolicy;
042 import java.util.List;
043 import java.util.Map;
044
045 import static org.jetbrains.jet.lang.resolve.BindingContextUtils.descriptorToDeclaration;
046
047 public abstract class AnnotationCodegen {
048 private final JetTypeMapper typeMapper;
049 private final BindingContext bindingContext;
050
051 private AnnotationCodegen(JetTypeMapper mapper) {
052 typeMapper = mapper;
053 bindingContext = typeMapper.getBindingContext();
054 }
055
056 public void genAnnotations(Annotated annotated) {
057 if (annotated == null) {
058 return;
059 }
060
061 if (!(annotated instanceof DeclarationDescriptor)) {
062 return;
063 }
064
065 PsiElement psiElement = descriptorToDeclaration(bindingContext, (DeclarationDescriptor) annotated);
066
067 JetModifierList modifierList = null;
068 if (annotated instanceof ConstructorDescriptor && psiElement instanceof JetClass) {
069 modifierList = ((JetClass) psiElement).getPrimaryConstructorModifierList();
070 }
071 else if (psiElement instanceof JetModifierListOwner) {
072 modifierList = ((JetModifierListOwner) psiElement).getModifierList();
073 }
074
075 if (modifierList == null) {
076 return;
077 }
078
079 List<JetAnnotationEntry> annotationEntries = modifierList.getAnnotationEntries();
080 for (JetAnnotationEntry annotationEntry : annotationEntries) {
081 ResolvedCall<? extends CallableDescriptor> resolvedCall =
082 bindingContext.get(BindingContext.RESOLVED_CALL, annotationEntry.getCalleeExpression());
083 if (resolvedCall == null) continue; // Skipping annotations if they are not resolved. Needed for JetLightClass generation
084
085 AnnotationDescriptor annotationDescriptor = bindingContext.get(BindingContext.ANNOTATION, annotationEntry);
086 if (annotationDescriptor == null) continue; // Skipping annotations if they are not resolved. Needed for JetLightClass generation
087
088 genAnnotation(annotationDescriptor);
089 }
090 }
091
092 private void genAnnotation(AnnotationDescriptor annotationDescriptor) {
093 ClassifierDescriptor classifierDescriptor = annotationDescriptor.getType().getConstructor().getDeclarationDescriptor();
094 RetentionPolicy rp = getRetentionPolicy(classifierDescriptor, typeMapper);
095 if (rp == RetentionPolicy.SOURCE) {
096 return;
097 }
098
099 String internalName = typeMapper.mapType(annotationDescriptor.getType()).getDescriptor();
100 AnnotationVisitor annotationVisitor = visitAnnotation(internalName, rp == RetentionPolicy.RUNTIME);
101
102 genAnnotationArguments(annotationDescriptor, annotationVisitor);
103 annotationVisitor.visitEnd();
104 }
105
106 private void genAnnotationArguments(AnnotationDescriptor annotationDescriptor, AnnotationVisitor annotationVisitor) {
107 for (Map.Entry<ValueParameterDescriptor, CompileTimeConstant<?>> entry : annotationDescriptor.getAllValueArguments().entrySet()) {
108 ValueParameterDescriptor descriptor = entry.getKey();
109 String name = descriptor.getName().asString();
110 genAnnotationArgument(name, entry.getValue(), annotationVisitor);
111 }
112 }
113
114 private void genAnnotationArgument(
115 @Nullable final String name,
116 @NotNull CompileTimeConstant<?> value,
117 @NotNull final AnnotationVisitor annotationVisitor
118 ) {
119 AnnotationArgumentVisitor argumentVisitor = new AnnotationArgumentVisitor<Void, Void>() {
120 @Override
121 public Void visitLongValue(@NotNull LongValue value, Void data) {
122 return visitSimpleValue(value);
123 }
124
125 @Override
126 public Void visitIntValue(IntValue value, Void data) {
127 return visitSimpleValue(value);
128 }
129
130 @Override
131 public Void visitShortValue(ShortValue value, Void data) {
132 return visitSimpleValue(value);
133 }
134
135 @Override
136 public Void visitByteValue(ByteValue value, Void data) {
137 return visitSimpleValue(value);
138 }
139
140 @Override
141 public Void visitDoubleValue(DoubleValue value, Void data) {
142 return visitSimpleValue(value);
143 }
144
145 @Override
146 public Void visitFloatValue(FloatValue value, Void data) {
147 return visitSimpleValue(value);
148 }
149
150 @Override
151 public Void visitBooleanValue(BooleanValue value, Void data) {
152 return visitSimpleValue(value);
153 }
154
155 @Override
156 public Void visitCharValue(CharValue value, Void data) {
157 return visitSimpleValue(value);
158 }
159
160 @Override
161 public Void visitStringValue(StringValue value, Void data) {
162 return visitSimpleValue(value);
163 }
164
165 @Override
166 public Void visitEnumValue(EnumValue value, Void data) {
167 String propertyName = value.getValue().getName().asString();
168 annotationVisitor.visitEnum(name, typeMapper.mapType(value.getType(KotlinBuiltIns.getInstance())).getDescriptor(), propertyName);
169 return null;
170 }
171
172 @Override
173 public Void visitArrayValue(ArrayValue value, Void data) {
174 AnnotationVisitor visitor = annotationVisitor.visitArray(name);
175 for (CompileTimeConstant<?> argument : value.getValue()) {
176 genAnnotationArgument(null, argument, visitor);
177 }
178 visitor.visitEnd();
179 return null;
180 }
181
182 @Override
183 public Void visitAnnotationValue(AnnotationValue value, Void data) {
184 String internalAnnName = typeMapper.mapType(value.getValue().getType()).getDescriptor();
185 AnnotationVisitor visitor = annotationVisitor.visitAnnotation(name, internalAnnName);
186 genAnnotationArguments(value.getValue(), visitor);
187 visitor.visitEnd();
188 return null;
189 }
190
191 @Override
192 public Void visitJavaClassValue(JavaClassValue value, Void data) {
193 annotationVisitor.visit(name, typeMapper.mapType(value.getValue()));
194 return null;
195 }
196
197 private Void visitSimpleValue(CompileTimeConstant value) {
198 annotationVisitor.visit(name, value.getValue());
199 return null;
200 }
201
202 @Override
203 public Void visitErrorValue(ErrorValue value, Void data) {
204 return visitUnsupportedValue(value);
205 }
206
207 @Override
208 public Void visitNullValue(NullValue value, Void data) {
209 return visitUnsupportedValue(value);
210 }
211
212 private Void visitUnsupportedValue(CompileTimeConstant value) {
213 throw new IllegalStateException("Don't know how to compile annotation value " + value);
214 }
215 };
216
217 value.accept(argumentVisitor, null);
218 }
219
220 private static RetentionPolicy getRetentionPolicy(ClassifierDescriptor descriptor, JetTypeMapper typeMapper) {
221 RetentionPolicy rp = RetentionPolicy.RUNTIME;
222 /*
223 @todo : when JavaDescriptoResolver provides ennough info
224 for (AnnotationDescriptor annotationDescriptor : descriptor.getAnnotations()) {
225 String internalName = typeMapper.mapType(annotationDescriptor.getType()).getInternalName();
226 if("java/lang/annotation/RetentionPolicy".equals(internalName)) {
227 CompileTimeConstant<?> compileTimeConstant = annotationDescriptor.getValueArguments().get(0);
228 System.out.println(compileTimeConstant);
229 break;
230 }
231 }
232 */
233 return rp; //To change body of created methods use File | Settings | File Templates.
234 }
235
236 abstract AnnotationVisitor visitAnnotation(String descr, boolean visible);
237
238 public static AnnotationCodegen forClass(final ClassVisitor cv, JetTypeMapper mapper) {
239 return new AnnotationCodegen(mapper) {
240 @Override
241 AnnotationVisitor visitAnnotation(String descr, boolean visible) {
242 return cv.visitAnnotation(descr, visible);
243 }
244 };
245 }
246
247 public static AnnotationCodegen forMethod(final MethodVisitor mv, JetTypeMapper mapper) {
248 return new AnnotationCodegen(mapper) {
249 @Override
250 AnnotationVisitor visitAnnotation(String descr, boolean visible) {
251 return mv.visitAnnotation(descr, visible);
252 }
253 };
254 }
255
256 public static AnnotationCodegen forField(final FieldVisitor fv, JetTypeMapper mapper) {
257 return new AnnotationCodegen(mapper) {
258 @Override
259 AnnotationVisitor visitAnnotation(String descr, boolean visible) {
260 return fv.visitAnnotation(descr, visible);
261 }
262 };
263 }
264
265 public static AnnotationCodegen forParameter(final int parameter, final MethodVisitor mv, JetTypeMapper mapper) {
266 return new AnnotationCodegen(mapper) {
267 @Override
268 AnnotationVisitor visitAnnotation(String descr, boolean visible) {
269 return mv.visitParameterAnnotation(parameter, descr, visible);
270 }
271 };
272 }
273 }