001 /*
002 * Copyright 2010-2015 JetBrains s.r.o.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 * http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016
017 package org.jetbrains.kotlin.diagnostics.rendering;
018
019 import com.google.common.base.Predicate;
020 import com.google.common.base.Predicates;
021 import com.google.common.collect.Lists;
022 import org.jetbrains.annotations.NotNull;
023 import org.jetbrains.annotations.Nullable;
024 import org.jetbrains.kotlin.descriptors.CallableDescriptor;
025 import org.jetbrains.kotlin.diagnostics.rendering.TabledDescriptorRenderer.TableRenderer.DescriptorRow;
026 import org.jetbrains.kotlin.diagnostics.rendering.TabledDescriptorRenderer.TableRenderer.FunctionArgumentsRow;
027 import org.jetbrains.kotlin.diagnostics.rendering.TabledDescriptorRenderer.TableRenderer.TableRow;
028 import org.jetbrains.kotlin.diagnostics.rendering.TabledDescriptorRenderer.TextRenderer.TextElement;
029 import org.jetbrains.kotlin.renderer.DescriptorRenderer;
030 import org.jetbrains.kotlin.renderer.Renderer;
031 import org.jetbrains.kotlin.resolve.calls.inference.constraintPosition.ConstraintPosition;
032 import org.jetbrains.kotlin.types.JetType;
033
034 import java.util.Iterator;
035 import java.util.List;
036
037 public class TabledDescriptorRenderer {
038 public interface TableOrTextRenderer {}
039
040 public static class TableRenderer implements TableOrTextRenderer{
041 public interface TableRow {
042 }
043
044 public static class DescriptorRow implements TableRow {
045 public final CallableDescriptor descriptor;
046
047 public DescriptorRow(CallableDescriptor descriptor) {
048 this.descriptor = descriptor;
049 }
050 }
051
052 public static class FunctionArgumentsRow implements TableRow {
053 public final JetType receiverType;
054 public final List<JetType> argumentTypes;
055 public final Predicate<ConstraintPosition> isErrorPosition;
056
057 public FunctionArgumentsRow(JetType receiverType, List<JetType> argumentTypes, Predicate<ConstraintPosition> isErrorPosition) {
058 this.receiverType = receiverType;
059 this.argumentTypes = argumentTypes;
060 this.isErrorPosition = isErrorPosition;
061 }
062 }
063
064 public final List<TableRow> rows = Lists.newArrayList();
065
066 public TableRenderer descriptor(CallableDescriptor descriptor) {
067 rows.add(new DescriptorRow(descriptor));
068 return this;
069 }
070
071 public TableRenderer functionArgumentTypeList(@Nullable JetType receiverType, @NotNull List<JetType> argumentTypes) {
072
073 return functionArgumentTypeList(receiverType, argumentTypes, Predicates.<ConstraintPosition>alwaysFalse());
074 }
075
076 public TableRenderer functionArgumentTypeList(@Nullable JetType receiverType,
077 @NotNull List<JetType> argumentTypes,
078 @NotNull Predicate<ConstraintPosition> isErrorPosition) {
079 rows.add(new FunctionArgumentsRow(receiverType, argumentTypes, isErrorPosition));
080 return this;
081 }
082
083 public TableRenderer text(@NotNull String text) {
084 rows.add(newText().normal(text));
085 return this;
086 }
087
088 public TableRenderer text(@NotNull TextRenderer textRenderer) {
089 rows.add(textRenderer);
090 return this;
091 }
092 }
093
094 public static class TextRenderer implements TableOrTextRenderer, TableRow {
095 public static class TextElement {
096
097 public TextElementType type;
098 public String text;
099
100 public TextElement(@NotNull TextElementType type, @NotNull String text) {
101 this.type = type;
102 this.text = text;
103 }
104 }
105
106 public final List<TextElement> elements = Lists.newArrayList();
107
108 public TextRenderer normal(@NotNull Object text) {
109 elements.add(new TextElement(TextElementType.DEFAULT, text.toString()));
110 return this;
111 }
112
113 public TextRenderer error(@NotNull Object text) {
114 elements.add(new TextElement(TextElementType.ERROR, text.toString()));
115 return this;
116 }
117
118 public TextRenderer strong(@NotNull Object text) {
119 elements.add(new TextElement(TextElementType.STRONG, text.toString()));
120 return this;
121 }
122 }
123
124 protected final List<TableOrTextRenderer> renderers = Lists.newArrayList();
125
126 public TabledDescriptorRenderer text(@NotNull TextRenderer textRenderer) {
127 renderers.add(textRenderer);
128 return this;
129 }
130
131 public TabledDescriptorRenderer table(@NotNull TableRenderer tableRenderer) {
132 renderers.add(tableRenderer);
133 return this;
134 }
135
136 public static TextRenderer newText() {
137 return new TextRenderer();
138 }
139
140 public static TableRenderer newTable() {
141 return new TableRenderer();
142 }
143
144 @Override
145 public String toString() {
146 StringBuilder result = new StringBuilder();
147 for (TableOrTextRenderer tableOrTextRenderer : renderers) {
148 if (tableOrTextRenderer instanceof TableRenderer) {
149 renderTable((TableRenderer)tableOrTextRenderer, result);
150 }
151 else {
152 renderText((TextRenderer)tableOrTextRenderer, result);
153 }
154 }
155 return result.toString();
156 }
157
158 @NotNull
159 public Renderer<JetType> getTypeRenderer() {
160 return Renderers.RENDER_TYPE;
161 }
162
163 protected void renderText(TextRenderer textRenderer, StringBuilder result) {
164 for (TextElement element : textRenderer.elements) {
165 result.append(element.text);
166 }
167 }
168
169 protected void renderTable(TableRenderer table, StringBuilder result) {
170 if (table.rows.isEmpty()) return;
171 for (TableRow row : table.rows) {
172 if (row instanceof TextRenderer) {
173 renderText((TextRenderer) row, result);
174 }
175 if (row instanceof DescriptorRow) {
176 result.append(DescriptorRenderer.COMPACT.render(((DescriptorRow) row).descriptor));
177 }
178 if (row instanceof FunctionArgumentsRow) {
179 FunctionArgumentsRow functionArgumentsRow = (FunctionArgumentsRow) row;
180 renderFunctionArguments(functionArgumentsRow.receiverType, functionArgumentsRow.argumentTypes, result);
181 }
182 result.append("\n");
183 }
184 }
185
186 private void renderFunctionArguments(@Nullable JetType receiverType, @NotNull List<JetType> argumentTypes, StringBuilder result) {
187 boolean hasReceiver = receiverType != null;
188 if (hasReceiver) {
189 result.append("receiver: ");
190 result.append(getTypeRenderer().render(receiverType));
191 result.append(" arguments: ");
192 }
193 if (argumentTypes.isEmpty()) {
194 result.append("()");
195 return;
196 }
197
198 result.append("(");
199 for (Iterator<JetType> iterator = argumentTypes.iterator(); iterator.hasNext(); ) {
200 JetType argumentType = iterator.next();
201 String renderedArgument = getTypeRenderer().render(argumentType);
202
203 result.append(renderedArgument);
204 if (iterator.hasNext()) {
205 result.append(",");
206 }
207 }
208 result.append(")");
209 }
210
211 public static TabledDescriptorRenderer create() {
212 return new TabledDescriptorRenderer();
213 }
214
215 public static enum TextElementType { STRONG, ERROR, DEFAULT }
216 }