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 }