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