001 /* 002 * Copyright 2010-2014 JetBrains s.r.o. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017 package org.jetbrains.jet.renderer; 018 019 import kotlin.Function1; 020 import kotlin.KotlinPackage; 021 import org.jetbrains.annotations.NotNull; 022 import org.jetbrains.annotations.Nullable; 023 import org.jetbrains.jet.lang.descriptors.*; 024 import org.jetbrains.jet.lang.descriptors.annotations.Annotated; 025 import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor; 026 import org.jetbrains.jet.lang.descriptors.annotations.DefaultAnnotationArgumentVisitor; 027 import org.jetbrains.jet.lang.descriptors.impl.DeclarationDescriptorVisitorEmptyBodies; 028 import org.jetbrains.jet.lang.resolve.DescriptorUtils; 029 import org.jetbrains.jet.lang.resolve.constants.AnnotationValue; 030 import org.jetbrains.jet.lang.resolve.constants.ArrayValue; 031 import org.jetbrains.jet.lang.resolve.constants.CompileTimeConstant; 032 import org.jetbrains.jet.lang.resolve.constants.JavaClassValue; 033 import org.jetbrains.jet.lang.resolve.name.FqName; 034 import org.jetbrains.jet.lang.resolve.name.FqNameBase; 035 import org.jetbrains.jet.lang.resolve.name.FqNameUnsafe; 036 import org.jetbrains.jet.lang.resolve.name.Name; 037 import org.jetbrains.jet.lang.types.*; 038 import org.jetbrains.jet.lang.types.ErrorUtils.UninferredParameterTypeConstructor; 039 import org.jetbrains.jet.lang.types.error.MissingDependencyErrorClass; 040 import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns; 041 import org.jetbrains.jet.utils.UtilsPackage; 042 043 import java.util.*; 044 045 import static org.jetbrains.jet.lang.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 boolean shortNames; 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 boolean shortNames, 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.shortNames = shortNames; 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 @NotNull 275 private String renderClassName(@NotNull ClassDescriptor klass) { 276 if (klass instanceof MissingDependencyErrorClass) { 277 return ((MissingDependencyErrorClass) klass).getFullFqName().asString(); 278 } 279 if (ErrorUtils.isError(klass)) { 280 return klass.getTypeConstructor().toString(); 281 } 282 if (shortNames) { 283 List<Name> qualifiedNameElements = new ArrayList<Name>(); 284 285 // for nested classes qualified name should be used 286 DeclarationDescriptor current = klass; 287 do { 288 if (((ClassDescriptor) current).getKind() != ClassKind.CLASS_OBJECT) { 289 qualifiedNameElements.add(current.getName()); 290 } 291 current = current.getContainingDeclaration(); 292 } 293 while (current instanceof ClassDescriptor); 294 295 Collections.reverse(qualifiedNameElements); 296 return renderFqName(qualifiedNameElements); 297 } 298 return renderFqName(DescriptorUtils.getFqName(klass)); 299 } 300 301 /* TYPES RENDERING */ 302 @NotNull 303 @Override 304 public String renderType(@NotNull JetType type) { 305 return renderNormalizedType(typeNormalizer.invoke(type)); 306 } 307 308 @NotNull 309 private String renderNormalizedType(@NotNull JetType type) { 310 if (type instanceof LazyType && debugMode) { 311 return type.toString(); 312 } 313 if (TypesPackage.isDynamic(type)) { 314 return "dynamic"; 315 } 316 if (TypesPackage.isFlexible(type)) { 317 if (debugMode) { 318 return renderFlexibleTypeWithBothBounds(TypesPackage.flexibility(type).getLowerBound(), 319 TypesPackage.flexibility(type).getUpperBound()); 320 } 321 else if (flexibleTypesForCode) { 322 String prefix = shortNames ? "" : Flexibility.FLEXIBLE_TYPE_CLASSIFIER.getPackageFqName().asString() + "."; 323 return prefix + Flexibility.FLEXIBLE_TYPE_CLASSIFIER.getRelativeClassName() 324 + lt() 325 + renderNormalizedType(TypesPackage.flexibility(type).getLowerBound()) + ", " 326 + renderNormalizedType(TypesPackage.flexibility(type).getUpperBound()) 327 + gt(); 328 } 329 else { 330 return renderFlexibleType(type); 331 } 332 } 333 return renderInflexibleType(type); 334 } 335 336 private String renderFlexibleTypeWithBothBounds(@NotNull JetType lower, @NotNull JetType upper) { 337 return "(" + renderNormalizedType(lower) + ".." + renderNormalizedType(upper) + ")"; 338 } 339 340 private String renderInflexibleType(@NotNull JetType type) { 341 assert !TypesPackage.isFlexible(type) : "Flexible types not allowed here: " + renderNormalizedType(type); 342 343 if (type == CANT_INFER_LAMBDA_PARAM_TYPE || TypeUtils.isDontCarePlaceholder(type)) { 344 return "???"; 345 } 346 if (ErrorUtils.isUninferredParameter(type)) { 347 if (uninferredTypeParameterAsName) { 348 return renderError(((UninferredParameterTypeConstructor) type.getConstructor()).getTypeParameterDescriptor().getName().toString()); 349 } 350 return "???"; 351 } 352 if (type.isError()) { 353 return renderDefaultType(type); 354 } 355 if (shouldRenderAsPrettyFunctionType(type)) { 356 return renderFunctionType(type); 357 } 358 return renderDefaultType(type); 359 } 360 361 private boolean shouldRenderAsPrettyFunctionType(@NotNull JetType type) { 362 return KotlinBuiltIns.isExactFunctionOrExtensionFunctionType(type) && prettyFunctionTypes; 363 } 364 365 @NotNull 366 private String renderFlexibleType(@NotNull JetType type) { 367 JetType lower = TypesPackage.flexibility(type).getLowerBound(); 368 JetType upper = TypesPackage.flexibility(type).getUpperBound(); 369 370 String lowerRendered = renderInflexibleType(lower); 371 String upperRendered = renderInflexibleType(upper); 372 373 if (differsOnlyInNullability(lowerRendered, upperRendered)) { 374 if (upperRendered.startsWith("(")) { 375 // the case of complex type, e.g. (() -> Unit)? 376 return "(" + lowerRendered + ")!"; 377 } 378 return lowerRendered + "!"; 379 } 380 381 String kotlinPrefix = !shortNames ? "kotlin." : ""; 382 String mutablePrefix = "Mutable"; 383 // java.util.List<Foo> -> (Mutable)List<Foo!>! 384 String simpleCollection = replacePrefixes( 385 lowerRendered, kotlinPrefix + mutablePrefix, upperRendered, kotlinPrefix, kotlinPrefix + "(" + mutablePrefix + ")" 386 ); 387 if (simpleCollection != null) return simpleCollection; 388 // java.util.Map.Entry<Foo, Bar> -> (Mutable)Map.(Mutable)Entry<Foo!, Bar!>! 389 String mutableEntry = replacePrefixes( 390 lowerRendered, kotlinPrefix + "MutableMap.MutableEntry", upperRendered, kotlinPrefix + "Map.Entry", 391 kotlinPrefix + "(Mutable)Map.(Mutable)Entry" 392 ); 393 if (mutableEntry != null) return mutableEntry; 394 395 // Foo[] -> Array<(out) Foo!>! 396 String array = replacePrefixes( 397 lowerRendered, kotlinPrefix + escape("Array<"), upperRendered, kotlinPrefix + escape("Array<out "), 398 kotlinPrefix + escape("Array<(out) ") 399 ); 400 if (array != null) return array; 401 return renderFlexibleTypeWithBothBounds(lower, upper); 402 } 403 404 @Nullable 405 private static String replacePrefixes( 406 @NotNull String lowerRendered, 407 @NotNull String lowerPrefix, 408 @NotNull String upperRendered, 409 @NotNull String upperPrefix, 410 @NotNull String foldedPrefix 411 ) { 412 if (lowerRendered.startsWith(lowerPrefix) && upperRendered.startsWith(upperPrefix)) { 413 String lowerWithoutPrefix = lowerRendered.substring(lowerPrefix.length()); 414 if (differsOnlyInNullability(lowerWithoutPrefix, upperRendered.substring(upperPrefix.length()))) { 415 return foldedPrefix + lowerWithoutPrefix + "!"; 416 } 417 } 418 return null; 419 } 420 421 private static boolean differsOnlyInNullability(String lower, String upper) { 422 return lower.equals(upper.replace("?", "")) 423 || upper.endsWith("?") && ((lower + "?").equals(upper)) || (("(" + lower + ")?").equals(upper)); 424 } 425 426 @NotNull 427 @Override 428 public String renderTypeArguments(@NotNull List<TypeProjection> typeArguments) { 429 if (typeArguments.isEmpty()) return ""; 430 StringBuilder sb = new StringBuilder(); 431 sb.append(lt()); 432 appendTypeProjections(typeArguments, sb); 433 sb.append(gt()); 434 return sb.toString(); 435 } 436 437 @NotNull 438 private String renderDefaultType(@NotNull JetType type) { 439 StringBuilder sb = new StringBuilder(); 440 441 if (type.isError()) { 442 sb.append(type.getConstructor().toString()); // Debug name of an error type is more informative 443 } 444 else { 445 sb.append(renderTypeName(type.getConstructor())); 446 } 447 sb.append(renderTypeArguments(type.getArguments())); 448 if (type.isMarkedNullable()) { 449 sb.append("?"); 450 } 451 return sb.toString(); 452 } 453 454 @NotNull 455 private String renderTypeName(@NotNull TypeConstructor typeConstructor) { 456 ClassifierDescriptor cd = typeConstructor.getDeclarationDescriptor(); 457 if (cd instanceof TypeParameterDescriptor) { 458 return renderName(cd.getName()); 459 } 460 else if (cd instanceof ClassDescriptor) { 461 return renderClassName((ClassDescriptor) cd); 462 } 463 else { 464 assert cd == null: "Unexpected classifier: " + cd.getClass(); 465 return typeConstructor.toString(); 466 } 467 } 468 469 private void appendTypeProjections(@NotNull List<TypeProjection> typeProjections, @NotNull StringBuilder builder) { 470 for (Iterator<TypeProjection> iterator = typeProjections.iterator(); iterator.hasNext(); ) { 471 TypeProjection typeProjection = iterator.next(); 472 if (typeProjection.getProjectionKind() != Variance.INVARIANT) { 473 builder.append(typeProjection.getProjectionKind()).append(" "); 474 } 475 builder.append(renderNormalizedType(typeProjection.getType())); 476 if (iterator.hasNext()) { 477 builder.append(", "); 478 } 479 } 480 } 481 482 @NotNull 483 private String renderFunctionType(@NotNull JetType type) { 484 StringBuilder sb = new StringBuilder(); 485 486 JetType receiverType = KotlinBuiltIns.getReceiverType(type); 487 if (receiverType != null) { 488 sb.append(renderNormalizedType(receiverType)); 489 sb.append("."); 490 } 491 492 sb.append("("); 493 appendTypeProjections(KotlinBuiltIns.getParameterTypeProjectionsFromFunctionType(type), sb); 494 sb.append(") ").append(arrow()).append(" "); 495 sb.append(renderNormalizedType(KotlinBuiltIns.getReturnTypeFromFunctionType(type))); 496 497 if (type.isMarkedNullable()) { 498 return "(" + sb + ")?"; 499 } 500 return sb.toString(); 501 } 502 503 504 /* METHODS FOR ALL KINDS OF DESCRIPTORS */ 505 private void appendDefinedIn(@NotNull DeclarationDescriptor descriptor, @NotNull StringBuilder builder) { 506 if (descriptor instanceof PackageFragmentDescriptor || descriptor instanceof PackageViewDescriptor) { 507 return; 508 } 509 if (descriptor instanceof ModuleDescriptor) { 510 builder.append(" is a module"); 511 return; 512 } 513 builder.append(" ").append(renderMessage("defined in")).append(" "); 514 515 DeclarationDescriptor containingDeclaration = descriptor.getContainingDeclaration(); 516 if (containingDeclaration != null) { 517 FqNameUnsafe fqName = DescriptorUtils.getFqName(containingDeclaration); 518 builder.append(FqName.ROOT.equalsTo(fqName) ? "root package" : renderFqName(fqName)); 519 } 520 } 521 522 private void renderAnnotations(@NotNull Annotated annotated, @NotNull StringBuilder builder) { 523 if (!modifiers.contains(Modifier.ANNOTATIONS)) return; 524 for (AnnotationDescriptor annotation : annotated.getAnnotations()) { 525 ClassDescriptor annotationClass = (ClassDescriptor) annotation.getType().getConstructor().getDeclarationDescriptor(); 526 assert annotationClass != null; 527 528 if (!excludedAnnotationClasses.contains(DescriptorUtils.getFqNameSafe(annotationClass))) { 529 builder.append(renderAnnotation(annotation)).append(" "); 530 } 531 } 532 } 533 534 @Override 535 @NotNull 536 public String renderAnnotation(@NotNull AnnotationDescriptor annotation) { 537 StringBuilder sb = new StringBuilder(); 538 sb.append(renderType(annotation.getType())); 539 if (verbose) { 540 sb.append("(").append(UtilsPackage.join(renderAndSortAnnotationArguments(annotation), ", ")).append(")"); 541 } 542 return sb.toString(); 543 } 544 545 @NotNull 546 private List<String> renderAndSortAnnotationArguments(@NotNull AnnotationDescriptor descriptor) { 547 Set<Map.Entry<ValueParameterDescriptor, CompileTimeConstant<?>>> valueArguments = descriptor.getAllValueArguments().entrySet(); 548 List<String> resultList = new ArrayList<String>(valueArguments.size()); 549 for (Map.Entry<ValueParameterDescriptor, CompileTimeConstant<?>> entry : valueArguments) { 550 CompileTimeConstant<?> value = entry.getValue(); 551 String typeSuffix = ": " + renderType(value.getType(KotlinBuiltIns.getInstance())); 552 resultList.add(entry.getKey().getName().asString() + " = " + renderConstant(value) + typeSuffix); 553 } 554 Collections.sort(resultList); 555 return resultList; 556 } 557 558 @NotNull 559 private String renderConstant(@NotNull CompileTimeConstant<?> value) { 560 return value.accept( 561 new DefaultAnnotationArgumentVisitor<String, Void>() { 562 @Override 563 public String visitValue(@NotNull CompileTimeConstant<?> value, Void data) { 564 return value.toString(); 565 } 566 567 @Override 568 public String visitArrayValue(ArrayValue value, Void data) { 569 List<String> renderedElements = 570 KotlinPackage.map(value.getValue(), 571 new Function1<CompileTimeConstant<?>, String>() { 572 @Override 573 public String invoke(CompileTimeConstant<?> constant) { 574 return renderConstant(constant); 575 } 576 }); 577 return "{" + UtilsPackage.join(renderedElements, ", ") + "}"; 578 } 579 580 @Override 581 public String visitAnnotationValue(AnnotationValue value, Void data) { 582 return renderAnnotation(value.getValue()); 583 } 584 585 @Override 586 public String visitJavaClassValue(JavaClassValue value, Void data) { 587 return renderType(value.getValue()) + ".class"; 588 } 589 }, 590 null 591 ); 592 } 593 594 private void renderVisibility(@NotNull Visibility visibility, @NotNull StringBuilder builder) { 595 if (!modifiers.contains(Modifier.VISIBILITY)) return; 596 if (normalizedVisibilities) { 597 visibility = visibility.normalize(); 598 } 599 if (!showInternalKeyword && visibility == Visibilities.INTERNAL) return; 600 builder.append(renderKeyword(visibility.toString())).append(" "); 601 } 602 603 private void renderModality(@NotNull Modality modality, @NotNull StringBuilder builder) { 604 if (!modifiers.contains(Modifier.MODALITY)) return; 605 String keyword = modality.name().toLowerCase(); 606 builder.append(renderKeyword(keyword)).append(" "); 607 } 608 609 private void renderInner(boolean isInner, @NotNull StringBuilder builder) { 610 if (!modifiers.contains(Modifier.INNER)) return; 611 if (isInner) { 612 builder.append(renderKeyword("inner")).append(" "); 613 } 614 } 615 616 private void renderModalityForCallable(@NotNull CallableMemberDescriptor callable, @NotNull StringBuilder builder) { 617 if (!DescriptorUtils.isTopLevelDeclaration(callable) || callable.getModality() != Modality.FINAL) { 618 if (overridesSomething(callable) 619 && overrideRenderingPolicy == OverrideRenderingPolicy.RENDER_OVERRIDE 620 && callable.getModality() == Modality.OPEN) { 621 return; 622 } 623 renderModality(callable.getModality(), builder); 624 } 625 } 626 627 private boolean overridesSomething(CallableMemberDescriptor callable) { 628 return !callable.getOverriddenDescriptors().isEmpty(); 629 } 630 631 private void renderOverride(@NotNull CallableMemberDescriptor callableMember, @NotNull StringBuilder builder) { 632 if (!modifiers.contains(Modifier.OVERRIDE)) return; 633 if (overridesSomething(callableMember)) { 634 if (overrideRenderingPolicy != OverrideRenderingPolicy.RENDER_OPEN) { 635 builder.append("override "); 636 if (verbose) { 637 builder.append("/*").append(callableMember.getOverriddenDescriptors().size()).append("*/ "); 638 } 639 } 640 } 641 } 642 643 private void renderMemberKind(CallableMemberDescriptor callableMember, StringBuilder builder) { 644 if (!modifiers.contains(Modifier.MEMBER_KIND)) return; 645 if (verbose && callableMember.getKind() != CallableMemberDescriptor.Kind.DECLARATION) { 646 builder.append("/*").append(callableMember.getKind().name().toLowerCase()).append("*/ "); 647 } 648 } 649 650 @NotNull 651 @Override 652 public String render(@NotNull DeclarationDescriptor declarationDescriptor) { 653 StringBuilder stringBuilder = new StringBuilder(); 654 declarationDescriptor.accept(new RenderDeclarationDescriptorVisitor(), stringBuilder); 655 656 if (withDefinedIn) { 657 appendDefinedIn(declarationDescriptor, stringBuilder); 658 } 659 return stringBuilder.toString(); 660 } 661 662 663 /* TYPE PARAMETERS */ 664 private void renderTypeParameter(@NotNull TypeParameterDescriptor typeParameter, @NotNull StringBuilder builder, boolean topLevel) { 665 if (topLevel) { 666 builder.append(lt()); 667 } 668 669 if (verbose) { 670 builder.append("/*").append(typeParameter.getIndex()).append("*/ "); 671 } 672 673 if (typeParameter.isReified()) { 674 builder.append(renderKeyword("reified")).append(" "); 675 } 676 String variance = typeParameter.getVariance().getLabel(); 677 if (!variance.isEmpty()) { 678 builder.append(renderKeyword(variance)).append(" "); 679 } 680 renderName(typeParameter, builder); 681 int upperBoundsCount = typeParameter.getUpperBounds().size(); 682 if ((upperBoundsCount > 1 && !topLevel) || upperBoundsCount == 1) { 683 JetType upperBound = typeParameter.getUpperBounds().iterator().next(); 684 if (!KotlinBuiltIns.getInstance().getDefaultBound().equals(upperBound)) { 685 builder.append(" : ").append(renderType(upperBound)); 686 } 687 } 688 else if (topLevel) { 689 boolean first = true; 690 for (JetType upperBound : typeParameter.getUpperBounds()) { 691 if (upperBound.equals(KotlinBuiltIns.getInstance().getDefaultBound())) { 692 continue; 693 } 694 if (first) { 695 builder.append(" : "); 696 } 697 else { 698 builder.append(" & "); 699 } 700 builder.append(renderType(upperBound)); 701 first = false; 702 } 703 } 704 else { 705 // rendered with "where" 706 } 707 708 if (topLevel) { 709 builder.append(gt()); 710 } 711 } 712 713 private void renderTypeParameters( 714 @NotNull List<TypeParameterDescriptor> typeParameters, 715 @NotNull StringBuilder builder, 716 boolean withSpace 717 ) { 718 if (withoutTypeParameters) return; 719 720 if (!typeParameters.isEmpty()) { 721 builder.append(lt()); 722 for (Iterator<TypeParameterDescriptor> iterator = typeParameters.iterator(); iterator.hasNext(); ) { 723 TypeParameterDescriptor typeParameterDescriptor = iterator.next(); 724 renderTypeParameter(typeParameterDescriptor, builder, false); 725 if (iterator.hasNext()) { 726 builder.append(", "); 727 } 728 } 729 builder.append(gt()); 730 if (withSpace) { 731 builder.append(" "); 732 } 733 } 734 } 735 736 /* FUNCTIONS */ 737 private void renderFunction(@NotNull FunctionDescriptor function, @NotNull StringBuilder builder) { 738 if (!startFromName) { 739 renderAnnotations(function, builder); 740 renderVisibility(function.getVisibility(), builder); 741 renderModalityForCallable(function, builder); 742 renderOverride(function, builder); 743 renderMemberKind(function, builder); 744 745 builder.append(renderKeyword("fun")).append(" "); 746 renderTypeParameters(function.getTypeParameters(), builder, true); 747 renderReceiver(function, builder); 748 } 749 750 renderName(function, builder); 751 752 renderValueParameters(function, builder); 753 754 renderReceiverAfterName(function, builder); 755 756 JetType returnType = function.getReturnType(); 757 if (unitReturnType || (returnType == null || !KotlinBuiltIns.isUnit(returnType))) { 758 builder.append(": ").append(returnType == null ? "[NULL]" : escape(renderType(returnType))); 759 } 760 761 renderWhereSuffix(function.getTypeParameters(), builder); 762 } 763 764 private void renderReceiverAfterName(CallableDescriptor callableDescriptor, StringBuilder builder) { 765 if (!receiverAfterName) return; 766 767 ReceiverParameterDescriptor receiver = callableDescriptor.getExtensionReceiverParameter(); 768 if (receiver != null) { 769 builder.append(" on ").append(escape(renderType(receiver.getType()))); 770 } 771 } 772 773 private void renderReceiver(CallableDescriptor callableDescriptor, StringBuilder builder) { 774 ReceiverParameterDescriptor receiver = callableDescriptor.getExtensionReceiverParameter(); 775 if (receiver != null) { 776 JetType type = receiver.getType(); 777 String result = escape(renderType(type)); 778 if (shouldRenderAsPrettyFunctionType(type) && !TypeUtils.isNullableType(type)) { 779 result = "(" + result + ")"; 780 } 781 builder.append(result).append("."); 782 } 783 } 784 785 private void renderConstructor(@NotNull ConstructorDescriptor constructor, @NotNull StringBuilder builder) { 786 renderAnnotations(constructor, builder); 787 renderVisibility(constructor.getVisibility(), builder); 788 renderMemberKind(constructor, builder); 789 790 builder.append(renderKeyword("constructor")).append(" "); 791 792 ClassDescriptor classDescriptor = constructor.getContainingDeclaration(); 793 renderName(classDescriptor, builder); 794 795 renderTypeParameters(classDescriptor.getTypeConstructor().getParameters(), builder, false); 796 renderValueParameters(constructor, builder); 797 renderWhereSuffix(constructor.getTypeParameters(), builder); 798 } 799 800 private void renderWhereSuffix(@NotNull List<TypeParameterDescriptor> typeParameters, @NotNull StringBuilder builder) { 801 if (withoutTypeParameters) return; 802 803 List<String> upperBoundStrings = new ArrayList<String>(0); 804 805 for (TypeParameterDescriptor typeParameter : typeParameters) { 806 if (typeParameter.getUpperBounds().size() > 1) { 807 boolean first = true; 808 for (JetType upperBound : typeParameter.getUpperBounds()) { 809 // first parameter is rendered by renderTypeParameter: 810 if (!first) { 811 upperBoundStrings.add(renderName(typeParameter.getName()) + " : " + escape(renderType(upperBound))); 812 } 813 first = false; 814 } 815 } 816 } 817 if (!upperBoundStrings.isEmpty()) { 818 builder.append(" ").append(renderKeyword("where")).append(" "); 819 builder.append(UtilsPackage.join(upperBoundStrings, ", ")); 820 } 821 } 822 823 @NotNull 824 @Override 825 public String renderFunctionParameters(@NotNull FunctionDescriptor functionDescriptor) { 826 StringBuilder stringBuilder = new StringBuilder(); 827 renderValueParameters(functionDescriptor, stringBuilder); 828 return stringBuilder.toString(); 829 } 830 831 private void renderValueParameters(@NotNull FunctionDescriptor function, @NotNull StringBuilder builder) { 832 boolean includeNames = !withoutFunctionParameterNames && 833 (includeSynthesizedParameterNames || !function.hasSynthesizedParameterNames()); 834 handler.appendBeforeValueParameters(function, builder); 835 for (ValueParameterDescriptor parameter : function.getValueParameters()) { 836 handler.appendBeforeValueParameter(parameter, builder); 837 renderValueParameter(parameter, includeNames, builder, false); 838 handler.appendAfterValueParameter(parameter, builder); 839 } 840 handler.appendAfterValueParameters(function, builder); 841 } 842 843 /* VARIABLES */ 844 private void renderValueParameter(@NotNull ValueParameterDescriptor valueParameter, boolean includeName, @NotNull StringBuilder builder, boolean topLevel) { 845 if (topLevel) { 846 builder.append(renderKeyword("value-parameter")).append(" "); 847 } 848 849 if (verbose) { 850 builder.append("/*").append(valueParameter.getIndex()).append("*/ "); 851 } 852 853 renderAnnotations(valueParameter, builder); 854 renderVariable(valueParameter, includeName, builder, topLevel); 855 boolean withDefaultValue = renderDefaultValues && (debugMode ? valueParameter.declaresDefaultValue() : valueParameter.hasDefaultValue()); 856 if (withDefaultValue) { 857 builder.append(" = ..."); 858 } 859 } 860 861 private void renderValVarPrefix(@NotNull VariableDescriptor variable, @NotNull StringBuilder builder) { 862 builder.append(renderKeyword(variable.isVar() ? "var" : "val")).append(" "); 863 } 864 865 private void renderVariable(@NotNull VariableDescriptor variable, boolean includeName, @NotNull StringBuilder builder, boolean topLevel) { 866 JetType realType = variable.getType(); 867 868 JetType varargElementType = variable instanceof ValueParameterDescriptor 869 ? ((ValueParameterDescriptor) variable).getVarargElementType() 870 : null; 871 JetType typeToRender = varargElementType != null ? varargElementType : realType; 872 873 if (varargElementType != null) { 874 builder.append(renderKeyword("vararg")).append(" "); 875 } 876 if (topLevel && !startFromName) { 877 renderValVarPrefix(variable, builder); 878 } 879 880 if (includeName) { 881 renderName(variable, builder); 882 builder.append(": "); 883 } 884 885 builder.append(escape(renderType(typeToRender))); 886 887 renderInitializer(variable, builder); 888 889 if (verbose && varargElementType != null) { 890 builder.append(" /*").append(escape(renderType(realType))).append("*/"); 891 } 892 } 893 894 private void renderProperty(@NotNull PropertyDescriptor property, @NotNull StringBuilder builder) { 895 if (!startFromName) { 896 renderAnnotations(property, builder); 897 renderVisibility(property.getVisibility(), builder); 898 renderModalityForCallable(property, builder); 899 renderOverride(property, builder); 900 renderMemberKind(property, builder); 901 renderValVarPrefix(property, builder); 902 renderTypeParameters(property.getTypeParameters(), builder, true); 903 renderReceiver(property, builder); 904 } 905 906 renderName(property, builder); 907 builder.append(": ").append(escape(renderType(property.getType()))); 908 909 renderReceiverAfterName(property, builder); 910 911 renderInitializer(property, builder); 912 913 renderWhereSuffix(property.getTypeParameters(), builder); 914 } 915 916 private void renderInitializer(@NotNull VariableDescriptor variable, @NotNull StringBuilder builder) { 917 if (includePropertyConstant) { 918 CompileTimeConstant<?> initializer = variable.getCompileTimeInitializer(); 919 if (initializer != null) { 920 builder.append(" = ").append(escape(renderConstant(initializer))); 921 } 922 } 923 } 924 925 /* CLASSES */ 926 private void renderClass(@NotNull ClassDescriptor klass, @NotNull StringBuilder builder) { 927 if (!startFromName) { 928 renderAnnotations(klass, builder); 929 renderVisibility(klass.getVisibility(), builder); 930 if (!(klass.getKind() == ClassKind.TRAIT && klass.getModality() == Modality.ABSTRACT 931 || klass.getKind().isSingleton() && klass.getModality() == Modality.FINAL)) { 932 renderModality(klass.getModality(), builder); 933 } 934 renderInner(klass.isInner(), builder); 935 renderClassKindPrefix(klass, builder); 936 } 937 938 if (klass.getKind() != ClassKind.CLASS_OBJECT) { 939 if (!startFromName) renderSpaceIfNeeded(builder); 940 renderName(klass, builder); 941 } 942 else { 943 renderClassObjectName(klass, builder); 944 } 945 946 List<TypeParameterDescriptor> typeParameters = klass.getTypeConstructor().getParameters(); 947 renderTypeParameters(typeParameters, builder, false); 948 949 if (!klass.getKind().isSingleton() && classWithPrimaryConstructor) { 950 ConstructorDescriptor primaryConstructor = klass.getUnsubstitutedPrimaryConstructor(); 951 if (primaryConstructor != null) { 952 renderValueParameters(primaryConstructor, builder); 953 } 954 } 955 956 renderSuperTypes(klass, builder); 957 renderWhereSuffix(typeParameters, builder); 958 } 959 960 private void renderSuperTypes(@NotNull ClassDescriptor klass, @NotNull StringBuilder builder) { 961 if (withoutSuperTypes) return; 962 963 if (!klass.equals(KotlinBuiltIns.getInstance().getNothing())) { 964 Collection<JetType> supertypes = klass.getTypeConstructor().getSupertypes(); 965 966 if (supertypes.isEmpty() || 967 supertypes.size() == 1 && KotlinBuiltIns.isAnyOrNullableAny(supertypes.iterator().next())) { 968 } 969 else { 970 renderSpaceIfNeeded(builder); 971 builder.append(": "); 972 for (Iterator<JetType> iterator = supertypes.iterator(); iterator.hasNext(); ) { 973 JetType supertype = iterator.next(); 974 builder.append(renderType(supertype)); 975 if (iterator.hasNext()) { 976 builder.append(", "); 977 } 978 } 979 } 980 } 981 } 982 983 private void renderClassKindPrefix(ClassDescriptor klass, StringBuilder builder) { 984 builder.append(renderKeyword(getClassKindPrefix(klass))); 985 } 986 987 @NotNull 988 public static String getClassKindPrefix(@NotNull ClassDescriptor klass) { 989 switch (klass.getKind()) { 990 case CLASS: 991 return "class"; 992 case TRAIT: 993 return "trait"; 994 case ENUM_CLASS: 995 return "enum class"; 996 case OBJECT: 997 return "object"; 998 case ANNOTATION_CLASS: 999 return "annotation class"; 1000 case CLASS_OBJECT: 1001 return "class object"; 1002 case ENUM_ENTRY: 1003 return "enum entry"; 1004 default: 1005 throw new IllegalStateException("unknown class kind: " + klass.getKind()); 1006 } 1007 } 1008 1009 1010 /* OTHER */ 1011 private void renderModuleOrScript(@NotNull DeclarationDescriptor moduleOrScript, @NotNull StringBuilder builder) { 1012 renderName(moduleOrScript, builder); 1013 } 1014 1015 private void renderPackageView(@NotNull PackageViewDescriptor packageView, @NotNull StringBuilder builder) { 1016 builder.append(renderKeyword("package")).append(" "); 1017 builder.append(renderFqName(packageView.getFqName())); 1018 if (debugMode) { 1019 builder.append(" in context of "); 1020 renderName(packageView.getModule(), builder); 1021 } 1022 } 1023 1024 private void renderPackageFragment(@NotNull PackageFragmentDescriptor fragment, @NotNull StringBuilder builder) { 1025 builder.append(renderKeyword("package-fragment")).append(" "); 1026 builder.append(renderFqName(fragment.getFqName())); 1027 if (debugMode) { 1028 builder.append(" in "); 1029 renderName(fragment.getContainingDeclaration(), builder); 1030 } 1031 } 1032 1033 1034 /* STUPID DISPATCH-ONLY VISITOR */ 1035 private class RenderDeclarationDescriptorVisitor extends DeclarationDescriptorVisitorEmptyBodies<Void, StringBuilder> { 1036 @Override 1037 public Void visitValueParameterDescriptor(ValueParameterDescriptor descriptor, StringBuilder builder) { 1038 renderValueParameter(descriptor, true, builder, true); 1039 return null; 1040 } 1041 1042 @Override 1043 public Void visitVariableDescriptor(VariableDescriptor descriptor, StringBuilder builder) { 1044 renderVariable(descriptor, true, builder, true); 1045 return null; 1046 } 1047 1048 @Override 1049 public Void visitPropertyDescriptor(PropertyDescriptor descriptor, StringBuilder builder) { 1050 renderProperty(descriptor, builder); 1051 return null; 1052 } 1053 1054 @Override 1055 public Void visitFunctionDescriptor(FunctionDescriptor descriptor, StringBuilder builder) { 1056 renderFunction(descriptor, builder); 1057 return null; 1058 } 1059 1060 @Override 1061 public Void visitReceiverParameterDescriptor(ReceiverParameterDescriptor descriptor, StringBuilder data) { 1062 throw new UnsupportedOperationException("Don't render receiver parameters"); 1063 } 1064 1065 @Override 1066 public Void visitConstructorDescriptor(ConstructorDescriptor constructorDescriptor, StringBuilder builder) { 1067 renderConstructor(constructorDescriptor, builder); 1068 return null; 1069 } 1070 1071 @Override 1072 public Void visitTypeParameterDescriptor(TypeParameterDescriptor descriptor, StringBuilder builder) { 1073 renderTypeParameter(descriptor, builder, true); 1074 return null; 1075 } 1076 1077 @Override 1078 public Void visitPackageFragmentDescriptor( 1079 PackageFragmentDescriptor descriptor, StringBuilder builder 1080 ) { 1081 renderPackageFragment(descriptor, builder); 1082 return null; 1083 } 1084 1085 @Override 1086 public Void visitPackageViewDescriptor( 1087 PackageViewDescriptor descriptor, StringBuilder builder 1088 ) { 1089 renderPackageView(descriptor, builder); 1090 return null; 1091 } 1092 1093 @Override 1094 public Void visitModuleDeclaration(ModuleDescriptor descriptor, StringBuilder builder) { 1095 renderModuleOrScript(descriptor, builder); 1096 return null; 1097 } 1098 1099 @Override 1100 public Void visitScriptDescriptor(ScriptDescriptor scriptDescriptor, StringBuilder builder) { 1101 renderModuleOrScript(scriptDescriptor, builder); 1102 return null; 1103 } 1104 1105 @Override 1106 public Void visitClassDescriptor(ClassDescriptor descriptor, StringBuilder builder) { 1107 renderClass(descriptor, builder); 1108 return null; 1109 } 1110 } 1111 }