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