001 /*
002 * Copyright 2010-2015 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.kotlin.serialization;
018
019 import kotlin.jvm.functions.Function1;
020 import org.jetbrains.annotations.NotNull;
021 import org.jetbrains.annotations.Nullable;
022 import org.jetbrains.kotlin.builtins.KotlinBuiltIns;
023 import org.jetbrains.kotlin.descriptors.*;
024 import org.jetbrains.kotlin.descriptors.annotations.Annotated;
025 import org.jetbrains.kotlin.resolve.DescriptorFactory;
026 import org.jetbrains.kotlin.resolve.MemberComparator;
027 import org.jetbrains.kotlin.resolve.constants.ConstantValue;
028 import org.jetbrains.kotlin.resolve.constants.NullValue;
029 import org.jetbrains.kotlin.types.*;
030
031 import java.util.ArrayList;
032 import java.util.Collection;
033 import java.util.Collections;
034 import java.util.List;
035
036 import static org.jetbrains.kotlin.resolve.DescriptorUtils.isEnumEntry;
037 import static org.jetbrains.kotlin.resolve.descriptorUtil.DescriptorUtilPackage.getSecondaryConstructors;
038
039 public class DescriptorSerializer {
040
041 private final StringTable stringTable;
042 private final Interner<TypeParameterDescriptor> typeParameters;
043 private final SerializerExtension extension;
044
045 private DescriptorSerializer(StringTable stringTable, Interner<TypeParameterDescriptor> typeParameters, SerializerExtension extension) {
046 this.stringTable = stringTable;
047 this.typeParameters = typeParameters;
048 this.extension = extension;
049 }
050
051 @NotNull
052 public static DescriptorSerializer createTopLevel(@NotNull SerializerExtension extension) {
053 return new DescriptorSerializer(new StringTable(extension), new Interner<TypeParameterDescriptor>(), extension);
054 }
055
056 @NotNull
057 public static DescriptorSerializer create(@NotNull ClassDescriptor descriptor, @NotNull SerializerExtension extension) {
058 DeclarationDescriptor container = descriptor.getContainingDeclaration();
059 DescriptorSerializer parentSerializer =
060 container instanceof ClassDescriptor
061 ? create((ClassDescriptor) container, extension)
062 : createTopLevel(extension);
063
064 // Calculate type parameter ids for the outer class beforehand, as it would've had happened if we were always
065 // serializing outer classes before nested classes.
066 // Otherwise our interner can get wrong ids because we may serialize classes in any order.
067 DescriptorSerializer serializer = parentSerializer.createChildSerializer();
068 for (TypeParameterDescriptor typeParameter : descriptor.getTypeConstructor().getParameters()) {
069 serializer.typeParameters.intern(typeParameter);
070 }
071 return serializer;
072 }
073
074 private DescriptorSerializer createChildSerializer() {
075 return new DescriptorSerializer(stringTable, new Interner<TypeParameterDescriptor>(typeParameters), extension);
076 }
077
078 @NotNull
079 public StringTable getStringTable() {
080 return stringTable;
081 }
082
083 @NotNull
084 public ProtoBuf.Class.Builder classProto(@NotNull ClassDescriptor classDescriptor) {
085 ProtoBuf.Class.Builder builder = ProtoBuf.Class.newBuilder();
086
087 int flags = Flags.getClassFlags(hasAnnotations(classDescriptor), classDescriptor.getVisibility(), classDescriptor.getModality(),
088 classDescriptor.getKind(), classDescriptor.isInner(), classDescriptor.isCompanionObject());
089 builder.setFlags(flags);
090
091 builder.setFqName(getClassId(classDescriptor));
092
093 for (TypeParameterDescriptor typeParameterDescriptor : classDescriptor.getTypeConstructor().getParameters()) {
094 builder.addTypeParameter(typeParameter(typeParameterDescriptor));
095 }
096
097 if (!KotlinBuiltIns.isSpecialClassWithNoSupertypes(classDescriptor)) {
098 // Special classes (Any, Nothing) have no supertypes
099 for (JetType supertype : classDescriptor.getTypeConstructor().getSupertypes()) {
100 builder.addSupertype(type(supertype));
101 }
102 }
103
104 ConstructorDescriptor primaryConstructor = classDescriptor.getUnsubstitutedPrimaryConstructor();
105 if (primaryConstructor != null) {
106 if (DescriptorFactory.isDefaultPrimaryConstructor(primaryConstructor)) {
107 builder.setPrimaryConstructor(ProtoBuf.Class.PrimaryConstructor.getDefaultInstance());
108 }
109 else {
110 ProtoBuf.Class.PrimaryConstructor.Builder constructorBuilder = ProtoBuf.Class.PrimaryConstructor.newBuilder();
111 constructorBuilder.setData(callableProto(primaryConstructor));
112 builder.setPrimaryConstructor(constructorBuilder);
113 }
114 }
115
116 for (ConstructorDescriptor constructorDescriptor : getSecondaryConstructors(classDescriptor)) {
117 builder.addSecondaryConstructor(callableProto(constructorDescriptor));
118 }
119
120 for (DeclarationDescriptor descriptor : sort(classDescriptor.getDefaultType().getMemberScope().getAllDescriptors())) {
121 if (descriptor instanceof CallableMemberDescriptor) {
122 CallableMemberDescriptor member = (CallableMemberDescriptor) descriptor;
123 if (member.getKind() == CallableMemberDescriptor.Kind.FAKE_OVERRIDE) continue;
124 builder.addMember(callableProto(member));
125 }
126 }
127
128 for (DeclarationDescriptor descriptor : sort(classDescriptor.getUnsubstitutedInnerClassesScope().getAllDescriptors())) {
129 int name = stringTable.getSimpleNameIndex(descriptor.getName());
130 if (isEnumEntry(descriptor)) {
131 builder.addEnumEntry(name);
132 }
133 else {
134 builder.addNestedClassName(name);
135 }
136 }
137
138 ClassDescriptor companionObjectDescriptor = classDescriptor.getCompanionObjectDescriptor();
139 if (companionObjectDescriptor != null) {
140 builder.setCompanionObjectName(stringTable.getSimpleNameIndex(companionObjectDescriptor.getName()));
141 }
142
143 extension.serializeClass(classDescriptor, builder, stringTable);
144
145 return builder;
146 }
147
148 @NotNull
149 public ProtoBuf.Callable.Builder callableProto(@NotNull CallableMemberDescriptor descriptor) {
150 ProtoBuf.Callable.Builder builder = ProtoBuf.Callable.newBuilder();
151
152 DescriptorSerializer local = createChildSerializer();
153
154 boolean hasGetter = false;
155 boolean hasSetter = false;
156 boolean hasConstant = false;
157 boolean lateInit = false;
158
159 if (descriptor instanceof PropertyDescriptor) {
160 PropertyDescriptor propertyDescriptor = (PropertyDescriptor) descriptor;
161 lateInit = propertyDescriptor.isLateInit();
162
163 int propertyFlags = Flags.getAccessorFlags(
164 hasAnnotations(propertyDescriptor),
165 propertyDescriptor.getVisibility(),
166 propertyDescriptor.getModality(),
167 false
168 );
169
170 PropertyGetterDescriptor getter = propertyDescriptor.getGetter();
171 if (getter != null) {
172 hasGetter = true;
173 int accessorFlags = getAccessorFlags(getter);
174 if (accessorFlags != propertyFlags) {
175 builder.setGetterFlags(accessorFlags);
176 }
177 }
178
179 PropertySetterDescriptor setter = propertyDescriptor.getSetter();
180 if (setter != null) {
181 hasSetter = true;
182 int accessorFlags = getAccessorFlags(setter);
183 if (accessorFlags != propertyFlags) {
184 builder.setSetterFlags(accessorFlags);
185 }
186
187 if (!setter.isDefault()) {
188 for (ValueParameterDescriptor valueParameterDescriptor : setter.getValueParameters()) {
189 builder.addValueParameter(local.valueParameter(valueParameterDescriptor));
190 }
191 }
192 }
193
194 ConstantValue<?> compileTimeConstant = propertyDescriptor.getCompileTimeInitializer();
195 hasConstant = !(compileTimeConstant == null || compileTimeConstant instanceof NullValue);
196 }
197
198 boolean hasAnnotations = (descriptor instanceof PropertyDescriptor)
199 ? !descriptor.getAnnotations().getAllAnnotations().isEmpty()
200 : hasAnnotations(descriptor);
201
202 builder.setFlags(Flags.getCallableFlags(
203 hasAnnotations,
204 descriptor.getVisibility(),
205 descriptor.getModality(),
206 descriptor.getKind(),
207 callableKind(descriptor),
208 hasGetter,
209 hasSetter,
210 hasConstant,
211 lateInit
212 ));
213
214 for (TypeParameterDescriptor typeParameterDescriptor : descriptor.getTypeParameters()) {
215 builder.addTypeParameter(local.typeParameter(typeParameterDescriptor));
216 }
217
218 ReceiverParameterDescriptor receiverParameter = descriptor.getExtensionReceiverParameter();
219 if (receiverParameter != null) {
220 builder.setReceiverType(local.type(receiverParameter.getType()));
221 }
222
223 builder.setName(stringTable.getSimpleNameIndex(descriptor.getName()));
224
225 for (ValueParameterDescriptor valueParameterDescriptor : descriptor.getValueParameters()) {
226 builder.addValueParameter(local.valueParameter(valueParameterDescriptor));
227 }
228
229 //noinspection ConstantConditions
230 builder.setReturnType(local.type(descriptor.getReturnType()));
231
232 extension.serializeCallable(descriptor, builder, stringTable);
233
234 return builder;
235 }
236
237 private static int getAccessorFlags(@NotNull PropertyAccessorDescriptor accessor) {
238 return Flags.getAccessorFlags(
239 hasAnnotations(accessor),
240 accessor.getVisibility(),
241 accessor.getModality(),
242 !accessor.isDefault()
243 );
244 }
245
246 @NotNull
247 private static ProtoBuf.Callable.CallableKind callableKind(@NotNull CallableMemberDescriptor descriptor) {
248 if (descriptor instanceof PropertyDescriptor) {
249 return ((PropertyDescriptor) descriptor).isVar() ? ProtoBuf.Callable.CallableKind.VAR : ProtoBuf.Callable.CallableKind.VAL;
250 }
251 if (descriptor instanceof ConstructorDescriptor) {
252 return ProtoBuf.Callable.CallableKind.CONSTRUCTOR;
253 }
254 assert descriptor instanceof FunctionDescriptor : "Unknown descriptor class: " + descriptor.getClass();
255 return ProtoBuf.Callable.CallableKind.FUN;
256 }
257
258 @NotNull
259 private ProtoBuf.Callable.ValueParameter.Builder valueParameter(@NotNull ValueParameterDescriptor descriptor) {
260 ProtoBuf.Callable.ValueParameter.Builder builder = ProtoBuf.Callable.ValueParameter.newBuilder();
261
262 builder.setFlags(Flags.getValueParameterFlags(hasAnnotations(descriptor), descriptor.declaresDefaultValue()));
263
264 builder.setName(stringTable.getSimpleNameIndex(descriptor.getName()));
265
266 builder.setType(type(descriptor.getType()));
267
268 JetType varargElementType = descriptor.getVarargElementType();
269 if (varargElementType != null) {
270 builder.setVarargElementType(type(varargElementType));
271 }
272
273 extension.serializeValueParameter(descriptor, builder, stringTable);
274
275 return builder;
276 }
277
278 private ProtoBuf.TypeParameter.Builder typeParameter(TypeParameterDescriptor typeParameter) {
279 ProtoBuf.TypeParameter.Builder builder = ProtoBuf.TypeParameter.newBuilder();
280
281 builder.setId(getTypeParameterId(typeParameter));
282
283 builder.setName(stringTable.getSimpleNameIndex(typeParameter.getName()));
284
285 // to avoid storing a default
286 if (typeParameter.isReified()) {
287 builder.setReified(true);
288 }
289
290 // to avoid storing a default
291 ProtoBuf.TypeParameter.Variance variance = variance(typeParameter.getVariance());
292 if (variance != ProtoBuf.TypeParameter.Variance.INV) {
293 builder.setVariance(variance);
294 }
295
296 for (JetType upperBound : typeParameter.getUpperBounds()) {
297 builder.addUpperBound(type(upperBound));
298 }
299
300 return builder;
301 }
302
303 private static ProtoBuf.TypeParameter.Variance variance(Variance variance) {
304 switch (variance) {
305 case INVARIANT:
306 return ProtoBuf.TypeParameter.Variance.INV;
307 case IN_VARIANCE:
308 return ProtoBuf.TypeParameter.Variance.IN;
309 case OUT_VARIANCE:
310 return ProtoBuf.TypeParameter.Variance.OUT;
311 }
312 throw new IllegalStateException("Unknown variance: " + variance);
313 }
314
315 @NotNull
316 public ProtoBuf.Type.Builder type(@NotNull JetType type) {
317 assert !type.isError() : "Can't serialize error types: " + type; // TODO
318
319 if (TypesPackage.isFlexible(type)) return flexibleType(type);
320
321 ProtoBuf.Type.Builder builder = ProtoBuf.Type.newBuilder();
322
323 builder.setConstructor(typeConstructor(type.getConstructor()));
324 setTypeConstructorFields(builder, type.getConstructor());
325
326 for (TypeProjection projection : type.getArguments()) {
327 builder.addArgument(typeArgument(projection));
328 }
329
330 // to avoid storing a default
331 if (type.isMarkedNullable()) {
332 builder.setNullable(true);
333 }
334
335 extension.serializeType(type, builder, stringTable);
336
337 return builder;
338 }
339
340 private void setTypeConstructorFields(@NotNull ProtoBuf.Type.Builder builder, @NotNull TypeConstructor typeConstructor) {
341 ClassifierDescriptor declarationDescriptor = typeConstructor.getDeclarationDescriptor();
342
343 assert declarationDescriptor instanceof TypeParameterDescriptor || declarationDescriptor instanceof ClassDescriptor
344 : "Unknown declaration descriptor: " + typeConstructor;
345 if (declarationDescriptor instanceof TypeParameterDescriptor) {
346 TypeParameterDescriptor typeParameterDescriptor = (TypeParameterDescriptor) declarationDescriptor;
347 builder.setConstructorTypeParameter(getTypeParameterId(typeParameterDescriptor));
348 }
349 else {
350 ClassDescriptor classDescriptor = (ClassDescriptor) declarationDescriptor;
351 builder.setConstructorClassName(getClassId(classDescriptor));
352 }
353 }
354
355 private ProtoBuf.Type.Builder flexibleType(@NotNull JetType type) {
356 Flexibility flexibility = TypesPackage.flexibility(type);
357
358 ProtoBuf.Type.Builder builder = type(flexibility.getLowerBound());
359
360 builder.setFlexibleTypeCapabilitiesId(stringTable.getStringIndex(flexibility.getExtraCapabilities().getId()));
361
362 builder.setFlexibleUpperBound(type(flexibility.getUpperBound()));
363
364 return builder;
365 }
366
367 @NotNull
368 private ProtoBuf.Type.Argument.Builder typeArgument(@NotNull TypeProjection typeProjection) {
369 ProtoBuf.Type.Argument.Builder builder = ProtoBuf.Type.Argument.newBuilder();
370
371 if (typeProjection.isStarProjection()) {
372 builder.setProjection(ProtoBuf.Type.Argument.Projection.STAR);
373 }
374 else {
375 ProtoBuf.Type.Argument.Projection projection = projection(typeProjection.getProjectionKind());
376
377 // to avoid storing a default
378 if (projection != ProtoBuf.Type.Argument.Projection.INV) {
379 builder.setProjection(projection);
380 }
381 builder.setType(type(typeProjection.getType()));
382 }
383
384 return builder;
385 }
386
387 @NotNull
388 private ProtoBuf.Type.Constructor.Builder typeConstructor(@NotNull TypeConstructor typeConstructor) {
389 ProtoBuf.Type.Constructor.Builder builder = ProtoBuf.Type.Constructor.newBuilder();
390
391 ClassifierDescriptor declarationDescriptor = typeConstructor.getDeclarationDescriptor();
392
393 assert declarationDescriptor instanceof TypeParameterDescriptor || declarationDescriptor instanceof ClassDescriptor
394 : "Unknown declaration descriptor: " + typeConstructor;
395 if (declarationDescriptor instanceof TypeParameterDescriptor) {
396 TypeParameterDescriptor typeParameterDescriptor = (TypeParameterDescriptor) declarationDescriptor;
397 builder.setKind(ProtoBuf.Type.Constructor.Kind.TYPE_PARAMETER);
398 builder.setId(getTypeParameterId(typeParameterDescriptor));
399 }
400 else {
401 ClassDescriptor classDescriptor = (ClassDescriptor) declarationDescriptor;
402 //default: builder.setKind(Type.Constructor.Kind.CLASS);
403 builder.setId(getClassId(classDescriptor));
404 }
405 return builder;
406 }
407
408 @NotNull
409 public ProtoBuf.Package.Builder packageProto(@NotNull Collection<PackageFragmentDescriptor> fragments) {
410 return packageProto(fragments, null);
411 }
412
413 @NotNull
414 public ProtoBuf.Package.Builder packageProto(@NotNull Collection<PackageFragmentDescriptor> fragments, @Nullable Function1<DeclarationDescriptor, Boolean> skip) {
415 ProtoBuf.Package.Builder builder = ProtoBuf.Package.newBuilder();
416
417 Collection<DeclarationDescriptor> members = new ArrayList<DeclarationDescriptor>();
418 for (PackageFragmentDescriptor fragment : fragments) {
419 members.addAll(fragment.getMemberScope().getAllDescriptors());
420 }
421
422 for (DeclarationDescriptor declaration : sort(members)) {
423 if (skip != null && skip.invoke(declaration)) continue;
424
425 if (declaration instanceof PropertyDescriptor || declaration instanceof FunctionDescriptor) {
426 builder.addMember(callableProto((CallableMemberDescriptor) declaration));
427 }
428 }
429
430 extension.serializePackage(fragments, builder, stringTable);
431
432 return builder;
433 }
434
435 @NotNull
436 public ProtoBuf.Package.Builder packagePartProto(@NotNull Collection<DeclarationDescriptor> members) {
437 ProtoBuf.Package.Builder builder = ProtoBuf.Package.newBuilder();
438
439 for (DeclarationDescriptor declaration : sort(members)) {
440 if (declaration instanceof PropertyDescriptor || declaration instanceof FunctionDescriptor) {
441 builder.addMember(callableProto((CallableMemberDescriptor) declaration));
442 }
443 }
444
445 return builder;
446 }
447
448 @NotNull
449 private static ProtoBuf.Type.Argument.Projection projection(@NotNull Variance projectionKind) {
450 switch (projectionKind) {
451 case INVARIANT:
452 return ProtoBuf.Type.Argument.Projection.INV;
453 case IN_VARIANCE:
454 return ProtoBuf.Type.Argument.Projection.IN;
455 case OUT_VARIANCE:
456 return ProtoBuf.Type.Argument.Projection.OUT;
457 }
458 throw new IllegalStateException("Unknown projectionKind: " + projectionKind);
459 }
460
461 private int getClassId(@NotNull ClassDescriptor descriptor) {
462 return stringTable.getFqNameIndex(descriptor);
463 }
464
465 private int getTypeParameterId(@NotNull TypeParameterDescriptor descriptor) {
466 return typeParameters.intern(descriptor);
467 }
468
469 private static boolean hasAnnotations(Annotated descriptor) {
470 return !descriptor.getAnnotations().isEmpty();
471 }
472
473 @NotNull
474 public static <T extends DeclarationDescriptor> List<T> sort(@NotNull Collection<T> descriptors) {
475 List<T> result = new ArrayList<T>(descriptors);
476 //NOTE: the exact comparator does matter here
477 Collections.sort(result, MemberComparator.INSTANCE);
478 return result;
479
480 }
481 }