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