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.descriptors.serialization;
018
019 import org.jetbrains.annotations.NotNull;
020 import org.jetbrains.jet.lang.descriptors.*;
021 import org.jetbrains.jet.lang.descriptors.annotations.Annotated;
022 import org.jetbrains.jet.lang.types.*;
023 import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
024 import org.jetbrains.jet.renderer.DescriptorRenderer;
025
026 import java.util.*;
027
028 import static org.jetbrains.jet.lang.resolve.DescriptorUtils.getEnumEntriesScope;
029 import static org.jetbrains.jet.lang.resolve.DescriptorUtils.isTopLevelOrInnerClass;
030
031 public class DescriptorSerializer {
032
033 private static final DescriptorRenderer RENDERER = DescriptorRenderer.STARTS_FROM_NAME;
034 private static final Comparator<DeclarationDescriptor> DESCRIPTOR_COMPARATOR = new Comparator<DeclarationDescriptor>() {
035 @Override
036 public int compare(
037 DeclarationDescriptor o1, DeclarationDescriptor o2
038 ) {
039 int names = o1.getName().compareTo(o2.getName());
040 if (names != 0) return names;
041
042 String o1String = RENDERER.render(o1);
043 String o2String = RENDERER.render(o2);
044 return o1String.compareTo(o2String);
045 }
046 };
047 private final NameTable nameTable;
048 private final Interner<TypeParameterDescriptor> typeParameters;
049 private final SerializerExtension extension;
050
051 public DescriptorSerializer() {
052 this(SerializerExtension.DEFAULT);
053 }
054
055 public DescriptorSerializer(@NotNull SerializerExtension extension) {
056 this(new NameTable(), new Interner<TypeParameterDescriptor>(), extension);
057 }
058
059 private DescriptorSerializer(NameTable nameTable, Interner<TypeParameterDescriptor> typeParameters, SerializerExtension extension) {
060 this.nameTable = nameTable;
061 this.typeParameters = typeParameters;
062 this.extension = extension;
063 }
064
065 private DescriptorSerializer createChildSerializer() {
066 return new DescriptorSerializer(nameTable, new Interner<TypeParameterDescriptor>(typeParameters), extension);
067 }
068
069 @NotNull
070 public NameTable getNameTable() {
071 return nameTable;
072 }
073
074 @NotNull
075 public ProtoBuf.Class.Builder classProto(@NotNull ClassDescriptor classDescriptor) {
076 ProtoBuf.Class.Builder builder = ProtoBuf.Class.newBuilder();
077
078 int flags = Flags.getClassFlags(hasAnnotations(classDescriptor), classDescriptor.getVisibility(),
079 classDescriptor.getModality(), classDescriptor.getKind(), classDescriptor.isInner());
080 builder.setFlags(flags);
081
082 // TODO extra visibility
083
084 builder.setName(nameTable.getSimpleNameIndex(classDescriptor.getName()));
085
086 DescriptorSerializer local = createChildSerializer();
087
088 for (TypeParameterDescriptor typeParameterDescriptor : classDescriptor.getTypeConstructor().getParameters()) {
089 builder.addTypeParameter(local.typeParameter(typeParameterDescriptor));
090 }
091
092 if (extension.hasSupertypes(classDescriptor)) {
093 // Special classes (Any, Nothing) have no supertypes
094 for (JetType supertype : classDescriptor.getTypeConstructor().getSupertypes()) {
095 builder.addSupertype(local.type(supertype));
096 }
097 }
098
099 ConstructorDescriptor primaryConstructor = classDescriptor.getUnsubstitutedPrimaryConstructor();
100 if (primaryConstructor != null) {
101 builder.setPrimaryConstructor(local.callableProto(primaryConstructor));
102 }
103 // TODO: other constructors
104
105 for (DeclarationDescriptor descriptor : sort(classDescriptor.getDefaultType().getMemberScope().getAllDescriptors())) {
106 if (descriptor instanceof CallableMemberDescriptor) {
107 CallableMemberDescriptor member = (CallableMemberDescriptor) descriptor;
108 if (member.getKind() == CallableMemberDescriptor.Kind.FAKE_OVERRIDE) continue;
109 builder.addMember(local.callableProto(member));
110 }
111 }
112
113 Collection<DeclarationDescriptor> nestedClasses = classDescriptor.getUnsubstitutedInnerClassesScope().getAllDescriptors();
114 for (DeclarationDescriptor descriptor : sort(nestedClasses)) {
115 ClassDescriptor nestedClass = (ClassDescriptor) descriptor;
116 int nameIndex = nameTable.getSimpleNameIndex(nestedClass.getName());
117 builder.addNestedClassName(nameIndex);
118 }
119
120 for (ClassDescriptor descriptor : sort(classDescriptor.getUnsubstitutedInnerClassesScope().getObjectDescriptors())) {
121 int nameIndex = nameTable.getSimpleNameIndex(descriptor.getName());
122 builder.addNestedObjectName(nameIndex);
123 }
124
125 if (classDescriptor.getClassObjectDescriptor() != null) {
126 // false is default
127 builder.setClassObjectPresent(true);
128 }
129
130 if (classDescriptor.getKind() == ClassKind.ENUM_CLASS) {
131 for (ClassDescriptor descriptor : getEnumEntriesScope(classDescriptor).getObjectDescriptors()) {
132 if (descriptor.getKind() == ClassKind.ENUM_ENTRY) {
133 builder.addEnumEntry(nameTable.getSimpleNameIndex(descriptor.getName()));
134 }
135 }
136 }
137
138 return builder;
139 }
140
141 @NotNull
142 public ProtoBuf.Callable.Builder callableProto(@NotNull CallableMemberDescriptor descriptor) {
143 ProtoBuf.Callable.Builder builder = ProtoBuf.Callable.newBuilder();
144
145 boolean hasGetter = false;
146 boolean hasSetter = false;
147 if (descriptor instanceof PropertyDescriptor) {
148 PropertyDescriptor propertyDescriptor = (PropertyDescriptor) descriptor;
149
150 int propertyFlags = Flags.getAccessorFlags(
151 hasAnnotations(propertyDescriptor),
152 propertyDescriptor.getVisibility(),
153 propertyDescriptor.getModality(),
154 false
155 );
156
157 PropertyGetterDescriptor getter = propertyDescriptor.getGetter();
158 if (getter != null) {
159 hasGetter = true;
160 int accessorFlags = getAccessorFlags(getter);
161 if (accessorFlags != propertyFlags) {
162 builder.setGetterFlags(accessorFlags);
163 }
164 }
165
166 PropertySetterDescriptor setter = propertyDescriptor.getSetter();
167 if (setter != null) {
168 hasSetter = true;
169 int accessorFlags = getAccessorFlags(setter);
170 if (accessorFlags != propertyFlags) {
171 builder.setSetterFlags(accessorFlags);
172 }
173
174 if (!setter.isDefault()) {
175 List<ValueParameterDescriptor> parameters = setter.getValueParameters();
176 assert parameters.size() == 1 : "Unexpected number of setter parameters: " + setter;
177 builder.setSetterParameterName(nameTable.getSimpleNameIndex(parameters.get(0).getName()));
178 }
179 }
180 }
181
182 builder.setFlags(Flags.getCallableFlags(
183 hasAnnotations(descriptor),
184 descriptor.getVisibility(),
185 descriptor.getModality(),
186 descriptor.getKind(),
187 callableKind(descriptor),
188 descriptor instanceof SimpleFunctionDescriptor &&
189 ((SimpleFunctionDescriptor) descriptor).isInline(),
190 hasGetter,
191 hasSetter
192 ));
193 //TODO builder.setExtraVisibility()
194
195 DescriptorSerializer local = createChildSerializer();
196
197 for (TypeParameterDescriptor typeParameterDescriptor : descriptor.getTypeParameters()) {
198 builder.addTypeParameter(local.typeParameter(typeParameterDescriptor));
199 }
200
201 ReceiverParameterDescriptor receiverParameter = descriptor.getReceiverParameter();
202 if (receiverParameter != null) {
203 builder.setReceiverType(local.type(receiverParameter.getType()));
204 }
205
206 builder.setName(nameTable.getSimpleNameIndex(descriptor.getName()));
207
208 for (ValueParameterDescriptor valueParameterDescriptor : descriptor.getValueParameters()) {
209 builder.addValueParameter(local.valueParameter(valueParameterDescriptor));
210 }
211
212 builder.setReturnType(local.type(getSerializableReturnType(descriptor.getReturnType())));
213
214 extension.serializeCallable(descriptor, builder, nameTable);
215
216 return builder;
217 }
218
219 @NotNull
220 private static JetType getSerializableReturnType(@NotNull JetType type) {
221 return isSerializableType(type) ? type : KotlinBuiltIns.getInstance().getAnyType();
222 }
223
224 /**
225 * @return true iff this type can be serialized. Types which correspond to type parameters, top-level classes, inner classes, and
226 * generic classes with serializable arguments are serializable. For other types (local classes, inner of local, etc.) it may be
227 * problematical to construct a FQ name for serialization
228 */
229 private static boolean isSerializableType(@NotNull JetType type) {
230 ClassifierDescriptor descriptor = type.getConstructor().getDeclarationDescriptor();
231 if (descriptor instanceof TypeParameterDescriptor) {
232 return true;
233 }
234 else if (descriptor instanceof ClassDescriptor) {
235 for (TypeProjection projection : type.getArguments()) {
236 if (!isSerializableType(projection.getType())) {
237 return false;
238 }
239 }
240
241 return isTopLevelOrInnerClass((ClassDescriptor) descriptor);
242 }
243 else {
244 throw new IllegalStateException("Unknown type constructor: " + type);
245 }
246 }
247
248 private static int getAccessorFlags(@NotNull PropertyAccessorDescriptor accessor) {
249 return Flags.getAccessorFlags(
250 hasAnnotations(accessor),
251 accessor.getVisibility(),
252 accessor.getModality(),
253 !accessor.isDefault()
254 );
255 }
256
257 private static ProtoBuf.Callable.CallableKind callableKind(CallableMemberDescriptor descriptor) {
258 if (descriptor instanceof VariableDescriptorForObject) {
259 return ProtoBuf.Callable.CallableKind.OBJECT_PROPERTY;
260 }
261 else if (descriptor instanceof PropertyDescriptor) {
262 PropertyDescriptor propertyDescriptor = (PropertyDescriptor) descriptor;
263 return propertyDescriptor.isVar() ? ProtoBuf.Callable.CallableKind.VAR : ProtoBuf.Callable.CallableKind.VAL;
264 }
265 if (descriptor instanceof ConstructorDescriptor) {
266 return ProtoBuf.Callable.CallableKind.CONSTRUCTOR;
267 }
268 assert descriptor instanceof FunctionDescriptor : "Unknown descriptor class: " + descriptor.getClass();
269 return ProtoBuf.Callable.CallableKind.FUN;
270 }
271
272 private ProtoBuf.Callable.ValueParameter.Builder valueParameter(ValueParameterDescriptor descriptor) {
273 ProtoBuf.Callable.ValueParameter.Builder builder = ProtoBuf.Callable.ValueParameter.newBuilder();
274
275 builder.setFlags(Flags.getValueParameterFlags(hasAnnotations(descriptor), descriptor.declaresDefaultValue()));
276
277 builder.setName(nameTable.getSimpleNameIndex(descriptor.getName()));
278
279 builder.setType(type(descriptor.getType()));
280
281 JetType varargElementType = descriptor.getVarargElementType();
282 if (varargElementType != null) {
283 builder.setVarargElementType(type(varargElementType));
284 }
285
286 return builder;
287 }
288
289 private ProtoBuf.TypeParameter.Builder typeParameter(TypeParameterDescriptor typeParameter) {
290 ProtoBuf.TypeParameter.Builder builder = ProtoBuf.TypeParameter.newBuilder();
291
292 builder.setId(getTypeParameterId(typeParameter));
293
294 builder.setName(nameTable.getSimpleNameIndex(typeParameter.getName()));
295
296 // to avoid storing a default
297 if (typeParameter.isReified()) {
298 builder.setReified(true);
299 }
300
301 // to avoid storing a default
302 ProtoBuf.TypeParameter.Variance variance = variance(typeParameter.getVariance());
303 if (variance != ProtoBuf.TypeParameter.Variance.INV) {
304 builder.setVariance(variance);
305 }
306
307 for (JetType upperBound : typeParameter.getUpperBounds()) {
308 builder.addUpperBound(type(upperBound));
309 }
310
311 return builder;
312 }
313
314 private static ProtoBuf.TypeParameter.Variance variance(Variance variance) {
315 switch (variance) {
316 case INVARIANT:
317 return ProtoBuf.TypeParameter.Variance.INV;
318 case IN_VARIANCE:
319 return ProtoBuf.TypeParameter.Variance.IN;
320 case OUT_VARIANCE:
321 return ProtoBuf.TypeParameter.Variance.OUT;
322 }
323 throw new IllegalStateException("Unknown variance: " + variance);
324 }
325
326 @NotNull
327 public ProtoBuf.Type.Builder type(@NotNull JetType type) {
328 assert !ErrorUtils.isErrorType(type) : "Can't serialize error types: " + type; // TODO
329
330 ProtoBuf.Type.Builder builder = ProtoBuf.Type.newBuilder();
331
332 builder.setConstructor(typeConstructor(type.getConstructor()));
333
334 for (TypeProjection projection : type.getArguments()) {
335 builder.addArgument(typeArgument(projection));
336 }
337
338 // to avoid storing a default
339 if (type.isNullable()) {
340 builder.setNullable(true);
341 }
342
343 return builder;
344 }
345
346 @NotNull
347 private ProtoBuf.Type.Argument.Builder typeArgument(@NotNull TypeProjection typeProjection) {
348 ProtoBuf.Type.Argument.Builder builder = ProtoBuf.Type.Argument.newBuilder();
349 ProtoBuf.Type.Argument.Projection projection = projection(typeProjection.getProjectionKind());
350
351 // to avoid storing a default
352 if (projection != ProtoBuf.Type.Argument.Projection.INV) {
353 builder.setProjection(projection);
354 }
355
356 builder.setType(type(typeProjection.getType()));
357 return builder;
358 }
359
360 @NotNull
361 private ProtoBuf.Type.Constructor.Builder typeConstructor(@NotNull TypeConstructor typeConstructor) {
362 ProtoBuf.Type.Constructor.Builder builder = ProtoBuf.Type.Constructor.newBuilder();
363
364 ClassifierDescriptor declarationDescriptor = typeConstructor.getDeclarationDescriptor();
365
366 assert declarationDescriptor instanceof TypeParameterDescriptor || declarationDescriptor instanceof ClassDescriptor
367 : "Unknown declaration descriptor: " + typeConstructor;
368 if (declarationDescriptor instanceof TypeParameterDescriptor) {
369 TypeParameterDescriptor typeParameterDescriptor = (TypeParameterDescriptor) declarationDescriptor;
370 builder.setKind(ProtoBuf.Type.Constructor.Kind.TYPE_PARAMETER);
371 builder.setId(getTypeParameterId(typeParameterDescriptor));
372 }
373 else {
374 ClassDescriptor classDescriptor = (ClassDescriptor) declarationDescriptor;
375 //default: builder.setKind(Type.Constructor.Kind.CLASS);
376 builder.setId(getClassId(classDescriptor));
377 }
378 return builder;
379 }
380
381 @NotNull
382 public ProtoBuf.Package.Builder packageProto(@NotNull NamespaceDescriptor descriptor) {
383 ProtoBuf.Package.Builder builder = ProtoBuf.Package.newBuilder();
384
385 for (DeclarationDescriptor declaration : sort(descriptor.getMemberScope().getAllDescriptors())) {
386 if (declaration instanceof PropertyDescriptor || declaration instanceof FunctionDescriptor) {
387 builder.addMember(callableProto((CallableMemberDescriptor) declaration));
388 }
389 }
390
391 return builder;
392 }
393
394 @NotNull
395 private static ProtoBuf.Type.Argument.Projection projection(@NotNull Variance projectionKind) {
396 switch (projectionKind) {
397 case INVARIANT:
398 return ProtoBuf.Type.Argument.Projection.INV;
399 case IN_VARIANCE:
400 return ProtoBuf.Type.Argument.Projection.IN;
401 case OUT_VARIANCE:
402 return ProtoBuf.Type.Argument.Projection.OUT;
403 }
404 throw new IllegalStateException("Unknown projectionKind: " + projectionKind);
405 }
406
407 private int getClassId(@NotNull ClassDescriptor descriptor) {
408 return nameTable.getFqNameIndex(descriptor);
409 }
410
411 private int getTypeParameterId(@NotNull TypeParameterDescriptor descriptor) {
412 return typeParameters.intern(descriptor);
413 }
414
415 private static boolean hasAnnotations(Annotated descriptor) {
416 return !descriptor.getAnnotations().isEmpty();
417 }
418
419 @NotNull
420 public static <T extends DeclarationDescriptor> List<T> sort(@NotNull Collection<T> descriptors) {
421 List<T> result = new ArrayList<T>(descriptors);
422 Collections.sort(result, DESCRIPTOR_COMPARATOR);
423 return result;
424
425 }
426 }