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 }