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