001 /* 002 * Copyright 2010-2014 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.util.Function; 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.annotations.DefaultAnnotationArgumentVisitor; 028 import org.jetbrains.jet.lang.descriptors.impl.DeclarationDescriptorVisitorEmptyBodies; 029 import org.jetbrains.jet.lang.resolve.DescriptorUtils; 030 import org.jetbrains.jet.lang.resolve.constants.AnnotationValue; 031 import org.jetbrains.jet.lang.resolve.constants.ArrayValue; 032 import org.jetbrains.jet.lang.resolve.constants.CompileTimeConstant; 033 import org.jetbrains.jet.lang.resolve.constants.JavaClassValue; 034 import org.jetbrains.jet.lang.resolve.name.FqName; 035 import org.jetbrains.jet.lang.resolve.name.FqNameBase; 036 import org.jetbrains.jet.lang.resolve.name.FqNameUnsafe; 037 import org.jetbrains.jet.lang.resolve.name.Name; 038 import org.jetbrains.jet.lang.types.*; 039 import org.jetbrains.jet.lang.types.error.MissingDependencyErrorClass; 040 import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns; 041 042 import java.util.*; 043 044 import static org.jetbrains.jet.lang.types.ErrorUtils.UninferredParameterType; 045 import static org.jetbrains.jet.lang.types.TypeUtils.CANT_INFER_LAMBDA_PARAM_TYPE; 046 import static org.jetbrains.jet.lang.types.TypeUtils.DONT_CARE; 047 048 public class DescriptorRendererImpl implements DescriptorRenderer { 049 private final boolean shortNames; 050 private final boolean withDefinedIn; 051 private final Set<DescriptorRenderer.Modifier> modifiers; 052 private final boolean startFromName; 053 private final boolean debugMode; 054 private final boolean classWithPrimaryConstructor; 055 private final boolean verbose; 056 private final boolean unitReturnType; 057 private final boolean normalizedVisibilities; 058 private final boolean showInternalKeyword; 059 private final boolean prettyFunctionTypes; 060 private final boolean uninferredTypeParameterAsName; 061 private final boolean includeSynthesizedParameterNames; 062 private final boolean withoutFunctionParameterNames; 063 private final boolean withoutTypeParameters; 064 private final boolean renderClassObjectName; 065 private final boolean withoutSuperTypes; 066 private final boolean receiverAfterName; 067 068 @NotNull 069 private final OverrideRenderingPolicy overrideRenderingPolicy; 070 @NotNull 071 private final ValueParametersHandler handler; 072 @NotNull 073 private final TextFormat textFormat; 074 private final boolean includePropertyConstant; 075 @NotNull 076 private final Set<FqName> excludedAnnotationClasses; 077 078 /* package */ DescriptorRendererImpl( 079 boolean shortNames, 080 boolean withDefinedIn, 081 Set<Modifier> modifiers, 082 boolean startFromName, 083 boolean debugMode, 084 boolean classWithPrimaryConstructor, 085 boolean verbose, 086 boolean unitReturnType, 087 boolean normalizedVisibilities, 088 boolean showInternalKeyword, 089 boolean prettyFunctionTypes, 090 boolean uninferredTypeParameterAsName, 091 @NotNull OverrideRenderingPolicy overrideRenderingPolicy, 092 @NotNull ValueParametersHandler handler, 093 @NotNull TextFormat textFormat, 094 @NotNull Collection<FqName> excludedAnnotationClasses, 095 boolean includePropertyConstant, 096 boolean includeSynthesizedParameterNames, 097 boolean withoutFunctionParameterNames, 098 boolean withoutTypeParameters, 099 boolean receiverAfterName, 100 boolean renderClassObjectName, 101 boolean withoutSuperTypes 102 ) { 103 this.shortNames = shortNames; 104 this.withDefinedIn = withDefinedIn; 105 this.modifiers = modifiers; 106 this.startFromName = startFromName; 107 this.handler = handler; 108 this.classWithPrimaryConstructor = classWithPrimaryConstructor; 109 this.verbose = verbose; 110 this.unitReturnType = unitReturnType; 111 this.normalizedVisibilities = normalizedVisibilities; 112 this.showInternalKeyword = showInternalKeyword; 113 this.overrideRenderingPolicy = overrideRenderingPolicy; 114 this.debugMode = debugMode; 115 this.textFormat = textFormat; 116 this.includePropertyConstant = includePropertyConstant; 117 this.excludedAnnotationClasses = Sets.newHashSet(excludedAnnotationClasses); 118 this.prettyFunctionTypes = prettyFunctionTypes; 119 this.uninferredTypeParameterAsName = uninferredTypeParameterAsName; 120 this.includeSynthesizedParameterNames = includeSynthesizedParameterNames; 121 this.withoutFunctionParameterNames = withoutFunctionParameterNames; 122 this.withoutTypeParameters = withoutTypeParameters; 123 this.receiverAfterName = receiverAfterName; 124 this.renderClassObjectName = renderClassObjectName; 125 this.withoutSuperTypes = withoutSuperTypes; 126 } 127 128 /* FORMATTING */ 129 @NotNull 130 private String renderKeyword(@NotNull String keyword) { 131 switch (textFormat) { 132 case PLAIN: 133 return keyword; 134 case HTML: 135 return "<b>" + keyword + "</b>"; 136 } 137 throw new IllegalStateException("Unexpected textFormat: " + textFormat); 138 } 139 140 @NotNull 141 private String renderError(@NotNull String keyword) { 142 switch (textFormat) { 143 case PLAIN: 144 return keyword; 145 case HTML: 146 return "<font color=red><b>" + keyword + "</b></font>"; 147 } 148 throw new IllegalStateException("Unexpected textFormat: " + textFormat); 149 } 150 151 @NotNull 152 private String escape(@NotNull String string) { 153 switch (textFormat) { 154 case PLAIN: 155 return string; 156 case HTML: 157 return string.replaceAll("<", "<").replaceAll(">", ">"); 158 } 159 throw new IllegalStateException("Unexpected textFormat: " + textFormat); 160 } 161 162 @NotNull 163 private String lt() { 164 return escape("<"); 165 } 166 167 @NotNull 168 private String gt() { 169 return escape(">"); 170 } 171 172 @NotNull 173 private String arrow() { 174 switch (textFormat) { 175 case PLAIN: 176 return escape("->"); 177 case HTML: 178 return "→"; 179 } 180 throw new IllegalStateException("Unexpected textFormat: " + textFormat); 181 } 182 183 @NotNull 184 private String renderMessage(@NotNull String message) { 185 switch (textFormat) { 186 case PLAIN: 187 return message; 188 case HTML: 189 return "<i>" + message + "</i>"; 190 } 191 throw new IllegalStateException("Unexpected textFormat: " + textFormat); 192 } 193 194 private static void renderSpaceIfNeeded(@NotNull StringBuilder builder) { 195 int length = builder.length(); 196 if (length == 0 || builder.charAt(length - 1) != ' ') { 197 builder.append(' '); 198 } 199 } 200 201 /* NAMES RENDERING */ 202 @NotNull 203 private String renderName(@NotNull Name identifier) { 204 String asString = identifier.toString(); 205 return escape(KeywordStringsGenerated.KEYWORDS.contains(asString) ? '`' + asString + '`' : asString); 206 } 207 208 private void renderName(@NotNull DeclarationDescriptor descriptor, @NotNull StringBuilder builder) { 209 builder.append(renderName(descriptor.getName())); 210 } 211 212 private void renderClassObjectName(@NotNull DeclarationDescriptor descriptor, @NotNull StringBuilder builder) { 213 if (renderClassObjectName) { 214 if (!startFromName) renderSpaceIfNeeded(builder); 215 builder.append("<class object>"); 216 } 217 if (verbose) { 218 if (!startFromName) renderSpaceIfNeeded(builder); 219 builder.append(renderName(descriptor.getName())); 220 } 221 } 222 223 @NotNull 224 private String renderFqName(@NotNull FqNameBase fqName) { 225 return renderFqName(fqName.pathSegments()); 226 } 227 228 229 @NotNull 230 private String renderFqName(@NotNull List<Name> pathSegments) { 231 StringBuilder buf = new StringBuilder(); 232 for (Name element : pathSegments) { 233 if (buf.length() != 0) { 234 buf.append("."); 235 } 236 buf.append(renderName(element)); 237 } 238 return buf.toString(); 239 } 240 241 @NotNull 242 private String renderClassName(@NotNull ClassDescriptor klass) { 243 if (klass instanceof MissingDependencyErrorClass) { 244 return ((MissingDependencyErrorClass) klass).getFullFqName().asString(); 245 } 246 if (ErrorUtils.isError(klass)) { 247 return klass.getTypeConstructor().toString(); 248 } 249 if (shortNames) { 250 List<Name> qualifiedNameElements = Lists.newArrayList(); 251 252 // for nested classes qualified name should be used 253 DeclarationDescriptor current = klass; 254 do { 255 if (((ClassDescriptor) current).getKind() != ClassKind.CLASS_OBJECT) { 256 qualifiedNameElements.add(current.getName()); 257 } 258 current = current.getContainingDeclaration(); 259 } 260 while (current instanceof ClassDescriptor); 261 262 Collections.reverse(qualifiedNameElements); 263 return renderFqName(qualifiedNameElements); 264 } 265 return renderFqName(DescriptorUtils.getFqName(klass)); 266 } 267 268 /* TYPES RENDERING */ 269 @NotNull 270 @Override 271 public String renderType(@NotNull JetType type) { 272 if (type == CANT_INFER_LAMBDA_PARAM_TYPE || type == DONT_CARE) { 273 return "???"; 274 } 275 if (ErrorUtils.isUninferredParameter(type)) { 276 if (uninferredTypeParameterAsName) { 277 return renderError(((UninferredParameterType) type).getTypeParameterDescriptor().getName().toString()); 278 } 279 return "???"; 280 } 281 if (type instanceof PackageType) { 282 return type.toString(); 283 } 284 if (type instanceof LazyType && debugMode) { 285 return type.toString(); 286 } 287 if (type.isError()) { 288 return renderDefaultType(type); 289 } 290 if (KotlinBuiltIns.getInstance().isExactFunctionOrExtensionFunctionType(type) && prettyFunctionTypes) { 291 return renderFunctionType(type); 292 } 293 return renderDefaultType(type); 294 } 295 296 @NotNull 297 @Override 298 public String renderTypeArguments(@NotNull List<TypeProjection> typeArguments) { 299 if (typeArguments.isEmpty()) return ""; 300 StringBuilder sb = new StringBuilder(); 301 sb.append(lt()); 302 appendTypeProjections(typeArguments, sb); 303 sb.append(gt()); 304 return sb.toString(); 305 } 306 307 @NotNull 308 private String renderDefaultType(@NotNull JetType type) { 309 StringBuilder sb = new StringBuilder(); 310 311 if (type.isError()) { 312 sb.append(type.getConstructor().toString()); // Debug name of an error type is more informative 313 } 314 else { 315 sb.append(renderTypeName(type.getConstructor())); 316 } 317 sb.append(renderTypeArguments(type.getArguments())); 318 if (type.isNullable()) { 319 sb.append("?"); 320 } 321 return sb.toString(); 322 } 323 324 @NotNull 325 private String renderTypeName(@NotNull TypeConstructor typeConstructor) { 326 ClassifierDescriptor cd = typeConstructor.getDeclarationDescriptor(); 327 if (cd instanceof TypeParameterDescriptor) { 328 return renderName(cd.getName()); 329 } 330 else if (cd instanceof ClassDescriptor) { 331 return renderClassName((ClassDescriptor) cd); 332 } 333 else { 334 assert cd == null: "Unexpected classifier: " + cd.getClass(); 335 return typeConstructor.toString(); 336 } 337 } 338 339 private void appendTypeProjections(@NotNull List<TypeProjection> typeProjections, @NotNull StringBuilder builder) { 340 for (Iterator<TypeProjection> iterator = typeProjections.iterator(); iterator.hasNext(); ) { 341 TypeProjection typeProjection = iterator.next(); 342 if (typeProjection.getProjectionKind() != Variance.INVARIANT) { 343 builder.append(typeProjection.getProjectionKind()).append(" "); 344 } 345 builder.append(renderType(typeProjection.getType())); 346 if (iterator.hasNext()) { 347 builder.append(", "); 348 } 349 } 350 } 351 352 @NotNull 353 private String renderFunctionType(@NotNull JetType type) { 354 StringBuilder sb = new StringBuilder(); 355 356 JetType receiverType = KotlinBuiltIns.getInstance().getReceiverType(type); 357 if (receiverType != null) { 358 sb.append(renderType(receiverType)); 359 sb.append("."); 360 } 361 362 sb.append("("); 363 appendTypeProjections(KotlinBuiltIns.getInstance().getParameterTypeProjectionsFromFunctionType(type), sb); 364 sb.append(") ").append(arrow()).append(" "); 365 sb.append(renderType(KotlinBuiltIns.getInstance().getReturnTypeFromFunctionType(type))); 366 367 if (type.isNullable()) { 368 return "(" + sb + ")?"; 369 } 370 return sb.toString(); 371 } 372 373 374 /* METHODS FOR ALL KINDS OF DESCRIPTORS */ 375 private void appendDefinedIn(@NotNull DeclarationDescriptor descriptor, @NotNull StringBuilder builder) { 376 if (descriptor instanceof PackageFragmentDescriptor || descriptor instanceof PackageViewDescriptor) { 377 return; 378 } 379 if (descriptor instanceof ModuleDescriptor) { 380 builder.append(" is a module"); 381 return; 382 } 383 builder.append(" ").append(renderMessage("defined in")).append(" "); 384 385 DeclarationDescriptor containingDeclaration = descriptor.getContainingDeclaration(); 386 if (containingDeclaration != null) { 387 FqNameUnsafe fqName = DescriptorUtils.getFqName(containingDeclaration); 388 builder.append(FqName.ROOT.equalsTo(fqName) ? "root package" : renderFqName(fqName)); 389 } 390 } 391 392 private void renderAnnotations(@NotNull Annotated annotated, @NotNull StringBuilder builder) { 393 if (!modifiers.contains(Modifier.ANNOTATIONS)) return; 394 for (AnnotationDescriptor annotation : annotated.getAnnotations()) { 395 ClassDescriptor annotationClass = (ClassDescriptor) annotation.getType().getConstructor().getDeclarationDescriptor(); 396 assert annotationClass != null; 397 398 if (!excludedAnnotationClasses.contains(DescriptorUtils.getFqNameSafe(annotationClass))) { 399 builder.append(renderAnnotation(annotation)).append(" "); 400 } 401 } 402 } 403 404 @Override 405 @NotNull 406 public String renderAnnotation(@NotNull AnnotationDescriptor annotation) { 407 StringBuilder sb = new StringBuilder(); 408 sb.append(renderType(annotation.getType())); 409 if (verbose) { 410 sb.append("(").append(StringUtil.join(renderAndSortAnnotationArguments(annotation), ", ")).append(")"); 411 } 412 return sb.toString(); 413 } 414 415 @NotNull 416 private List<String> renderAndSortAnnotationArguments(@NotNull AnnotationDescriptor descriptor) { 417 List<String> resultList = Lists.newArrayList(); 418 for (Map.Entry<ValueParameterDescriptor, CompileTimeConstant<?>> entry : descriptor.getAllValueArguments().entrySet()) { 419 CompileTimeConstant<?> value = entry.getValue(); 420 String typeSuffix = ": " + renderType(value.getType(KotlinBuiltIns.getInstance())); 421 resultList.add(entry.getKey().getName().asString() + " = " + renderConstant(value) + typeSuffix); 422 } 423 Collections.sort(resultList); 424 return resultList; 425 } 426 427 @NotNull 428 private String renderConstant(@NotNull CompileTimeConstant<?> value) { 429 return value.accept( 430 new DefaultAnnotationArgumentVisitor<String, Void>() { 431 @Override 432 public String visitValue(@NotNull CompileTimeConstant<?> value, Void data) { 433 return value.toString(); 434 } 435 436 @Override 437 public String visitArrayValue(ArrayValue value, Void data) { 438 return "{" + 439 StringUtil.join( 440 value.getValue(), 441 new Function<CompileTimeConstant<?>, String>() { 442 @Override 443 public String fun(CompileTimeConstant<?> constant) { 444 return renderConstant(constant); 445 } 446 }, 447 ", ") + 448 "}"; 449 } 450 451 @Override 452 public String visitAnnotationValue(AnnotationValue value, Void data) { 453 return renderAnnotation(value.getValue()); 454 } 455 456 @Override 457 public String visitJavaClassValue(JavaClassValue value, Void data) { 458 return renderType(value.getValue()) + ".class"; 459 } 460 }, 461 null 462 ); 463 } 464 465 private void renderVisibility(@NotNull Visibility visibility, @NotNull StringBuilder builder) { 466 if (!modifiers.contains(Modifier.VISIBILITY)) return; 467 if (normalizedVisibilities) { 468 visibility = visibility.normalize(); 469 } 470 if (!showInternalKeyword && visibility == Visibilities.INTERNAL) return; 471 builder.append(renderKeyword(visibility.toString())).append(" "); 472 } 473 474 private void renderModality(@NotNull Modality modality, @NotNull StringBuilder builder) { 475 if (!modifiers.contains(Modifier.MODALITY)) return; 476 String keyword = modality.name().toLowerCase(); 477 builder.append(renderKeyword(keyword)).append(" "); 478 } 479 480 private void renderInner(boolean isInner, @NotNull StringBuilder builder) { 481 if (!modifiers.contains(Modifier.INNER)) return; 482 if (isInner) { 483 builder.append(renderKeyword("inner")).append(" "); 484 } 485 } 486 487 private void renderModalityForCallable(@NotNull CallableMemberDescriptor callable, @NotNull StringBuilder builder) { 488 if (!DescriptorUtils.isTopLevelDeclaration(callable) || callable.getModality() != Modality.FINAL) { 489 if (overridesSomething(callable) 490 && overrideRenderingPolicy == OverrideRenderingPolicy.RENDER_OVERRIDE 491 && callable.getModality() == Modality.OPEN) { 492 return; 493 } 494 renderModality(callable.getModality(), builder); 495 } 496 } 497 498 private boolean overridesSomething(CallableMemberDescriptor callable) { 499 return !callable.getOverriddenDescriptors().isEmpty(); 500 } 501 502 private void renderOverride(@NotNull CallableMemberDescriptor callableMember, @NotNull StringBuilder builder) { 503 if (!modifiers.contains(Modifier.OVERRIDE)) return; 504 if (overridesSomething(callableMember)) { 505 if (overrideRenderingPolicy != OverrideRenderingPolicy.RENDER_OPEN) { 506 builder.append("override "); 507 if (verbose) { 508 builder.append("/*").append(callableMember.getOverriddenDescriptors().size()).append("*/ "); 509 } 510 } 511 } 512 } 513 514 private void renderMemberKind(CallableMemberDescriptor callableMember, StringBuilder builder) { 515 if (!modifiers.contains(Modifier.MEMBER_KIND)) return; 516 if (verbose && callableMember.getKind() != CallableMemberDescriptor.Kind.DECLARATION) { 517 builder.append("/*").append(callableMember.getKind().name().toLowerCase()).append("*/ "); 518 } 519 } 520 521 @NotNull 522 @Override 523 public String render(@NotNull DeclarationDescriptor declarationDescriptor) { 524 StringBuilder stringBuilder = new StringBuilder(); 525 declarationDescriptor.accept(new RenderDeclarationDescriptorVisitor(), stringBuilder); 526 527 if (withDefinedIn) { 528 appendDefinedIn(declarationDescriptor, stringBuilder); 529 } 530 return stringBuilder.toString(); 531 } 532 533 534 /* TYPE PARAMETERS */ 535 private void renderTypeParameter(@NotNull TypeParameterDescriptor typeParameter, @NotNull StringBuilder builder, boolean topLevel) { 536 if (topLevel) { 537 builder.append(lt()); 538 } 539 540 if (verbose) { 541 builder.append("/*").append(typeParameter.getIndex()).append("*/ "); 542 } 543 544 if (typeParameter.isReified()) { 545 builder.append(renderKeyword("reified")).append(" "); 546 } 547 String variance = typeParameter.getVariance().toString(); 548 if (!variance.isEmpty()) { 549 builder.append(renderKeyword(variance)).append(" "); 550 } 551 renderName(typeParameter, builder); 552 int upperBoundsCount = typeParameter.getUpperBounds().size(); 553 if ((upperBoundsCount > 1 && !topLevel) || upperBoundsCount == 1) { 554 JetType upperBound = typeParameter.getUpperBounds().iterator().next(); 555 if (!KotlinBuiltIns.getInstance().getDefaultBound().equals(upperBound)) { 556 builder.append(" : ").append(renderType(upperBound)); 557 } 558 } 559 else if (topLevel) { 560 boolean first = true; 561 for (JetType upperBound : typeParameter.getUpperBounds()) { 562 if (upperBound.equals(KotlinBuiltIns.getInstance().getDefaultBound())) { 563 continue; 564 } 565 if (first) { 566 builder.append(" : "); 567 } 568 else { 569 builder.append(" & "); 570 } 571 builder.append(renderType(upperBound)); 572 first = false; 573 } 574 } 575 else { 576 // rendered with "where" 577 } 578 579 if (topLevel) { 580 builder.append(gt()); 581 } 582 } 583 584 private void renderTypeParameters( 585 @NotNull List<TypeParameterDescriptor> typeParameters, 586 @NotNull StringBuilder builder, 587 boolean withSpace 588 ) { 589 if (withoutTypeParameters) return; 590 591 if (!typeParameters.isEmpty()) { 592 builder.append(lt()); 593 for (Iterator<TypeParameterDescriptor> iterator = typeParameters.iterator(); iterator.hasNext(); ) { 594 TypeParameterDescriptor typeParameterDescriptor = iterator.next(); 595 renderTypeParameter(typeParameterDescriptor, builder, false); 596 if (iterator.hasNext()) { 597 builder.append(", "); 598 } 599 } 600 builder.append(gt()); 601 if (withSpace) { 602 builder.append(" "); 603 } 604 } 605 } 606 607 /* FUNCTIONS */ 608 private void renderFunction(@NotNull FunctionDescriptor function, @NotNull StringBuilder builder) { 609 if (!startFromName) { 610 renderAnnotations(function, builder); 611 renderVisibility(function.getVisibility(), builder); 612 renderModalityForCallable(function, builder); 613 renderOverride(function, builder); 614 renderMemberKind(function, builder); 615 616 builder.append(renderKeyword("fun")).append(" "); 617 renderTypeParameters(function.getTypeParameters(), builder, true); 618 renderReceiver(function, builder); 619 } 620 621 renderName(function, builder); 622 623 renderValueParameters(function, builder); 624 625 renderReceiverAfterName(function, builder); 626 627 JetType returnType = function.getReturnType(); 628 if (unitReturnType || (returnType == null || !KotlinBuiltIns.getInstance().isUnit(returnType))) { 629 builder.append(": ").append(returnType == null ? "[NULL]" : escape(renderType(returnType))); 630 } 631 632 renderWhereSuffix(function.getTypeParameters(), builder); 633 } 634 635 private void renderReceiverAfterName(CallableDescriptor callableDescriptor, StringBuilder builder) { 636 if (!receiverAfterName) return; 637 638 ReceiverParameterDescriptor receiver = callableDescriptor.getReceiverParameter(); 639 if (receiver != null) { 640 builder.append(" on ").append(escape(renderType(receiver.getType()))); 641 } 642 } 643 644 private void renderReceiver(CallableDescriptor callableDescriptor, StringBuilder builder) { 645 ReceiverParameterDescriptor receiver = callableDescriptor.getReceiverParameter(); 646 if (receiver != null) { 647 builder.append(escape(renderType(receiver.getType()))).append("."); 648 } 649 } 650 651 private void renderConstructor(@NotNull ConstructorDescriptor constructor, @NotNull StringBuilder builder) { 652 renderAnnotations(constructor, builder); 653 renderVisibility(constructor.getVisibility(), builder); 654 renderMemberKind(constructor, builder); 655 656 builder.append(renderKeyword("constructor")).append(" "); 657 658 ClassDescriptor classDescriptor = constructor.getContainingDeclaration(); 659 renderName(classDescriptor, builder); 660 661 renderTypeParameters(classDescriptor.getTypeConstructor().getParameters(), builder, false); 662 renderValueParameters(constructor, builder); 663 renderWhereSuffix(constructor.getTypeParameters(), builder); 664 } 665 666 private void renderWhereSuffix(@NotNull List<TypeParameterDescriptor> typeParameters, @NotNull StringBuilder builder) { 667 if (withoutTypeParameters) return; 668 669 List<String> upperBoundStrings = Lists.newArrayList(); 670 671 for (TypeParameterDescriptor typeParameter : typeParameters) { 672 if (typeParameter.getUpperBounds().size() > 1) { 673 boolean first = true; 674 for (JetType upperBound : typeParameter.getUpperBounds()) { 675 // first parameter is rendered by renderTypeParameter: 676 if (!first) { 677 upperBoundStrings.add(renderName(typeParameter.getName()) + " : " + escape(renderType(upperBound))); 678 } 679 first = false; 680 } 681 } 682 } 683 if (!upperBoundStrings.isEmpty()) { 684 builder.append(" ").append(renderKeyword("where")).append(" "); 685 builder.append(StringUtil.join(upperBoundStrings, ", ")); 686 } 687 } 688 689 @NotNull 690 @Override 691 public String renderFunctionParameters(@NotNull FunctionDescriptor functionDescriptor) { 692 StringBuilder stringBuilder = new StringBuilder(); 693 renderValueParameters(functionDescriptor, stringBuilder); 694 return stringBuilder.toString(); 695 } 696 697 private void renderValueParameters(@NotNull FunctionDescriptor function, @NotNull StringBuilder builder) { 698 boolean includeNames = !withoutFunctionParameterNames && 699 (includeSynthesizedParameterNames || !function.hasSynthesizedParameterNames()); 700 handler.appendBeforeValueParameters(function, builder); 701 for (ValueParameterDescriptor parameter : function.getValueParameters()) { 702 handler.appendBeforeValueParameter(parameter, builder); 703 renderValueParameter(parameter, includeNames, builder, false); 704 handler.appendAfterValueParameter(parameter, builder); 705 } 706 handler.appendAfterValueParameters(function, builder); 707 } 708 709 /* VARIABLES */ 710 private void renderValueParameter(@NotNull ValueParameterDescriptor valueParameter, boolean includeName, @NotNull StringBuilder builder, boolean topLevel) { 711 if (topLevel) { 712 builder.append(renderKeyword("value-parameter")).append(" "); 713 } 714 715 if (verbose) { 716 builder.append("/*").append(valueParameter.getIndex()).append("*/ "); 717 } 718 719 renderAnnotations(valueParameter, builder); 720 renderVariable(valueParameter, includeName, builder, topLevel); 721 boolean withDefaultValue = debugMode ? valueParameter.declaresDefaultValue() : valueParameter.hasDefaultValue(); 722 if (withDefaultValue) { 723 builder.append(" = ..."); 724 } 725 } 726 727 private void renderValVarPrefix(@NotNull VariableDescriptor variable, @NotNull StringBuilder builder) { 728 builder.append(renderKeyword(variable.isVar() ? "var" : "val")).append(" "); 729 } 730 731 private void renderVariable(@NotNull VariableDescriptor variable, boolean includeName, @NotNull StringBuilder builder, boolean topLevel) { 732 JetType realType = variable.getType(); 733 734 JetType varargElementType = variable instanceof ValueParameterDescriptor 735 ? ((ValueParameterDescriptor) variable).getVarargElementType() 736 : null; 737 JetType typeToRender = varargElementType != null ? varargElementType : realType; 738 739 if (varargElementType != null) { 740 builder.append(renderKeyword("vararg")).append(" "); 741 } 742 if (topLevel && !startFromName) { 743 renderValVarPrefix(variable, builder); 744 } 745 746 if (includeName) { 747 renderName(variable, builder); 748 builder.append(": "); 749 } 750 751 builder.append(escape(renderType(typeToRender))); 752 753 renderInitializer(variable, builder); 754 755 if (verbose && varargElementType != null) { 756 builder.append(" /*").append(escape(renderType(realType))).append("*/"); 757 } 758 } 759 760 private void renderProperty(@NotNull PropertyDescriptor property, @NotNull StringBuilder builder) { 761 if (!startFromName) { 762 renderAnnotations(property, builder); 763 renderVisibility(property.getVisibility(), builder); 764 renderModalityForCallable(property, builder); 765 renderOverride(property, builder); 766 renderMemberKind(property, builder); 767 renderValVarPrefix(property, builder); 768 renderTypeParameters(property.getTypeParameters(), builder, true); 769 renderReceiver(property, builder); 770 } 771 772 renderName(property, builder); 773 builder.append(": ").append(escape(renderType(property.getType()))); 774 775 renderReceiverAfterName(property, builder); 776 777 renderInitializer(property, builder); 778 779 renderWhereSuffix(property.getTypeParameters(), builder); 780 } 781 782 private void renderInitializer(@NotNull VariableDescriptor variable, @NotNull StringBuilder builder) { 783 if (includePropertyConstant) { 784 CompileTimeConstant<?> initializer = variable.getCompileTimeInitializer(); 785 if (initializer != null) { 786 builder.append(" = ").append(escape(renderConstant(initializer))); 787 } 788 } 789 } 790 791 /* CLASSES */ 792 private void renderClass(@NotNull ClassDescriptor klass, @NotNull StringBuilder builder) { 793 if (!startFromName) { 794 renderAnnotations(klass, builder); 795 renderVisibility(klass.getVisibility(), builder); 796 if (!(klass.getKind() == ClassKind.TRAIT && klass.getModality() == Modality.ABSTRACT 797 || klass.getKind().isSingleton() && klass.getModality() == Modality.FINAL)) { 798 renderModality(klass.getModality(), builder); 799 } 800 renderInner(klass.isInner(), builder); 801 renderClassKindPrefix(klass, builder); 802 } 803 804 if (klass.getKind() != ClassKind.CLASS_OBJECT) { 805 if (!startFromName) renderSpaceIfNeeded(builder); 806 renderName(klass, builder); 807 } 808 else { 809 renderClassObjectName(klass, builder); 810 } 811 812 List<TypeParameterDescriptor> typeParameters = klass.getTypeConstructor().getParameters(); 813 renderTypeParameters(typeParameters, builder, false); 814 815 if (!klass.getKind().isSingleton() && classWithPrimaryConstructor) { 816 ConstructorDescriptor primaryConstructor = klass.getUnsubstitutedPrimaryConstructor(); 817 if (primaryConstructor != null) { 818 renderValueParameters(primaryConstructor, builder); 819 } 820 } 821 822 renderSuperTypes(klass, builder); 823 renderWhereSuffix(typeParameters, builder); 824 } 825 826 private void renderSuperTypes(@NotNull ClassDescriptor klass, @NotNull StringBuilder builder) { 827 if (withoutSuperTypes) return; 828 829 if (!klass.equals(KotlinBuiltIns.getInstance().getNothing())) { 830 Collection<JetType> supertypes = klass.getTypeConstructor().getSupertypes(); 831 832 if (supertypes.isEmpty() || 833 supertypes.size() == 1 && KotlinBuiltIns.getInstance().isAnyOrNullableAny(supertypes.iterator().next())) { 834 } 835 else { 836 renderSpaceIfNeeded(builder); 837 builder.append(": "); 838 for (Iterator<JetType> iterator = supertypes.iterator(); iterator.hasNext(); ) { 839 JetType supertype = iterator.next(); 840 builder.append(renderType(supertype)); 841 if (iterator.hasNext()) { 842 builder.append(", "); 843 } 844 } 845 } 846 } 847 } 848 849 private void renderClassKindPrefix(ClassDescriptor klass, StringBuilder builder) { 850 builder.append(renderKeyword(getClassKindPrefix(klass))); 851 } 852 853 @NotNull 854 private static String getClassKindPrefix(@NotNull ClassDescriptor klass) { 855 switch (klass.getKind()) { 856 case CLASS: 857 return "class"; 858 case TRAIT: 859 return "trait"; 860 case ENUM_CLASS: 861 return "enum class"; 862 case OBJECT: 863 return "object"; 864 case ANNOTATION_CLASS: 865 return "annotation class"; 866 case CLASS_OBJECT: 867 return "class object"; 868 case ENUM_ENTRY: 869 return "enum entry"; 870 default: 871 throw new IllegalStateException("unknown class kind: " + klass.getKind()); 872 } 873 } 874 875 876 /* OTHER */ 877 private void renderModuleOrScript(@NotNull DeclarationDescriptor moduleOrScript, @NotNull StringBuilder builder) { 878 renderName(moduleOrScript, builder); 879 } 880 881 private void renderPackageView(@NotNull PackageViewDescriptor packageView, @NotNull StringBuilder builder) { 882 builder.append(renderKeyword("package")).append(" "); 883 builder.append(renderFqName(packageView.getFqName())); 884 if (debugMode) { 885 builder.append(" in context of "); 886 renderName(packageView.getModule(), builder); 887 } 888 } 889 890 private void renderPackageFragment(@NotNull PackageFragmentDescriptor fragment, @NotNull StringBuilder builder) { 891 builder.append(renderKeyword("package-fragment")).append(" "); 892 builder.append(renderFqName(fragment.getFqName())); 893 if (debugMode) { 894 builder.append(" in "); 895 renderName(fragment.getContainingDeclaration(), builder); 896 } 897 } 898 899 900 /* STUPID DISPATCH-ONLY VISITOR */ 901 private class RenderDeclarationDescriptorVisitor extends DeclarationDescriptorVisitorEmptyBodies<Void, StringBuilder> { 902 @Override 903 public Void visitValueParameterDescriptor(ValueParameterDescriptor descriptor, StringBuilder builder) { 904 renderValueParameter(descriptor, true, builder, true); 905 return null; 906 } 907 908 @Override 909 public Void visitVariableDescriptor(VariableDescriptor descriptor, StringBuilder builder) { 910 renderVariable(descriptor, true, builder, true); 911 return null; 912 } 913 914 @Override 915 public Void visitPropertyDescriptor(PropertyDescriptor descriptor, StringBuilder builder) { 916 renderProperty(descriptor, builder); 917 return null; 918 } 919 920 @Override 921 public Void visitFunctionDescriptor(FunctionDescriptor descriptor, StringBuilder builder) { 922 renderFunction(descriptor, builder); 923 return null; 924 } 925 926 @Override 927 public Void visitReceiverParameterDescriptor(ReceiverParameterDescriptor descriptor, StringBuilder data) { 928 throw new UnsupportedOperationException("Don't render receiver parameters"); 929 } 930 931 @Override 932 public Void visitConstructorDescriptor(ConstructorDescriptor constructorDescriptor, StringBuilder builder) { 933 renderConstructor(constructorDescriptor, builder); 934 return null; 935 } 936 937 @Override 938 public Void visitTypeParameterDescriptor(TypeParameterDescriptor descriptor, StringBuilder builder) { 939 renderTypeParameter(descriptor, builder, true); 940 return null; 941 } 942 943 @Override 944 public Void visitPackageFragmentDescriptor( 945 PackageFragmentDescriptor descriptor, StringBuilder builder 946 ) { 947 renderPackageFragment(descriptor, builder); 948 return null; 949 } 950 951 @Override 952 public Void visitPackageViewDescriptor( 953 PackageViewDescriptor descriptor, StringBuilder builder 954 ) { 955 renderPackageView(descriptor, builder); 956 return null; 957 } 958 959 @Override 960 public Void visitModuleDeclaration(ModuleDescriptor descriptor, StringBuilder builder) { 961 renderModuleOrScript(descriptor, builder); 962 return null; 963 } 964 965 @Override 966 public Void visitScriptDescriptor(ScriptDescriptor scriptDescriptor, StringBuilder builder) { 967 renderModuleOrScript(scriptDescriptor, builder); 968 return null; 969 } 970 971 @Override 972 public Void visitClassDescriptor(ClassDescriptor descriptor, StringBuilder builder) { 973 renderClass(descriptor, builder); 974 return null; 975 } 976 } 977 }