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