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