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.renderer;
018    
019    import com.google.common.collect.Lists;
020    import com.google.common.collect.Sets;
021    import com.intellij.openapi.util.text.StringUtil;
022    import org.jetbrains.annotations.NotNull;
023    import org.jetbrains.jet.lang.descriptors.*;
024    import org.jetbrains.jet.lang.descriptors.annotations.Annotated;
025    import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor;
026    import org.jetbrains.jet.lang.descriptors.impl.DeclarationDescriptorVisitorEmptyBodies;
027    import org.jetbrains.jet.lang.resolve.DescriptorUtils;
028    import org.jetbrains.jet.lang.resolve.name.FqName;
029    import org.jetbrains.jet.lang.resolve.name.FqNameUnsafe;
030    import org.jetbrains.jet.lang.resolve.name.Name;
031    import org.jetbrains.jet.lang.types.*;
032    import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
033    
034    import java.util.*;
035    
036    import static org.jetbrains.jet.lang.types.TypeUtils.CANT_INFER_LAMBDA_PARAM_TYPE;
037    import static org.jetbrains.jet.lang.types.TypeUtils.CANT_INFER_TYPE_PARAMETER;
038    
039    public class DescriptorRendererImpl implements DescriptorRenderer {
040        private final boolean shortNames;
041        private final boolean withDefinedIn;
042        private final Set<DescriptorRenderer.Modifier> modifiers;
043        private final boolean startFromName;
044        private final boolean debugMode;
045        private final boolean classWithPrimaryConstructor;
046        private final boolean verbose;
047        private final boolean unitReturnType;
048        private final boolean normalizedVisibilities;
049        private final boolean showInternalKeyword;
050        private final boolean alwaysRenderAny;
051        private final boolean prettyFunctionTypes;
052        @NotNull
053        private final OverrideRenderingPolicy overrideRenderingPolicy;
054        @NotNull
055        private final ValueParametersHandler handler;
056        @NotNull
057        private final TextFormat textFormat;
058        @NotNull
059        private final Set<FqName> excludedAnnotationClasses;
060    
061        /* package */ DescriptorRendererImpl(
062                boolean shortNames,
063                boolean withDefinedIn,
064                Set<DescriptorRenderer.Modifier> modifiers,
065                boolean startFromName,
066                boolean debugMode,
067                boolean classWithPrimaryConstructor,
068                boolean verbose,
069                boolean unitReturnType,
070                boolean normalizedVisibilities,
071                boolean showInternalKeyword,
072                boolean alwaysRenderAny,
073                boolean prettyFunctionTypes,
074                @NotNull OverrideRenderingPolicy overrideRenderingPolicy,
075                @NotNull ValueParametersHandler handler,
076                @NotNull TextFormat textFormat,
077                @NotNull Collection<FqName> excludedAnnotationClasses
078        ) {
079            this.shortNames = shortNames;
080            this.withDefinedIn = withDefinedIn;
081            this.modifiers = modifiers;
082            this.startFromName = startFromName;
083            this.handler = handler;
084            this.classWithPrimaryConstructor = classWithPrimaryConstructor;
085            this.verbose = verbose;
086            this.unitReturnType = unitReturnType;
087            this.normalizedVisibilities = normalizedVisibilities;
088            this.showInternalKeyword = showInternalKeyword;
089            this.overrideRenderingPolicy = overrideRenderingPolicy;
090            this.debugMode = debugMode;
091            this.textFormat = textFormat;
092            this.excludedAnnotationClasses = Sets.newHashSet(excludedAnnotationClasses);
093            this.alwaysRenderAny = alwaysRenderAny;
094            this.prettyFunctionTypes = prettyFunctionTypes;
095        }
096    
097    
098        /* FORMATTING */
099        @NotNull
100        private String renderKeyword(@NotNull String keyword) {
101            switch (textFormat) {
102                case PLAIN:
103                    return keyword;
104                case HTML:
105                    return "<b>" + keyword + "</b>";
106            }
107            throw new IllegalStateException("Unexpected textFormat: " + textFormat);
108        }
109    
110        @NotNull
111        private String escape(@NotNull String string) {
112            switch (textFormat) {
113                case PLAIN:
114                    return string;
115                case HTML:
116                    return string.replaceAll("<", "&lt;").replaceAll(">", "&gt;");
117            }
118            throw new IllegalStateException("Unexpected textFormat: " + textFormat);
119        }
120    
121        @NotNull
122        private String lt() {
123            return escape("<");
124        }
125    
126        @NotNull
127        private String arrow() {
128            switch (textFormat) {
129                case PLAIN:
130                    return escape("->");
131                case HTML:
132                    return "&rarr;";
133            }
134            throw new IllegalStateException("Unexpected textFormat: " + textFormat);
135        }
136    
137        @NotNull
138        private String renderMessage(@NotNull String message) {
139            switch (textFormat) {
140                case PLAIN:
141                    return message;
142                case HTML:
143                    return "<i>" + message + "</i>";
144            }
145            throw new IllegalStateException("Unexpected textFormat: " + textFormat);
146        }
147    
148    
149        /* NAMES RENDERING */
150        @NotNull
151        private String renderName(@NotNull Name identifier) {
152            String asString = identifier.toString();
153            return escape(KeywordStringsGenerated.KEYWORDS.contains(asString) ? '`' + asString + '`' : asString);
154        }
155    
156        private void renderName(@NotNull DeclarationDescriptor descriptor, @NotNull StringBuilder builder) {
157            builder.append(renderName(descriptor.getName()));
158        }
159    
160        @NotNull
161        private String renderFqName(@NotNull FqNameUnsafe fqName) {
162            return renderFqName(fqName.pathSegments());
163        }
164    
165    
166        @NotNull
167        private String renderFqName(@NotNull List<Name> pathSegments) {
168            StringBuilder buf = new StringBuilder();
169            for (Name element : pathSegments) {
170                if (buf.length() != 0) {
171                    buf.append(".");
172                }
173                buf.append(renderName(element));
174            }
175            return buf.toString();
176        }
177    
178        @NotNull
179        private String renderClassName(@NotNull ClassDescriptor klass) {
180            if (ErrorUtils.isError(klass)) {
181                return klass.getTypeConstructor().toString();
182            }
183            if (shortNames) {
184                List<Name> qualifiedNameElements = Lists.newArrayList();
185    
186                // for nested classes qualified name should be used
187                DeclarationDescriptor current = klass;
188                do {
189                    if (((ClassDescriptor) current).getKind() != ClassKind.CLASS_OBJECT) {
190                        qualifiedNameElements.add(current.getName());
191                    }
192                    current = current.getContainingDeclaration();
193                }
194                while (current instanceof ClassDescriptor);
195    
196                Collections.reverse(qualifiedNameElements);
197                return renderFqName(qualifiedNameElements);
198            }
199            return renderFqName(DescriptorUtils.getFQName(klass));
200        }
201    
202        /* TYPES RENDERING */
203        @NotNull
204        @Override
205        public String renderType(@NotNull JetType type) {
206            return escape(renderTypeWithoutEscape(type));
207        }
208    
209        private String renderTypeWithoutEscape(@NotNull JetType type) {
210            if (type == CANT_INFER_LAMBDA_PARAM_TYPE || type == CANT_INFER_TYPE_PARAMETER) {
211                return "???";
212            }
213            if (type.isError()) {
214                return type.toString();
215            }
216            if (KotlinBuiltIns.getInstance().isFunctionOrExtensionFunctionType(type) && prettyFunctionTypes) {
217                return renderFunctionType(type);
218            }
219            return renderDefaultType(type);
220        }
221    
222        @NotNull
223        private String renderDefaultType(@NotNull JetType type) {
224            StringBuilder sb = new StringBuilder();
225    
226            sb.append(renderTypeName(type.getConstructor()));
227            if (!type.getArguments().isEmpty()) {
228                sb.append("<");
229                appendTypeProjections(type.getArguments(), sb);
230                sb.append(">");
231            }
232            if (type.isNullable()) {
233                sb.append("?");
234            }
235            return sb.toString();
236        }
237    
238        @NotNull
239        private String renderTypeName(@NotNull TypeConstructor typeConstructor) {
240            ClassifierDescriptor cd = typeConstructor.getDeclarationDescriptor();
241            if (cd instanceof TypeParameterDescriptor) {
242                return renderName(cd.getName());
243            }
244            else if (cd instanceof ClassDescriptor) {
245                return renderClassName((ClassDescriptor) cd);
246            }
247            else {
248                assert cd == null: "Unexpected classifier: " + cd.getClass();
249                return typeConstructor.toString();
250            }
251        }
252    
253        private void appendTypeProjections(@NotNull List<TypeProjection> typeProjections, @NotNull StringBuilder builder) {
254            for (Iterator<TypeProjection> iterator = typeProjections.iterator(); iterator.hasNext(); ) {
255                TypeProjection typeProjection = iterator.next();
256                if (typeProjection.getProjectionKind() != Variance.INVARIANT) {
257                    builder.append(typeProjection.getProjectionKind()).append(" ");
258                }
259                builder.append(renderType(typeProjection.getType()));
260                if (iterator.hasNext()) {
261                    builder.append(", ");
262                }
263            }
264        }
265    
266        @NotNull
267        private String renderFunctionType(@NotNull JetType type) {
268            StringBuilder sb = new StringBuilder();
269    
270            JetType receiverType = KotlinBuiltIns.getInstance().getReceiverType(type);
271            if (receiverType != null) {
272                sb.append(renderType(receiverType));
273                sb.append(".");
274            }
275    
276            sb.append("(");
277            appendTypeProjections(KotlinBuiltIns.getInstance().getParameterTypeProjectionsFromFunctionType(type), sb);
278            sb.append(") " + arrow() + " ");
279            sb.append(renderType(KotlinBuiltIns.getInstance().getReturnTypeFromFunctionType(type)));
280    
281            if (type.isNullable()) {
282                return "(" + sb + ")?";
283            }
284            return sb.toString();
285        }
286    
287    
288        /* METHODS FOR ALL KINDS OF DESCRIPTORS */
289        private void appendDefinedIn(@NotNull DeclarationDescriptor descriptor, @NotNull StringBuilder builder) {
290            if (descriptor instanceof ModuleDescriptor) {
291                builder.append(" is a module");
292                return;
293            }
294            builder.append(" ").append(renderMessage("defined in")).append(" ");
295    
296            DeclarationDescriptor containingDeclaration = descriptor.getContainingDeclaration();
297            if (containingDeclaration != null) {
298                FqNameUnsafe fqName = DescriptorUtils.getFQName(containingDeclaration);
299                builder.append(FqName.ROOT.equalsTo(fqName) ? "root package" : renderFqName(fqName));
300            }
301        }
302    
303        private void renderAnnotations(@NotNull Annotated annotated, @NotNull StringBuilder builder) {
304            if (!modifiers.contains(Modifier.ANNOTATIONS)) return;
305            for (AnnotationDescriptor annotation : annotated.getAnnotations()) {
306                ClassDescriptor annotationClass = (ClassDescriptor) annotation.getType().getConstructor().getDeclarationDescriptor();
307                assert annotationClass != null;
308    
309                if (!excludedAnnotationClasses.contains(DescriptorUtils.getFQName(annotationClass).toSafe())) {
310                    builder.append(renderType(annotation.getType()));
311                    if (verbose) {
312                        builder.append("(").append(StringUtil.join(DescriptorUtils.getSortedValueArguments(annotation, this), ", ")).append(")");
313                    }
314                    builder.append(" ");
315                }
316            }
317        }
318    
319        private void renderVisibility(@NotNull Visibility visibility, @NotNull StringBuilder builder) {
320            if (!modifiers.contains(Modifier.VISIBILITY)) return;
321            if (normalizedVisibilities) {
322                visibility = visibility.normalize();
323            }
324            if (!showInternalKeyword && visibility == Visibilities.INTERNAL) return;
325            builder.append(renderKeyword(visibility.toString())).append(" ");
326        }
327    
328        private void renderModality(@NotNull Modality modality, @NotNull StringBuilder builder) {
329            if (!modifiers.contains(Modifier.MODALITY)) return;
330            String keyword = modality.name().toLowerCase();
331            builder.append(renderKeyword(keyword)).append(" ");
332        }
333    
334        private void renderInner(boolean isInner, @NotNull StringBuilder builder) {
335            if (!modifiers.contains(Modifier.INNER)) return;
336            if (isInner) {
337                builder.append(renderKeyword("inner")).append(" ");
338            }
339        }
340    
341        private void renderModalityForCallable(@NotNull CallableMemberDescriptor callable, @NotNull StringBuilder builder) {
342            if (!DescriptorUtils.isTopLevelDeclaration(callable) || callable.getModality() != Modality.FINAL) {
343                if (overridesSomething(callable)
344                    && overrideRenderingPolicy == OverrideRenderingPolicy.RENDER_OVERRIDE
345                    && callable.getModality() == Modality.OPEN) {
346                    return;
347                }
348                renderModality(callable.getModality(), builder);
349            }
350        }
351    
352        private boolean overridesSomething(CallableMemberDescriptor callable) {
353            return !callable.getOverriddenDescriptors().isEmpty();
354        }
355    
356        private void renderOverride(@NotNull CallableMemberDescriptor callableMember, @NotNull StringBuilder builder) {
357            if (!modifiers.contains(Modifier.OVERRIDE)) return;
358            if (overridesSomething(callableMember)) {
359                if (overrideRenderingPolicy != OverrideRenderingPolicy.RENDER_OPEN) {
360                    builder.append("override ");
361                    if (verbose) {
362                        builder.append("/*").append(callableMember.getOverriddenDescriptors().size()).append("*/ ");
363                    }
364                }
365            }
366        }
367    
368        private void renderMemberKind(CallableMemberDescriptor callableMember, StringBuilder builder) {
369            if (!modifiers.contains(Modifier.MEMBER_KIND)) return;
370            if (verbose && callableMember.getKind() != CallableMemberDescriptor.Kind.DECLARATION) {
371                builder.append("/*").append(callableMember.getKind().name().toLowerCase()).append("*/ ");
372            }
373        }
374    
375        @NotNull
376        @Override
377        public String render(@NotNull DeclarationDescriptor declarationDescriptor) {
378            StringBuilder stringBuilder = new StringBuilder();
379            declarationDescriptor.accept(new RenderDeclarationDescriptorVisitor(), stringBuilder);
380    
381            if (withDefinedIn) {
382                appendDefinedIn(declarationDescriptor, stringBuilder);
383            }
384            return stringBuilder.toString();
385        }
386    
387    
388        /* TYPE PARAMETERS */
389        private void renderTypeParameter(@NotNull TypeParameterDescriptor typeParameter, @NotNull StringBuilder builder, boolean topLevel) {
390            if (topLevel) {
391                builder.append(lt());
392            }
393    
394            if (verbose) {
395                builder.append("/*").append(typeParameter.getIndex()).append("*/ ");
396            }
397    
398            if (typeParameter.isReified()) {
399                builder.append(renderKeyword("reified")).append(" ");
400            }
401            String variance = typeParameter.getVariance().toString();
402            if (!variance.isEmpty()) {
403                builder.append(renderKeyword(variance)).append(" ");
404            }
405            renderName(typeParameter, builder);
406            int upperBoundsCount = typeParameter.getUpperBounds().size();
407            if ((upperBoundsCount > 1 && !topLevel) || upperBoundsCount == 1) {
408                JetType upperBound = typeParameter.getUpperBounds().iterator().next();
409                if (!KotlinBuiltIns.getInstance().getDefaultBound().equals(upperBound) || alwaysRenderAny) {
410                    builder.append(" : ").append(renderType(upperBound));
411                }
412            }
413            else if (topLevel) {
414                boolean first = true;
415                for (JetType upperBound : typeParameter.getUpperBounds()) {
416                    if (upperBound.equals(KotlinBuiltIns.getInstance().getDefaultBound())) {
417                        continue;
418                    }
419                    if (first) {
420                        builder.append(" : ");
421                    }
422                    else {
423                        builder.append(" & ");
424                    }
425                    builder.append(renderType(upperBound));
426                    first = false;
427                }
428            }
429            else {
430                // rendered with "where"
431            }
432    
433            if (topLevel) {
434                builder.append(">");
435            }
436        }
437    
438        private void renderTypeParameters(
439                @NotNull List<TypeParameterDescriptor> typeParameters,
440                @NotNull StringBuilder builder,
441                boolean withSpace
442        ) {
443            if (!typeParameters.isEmpty()) {
444                builder.append(lt());
445                for (Iterator<TypeParameterDescriptor> iterator = typeParameters.iterator(); iterator.hasNext(); ) {
446                    TypeParameterDescriptor typeParameterDescriptor = iterator.next();
447                    renderTypeParameter(typeParameterDescriptor, builder, false);
448                    if (iterator.hasNext()) {
449                        builder.append(", ");
450                    }
451                }
452                builder.append(">");
453                if (withSpace) {
454                    builder.append(" ");
455                }
456            }
457        }
458    
459        /* FUNCTIONS */
460        private void renderFunction(@NotNull FunctionDescriptor function, @NotNull StringBuilder builder) {
461            if (!startFromName) {
462                renderAnnotations(function, builder);
463                renderVisibility(function.getVisibility(), builder);
464                renderModalityForCallable(function, builder);
465                renderOverride(function, builder);
466                renderMemberKind(function, builder);
467    
468                builder.append(renderKeyword("fun")).append(" ");
469                renderTypeParameters(function.getTypeParameters(), builder, true);
470    
471                ReceiverParameterDescriptor receiver = function.getReceiverParameter();
472                if (receiver != null) {
473                    builder.append(escape(renderType(receiver.getType()))).append(".");
474                }
475            }
476    
477            renderName(function, builder);
478            renderValueParameters(function, builder);
479            JetType returnType = function.getReturnType();
480            if (unitReturnType || !KotlinBuiltIns.getInstance().isUnit(returnType)) {
481                builder.append(": ").append(returnType == null ? "[NULL]" : escape(renderType(returnType)));
482            }
483            renderWhereSuffix(function.getTypeParameters(), builder);
484        }
485    
486        private void renderConstructor(@NotNull ConstructorDescriptor constructor, @NotNull StringBuilder builder) {
487            renderAnnotations(constructor, builder);
488            renderVisibility(constructor.getVisibility(), builder);
489            renderMemberKind(constructor, builder);
490    
491            builder.append(renderKeyword("constructor")).append(" ");
492    
493            ClassDescriptor classDescriptor = constructor.getContainingDeclaration();
494            renderName(classDescriptor, builder);
495    
496            renderTypeParameters(classDescriptor.getTypeConstructor().getParameters(), builder, false);
497            renderValueParameters(constructor, builder);
498            renderWhereSuffix(constructor.getTypeParameters(), builder);
499        }
500    
501        private void renderWhereSuffix(@NotNull List<TypeParameterDescriptor> typeParameters, @NotNull StringBuilder builder) {
502            List<String> upperBoundStrings = Lists.newArrayList();
503    
504            for (TypeParameterDescriptor typeParameter : typeParameters) {
505                if (typeParameter.getUpperBounds().size() > 1) {
506                    boolean first = true;
507                    for (JetType upperBound : typeParameter.getUpperBounds()) {
508                        // first parameter is rendered by renderTypeParameter:
509                        if (!first) {
510                            upperBoundStrings.add(renderName(typeParameter.getName()) + " : " + escape(renderType(upperBound)));
511                        }
512                        first = false;
513                    }
514                }
515            }
516            if (!upperBoundStrings.isEmpty()) {
517                builder.append(" ").append(renderKeyword("where")).append(" ");
518                builder.append(StringUtil.join(upperBoundStrings, ", "));
519            }
520        }
521    
522        @NotNull
523        @Override
524        public String renderFunctionParameters(@NotNull FunctionDescriptor functionDescriptor) {
525            StringBuilder stringBuilder = new StringBuilder();
526            renderValueParameters(functionDescriptor, stringBuilder);
527            return stringBuilder.toString();
528        }
529    
530        private void renderValueParameters(@NotNull FunctionDescriptor function, @NotNull StringBuilder builder) {
531            handler.appendBeforeValueParameters(function, builder);
532            for (ValueParameterDescriptor parameter : function.getValueParameters()) {
533                handler.appendBeforeValueParameter(parameter, builder);
534                renderValueParameter(parameter, builder, false);
535                handler.appendAfterValueParameter(parameter, builder);
536            }
537            handler.appendAfterValueParameters(function, builder);
538        }
539    
540        /* VARIABLES */
541        private void renderValueParameter(@NotNull ValueParameterDescriptor valueParameter, @NotNull StringBuilder builder, boolean topLevel) {
542            if (topLevel) {
543                builder.append(renderKeyword("value-parameter")).append(" ");
544            }
545    
546            if (verbose) {
547                builder.append("/*").append(valueParameter.getIndex()).append("*/ ");
548            }
549    
550            renderVariable(valueParameter, builder, topLevel);
551            boolean withDefaultValue = debugMode ? valueParameter.declaresDefaultValue() : valueParameter.hasDefaultValue();
552            if (withDefaultValue) {
553                builder.append(" = ...");
554            }
555        }
556    
557        private void renderValVarPrefix(@NotNull VariableDescriptor variable, @NotNull StringBuilder builder) {
558            builder.append(renderKeyword(variable.isVar() ? "var" : "val")).append(" ");
559        }
560    
561        private void renderVariable(@NotNull VariableDescriptor variable, @NotNull StringBuilder builder, boolean topLevel) {
562            JetType realType = variable.getType();
563    
564            JetType varargElementType = variable instanceof ValueParameterDescriptor
565                                        ? ((ValueParameterDescriptor) variable).getVarargElementType()
566                                        : null;
567            JetType typeToRender = varargElementType != null ? varargElementType : realType;
568    
569            if (varargElementType != null) {
570                builder.append(renderKeyword("vararg")).append(" ");
571            }
572            if (topLevel && !startFromName) {
573                renderValVarPrefix(variable, builder);
574            }
575    
576            renderName(variable, builder);
577            builder.append(": ").append(escape(renderType(typeToRender)));
578    
579            if (verbose && varargElementType != null) {
580                builder.append(" /*").append(escape(renderType(realType))).append("*/");
581            }
582        }
583    
584        private void renderProperty(@NotNull PropertyDescriptor property, @NotNull StringBuilder builder) {
585            if (!startFromName) {
586                renderAnnotations(property, builder);
587                renderVisibility(property.getVisibility(), builder);
588                renderModalityForCallable(property, builder);
589                renderOverride(property, builder);
590                renderMemberKind(property, builder);
591    
592                renderValVarPrefix(property, builder);
593            }
594    
595            renderTypeParameters(property.getTypeParameters(), builder, true);
596    
597            ReceiverParameterDescriptor receiver = property.getReceiverParameter();
598            if (receiver != null) {
599                builder.append(escape(renderType(receiver.getType()))).append(".");
600            }
601            renderName(property, builder);
602            builder.append(": ").append(escape(renderType(property.getType())));
603    
604            renderWhereSuffix(property.getTypeParameters(), builder);
605        }
606    
607    
608        /* CLASSES */
609        private void renderClass(@NotNull ClassDescriptor klass, @NotNull StringBuilder builder) {
610            if (!startFromName) {
611                renderAnnotations(klass, builder);
612                renderVisibility(klass.getVisibility(), builder);
613                if (!(klass.getKind() == ClassKind.TRAIT && klass.getModality() == Modality.ABSTRACT
614                    || klass.getKind().isObject() && klass.getModality() == Modality.FINAL)) {
615                    renderModality(klass.getModality(), builder);
616                }
617                renderInner(klass.isInner(), builder);
618                builder.append(renderKeyword(getClassKindPrefix(klass)));
619            }
620    
621            if (klass.getKind() != ClassKind.CLASS_OBJECT || verbose) {
622                builder.append(" ");
623                renderName(klass, builder);
624            }
625    
626            List<TypeParameterDescriptor> typeParameters = klass.getTypeConstructor().getParameters();
627            renderTypeParameters(typeParameters, builder, false);
628    
629            if (!klass.getKind().isObject() && classWithPrimaryConstructor) {
630                ConstructorDescriptor primaryConstructor = klass.getUnsubstitutedPrimaryConstructor();
631                if (primaryConstructor != null) {
632                    renderValueParameters(primaryConstructor, builder);
633                }
634            }
635    
636            if (!klass.equals(KotlinBuiltIns.getInstance().getNothing())) {
637                Collection<JetType> supertypes = klass.getTypeConstructor().getSupertypes();
638                if (supertypes.isEmpty() || !alwaysRenderAny && supertypes.size() == 1 && KotlinBuiltIns.getInstance().isAny(supertypes.iterator().next())) {
639                }
640                else {
641                    builder.append(" : ");
642                    for (Iterator<JetType> iterator = supertypes.iterator(); iterator.hasNext(); ) {
643                        JetType supertype = iterator.next();
644                        builder.append(renderType(supertype));
645                        if (iterator.hasNext()) {
646                            builder.append(", ");
647                        }
648                    }
649                }
650            }
651    
652            renderWhereSuffix(typeParameters, builder);
653        }
654    
655        @NotNull
656        private static String getClassKindPrefix(@NotNull ClassDescriptor klass) {
657            switch (klass.getKind()) {
658                case CLASS:
659                    return "class";
660                case TRAIT:
661                    return "trait";
662                case ENUM_CLASS:
663                    return "enum class";
664                case OBJECT:
665                    return "object";
666                case ANNOTATION_CLASS:
667                    return "annotation class";
668                case CLASS_OBJECT:
669                    return "class object";
670                case ENUM_ENTRY:
671                    return "enum entry";
672                default:
673                    throw new IllegalStateException("unknown class kind: " + klass.getKind());
674            }
675        }
676    
677    
678        /* OTHER */
679        private void renderModuleOrScript(@NotNull DeclarationDescriptor moduleOrScript, @NotNull StringBuilder builder) {
680            renderName(moduleOrScript, builder);
681        }
682    
683        private void renderNamespace(@NotNull NamespaceDescriptor namespace, @NotNull StringBuilder builder) {
684            builder.append(renderKeyword("package")).append(" ");
685            renderName(namespace, builder);
686        }
687    
688    
689        /* STUPID DISPATCH-ONLY VISITOR */
690        private class RenderDeclarationDescriptorVisitor extends DeclarationDescriptorVisitorEmptyBodies<Void, StringBuilder> {
691            @Override
692            public Void visitValueParameterDescriptor(ValueParameterDescriptor descriptor, StringBuilder builder) {
693                renderValueParameter(descriptor, builder, true);
694                return null;
695            }
696    
697            @Override
698            public Void visitVariableDescriptor(VariableDescriptor descriptor, StringBuilder builder) {
699                renderVariable(descriptor, builder, true);
700                return null;
701            }
702    
703            @Override
704            public Void visitPropertyDescriptor(PropertyDescriptor descriptor, StringBuilder builder) {
705                renderProperty(descriptor, builder);
706                return null;
707            }
708    
709            @Override
710            public Void visitFunctionDescriptor(FunctionDescriptor descriptor, StringBuilder builder) {
711                renderFunction(descriptor, builder);
712                return null;
713            }
714    
715            @Override
716            public Void visitReceiverParameterDescriptor(ReceiverParameterDescriptor descriptor, StringBuilder data) {
717                throw new UnsupportedOperationException("Don't render receiver parameters");
718            }
719    
720            @Override
721            public Void visitConstructorDescriptor(ConstructorDescriptor constructorDescriptor, StringBuilder builder) {
722                renderConstructor(constructorDescriptor, builder);
723                return null;
724            }
725    
726            @Override
727            public Void visitTypeParameterDescriptor(TypeParameterDescriptor descriptor, StringBuilder builder) {
728                renderTypeParameter(descriptor, builder, true);
729                return null;
730            }
731    
732            @Override
733            public Void visitNamespaceDescriptor(NamespaceDescriptor namespaceDescriptor, StringBuilder builder) {
734                renderNamespace(namespaceDescriptor, builder);
735                return null;
736            }
737    
738            @Override
739            public Void visitModuleDeclaration(ModuleDescriptor descriptor, StringBuilder builder) {
740                renderModuleOrScript(descriptor, builder);
741                return null;
742            }
743    
744            @Override
745            public Void visitScriptDescriptor(ScriptDescriptor scriptDescriptor, StringBuilder builder) {
746                renderModuleOrScript(scriptDescriptor, builder);
747                return null;
748            }
749    
750            @Override
751            public Void visitClassDescriptor(ClassDescriptor descriptor, StringBuilder builder) {
752                renderClass(descriptor, builder);
753                return null;
754            }
755       }
756    }