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 }