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