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