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