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