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 com.google.protobuf.MessageLite;
020    import kotlin.collections.CollectionsKt;
021    import kotlin.jvm.functions.Function1;
022    import org.jetbrains.annotations.NotNull;
023    import org.jetbrains.annotations.Nullable;
024    import org.jetbrains.kotlin.builtins.KotlinBuiltIns;
025    import org.jetbrains.kotlin.descriptors.*;
026    import org.jetbrains.kotlin.descriptors.annotations.Annotated;
027    import org.jetbrains.kotlin.name.Name;
028    import org.jetbrains.kotlin.resolve.DescriptorUtils;
029    import org.jetbrains.kotlin.resolve.MemberComparator;
030    import org.jetbrains.kotlin.resolve.constants.ConstantValue;
031    import org.jetbrains.kotlin.resolve.constants.NullValue;
032    import org.jetbrains.kotlin.types.*;
033    import org.jetbrains.kotlin.utils.ExceptionUtilsKt;
034    import org.jetbrains.kotlin.utils.Interner;
035    
036    import java.io.ByteArrayOutputStream;
037    import java.io.IOException;
038    import java.util.ArrayList;
039    import java.util.Collection;
040    import java.util.Collections;
041    import java.util.List;
042    
043    import static org.jetbrains.kotlin.resolve.DescriptorUtils.isEnumEntry;
044    
045    public class DescriptorSerializer {
046        private final DeclarationDescriptor containingDeclaration;
047        private final Interner<TypeParameterDescriptor> typeParameters;
048        private final SerializerExtension extension;
049        private final MutableTypeTable typeTable;
050        private final boolean serializeTypeTableToFunction;
051    
052        private DescriptorSerializer(
053                @Nullable DeclarationDescriptor containingDeclaration,
054                @NotNull Interner<TypeParameterDescriptor> typeParameters,
055                @NotNull SerializerExtension extension,
056                @NotNull MutableTypeTable typeTable,
057                boolean serializeTypeTableToFunction
058        ) {
059            this.containingDeclaration = containingDeclaration;
060            this.typeParameters = typeParameters;
061            this.extension = extension;
062            this.typeTable = typeTable;
063            this.serializeTypeTableToFunction = serializeTypeTableToFunction;
064        }
065    
066        @NotNull
067        public byte[] serialize(@NotNull MessageLite message) {
068            try {
069                ByteArrayOutputStream result = new ByteArrayOutputStream();
070                getStringTable().serializeTo(result);
071                message.writeTo(result);
072                return result.toByteArray();
073            }
074            catch (IOException e) {
075                throw ExceptionUtilsKt.rethrow(e);
076            }
077        }
078    
079        @NotNull
080        public static DescriptorSerializer createTopLevel(@NotNull SerializerExtension extension) {
081            return new DescriptorSerializer(null, new Interner<TypeParameterDescriptor>(), extension, new MutableTypeTable(), false);
082        }
083    
084        @NotNull
085        public static DescriptorSerializer createForLambda(@NotNull SerializerExtension extension) {
086            return new DescriptorSerializer(null, new Interner<TypeParameterDescriptor>(), extension, new MutableTypeTable(), true);
087        }
088    
089        @NotNull
090        public static DescriptorSerializer create(@NotNull ClassDescriptor descriptor, @NotNull SerializerExtension extension) {
091            DeclarationDescriptor container = descriptor.getContainingDeclaration();
092            DescriptorSerializer parentSerializer =
093                    container instanceof ClassDescriptor
094                    ? create((ClassDescriptor) container, extension)
095                    : createTopLevel(extension);
096    
097            // Calculate type parameter ids for the outer class beforehand, as it would've had happened if we were always
098            // serializing outer classes before nested classes.
099            // Otherwise our interner can get wrong ids because we may serialize classes in any order.
100            DescriptorSerializer serializer = new DescriptorSerializer(
101                    descriptor,
102                    new Interner<TypeParameterDescriptor>(parentSerializer.typeParameters),
103                    parentSerializer.extension,
104                    new MutableTypeTable(),
105                    false
106            );
107            for (TypeParameterDescriptor typeParameter : descriptor.getDeclaredTypeParameters()) {
108                serializer.typeParameters.intern(typeParameter);
109            }
110            return serializer;
111        }
112    
113        @NotNull
114        private DescriptorSerializer createChildSerializer(@NotNull CallableDescriptor callable) {
115            return new DescriptorSerializer(callable, new Interner<TypeParameterDescriptor>(typeParameters), extension, typeTable, false);
116        }
117    
118        @NotNull
119        public StringTable getStringTable() {
120            return extension.getStringTable();
121        }
122    
123        private boolean useTypeTable() {
124            return extension.shouldUseTypeTable();
125        }
126    
127        @NotNull
128        public ProtoBuf.Class.Builder classProto(@NotNull ClassDescriptor classDescriptor) {
129            ProtoBuf.Class.Builder builder = ProtoBuf.Class.newBuilder();
130    
131            int flags = Flags.getClassFlags(hasAnnotations(classDescriptor), classDescriptor.getVisibility(), classDescriptor.getModality(),
132                                            classDescriptor.getKind(), classDescriptor.isInner(), classDescriptor.isCompanionObject(),
133                                            classDescriptor.isData());
134            if (flags != builder.getFlags()) {
135                builder.setFlags(flags);
136            }
137    
138            builder.setFqName(getClassId(classDescriptor));
139    
140            for (TypeParameterDescriptor typeParameterDescriptor : classDescriptor.getDeclaredTypeParameters()) {
141                builder.addTypeParameter(typeParameter(typeParameterDescriptor));
142            }
143    
144            if (!KotlinBuiltIns.isSpecialClassWithNoSupertypes(classDescriptor)) {
145                // Special classes (Any, Nothing) have no supertypes
146                for (KotlinType supertype : classDescriptor.getTypeConstructor().getSupertypes()) {
147                    if (useTypeTable()) {
148                        builder.addSupertypeId(typeId(supertype));
149                    }
150                    else {
151                        builder.addSupertype(type(supertype));
152                    }
153                }
154            }
155    
156            for (ConstructorDescriptor descriptor : classDescriptor.getConstructors()) {
157                builder.addConstructor(constructorProto(descriptor));
158            }
159    
160            for (DeclarationDescriptor descriptor : sort(DescriptorUtils.getAllDescriptors(classDescriptor.getDefaultType().getMemberScope()))) {
161                if (descriptor instanceof CallableMemberDescriptor) {
162                    CallableMemberDescriptor member = (CallableMemberDescriptor) descriptor;
163                    if (member.getKind() == CallableMemberDescriptor.Kind.FAKE_OVERRIDE) continue;
164    
165                    if (descriptor instanceof PropertyDescriptor) {
166                        builder.addProperty(propertyProto((PropertyDescriptor) descriptor));
167                    }
168                    else if (descriptor instanceof FunctionDescriptor) {
169                        builder.addFunction(functionProto((FunctionDescriptor) descriptor));
170                    }
171                }
172            }
173    
174            for (DeclarationDescriptor descriptor : sort(DescriptorUtils.getAllDescriptors(classDescriptor.getUnsubstitutedInnerClassesScope()))) {
175                int name = getSimpleNameIndex(descriptor.getName());
176                if (isEnumEntry(descriptor)) {
177                    builder.addEnumEntry(enumEntryProto((ClassDescriptor) descriptor));
178                }
179                else {
180                    builder.addNestedClassName(name);
181                }
182            }
183    
184            ClassDescriptor companionObjectDescriptor = classDescriptor.getCompanionObjectDescriptor();
185            if (companionObjectDescriptor != null) {
186                builder.setCompanionObjectName(getSimpleNameIndex(companionObjectDescriptor.getName()));
187            }
188    
189            ProtoBuf.TypeTable typeTableProto = typeTable.serialize();
190            if (typeTableProto != null) {
191                builder.setTypeTable(typeTableProto);
192            }
193    
194            extension.serializeClass(classDescriptor, builder);
195    
196            return builder;
197        }
198    
199        @NotNull
200        public ProtoBuf.Property.Builder propertyProto(@NotNull PropertyDescriptor descriptor) {
201            ProtoBuf.Property.Builder builder = ProtoBuf.Property.newBuilder();
202    
203            DescriptorSerializer local = createChildSerializer(descriptor);
204    
205            boolean hasGetter = false;
206            boolean hasSetter = false;
207            boolean lateInit = descriptor.isLateInit();
208            boolean isConst = descriptor.isConst();
209    
210            ConstantValue<?> compileTimeConstant = descriptor.getCompileTimeInitializer();
211            boolean hasConstant = !(compileTimeConstant == null || compileTimeConstant instanceof NullValue);
212    
213            boolean hasAnnotations = !descriptor.getAnnotations().getAllAnnotations().isEmpty();
214    
215            int propertyFlags = Flags.getAccessorFlags(
216                    hasAnnotations,
217                    descriptor.getVisibility(),
218                    descriptor.getModality(),
219                    false,
220                    false
221            );
222    
223            PropertyGetterDescriptor getter = descriptor.getGetter();
224            if (getter != null) {
225                hasGetter = true;
226                int accessorFlags = getAccessorFlags(getter);
227                if (accessorFlags != propertyFlags) {
228                    builder.setGetterFlags(accessorFlags);
229                }
230            }
231    
232            PropertySetterDescriptor setter = descriptor.getSetter();
233            if (setter != null) {
234                hasSetter = true;
235                int accessorFlags = getAccessorFlags(setter);
236                if (accessorFlags != propertyFlags) {
237                    builder.setSetterFlags(accessorFlags);
238                }
239    
240                if (!setter.isDefault()) {
241                    DescriptorSerializer setterLocal = local.createChildSerializer(setter);
242                    for (ValueParameterDescriptor valueParameterDescriptor : setter.getValueParameters()) {
243                        builder.setSetterValueParameter(setterLocal.valueParameter(valueParameterDescriptor));
244                    }
245                }
246            }
247    
248            int flags = Flags.getPropertyFlags(
249                    hasAnnotations, descriptor.getVisibility(), descriptor.getModality(), descriptor.getKind(), descriptor.isVar(),
250                    hasGetter, hasSetter, hasConstant, isConst, lateInit
251            );
252            if (flags != builder.getFlags()) {
253                builder.setFlags(flags);
254            }
255    
256            builder.setName(getSimpleNameIndex(descriptor.getName()));
257    
258            if (useTypeTable()) {
259                builder.setReturnTypeId(local.typeId(descriptor.getType()));
260            }
261            else {
262                builder.setReturnType(local.type(descriptor.getType()));
263            }
264    
265            for (TypeParameterDescriptor typeParameterDescriptor : descriptor.getTypeParameters()) {
266                builder.addTypeParameter(local.typeParameter(typeParameterDescriptor));
267            }
268    
269            ReceiverParameterDescriptor receiverParameter = descriptor.getExtensionReceiverParameter();
270            if (receiverParameter != null) {
271                if (useTypeTable()) {
272                    builder.setReceiverTypeId(local.typeId(receiverParameter.getType()));
273                }
274                else {
275                    builder.setReceiverType(local.type(receiverParameter.getType()));
276                }
277            }
278    
279            extension.serializeProperty(descriptor, builder);
280    
281            return builder;
282        }
283    
284        @NotNull
285        public ProtoBuf.Function.Builder functionProto(@NotNull FunctionDescriptor descriptor) {
286            ProtoBuf.Function.Builder builder = ProtoBuf.Function.newBuilder();
287    
288            DescriptorSerializer local = createChildSerializer(descriptor);
289    
290            int flags = Flags.getFunctionFlags(
291                    hasAnnotations(descriptor), descriptor.getVisibility(), descriptor.getModality(), descriptor.getKind(),
292                    descriptor.isOperator(), descriptor.isInfix(), descriptor.isInline(), descriptor.isTailrec(),
293                    descriptor.isExternal()
294            );
295            if (flags != builder.getFlags()) {
296                builder.setFlags(flags);
297            }
298    
299            builder.setName(getSimpleNameIndex(descriptor.getName()));
300    
301            if (useTypeTable()) {
302                //noinspection ConstantConditions
303                builder.setReturnTypeId(local.typeId(descriptor.getReturnType()));
304            }
305            else {
306                //noinspection ConstantConditions
307                builder.setReturnType(local.type(descriptor.getReturnType()));
308            }
309    
310            for (TypeParameterDescriptor typeParameterDescriptor : descriptor.getTypeParameters()) {
311                builder.addTypeParameter(local.typeParameter(typeParameterDescriptor));
312            }
313    
314            ReceiverParameterDescriptor receiverParameter = descriptor.getExtensionReceiverParameter();
315            if (receiverParameter != null) {
316                if (useTypeTable()) {
317                    builder.setReceiverTypeId(local.typeId(receiverParameter.getType()));
318                }
319                else {
320                    builder.setReceiverType(local.type(receiverParameter.getType()));
321                }
322            }
323    
324            for (ValueParameterDescriptor valueParameterDescriptor : descriptor.getValueParameters()) {
325                builder.addValueParameter(local.valueParameter(valueParameterDescriptor));
326            }
327    
328            if (serializeTypeTableToFunction) {
329                ProtoBuf.TypeTable typeTableProto = typeTable.serialize();
330                if (typeTableProto != null) {
331                    builder.setTypeTable(typeTableProto);
332                }
333            }
334    
335            extension.serializeFunction(descriptor, builder);
336    
337            return builder;
338        }
339    
340        @NotNull
341        public ProtoBuf.Constructor.Builder constructorProto(@NotNull ConstructorDescriptor descriptor) {
342            ProtoBuf.Constructor.Builder builder = ProtoBuf.Constructor.newBuilder();
343    
344            DescriptorSerializer local = createChildSerializer(descriptor);
345    
346            int flags = Flags.getConstructorFlags(hasAnnotations(descriptor), descriptor.getVisibility(), !descriptor.isPrimary());
347            if (flags != builder.getFlags()) {
348                builder.setFlags(flags);
349            }
350    
351            for (ValueParameterDescriptor valueParameterDescriptor : descriptor.getValueParameters()) {
352                builder.addValueParameter(local.valueParameter(valueParameterDescriptor));
353            }
354    
355            extension.serializeConstructor(descriptor, builder);
356    
357            return builder;
358        }
359    
360        @NotNull
361        public ProtoBuf.EnumEntry.Builder enumEntryProto(@NotNull ClassDescriptor descriptor) {
362            ProtoBuf.EnumEntry.Builder builder = ProtoBuf.EnumEntry.newBuilder();
363            builder.setName(getSimpleNameIndex(descriptor.getName()));
364            extension.serializeEnumEntry(descriptor, builder);
365            return builder;
366        }
367    
368        private static int getAccessorFlags(@NotNull PropertyAccessorDescriptor accessor) {
369            return Flags.getAccessorFlags(
370                    hasAnnotations(accessor),
371                    accessor.getVisibility(),
372                    accessor.getModality(),
373                    !accessor.isDefault(),
374                    accessor.isExternal()
375            );
376        }
377    
378        @NotNull
379        private ProtoBuf.ValueParameter.Builder valueParameter(@NotNull ValueParameterDescriptor descriptor) {
380            ProtoBuf.ValueParameter.Builder builder = ProtoBuf.ValueParameter.newBuilder();
381    
382            int flags = Flags.getValueParameterFlags(hasAnnotations(descriptor), descriptor.declaresDefaultValue(),
383                                                     descriptor.isCrossinline(), descriptor.isNoinline());
384            if (flags != builder.getFlags()) {
385                builder.setFlags(flags);
386            }
387    
388            builder.setName(getSimpleNameIndex(descriptor.getName()));
389    
390            if (useTypeTable()) {
391                builder.setTypeId(typeId(descriptor.getType()));
392            }
393            else {
394                builder.setType(type(descriptor.getType()));
395            }
396    
397            KotlinType varargElementType = descriptor.getVarargElementType();
398            if (varargElementType != null) {
399                if (useTypeTable()) {
400                    builder.setVarargElementTypeId(typeId(varargElementType));
401                }
402                else {
403                    builder.setVarargElementType(type(varargElementType));
404                }
405            }
406    
407            extension.serializeValueParameter(descriptor, builder);
408    
409            return builder;
410        }
411    
412        private ProtoBuf.TypeParameter.Builder typeParameter(TypeParameterDescriptor typeParameter) {
413            ProtoBuf.TypeParameter.Builder builder = ProtoBuf.TypeParameter.newBuilder();
414    
415            builder.setId(getTypeParameterId(typeParameter));
416    
417            builder.setName(getSimpleNameIndex(typeParameter.getName()));
418    
419            if (typeParameter.isReified() != builder.getReified()) {
420                builder.setReified(typeParameter.isReified());
421            }
422    
423            ProtoBuf.TypeParameter.Variance variance = variance(typeParameter.getVariance());
424            if (variance != builder.getVariance()) {
425                builder.setVariance(variance);
426            }
427            extension.serializeTypeParameter(typeParameter, builder);
428    
429            List<KotlinType> upperBounds = typeParameter.getUpperBounds();
430            if (upperBounds.size() == 1 && KotlinBuiltIns.isDefaultBound(CollectionsKt.single(upperBounds))) return builder;
431    
432            for (KotlinType upperBound : upperBounds) {
433                if (useTypeTable()) {
434                    builder.addUpperBoundId(typeId(upperBound));
435                }
436                else {
437                    builder.addUpperBound(type(upperBound));
438                }
439            }
440    
441            return builder;
442        }
443    
444        private static ProtoBuf.TypeParameter.Variance variance(Variance variance) {
445            switch (variance) {
446                case INVARIANT:
447                    return ProtoBuf.TypeParameter.Variance.INV;
448                case IN_VARIANCE:
449                    return ProtoBuf.TypeParameter.Variance.IN;
450                case OUT_VARIANCE:
451                    return ProtoBuf.TypeParameter.Variance.OUT;
452            }
453            throw new IllegalStateException("Unknown variance: " + variance);
454        }
455    
456        private int typeId(@NotNull KotlinType type) {
457            return typeTable.get(type(type));
458        }
459    
460        @NotNull
461        private ProtoBuf.Type.Builder type(@NotNull KotlinType type) {
462            assert !type.isError() : "Can't serialize error types: " + type; // TODO
463    
464            if (FlexibleTypesKt.isFlexible(type)) {
465                Flexibility flexibility = FlexibleTypesKt.flexibility(type);
466    
467                ProtoBuf.Type.Builder lowerBound = type(flexibility.getLowerBound());
468                lowerBound.setFlexibleTypeCapabilitiesId(getStringTable().getStringIndex(flexibility.getExtraCapabilities().getId()));
469                if (useTypeTable()) {
470                    lowerBound.setFlexibleUpperBoundId(typeId(flexibility.getUpperBound()));
471                }
472                else {
473                    lowerBound.setFlexibleUpperBound(type(flexibility.getUpperBound()));
474                }
475                return lowerBound;
476            }
477    
478            ProtoBuf.Type.Builder builder = ProtoBuf.Type.newBuilder();
479    
480            ClassifierDescriptor descriptor = type.getConstructor().getDeclarationDescriptor();
481            if (descriptor instanceof ClassDescriptor) {
482                PossiblyInnerType possiblyInnerType = TypeParameterUtilsKt.buildPossiblyInnerType(type);
483                assert possiblyInnerType != null : "possiblyInnerType should not be null in case of class";
484    
485                fillFromPossiblyInnerType(builder, possiblyInnerType);
486    
487            }
488            if (descriptor instanceof TypeParameterDescriptor) {
489                TypeParameterDescriptor typeParameter = (TypeParameterDescriptor) descriptor;
490                if (typeParameter.getContainingDeclaration() == containingDeclaration) {
491                    builder.setTypeParameterName(getSimpleNameIndex(typeParameter.getName()));
492                }
493                else {
494                    builder.setTypeParameter(getTypeParameterId(typeParameter));
495                }
496    
497                assert type.getArguments().isEmpty() : "Found arguments for type constructor build on type parameter: " + descriptor;
498            }
499    
500            if (type.isMarkedNullable() != builder.getNullable()) {
501                builder.setNullable(type.isMarkedNullable());
502            }
503    
504            extension.serializeType(type, builder);
505    
506            return builder;
507        }
508    
509        private void fillFromPossiblyInnerType(
510                @NotNull ProtoBuf.Type.Builder builder,
511                @NotNull PossiblyInnerType type
512        ) {
513            builder.setClassName(getClassId(type.getClassDescriptor()));
514    
515            for (TypeProjection projection : type.getArguments()) {
516                builder.addArgument(typeArgument(projection));
517            }
518    
519            if (type.getOuterType() != null) {
520                ProtoBuf.Type.Builder outerBuilder = ProtoBuf.Type.newBuilder();
521                fillFromPossiblyInnerType(outerBuilder, type.getOuterType());
522                if (useTypeTable()) {
523                    builder.setOuterTypeId(typeTable.get(outerBuilder));
524                }
525                else {
526                    builder.setOuterType(outerBuilder);
527                }
528    
529            }
530        }
531    
532        @NotNull
533        private ProtoBuf.Type.Argument.Builder typeArgument(@NotNull TypeProjection typeProjection) {
534            ProtoBuf.Type.Argument.Builder builder = ProtoBuf.Type.Argument.newBuilder();
535    
536            if (typeProjection.isStarProjection()) {
537                builder.setProjection(ProtoBuf.Type.Argument.Projection.STAR);
538            }
539            else {
540                ProtoBuf.Type.Argument.Projection projection = projection(typeProjection.getProjectionKind());
541    
542                if (projection != builder.getProjection()) {
543                    builder.setProjection(projection);
544                }
545    
546                if (useTypeTable()) {
547                    builder.setTypeId(typeId(typeProjection.getType()));
548                }
549                else {
550                    builder.setType(type(typeProjection.getType()));
551                }
552            }
553    
554            return builder;
555        }
556    
557        @NotNull
558        public ProtoBuf.Package.Builder packageProto(@NotNull Collection<PackageFragmentDescriptor> fragments) {
559            return packageProto(fragments, null);
560        }
561    
562        @NotNull
563        public ProtoBuf.Package.Builder packageProto(
564                @NotNull Collection<PackageFragmentDescriptor> fragments,
565                @Nullable Function1<DeclarationDescriptor, Boolean> skip
566        ) {
567            ProtoBuf.Package.Builder builder = ProtoBuf.Package.newBuilder();
568    
569            Collection<DeclarationDescriptor> members = new ArrayList<DeclarationDescriptor>();
570            for (PackageFragmentDescriptor fragment : fragments) {
571                members.addAll(DescriptorUtils.getAllDescriptors(fragment.getMemberScope()));
572            }
573    
574            for (DeclarationDescriptor declaration : sort(members)) {
575                if (skip != null && skip.invoke(declaration)) continue;
576    
577                if (declaration instanceof PropertyDescriptor) {
578                    builder.addProperty(propertyProto((PropertyDescriptor) declaration));
579                }
580                else if (declaration instanceof FunctionDescriptor) {
581                    builder.addFunction(functionProto((FunctionDescriptor) declaration));
582                }
583            }
584    
585            ProtoBuf.TypeTable typeTableProto = typeTable.serialize();
586            if (typeTableProto != null) {
587                builder.setTypeTable(typeTableProto);
588            }
589    
590            extension.serializePackage(builder);
591    
592            return builder;
593        }
594    
595        @NotNull
596        public ProtoBuf.Package.Builder packagePartProto(@NotNull Collection<DeclarationDescriptor> members) {
597            ProtoBuf.Package.Builder builder = ProtoBuf.Package.newBuilder();
598    
599            for (DeclarationDescriptor declaration : sort(members)) {
600                if (declaration instanceof PropertyDescriptor) {
601                    builder.addProperty(propertyProto((PropertyDescriptor) declaration));
602                }
603                else if (declaration instanceof FunctionDescriptor) {
604                    builder.addFunction(functionProto((FunctionDescriptor) declaration));
605                }
606            }
607    
608            ProtoBuf.TypeTable typeTableProto = typeTable.serialize();
609            if (typeTableProto != null) {
610                builder.setTypeTable(typeTableProto);
611            }
612    
613            extension.serializePackage(builder);
614    
615            return builder;
616        }
617    
618        @NotNull
619        private static ProtoBuf.Type.Argument.Projection projection(@NotNull Variance projectionKind) {
620            switch (projectionKind) {
621                case INVARIANT:
622                    return ProtoBuf.Type.Argument.Projection.INV;
623                case IN_VARIANCE:
624                    return ProtoBuf.Type.Argument.Projection.IN;
625                case OUT_VARIANCE:
626                    return ProtoBuf.Type.Argument.Projection.OUT;
627            }
628            throw new IllegalStateException("Unknown projectionKind: " + projectionKind);
629        }
630    
631        private int getClassId(@NotNull ClassDescriptor descriptor) {
632            return getStringTable().getFqNameIndex(descriptor);
633        }
634    
635        private int getSimpleNameIndex(@NotNull Name name) {
636            return getStringTable().getStringIndex(name.asString());
637        }
638    
639        private int getTypeParameterId(@NotNull TypeParameterDescriptor descriptor) {
640            return typeParameters.intern(descriptor);
641        }
642    
643        private static boolean hasAnnotations(Annotated descriptor) {
644            return !descriptor.getAnnotations().isEmpty();
645        }
646    
647        @NotNull
648        public static <T extends DeclarationDescriptor> List<T> sort(@NotNull Collection<T> descriptors) {
649            List<T> result = new ArrayList<T>(descriptors);
650            //NOTE: the exact comparator does matter here
651            Collections.sort(result, MemberComparator.INSTANCE);
652            return result;
653    
654        }
655    }