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