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 017package org.jetbrains.jet.lang.diagnostics.rendering; 018 019import com.google.common.base.Predicate; 020import com.google.common.base.Predicates; 021import com.google.common.collect.Lists; 022import org.jetbrains.annotations.NotNull; 023import org.jetbrains.annotations.Nullable; 024import org.jetbrains.jet.lang.descriptors.CallableDescriptor; 025import org.jetbrains.jet.lang.diagnostics.rendering.TabledDescriptorRenderer.TableRenderer.*; 026import org.jetbrains.jet.lang.diagnostics.rendering.TabledDescriptorRenderer.TextRenderer.TextElement; 027import org.jetbrains.jet.lang.resolve.calls.inference.ConstraintPosition; 028import org.jetbrains.jet.lang.types.JetType; 029import org.jetbrains.jet.renderer.DescriptorRenderer; 030 031import java.util.Iterator; 032import java.util.List; 033 034public 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}