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("<", "<").replaceAll(">", ">");
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 "→";
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 renderAnnotations(valueParameter, builder);
551 renderVariable(valueParameter, builder, topLevel);
552 boolean withDefaultValue = debugMode ? valueParameter.declaresDefaultValue() : valueParameter.hasDefaultValue();
553 if (withDefaultValue) {
554 builder.append(" = ...");
555 }
556 }
557
558 private void renderValVarPrefix(@NotNull VariableDescriptor variable, @NotNull StringBuilder builder) {
559 builder.append(renderKeyword(variable.isVar() ? "var" : "val")).append(" ");
560 }
561
562 private void renderVariable(@NotNull VariableDescriptor variable, @NotNull StringBuilder builder, boolean topLevel) {
563 JetType realType = variable.getType();
564
565 JetType varargElementType = variable instanceof ValueParameterDescriptor
566 ? ((ValueParameterDescriptor) variable).getVarargElementType()
567 : null;
568 JetType typeToRender = varargElementType != null ? varargElementType : realType;
569
570 if (varargElementType != null) {
571 builder.append(renderKeyword("vararg")).append(" ");
572 }
573 if (topLevel && !startFromName) {
574 renderValVarPrefix(variable, builder);
575 }
576
577 renderName(variable, builder);
578 builder.append(": ").append(escape(renderType(typeToRender)));
579
580 if (verbose && varargElementType != null) {
581 builder.append(" /*").append(escape(renderType(realType))).append("*/");
582 }
583 }
584
585 private void renderProperty(@NotNull PropertyDescriptor property, @NotNull StringBuilder builder) {
586 if (!startFromName) {
587 renderAnnotations(property, builder);
588 renderVisibility(property.getVisibility(), builder);
589 renderModalityForCallable(property, builder);
590 renderOverride(property, builder);
591 renderMemberKind(property, builder);
592
593 renderValVarPrefix(property, builder);
594 }
595
596 renderTypeParameters(property.getTypeParameters(), builder, true);
597
598 ReceiverParameterDescriptor receiver = property.getReceiverParameter();
599 if (receiver != null) {
600 builder.append(escape(renderType(receiver.getType()))).append(".");
601 }
602 renderName(property, builder);
603 builder.append(": ").append(escape(renderType(property.getType())));
604
605 renderWhereSuffix(property.getTypeParameters(), builder);
606 }
607
608
609 /* CLASSES */
610 private void renderClass(@NotNull ClassDescriptor klass, @NotNull StringBuilder builder) {
611 if (!startFromName) {
612 renderAnnotations(klass, builder);
613 renderVisibility(klass.getVisibility(), builder);
614 if (!(klass.getKind() == ClassKind.TRAIT && klass.getModality() == Modality.ABSTRACT
615 || klass.getKind().isObject() && klass.getModality() == Modality.FINAL)) {
616 renderModality(klass.getModality(), builder);
617 }
618 renderInner(klass.isInner(), builder);
619 builder.append(renderKeyword(getClassKindPrefix(klass)));
620 }
621
622 if (klass.getKind() != ClassKind.CLASS_OBJECT || verbose) {
623 builder.append(" ");
624 renderName(klass, builder);
625 }
626
627 List<TypeParameterDescriptor> typeParameters = klass.getTypeConstructor().getParameters();
628 renderTypeParameters(typeParameters, builder, false);
629
630 if (!klass.getKind().isObject() && classWithPrimaryConstructor) {
631 ConstructorDescriptor primaryConstructor = klass.getUnsubstitutedPrimaryConstructor();
632 if (primaryConstructor != null) {
633 renderValueParameters(primaryConstructor, builder);
634 }
635 }
636
637 if (!klass.equals(KotlinBuiltIns.getInstance().getNothing())) {
638 Collection<JetType> supertypes = klass.getTypeConstructor().getSupertypes();
639 if (supertypes.isEmpty() || !alwaysRenderAny && supertypes.size() == 1 && KotlinBuiltIns.getInstance().isAny(supertypes.iterator().next())) {
640 }
641 else {
642 builder.append(" : ");
643 for (Iterator<JetType> iterator = supertypes.iterator(); iterator.hasNext(); ) {
644 JetType supertype = iterator.next();
645 builder.append(renderType(supertype));
646 if (iterator.hasNext()) {
647 builder.append(", ");
648 }
649 }
650 }
651 }
652
653 renderWhereSuffix(typeParameters, builder);
654 }
655
656 @NotNull
657 private static String getClassKindPrefix(@NotNull ClassDescriptor klass) {
658 switch (klass.getKind()) {
659 case CLASS:
660 return "class";
661 case TRAIT:
662 return "trait";
663 case ENUM_CLASS:
664 return "enum class";
665 case OBJECT:
666 return "object";
667 case ANNOTATION_CLASS:
668 return "annotation class";
669 case CLASS_OBJECT:
670 return "class object";
671 case ENUM_ENTRY:
672 return "enum entry";
673 default:
674 throw new IllegalStateException("unknown class kind: " + klass.getKind());
675 }
676 }
677
678
679 /* OTHER */
680 private void renderModuleOrScript(@NotNull DeclarationDescriptor moduleOrScript, @NotNull StringBuilder builder) {
681 renderName(moduleOrScript, builder);
682 }
683
684 private void renderNamespace(@NotNull NamespaceDescriptor namespace, @NotNull StringBuilder builder) {
685 builder.append(renderKeyword("package")).append(" ");
686 renderName(namespace, builder);
687 }
688
689
690 /* STUPID DISPATCH-ONLY VISITOR */
691 private class RenderDeclarationDescriptorVisitor extends DeclarationDescriptorVisitorEmptyBodies<Void, StringBuilder> {
692 @Override
693 public Void visitValueParameterDescriptor(ValueParameterDescriptor descriptor, StringBuilder builder) {
694 renderValueParameter(descriptor, builder, true);
695 return null;
696 }
697
698 @Override
699 public Void visitVariableDescriptor(VariableDescriptor descriptor, StringBuilder builder) {
700 renderVariable(descriptor, builder, true);
701 return null;
702 }
703
704 @Override
705 public Void visitPropertyDescriptor(PropertyDescriptor descriptor, StringBuilder builder) {
706 renderProperty(descriptor, builder);
707 return null;
708 }
709
710 @Override
711 public Void visitFunctionDescriptor(FunctionDescriptor descriptor, StringBuilder builder) {
712 renderFunction(descriptor, builder);
713 return null;
714 }
715
716 @Override
717 public Void visitReceiverParameterDescriptor(ReceiverParameterDescriptor descriptor, StringBuilder data) {
718 throw new UnsupportedOperationException("Don't render receiver parameters");
719 }
720
721 @Override
722 public Void visitConstructorDescriptor(ConstructorDescriptor constructorDescriptor, StringBuilder builder) {
723 renderConstructor(constructorDescriptor, builder);
724 return null;
725 }
726
727 @Override
728 public Void visitTypeParameterDescriptor(TypeParameterDescriptor descriptor, StringBuilder builder) {
729 renderTypeParameter(descriptor, builder, true);
730 return null;
731 }
732
733 @Override
734 public Void visitNamespaceDescriptor(NamespaceDescriptor namespaceDescriptor, StringBuilder builder) {
735 renderNamespace(namespaceDescriptor, builder);
736 return null;
737 }
738
739 @Override
740 public Void visitModuleDeclaration(ModuleDescriptor descriptor, StringBuilder builder) {
741 renderModuleOrScript(descriptor, builder);
742 return null;
743 }
744
745 @Override
746 public Void visitScriptDescriptor(ScriptDescriptor scriptDescriptor, StringBuilder builder) {
747 renderModuleOrScript(scriptDescriptor, builder);
748 return null;
749 }
750
751 @Override
752 public Void visitClassDescriptor(ClassDescriptor descriptor, StringBuilder builder) {
753 renderClass(descriptor, builder);
754 return null;
755 }
756 }
757 }