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