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