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