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