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