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 }