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