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