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