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.lang.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.jet.lang.descriptors.CallableDescriptor;
025 import org.jetbrains.jet.lang.diagnostics.rendering.TabledDescriptorRenderer.TableRenderer.*;
026 import org.jetbrains.jet.lang.diagnostics.rendering.TabledDescriptorRenderer.TextRenderer.TextElement;
027 import org.jetbrains.jet.lang.resolve.calls.inference.ConstraintPosition;
028 import org.jetbrains.jet.lang.types.JetType;
029 import org.jetbrains.jet.renderer.DescriptorRenderer;
030
031 import java.util.Iterator;
032 import java.util.List;
033
034 public class TabledDescriptorRenderer {
035 public interface TableOrTextRenderer {}
036
037 public static class TableRenderer implements TableOrTextRenderer{
038 public interface TableRow {
039 }
040
041 public static class DescriptorRow implements TableRow {
042 public final CallableDescriptor descriptor;
043
044 public DescriptorRow(CallableDescriptor descriptor) {
045 this.descriptor = descriptor;
046 }
047 }
048
049 public static class FunctionArgumentsRow implements TableRow {
050 public final JetType receiverType;
051 public final List<JetType> argumentTypes;
052 public final Predicate<ConstraintPosition> isErrorPosition;
053
054 public FunctionArgumentsRow(JetType receiverType, List<JetType> argumentTypes, Predicate<ConstraintPosition> isErrorPosition) {
055 this.receiverType = receiverType;
056 this.argumentTypes = argumentTypes;
057 this.isErrorPosition = isErrorPosition;
058 }
059 }
060
061 public final List<TableRow> rows = Lists.newArrayList();
062
063 public TableRenderer descriptor(CallableDescriptor descriptor) {
064 rows.add(new DescriptorRow(descriptor));
065 return this;
066 }
067
068 public TableRenderer functionArgumentTypeList(@Nullable JetType receiverType, @NotNull List<JetType> argumentTypes) {
069
070 return functionArgumentTypeList(receiverType, argumentTypes, Predicates.<ConstraintPosition>alwaysFalse());
071 }
072
073 public TableRenderer functionArgumentTypeList(@Nullable JetType receiverType,
074 @NotNull List<JetType> argumentTypes,
075 @NotNull Predicate<ConstraintPosition> isErrorPosition) {
076 rows.add(new FunctionArgumentsRow(receiverType, argumentTypes, isErrorPosition));
077 return this;
078 }
079
080 public TableRenderer text(@NotNull String text) {
081 rows.add(newText().normal(text));
082 return this;
083 }
084
085 public TableRenderer text(@NotNull TextRenderer textRenderer) {
086 rows.add(textRenderer);
087 return this;
088 }
089 }
090
091 public static class TextRenderer implements TableOrTextRenderer, TableRow {
092 public static class TextElement {
093
094 public TextElementType type;
095 public String text;
096
097 public TextElement(@NotNull TextElementType type, @NotNull String text) {
098 this.type = type;
099 this.text = text;
100 }
101 }
102
103 public final List<TextElement> elements = Lists.newArrayList();
104
105 public TextRenderer normal(@NotNull Object text) {
106 elements.add(new TextElement(TextElementType.DEFAULT, text.toString()));
107 return this;
108 }
109
110 public TextRenderer error(@NotNull Object text) {
111 elements.add(new TextElement(TextElementType.ERROR, text.toString()));
112 return this;
113 }
114
115 public TextRenderer strong(@NotNull Object text) {
116 elements.add(new TextElement(TextElementType.STRONG, text.toString()));
117 return this;
118 }
119 }
120
121 protected final List<TableOrTextRenderer> renderers = Lists.newArrayList();
122
123 public TabledDescriptorRenderer text(@NotNull TextRenderer textRenderer) {
124 renderers.add(textRenderer);
125 return this;
126 }
127
128 public TabledDescriptorRenderer table(@NotNull TableRenderer tableRenderer) {
129 renderers.add(tableRenderer);
130 return this;
131 }
132
133 public static TextRenderer newText() {
134 return new TextRenderer();
135 }
136
137 public static TableRenderer newTable() {
138 return new TableRenderer();
139 }
140
141 @Override
142 public String toString() {
143 StringBuilder result = new StringBuilder();
144 for (TableOrTextRenderer tableOrTextRenderer : renderers) {
145 if (tableOrTextRenderer instanceof TableRenderer) {
146 renderTable((TableRenderer)tableOrTextRenderer, result);
147 }
148 else {
149 renderText((TextRenderer)tableOrTextRenderer, result);
150 }
151 }
152 return result.toString();
153 }
154
155 @NotNull
156 public Renderer<JetType> getTypeRenderer() {
157 return Renderers.RENDER_TYPE;
158 }
159
160 protected void renderText(TextRenderer textRenderer, StringBuilder result) {
161 for (TextElement element : textRenderer.elements) {
162 result.append(element.text);
163 }
164 }
165
166 protected void renderTable(TableRenderer table, StringBuilder result) {
167 if (table.rows.isEmpty()) return;
168 for (TableRow row : table.rows) {
169 if (row instanceof TextRenderer) {
170 renderText((TextRenderer) row, result);
171 }
172 if (row instanceof DescriptorRow) {
173 result.append(DescriptorRenderer.COMPACT.render(((DescriptorRow) row).descriptor));
174 }
175 if (row instanceof FunctionArgumentsRow) {
176 FunctionArgumentsRow functionArgumentsRow = (FunctionArgumentsRow) row;
177 renderFunctionArguments(functionArgumentsRow.receiverType, functionArgumentsRow.argumentTypes, result);
178 }
179 result.append("\n");
180 }
181 }
182
183 private void renderFunctionArguments(@Nullable JetType receiverType, @NotNull List<JetType> argumentTypes, StringBuilder result) {
184 boolean hasReceiver = receiverType != null;
185 if (hasReceiver) {
186 result.append("receiver: ");
187 result.append(getTypeRenderer().render(receiverType));
188 result.append(" arguments: ");
189 }
190 if (argumentTypes.isEmpty()) {
191 result.append("()");
192 return;
193 }
194
195 result.append("(");
196 for (Iterator<JetType> iterator = argumentTypes.iterator(); iterator.hasNext(); ) {
197 JetType argumentType = iterator.next();
198 String renderedArgument = getTypeRenderer().render(argumentType);
199
200 result.append(renderedArgument);
201 if (iterator.hasNext()) {
202 result.append(",");
203 }
204 }
205 result.append(")");
206 }
207
208 public static TabledDescriptorRenderer create() {
209 return new TabledDescriptorRenderer();
210 }
211
212 public static enum TextElementType { STRONG, ERROR, DEFAULT }
213 }