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