001 /* 002 * Copyright 2010-2013 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 com.google.common.collect.Lists; 020 import com.google.common.collect.Sets; 021 import com.intellij.openapi.util.text.StringUtil; 022 import com.intellij.util.Function; 023 import org.jetbrains.annotations.NotNull; 024 import org.jetbrains.jet.lang.descriptors.*; 025 import org.jetbrains.jet.lang.descriptors.annotations.Annotated; 026 import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor; 027 import org.jetbrains.jet.lang.descriptors.annotations.DefaultAnnotationArgumentVisitor; 028 import org.jetbrains.jet.lang.descriptors.impl.DeclarationDescriptorVisitorEmptyBodies; 029 import org.jetbrains.jet.lang.resolve.DescriptorUtils; 030 import org.jetbrains.jet.lang.resolve.constants.AnnotationValue; 031 import org.jetbrains.jet.lang.resolve.constants.ArrayValue; 032 import org.jetbrains.jet.lang.resolve.constants.CompileTimeConstant; 033 import org.jetbrains.jet.lang.resolve.constants.JavaClassValue; 034 import org.jetbrains.jet.lang.resolve.name.FqName; 035 import org.jetbrains.jet.lang.resolve.name.FqNameBase; 036 import org.jetbrains.jet.lang.resolve.name.FqNameUnsafe; 037 import org.jetbrains.jet.lang.resolve.name.Name; 038 import org.jetbrains.jet.lang.types.*; 039 import org.jetbrains.jet.lang.types.error.MissingDependencyErrorClass; 040 import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns; 041 042 import java.util.*; 043 044 import static org.jetbrains.jet.lang.types.ErrorUtils.UninferredParameterType; 045 import static org.jetbrains.jet.lang.types.TypeUtils.*; 046 047 public class DescriptorRendererImpl implements DescriptorRenderer { 048 private final boolean shortNames; 049 private final boolean withDefinedIn; 050 private final Set<DescriptorRenderer.Modifier> modifiers; 051 private final boolean startFromName; 052 private final boolean debugMode; 053 private final boolean classWithPrimaryConstructor; 054 private final boolean verbose; 055 private final boolean unitReturnType; 056 private final boolean normalizedVisibilities; 057 private final boolean showInternalKeyword; 058 private final boolean prettyFunctionTypes; 059 private final boolean uninferredTypeParameterAsName; 060 private final boolean includeSynthesizedParameterNames; 061 062 @NotNull 063 private final OverrideRenderingPolicy overrideRenderingPolicy; 064 @NotNull 065 private final ValueParametersHandler handler; 066 @NotNull 067 private final TextFormat textFormat; 068 private final boolean includePropertyConstant; 069 @NotNull 070 private final Set<FqName> excludedAnnotationClasses; 071 072 /* package */ DescriptorRendererImpl( 073 boolean shortNames, 074 boolean withDefinedIn, 075 Set<Modifier> modifiers, 076 boolean startFromName, 077 boolean debugMode, 078 boolean classWithPrimaryConstructor, 079 boolean verbose, 080 boolean unitReturnType, 081 boolean normalizedVisibilities, 082 boolean showInternalKeyword, 083 boolean prettyFunctionTypes, 084 boolean uninferredTypeParameterAsName, 085 @NotNull OverrideRenderingPolicy overrideRenderingPolicy, 086 @NotNull ValueParametersHandler handler, 087 @NotNull TextFormat textFormat, 088 @NotNull Collection<FqName> excludedAnnotationClasses, 089 boolean includePropertyConstant, 090 boolean includeSynthesizedParameterNames 091 ) { 092 this.shortNames = shortNames; 093 this.withDefinedIn = withDefinedIn; 094 this.modifiers = modifiers; 095 this.startFromName = startFromName; 096 this.handler = handler; 097 this.classWithPrimaryConstructor = classWithPrimaryConstructor; 098 this.verbose = verbose; 099 this.unitReturnType = unitReturnType; 100 this.normalizedVisibilities = normalizedVisibilities; 101 this.showInternalKeyword = showInternalKeyword; 102 this.overrideRenderingPolicy = overrideRenderingPolicy; 103 this.debugMode = debugMode; 104 this.textFormat = textFormat; 105 this.includePropertyConstant = includePropertyConstant; 106 this.excludedAnnotationClasses = Sets.newHashSet(excludedAnnotationClasses); 107 this.prettyFunctionTypes = prettyFunctionTypes; 108 this.uninferredTypeParameterAsName = uninferredTypeParameterAsName; 109 this.includeSynthesizedParameterNames = includeSynthesizedParameterNames; 110 } 111 112 /* FORMATTING */ 113 @NotNull 114 private String renderKeyword(@NotNull String keyword) { 115 switch (textFormat) { 116 case PLAIN: 117 return keyword; 118 case HTML: 119 return "<b>" + keyword + "</b>"; 120 } 121 throw new IllegalStateException("Unexpected textFormat: " + textFormat); 122 } 123 124 @NotNull 125 private String renderError(@NotNull String keyword) { 126 switch (textFormat) { 127 case PLAIN: 128 return keyword; 129 case HTML: 130 return "<font color=red><b>" + keyword + "</b></font>"; 131 } 132 throw new IllegalStateException("Unexpected textFormat: " + textFormat); 133 } 134 135 @NotNull 136 private String escape(@NotNull String string) { 137 switch (textFormat) { 138 case PLAIN: 139 return string; 140 case HTML: 141 return string.replaceAll("<", "<").replaceAll(">", ">"); 142 } 143 throw new IllegalStateException("Unexpected textFormat: " + textFormat); 144 } 145 146 @NotNull 147 private String lt() { 148 return escape("<"); 149 } 150 151 @NotNull 152 private String gt() { 153 return escape(">"); 154 } 155 156 @NotNull 157 private String arrow() { 158 switch (textFormat) { 159 case PLAIN: 160 return escape("->"); 161 case HTML: 162 return "→"; 163 } 164 throw new IllegalStateException("Unexpected textFormat: " + textFormat); 165 } 166 167 @NotNull 168 private String renderMessage(@NotNull String message) { 169 switch (textFormat) { 170 case PLAIN: 171 return message; 172 case HTML: 173 return "<i>" + message + "</i>"; 174 } 175 throw new IllegalStateException("Unexpected textFormat: " + textFormat); 176 } 177 178 179 /* NAMES RENDERING */ 180 @NotNull 181 private String renderName(@NotNull Name identifier) { 182 String asString = identifier.toString(); 183 return escape(KeywordStringsGenerated.KEYWORDS.contains(asString) ? '`' + asString + '`' : asString); 184 } 185 186 private void renderName(@NotNull DeclarationDescriptor descriptor, @NotNull StringBuilder builder) { 187 builder.append(renderName(descriptor.getName())); 188 } 189 190 @NotNull 191 private String renderFqName(@NotNull FqNameBase fqName) { 192 return renderFqName(fqName.pathSegments()); 193 } 194 195 196 @NotNull 197 private String renderFqName(@NotNull List<Name> pathSegments) { 198 StringBuilder buf = new StringBuilder(); 199 for (Name element : pathSegments) { 200 if (buf.length() != 0) { 201 buf.append("."); 202 } 203 buf.append(renderName(element)); 204 } 205 return buf.toString(); 206 } 207 208 @NotNull 209 private String renderClassName(@NotNull ClassDescriptor klass) { 210 if (klass instanceof MissingDependencyErrorClass) { 211 return ((MissingDependencyErrorClass) klass).getFullFqName().asString(); 212 } 213 if (ErrorUtils.isError(klass)) { 214 return klass.getTypeConstructor().toString(); 215 } 216 if (shortNames) { 217 List<Name> qualifiedNameElements = Lists.newArrayList(); 218 219 // for nested classes qualified name should be used 220 DeclarationDescriptor current = klass; 221 do { 222 if (((ClassDescriptor) current).getKind() != ClassKind.CLASS_OBJECT) { 223 qualifiedNameElements.add(current.getName()); 224 } 225 current = current.getContainingDeclaration(); 226 } 227 while (current instanceof ClassDescriptor); 228 229 Collections.reverse(qualifiedNameElements); 230 return renderFqName(qualifiedNameElements); 231 } 232 return renderFqName(DescriptorUtils.getFqName(klass)); 233 } 234 235 /* TYPES RENDERING */ 236 @NotNull 237 @Override 238 public String renderType(@NotNull JetType type) { 239 if (type == CANT_INFER_LAMBDA_PARAM_TYPE || type == DONT_CARE) { 240 return "???"; 241 } 242 if (ErrorUtils.isUninferredParameter(type)) { 243 if (uninferredTypeParameterAsName) { 244 return renderError(((UninferredParameterType) type).getTypeParameterDescriptor().getName().toString()); 245 } 246 return "???"; 247 } 248 if (type instanceof LazyType && debugMode) { 249 return type.toString(); 250 } 251 if (type.isError()) { 252 return renderDefaultType(type); 253 } 254 if (KotlinBuiltIns.getInstance().isExactFunctionOrExtensionFunctionType(type) && prettyFunctionTypes) { 255 return renderFunctionType(type); 256 } 257 return renderDefaultType(type); 258 } 259 260 @NotNull 261 @Override 262 public String renderTypeArguments(@NotNull List<TypeProjection> typeArguments) { 263 if (typeArguments.isEmpty()) return ""; 264 StringBuilder sb = new StringBuilder(); 265 sb.append(lt()); 266 appendTypeProjections(typeArguments, sb); 267 sb.append(gt()); 268 return sb.toString(); 269 } 270 271 @NotNull 272 private String renderDefaultType(@NotNull JetType type) { 273 StringBuilder sb = new StringBuilder(); 274 275 if (type.isError()) { 276 sb.append(type.getConstructor().toString()); // Debug name of an error type is more informative 277 } 278 else { 279 sb.append(renderTypeName(type.getConstructor())); 280 } 281 sb.append(renderTypeArguments(type.getArguments())); 282 if (type.isNullable()) { 283 sb.append("?"); 284 } 285 return sb.toString(); 286 } 287 288 @NotNull 289 private String renderTypeName(@NotNull TypeConstructor typeConstructor) { 290 ClassifierDescriptor cd = typeConstructor.getDeclarationDescriptor(); 291 if (cd instanceof TypeParameterDescriptor) { 292 return renderName(cd.getName()); 293 } 294 else if (cd instanceof ClassDescriptor) { 295 return renderClassName((ClassDescriptor) cd); 296 } 297 else { 298 assert cd == null: "Unexpected classifier: " + cd.getClass(); 299 return typeConstructor.toString(); 300 } 301 } 302 303 private void appendTypeProjections(@NotNull List<TypeProjection> typeProjections, @NotNull StringBuilder builder) { 304 for (Iterator<TypeProjection> iterator = typeProjections.iterator(); iterator.hasNext(); ) { 305 TypeProjection typeProjection = iterator.next(); 306 if (typeProjection.getProjectionKind() != Variance.INVARIANT) { 307 builder.append(typeProjection.getProjectionKind()).append(" "); 308 } 309 builder.append(renderType(typeProjection.getType())); 310 if (iterator.hasNext()) { 311 builder.append(", "); 312 } 313 } 314 } 315 316 @NotNull 317 private String renderFunctionType(@NotNull JetType type) { 318 StringBuilder sb = new StringBuilder(); 319 320 JetType receiverType = KotlinBuiltIns.getInstance().getReceiverType(type); 321 if (receiverType != null) { 322 sb.append(renderType(receiverType)); 323 sb.append("."); 324 } 325 326 sb.append("("); 327 appendTypeProjections(KotlinBuiltIns.getInstance().getParameterTypeProjectionsFromFunctionType(type), sb); 328 sb.append(") ").append(arrow()).append(" "); 329 sb.append(renderType(KotlinBuiltIns.getInstance().getReturnTypeFromFunctionType(type))); 330 331 if (type.isNullable()) { 332 return "(" + sb + ")?"; 333 } 334 return sb.toString(); 335 } 336 337 338 /* METHODS FOR ALL KINDS OF DESCRIPTORS */ 339 private void appendDefinedIn(@NotNull DeclarationDescriptor descriptor, @NotNull StringBuilder builder) { 340 if (descriptor instanceof PackageFragmentDescriptor || descriptor instanceof PackageViewDescriptor) { 341 return; 342 } 343 if (descriptor instanceof ModuleDescriptor) { 344 builder.append(" is a module"); 345 return; 346 } 347 builder.append(" ").append(renderMessage("defined in")).append(" "); 348 349 DeclarationDescriptor containingDeclaration = descriptor.getContainingDeclaration(); 350 if (containingDeclaration != null) { 351 FqNameUnsafe fqName = DescriptorUtils.getFqName(containingDeclaration); 352 builder.append(FqName.ROOT.equalsTo(fqName) ? "root package" : renderFqName(fqName)); 353 } 354 } 355 356 private void renderAnnotations(@NotNull Annotated annotated, @NotNull StringBuilder builder) { 357 if (!modifiers.contains(Modifier.ANNOTATIONS)) return; 358 for (AnnotationDescriptor annotation : annotated.getAnnotations()) { 359 ClassDescriptor annotationClass = (ClassDescriptor) annotation.getType().getConstructor().getDeclarationDescriptor(); 360 assert annotationClass != null; 361 362 if (!excludedAnnotationClasses.contains(DescriptorUtils.getFqNameSafe(annotationClass))) { 363 builder.append(renderAnnotation(annotation)).append(" "); 364 } 365 } 366 } 367 368 @Override 369 @NotNull 370 public String renderAnnotation(@NotNull AnnotationDescriptor annotation) { 371 StringBuilder sb = new StringBuilder(); 372 sb.append(renderType(annotation.getType())); 373 if (verbose) { 374 sb.append("(").append(StringUtil.join(renderAndSortAnnotationArguments(annotation), ", ")).append(")"); 375 } 376 return sb.toString(); 377 } 378 379 @NotNull 380 private List<String> renderAndSortAnnotationArguments(@NotNull AnnotationDescriptor descriptor) { 381 List<String> resultList = Lists.newArrayList(); 382 for (Map.Entry<ValueParameterDescriptor, CompileTimeConstant<?>> entry : descriptor.getAllValueArguments().entrySet()) { 383 CompileTimeConstant<?> value = entry.getValue(); 384 String typeSuffix = ": " + renderType(value.getType(KotlinBuiltIns.getInstance())); 385 resultList.add(entry.getKey().getName().asString() + " = " + renderConstant(value) + typeSuffix); 386 } 387 Collections.sort(resultList); 388 return resultList; 389 } 390 391 @NotNull 392 private String renderConstant(@NotNull CompileTimeConstant<?> value) { 393 return value.accept( 394 new DefaultAnnotationArgumentVisitor<String, Void>() { 395 @Override 396 public String visitValue(@NotNull CompileTimeConstant<?> value, Void data) { 397 return value.toString(); 398 } 399 400 @Override 401 public String visitArrayValue(ArrayValue value, Void data) { 402 return "{" + 403 StringUtil.join( 404 value.getValue(), 405 new Function<CompileTimeConstant<?>, String>() { 406 @Override 407 public String fun(CompileTimeConstant<?> constant) { 408 return renderConstant(constant); 409 } 410 }, 411 ", ") + 412 "}"; 413 } 414 415 @Override 416 public String visitAnnotationValue(AnnotationValue value, Void data) { 417 return renderAnnotation(value.getValue()); 418 } 419 420 @Override 421 public String visitJavaClassValue(JavaClassValue value, Void data) { 422 return renderType(value.getValue()) + ".class"; 423 } 424 }, 425 null 426 ); 427 } 428 429 private void renderVisibility(@NotNull Visibility visibility, @NotNull StringBuilder builder) { 430 if (!modifiers.contains(Modifier.VISIBILITY)) return; 431 if (normalizedVisibilities) { 432 visibility = visibility.normalize(); 433 } 434 if (!showInternalKeyword && visibility == Visibilities.INTERNAL) return; 435 builder.append(renderKeyword(visibility.toString())).append(" "); 436 } 437 438 private void renderModality(@NotNull Modality modality, @NotNull StringBuilder builder) { 439 if (!modifiers.contains(Modifier.MODALITY)) return; 440 String keyword = modality.name().toLowerCase(); 441 builder.append(renderKeyword(keyword)).append(" "); 442 } 443 444 private void renderInner(boolean isInner, @NotNull StringBuilder builder) { 445 if (!modifiers.contains(Modifier.INNER)) return; 446 if (isInner) { 447 builder.append(renderKeyword("inner")).append(" "); 448 } 449 } 450 451 private void renderModalityForCallable(@NotNull CallableMemberDescriptor callable, @NotNull StringBuilder builder) { 452 if (!DescriptorUtils.isTopLevelDeclaration(callable) || callable.getModality() != Modality.FINAL) { 453 if (overridesSomething(callable) 454 && overrideRenderingPolicy == OverrideRenderingPolicy.RENDER_OVERRIDE 455 && callable.getModality() == Modality.OPEN) { 456 return; 457 } 458 renderModality(callable.getModality(), builder); 459 } 460 } 461 462 private boolean overridesSomething(CallableMemberDescriptor callable) { 463 return !callable.getOverriddenDescriptors().isEmpty(); 464 } 465 466 private void renderOverride(@NotNull CallableMemberDescriptor callableMember, @NotNull StringBuilder builder) { 467 if (!modifiers.contains(Modifier.OVERRIDE)) return; 468 if (overridesSomething(callableMember)) { 469 if (overrideRenderingPolicy != OverrideRenderingPolicy.RENDER_OPEN) { 470 builder.append("override "); 471 if (verbose) { 472 builder.append("/*").append(callableMember.getOverriddenDescriptors().size()).append("*/ "); 473 } 474 } 475 } 476 } 477 478 private void renderMemberKind(CallableMemberDescriptor callableMember, StringBuilder builder) { 479 if (!modifiers.contains(Modifier.MEMBER_KIND)) return; 480 if (verbose && callableMember.getKind() != CallableMemberDescriptor.Kind.DECLARATION) { 481 builder.append("/*").append(callableMember.getKind().name().toLowerCase()).append("*/ "); 482 } 483 } 484 485 @NotNull 486 @Override 487 public String render(@NotNull DeclarationDescriptor declarationDescriptor) { 488 StringBuilder stringBuilder = new StringBuilder(); 489 declarationDescriptor.accept(new RenderDeclarationDescriptorVisitor(), stringBuilder); 490 491 if (withDefinedIn) { 492 appendDefinedIn(declarationDescriptor, stringBuilder); 493 } 494 return stringBuilder.toString(); 495 } 496 497 498 /* TYPE PARAMETERS */ 499 private void renderTypeParameter(@NotNull TypeParameterDescriptor typeParameter, @NotNull StringBuilder builder, boolean topLevel) { 500 if (topLevel) { 501 builder.append(lt()); 502 } 503 504 if (verbose) { 505 builder.append("/*").append(typeParameter.getIndex()).append("*/ "); 506 } 507 508 if (typeParameter.isReified()) { 509 builder.append(renderKeyword("reified")).append(" "); 510 } 511 String variance = typeParameter.getVariance().toString(); 512 if (!variance.isEmpty()) { 513 builder.append(renderKeyword(variance)).append(" "); 514 } 515 renderName(typeParameter, builder); 516 int upperBoundsCount = typeParameter.getUpperBounds().size(); 517 if ((upperBoundsCount > 1 && !topLevel) || upperBoundsCount == 1) { 518 JetType upperBound = typeParameter.getUpperBounds().iterator().next(); 519 if (!KotlinBuiltIns.getInstance().getDefaultBound().equals(upperBound)) { 520 builder.append(" : ").append(renderType(upperBound)); 521 } 522 } 523 else if (topLevel) { 524 boolean first = true; 525 for (JetType upperBound : typeParameter.getUpperBounds()) { 526 if (upperBound.equals(KotlinBuiltIns.getInstance().getDefaultBound())) { 527 continue; 528 } 529 if (first) { 530 builder.append(" : "); 531 } 532 else { 533 builder.append(" & "); 534 } 535 builder.append(renderType(upperBound)); 536 first = false; 537 } 538 } 539 else { 540 // rendered with "where" 541 } 542 543 if (topLevel) { 544 builder.append(gt()); 545 } 546 } 547 548 private void renderTypeParameters( 549 @NotNull List<TypeParameterDescriptor> typeParameters, 550 @NotNull StringBuilder builder, 551 boolean withSpace 552 ) { 553 if (!typeParameters.isEmpty()) { 554 builder.append(lt()); 555 for (Iterator<TypeParameterDescriptor> iterator = typeParameters.iterator(); iterator.hasNext(); ) { 556 TypeParameterDescriptor typeParameterDescriptor = iterator.next(); 557 renderTypeParameter(typeParameterDescriptor, builder, false); 558 if (iterator.hasNext()) { 559 builder.append(", "); 560 } 561 } 562 builder.append(gt()); 563 if (withSpace) { 564 builder.append(" "); 565 } 566 } 567 } 568 569 /* FUNCTIONS */ 570 private void renderFunction(@NotNull FunctionDescriptor function, @NotNull StringBuilder builder) { 571 if (!startFromName) { 572 renderAnnotations(function, builder); 573 renderVisibility(function.getVisibility(), builder); 574 renderModalityForCallable(function, builder); 575 renderOverride(function, builder); 576 renderMemberKind(function, builder); 577 578 builder.append(renderKeyword("fun")).append(" "); 579 renderTypeParameters(function.getTypeParameters(), builder, true); 580 581 ReceiverParameterDescriptor receiver = function.getReceiverParameter(); 582 if (receiver != null) { 583 builder.append(escape(renderType(receiver.getType()))).append("."); 584 } 585 } 586 587 renderName(function, builder); 588 589 renderValueParameters(function, builder); 590 591 JetType returnType = function.getReturnType(); 592 if (unitReturnType || !KotlinBuiltIns.getInstance().isUnit(returnType)) { 593 builder.append(": ").append(returnType == null ? "[NULL]" : escape(renderType(returnType))); 594 } 595 renderWhereSuffix(function.getTypeParameters(), builder); 596 } 597 598 private void renderConstructor(@NotNull ConstructorDescriptor constructor, @NotNull StringBuilder builder) { 599 renderAnnotations(constructor, builder); 600 renderVisibility(constructor.getVisibility(), builder); 601 renderMemberKind(constructor, builder); 602 603 builder.append(renderKeyword("constructor")).append(" "); 604 605 ClassDescriptor classDescriptor = constructor.getContainingDeclaration(); 606 renderName(classDescriptor, builder); 607 608 renderTypeParameters(classDescriptor.getTypeConstructor().getParameters(), builder, false); 609 renderValueParameters(constructor, builder); 610 renderWhereSuffix(constructor.getTypeParameters(), builder); 611 } 612 613 private void renderWhereSuffix(@NotNull List<TypeParameterDescriptor> typeParameters, @NotNull StringBuilder builder) { 614 List<String> upperBoundStrings = Lists.newArrayList(); 615 616 for (TypeParameterDescriptor typeParameter : typeParameters) { 617 if (typeParameter.getUpperBounds().size() > 1) { 618 boolean first = true; 619 for (JetType upperBound : typeParameter.getUpperBounds()) { 620 // first parameter is rendered by renderTypeParameter: 621 if (!first) { 622 upperBoundStrings.add(renderName(typeParameter.getName()) + " : " + escape(renderType(upperBound))); 623 } 624 first = false; 625 } 626 } 627 } 628 if (!upperBoundStrings.isEmpty()) { 629 builder.append(" ").append(renderKeyword("where")).append(" "); 630 builder.append(StringUtil.join(upperBoundStrings, ", ")); 631 } 632 } 633 634 @NotNull 635 @Override 636 public String renderFunctionParameters(@NotNull FunctionDescriptor functionDescriptor) { 637 StringBuilder stringBuilder = new StringBuilder(); 638 renderValueParameters(functionDescriptor, stringBuilder); 639 return stringBuilder.toString(); 640 } 641 642 private void renderValueParameters(@NotNull FunctionDescriptor function, @NotNull StringBuilder builder) { 643 boolean includeNames = includeSynthesizedParameterNames || !function.hasSynthesizedParameterNames(); 644 handler.appendBeforeValueParameters(function, builder); 645 for (ValueParameterDescriptor parameter : function.getValueParameters()) { 646 handler.appendBeforeValueParameter(parameter, builder); 647 renderValueParameter(parameter, includeNames, builder, false); 648 handler.appendAfterValueParameter(parameter, builder); 649 } 650 handler.appendAfterValueParameters(function, builder); 651 } 652 653 /* VARIABLES */ 654 private void renderValueParameter(@NotNull ValueParameterDescriptor valueParameter, boolean includeName, @NotNull StringBuilder builder, boolean topLevel) { 655 if (topLevel) { 656 builder.append(renderKeyword("value-parameter")).append(" "); 657 } 658 659 if (verbose) { 660 builder.append("/*").append(valueParameter.getIndex()).append("*/ "); 661 } 662 663 renderAnnotations(valueParameter, builder); 664 renderVariable(valueParameter, includeName, builder, topLevel); 665 boolean withDefaultValue = debugMode ? valueParameter.declaresDefaultValue() : valueParameter.hasDefaultValue(); 666 if (withDefaultValue) { 667 builder.append(" = ..."); 668 } 669 } 670 671 private void renderValVarPrefix(@NotNull VariableDescriptor variable, @NotNull StringBuilder builder) { 672 builder.append(renderKeyword(variable.isVar() ? "var" : "val")).append(" "); 673 } 674 675 private void renderVariable(@NotNull VariableDescriptor variable, boolean includeName, @NotNull StringBuilder builder, boolean topLevel) { 676 JetType realType = variable.getType(); 677 678 JetType varargElementType = variable instanceof ValueParameterDescriptor 679 ? ((ValueParameterDescriptor) variable).getVarargElementType() 680 : null; 681 JetType typeToRender = varargElementType != null ? varargElementType : realType; 682 683 if (varargElementType != null) { 684 builder.append(renderKeyword("vararg")).append(" "); 685 } 686 if (topLevel && !startFromName) { 687 renderValVarPrefix(variable, builder); 688 } 689 690 if (includeName) { 691 renderName(variable, builder); 692 builder.append(": "); 693 } 694 695 builder.append(escape(renderType(typeToRender))); 696 697 renderInitializer(variable, builder); 698 699 if (verbose && varargElementType != null) { 700 builder.append(" /*").append(escape(renderType(realType))).append("*/"); 701 } 702 } 703 704 private void renderProperty(@NotNull PropertyDescriptor property, @NotNull StringBuilder builder) { 705 if (!startFromName) { 706 renderAnnotations(property, builder); 707 renderVisibility(property.getVisibility(), builder); 708 renderModalityForCallable(property, builder); 709 renderOverride(property, builder); 710 renderMemberKind(property, builder); 711 712 renderValVarPrefix(property, builder); 713 } 714 715 renderTypeParameters(property.getTypeParameters(), builder, true); 716 717 ReceiverParameterDescriptor receiver = property.getReceiverParameter(); 718 if (receiver != null) { 719 builder.append(escape(renderType(receiver.getType()))).append("."); 720 } 721 renderName(property, builder); 722 builder.append(": ").append(escape(renderType(property.getType()))); 723 724 renderInitializer(property, builder); 725 726 renderWhereSuffix(property.getTypeParameters(), builder); 727 } 728 729 private void renderInitializer(@NotNull VariableDescriptor variable, @NotNull StringBuilder builder) { 730 if (includePropertyConstant) { 731 CompileTimeConstant<?> initializer = variable.getCompileTimeInitializer(); 732 if (initializer != null) { 733 builder.append(" = ").append(escape(renderConstant(initializer))); 734 } 735 } 736 } 737 738 /* CLASSES */ 739 private void renderClass(@NotNull ClassDescriptor klass, @NotNull StringBuilder builder) { 740 if (!startFromName) { 741 renderAnnotations(klass, builder); 742 renderVisibility(klass.getVisibility(), builder); 743 if (!(klass.getKind() == ClassKind.TRAIT && klass.getModality() == Modality.ABSTRACT 744 || klass.getKind().isSingleton() && klass.getModality() == Modality.FINAL)) { 745 renderModality(klass.getModality(), builder); 746 } 747 renderInner(klass.isInner(), builder); 748 builder.append(renderKeyword(getClassKindPrefix(klass))); 749 } 750 751 if (klass.getKind() != ClassKind.CLASS_OBJECT || verbose) { 752 builder.append(" "); 753 renderName(klass, builder); 754 } 755 756 List<TypeParameterDescriptor> typeParameters = klass.getTypeConstructor().getParameters(); 757 renderTypeParameters(typeParameters, builder, false); 758 759 if (!klass.getKind().isSingleton() && classWithPrimaryConstructor) { 760 ConstructorDescriptor primaryConstructor = klass.getUnsubstitutedPrimaryConstructor(); 761 if (primaryConstructor != null) { 762 renderValueParameters(primaryConstructor, builder); 763 } 764 } 765 766 if (!klass.equals(KotlinBuiltIns.getInstance().getNothing())) { 767 Collection<JetType> supertypes = klass.getTypeConstructor().getSupertypes(); 768 if (supertypes.isEmpty() || supertypes.size() == 1 && KotlinBuiltIns.getInstance().isAnyOrNullableAny( 769 supertypes.iterator().next())) { 770 } 771 else { 772 builder.append(" : "); 773 for (Iterator<JetType> iterator = supertypes.iterator(); iterator.hasNext(); ) { 774 JetType supertype = iterator.next(); 775 builder.append(renderType(supertype)); 776 if (iterator.hasNext()) { 777 builder.append(", "); 778 } 779 } 780 } 781 } 782 783 renderWhereSuffix(typeParameters, builder); 784 } 785 786 @NotNull 787 private static String getClassKindPrefix(@NotNull ClassDescriptor klass) { 788 switch (klass.getKind()) { 789 case CLASS: 790 return "class"; 791 case TRAIT: 792 return "trait"; 793 case ENUM_CLASS: 794 return "enum class"; 795 case OBJECT: 796 return "object"; 797 case ANNOTATION_CLASS: 798 return "annotation class"; 799 case CLASS_OBJECT: 800 return "class object"; 801 case ENUM_ENTRY: 802 return "enum entry"; 803 default: 804 throw new IllegalStateException("unknown class kind: " + klass.getKind()); 805 } 806 } 807 808 809 /* OTHER */ 810 private void renderModuleOrScript(@NotNull DeclarationDescriptor moduleOrScript, @NotNull StringBuilder builder) { 811 renderName(moduleOrScript, builder); 812 } 813 814 private void renderPackageView(@NotNull PackageViewDescriptor packageView, @NotNull StringBuilder builder) { 815 builder.append(renderKeyword("package")).append(" "); 816 builder.append(renderFqName(packageView.getFqName())); 817 if (debugMode) { 818 builder.append(" in context of "); 819 renderName(packageView.getModule(), builder); 820 } 821 } 822 823 private void renderPackageFragment(@NotNull PackageFragmentDescriptor fragment, @NotNull StringBuilder builder) { 824 builder.append(renderKeyword("package-fragment")).append(" "); 825 builder.append(renderFqName(fragment.getFqName())); 826 if (debugMode) { 827 builder.append(" in "); 828 renderName(fragment.getContainingDeclaration(), builder); 829 } 830 } 831 832 833 /* STUPID DISPATCH-ONLY VISITOR */ 834 private class RenderDeclarationDescriptorVisitor extends DeclarationDescriptorVisitorEmptyBodies<Void, StringBuilder> { 835 @Override 836 public Void visitValueParameterDescriptor(ValueParameterDescriptor descriptor, StringBuilder builder) { 837 renderValueParameter(descriptor, true, builder, true); 838 return null; 839 } 840 841 @Override 842 public Void visitVariableDescriptor(VariableDescriptor descriptor, StringBuilder builder) { 843 renderVariable(descriptor, true, builder, true); 844 return null; 845 } 846 847 @Override 848 public Void visitPropertyDescriptor(PropertyDescriptor descriptor, StringBuilder builder) { 849 renderProperty(descriptor, builder); 850 return null; 851 } 852 853 @Override 854 public Void visitFunctionDescriptor(FunctionDescriptor descriptor, StringBuilder builder) { 855 renderFunction(descriptor, builder); 856 return null; 857 } 858 859 @Override 860 public Void visitReceiverParameterDescriptor(ReceiverParameterDescriptor descriptor, StringBuilder data) { 861 throw new UnsupportedOperationException("Don't render receiver parameters"); 862 } 863 864 @Override 865 public Void visitConstructorDescriptor(ConstructorDescriptor constructorDescriptor, StringBuilder builder) { 866 renderConstructor(constructorDescriptor, builder); 867 return null; 868 } 869 870 @Override 871 public Void visitTypeParameterDescriptor(TypeParameterDescriptor descriptor, StringBuilder builder) { 872 renderTypeParameter(descriptor, builder, true); 873 return null; 874 } 875 876 @Override 877 public Void visitPackageFragmentDescriptor( 878 PackageFragmentDescriptor descriptor, StringBuilder builder 879 ) { 880 renderPackageFragment(descriptor, builder); 881 return null; 882 } 883 884 @Override 885 public Void visitPackageViewDescriptor( 886 PackageViewDescriptor descriptor, StringBuilder builder 887 ) { 888 renderPackageView(descriptor, builder); 889 return null; 890 } 891 892 @Override 893 public Void visitModuleDeclaration(ModuleDescriptor descriptor, StringBuilder builder) { 894 renderModuleOrScript(descriptor, builder); 895 return null; 896 } 897 898 @Override 899 public Void visitScriptDescriptor(ScriptDescriptor scriptDescriptor, StringBuilder builder) { 900 renderModuleOrScript(scriptDescriptor, builder); 901 return null; 902 } 903 904 @Override 905 public Void visitClassDescriptor(ClassDescriptor descriptor, StringBuilder builder) { 906 renderClass(descriptor, builder); 907 return null; 908 } 909 } 910 }