src/share/classes/com/sun/tools/javac/util/RichDiagnosticFormatter.java

Tue, 24 Dec 2013 09:17:37 -0800

author
ksrini
date
Tue, 24 Dec 2013 09:17:37 -0800
changeset 2227
998b10c43157
parent 1887
7b756b307e12
child 2525
2eb010b6cb22
permissions
-rw-r--r--

8029230: Update copyright year to match last edit in jdk8 langtools repository for 2013
Reviewed-by: ksrini
Contributed-by: steve.sides@oracle.com

mcimadamore@288 1 /*
ksrini@2227 2 * Copyright (c) 2009, 2013, Oracle and/or its affiliates. All rights reserved.
mcimadamore@288 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
mcimadamore@288 4 *
mcimadamore@288 5 * This code is free software; you can redistribute it and/or modify it
mcimadamore@288 6 * under the terms of the GNU General Public License version 2 only, as
ohair@554 7 * published by the Free Software Foundation. Oracle designates this
mcimadamore@288 8 * particular file as subject to the "Classpath" exception as provided
ohair@554 9 * by Oracle in the LICENSE file that accompanied this code.
mcimadamore@288 10 *
mcimadamore@288 11 * This code is distributed in the hope that it will be useful, but WITHOUT
mcimadamore@288 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
mcimadamore@288 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
mcimadamore@288 14 * version 2 for more details (a copy is included in the LICENSE file that
mcimadamore@288 15 * accompanied this code).
mcimadamore@288 16 *
mcimadamore@288 17 * You should have received a copy of the GNU General Public License version
mcimadamore@288 18 * 2 along with this work; if not, write to the Free Software Foundation,
mcimadamore@288 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
mcimadamore@288 20 *
ohair@554 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
ohair@554 22 * or visit www.oracle.com if you need additional information or have any
ohair@554 23 * questions.
mcimadamore@288 24 */
mcimadamore@288 25 package com.sun.tools.javac.util;
mcimadamore@288 26
jjg@1569 27 import java.util.EnumMap;
mcimadamore@288 28 import java.util.EnumSet;
mcimadamore@288 29 import java.util.HashMap;
mcimadamore@288 30 import java.util.LinkedHashMap;
mcimadamore@288 31 import java.util.Locale;
mcimadamore@288 32 import java.util.Map;
mcimadamore@288 33
mcimadamore@288 34 import com.sun.tools.javac.code.Kinds;
mcimadamore@288 35 import com.sun.tools.javac.code.Printer;
mcimadamore@288 36 import com.sun.tools.javac.code.Symbol;
mcimadamore@288 37 import com.sun.tools.javac.code.Symbol.*;
mcimadamore@288 38 import com.sun.tools.javac.code.Symtab;
mcimadamore@288 39 import com.sun.tools.javac.code.Type;
mcimadamore@288 40 import com.sun.tools.javac.code.Type.*;
mcimadamore@288 41 import com.sun.tools.javac.code.Types;
mcimadamore@288 42
jjg@1374 43 import static com.sun.tools.javac.code.TypeTag.*;
mcimadamore@288 44 import static com.sun.tools.javac.code.Flags.*;
mcimadamore@288 45 import static com.sun.tools.javac.util.LayoutCharacters.*;
mcimadamore@288 46 import static com.sun.tools.javac.util.RichDiagnosticFormatter.RichConfiguration.*;
mcimadamore@288 47
mcimadamore@288 48 /**
mcimadamore@288 49 * A rich diagnostic formatter is a formatter that provides better integration
mcimadamore@288 50 * with javac's type system. A diagostic is first preprocessed in order to keep
mcimadamore@288 51 * track of each types/symbols in it; after these informations are collected,
mcimadamore@288 52 * the diagnostic is rendered using a standard formatter, whose type/symbol printer
mcimadamore@288 53 * has been replaced by a more refined version provided by this rich formatter.
mcimadamore@288 54 * The rich formatter currently enables three different features: (i) simple class
mcimadamore@288 55 * names - that is class names are displayed used a non qualified name (thus
mcimadamore@288 56 * omitting package info) whenever possible - (ii) where clause list - a list of
mcimadamore@288 57 * additional subdiagnostics that provide specific info about type-variables,
mcimadamore@288 58 * captured types, intersection types that occur in the diagnostic that is to be
mcimadamore@288 59 * formatted and (iii) type-variable disambiguation - when the diagnostic refers
mcimadamore@288 60 * to two different type-variables with the same name, their representation is
mcimadamore@288 61 * disambiguated by appending an index to the type variable name.
jjg@333 62 *
jjg@581 63 * <p><b>This is NOT part of any supported API.
jjg@333 64 * If you write code that depends on this, you do so at your own risk.
jjg@333 65 * This code and its internal interfaces are subject to change or
jjg@333 66 * deletion without notice.</b>
mcimadamore@288 67 */
mcimadamore@288 68 public class RichDiagnosticFormatter extends
mcimadamore@288 69 ForwardingDiagnosticFormatter<JCDiagnostic, AbstractDiagnosticFormatter> {
mcimadamore@288 70
mcimadamore@288 71 final Symtab syms;
mcimadamore@288 72 final Types types;
mcimadamore@288 73 final JCDiagnostic.Factory diags;
mcimadamore@288 74 final JavacMessages messages;
mcimadamore@288 75
mcimadamore@288 76 /* name simplifier used by this formatter */
mcimadamore@304 77 protected ClassNameSimplifier nameSimplifier;
mcimadamore@304 78
mcimadamore@304 79 /* type/symbol printer used by this formatter */
mcimadamore@304 80 private RichPrinter printer;
mcimadamore@288 81
mcimadamore@288 82 /* map for keeping track of a where clause associated to a given type */
mcimadamore@288 83 Map<WhereClauseKind, Map<Type, JCDiagnostic>> whereClauses;
mcimadamore@288 84
mcimadamore@288 85 /** Get the DiagnosticFormatter instance for this context. */
mcimadamore@288 86 public static RichDiagnosticFormatter instance(Context context) {
mcimadamore@288 87 RichDiagnosticFormatter instance = context.get(RichDiagnosticFormatter.class);
mcimadamore@288 88 if (instance == null)
mcimadamore@288 89 instance = new RichDiagnosticFormatter(context);
mcimadamore@288 90 return instance;
mcimadamore@288 91 }
mcimadamore@288 92
mcimadamore@288 93 protected RichDiagnosticFormatter(Context context) {
mcimadamore@288 94 super((AbstractDiagnosticFormatter)Log.instance(context).getDiagnosticFormatter());
mcimadamore@304 95 setRichPrinter(new RichPrinter());
mcimadamore@288 96 this.syms = Symtab.instance(context);
mcimadamore@288 97 this.diags = JCDiagnostic.Factory.instance(context);
mcimadamore@288 98 this.types = Types.instance(context);
mcimadamore@288 99 this.messages = JavacMessages.instance(context);
jjg@1569 100 whereClauses = new EnumMap<WhereClauseKind, Map<Type, JCDiagnostic>>(WhereClauseKind.class);
mcimadamore@288 101 configuration = new RichConfiguration(Options.instance(context), formatter);
mcimadamore@288 102 for (WhereClauseKind kind : WhereClauseKind.values())
mcimadamore@288 103 whereClauses.put(kind, new LinkedHashMap<Type, JCDiagnostic>());
mcimadamore@288 104 }
mcimadamore@288 105
mcimadamore@288 106 @Override
mcimadamore@288 107 public String format(JCDiagnostic diag, Locale l) {
mcimadamore@288 108 StringBuilder sb = new StringBuilder();
mcimadamore@288 109 nameSimplifier = new ClassNameSimplifier();
mcimadamore@288 110 for (WhereClauseKind kind : WhereClauseKind.values())
mcimadamore@288 111 whereClauses.get(kind).clear();
mcimadamore@288 112 preprocessDiagnostic(diag);
mcimadamore@288 113 sb.append(formatter.format(diag, l));
mcimadamore@288 114 if (getConfiguration().isEnabled(RichFormatterFeature.WHERE_CLAUSES)) {
mcimadamore@288 115 List<JCDiagnostic> clauses = getWhereClauses();
mcimadamore@288 116 String indent = formatter.isRaw() ? "" :
mcimadamore@288 117 formatter.indentString(DetailsInc);
mcimadamore@288 118 for (JCDiagnostic d : clauses) {
mcimadamore@288 119 String whereClause = formatter.format(d, l);
mcimadamore@288 120 if (whereClause.length() > 0) {
mcimadamore@288 121 sb.append('\n' + indent + whereClause);
mcimadamore@288 122 }
mcimadamore@288 123 }
mcimadamore@288 124 }
mcimadamore@288 125 return sb.toString();
mcimadamore@288 126 }
mcimadamore@288 127
mcimadamore@1798 128 @Override
mcimadamore@1798 129 public String formatMessage(JCDiagnostic diag, Locale l) {
mcimadamore@1798 130 nameSimplifier = new ClassNameSimplifier();
mcimadamore@1798 131 preprocessDiagnostic(diag);
mcimadamore@1798 132 return super.formatMessage(diag, l);
mcimadamore@1798 133 }
mcimadamore@1798 134
mcimadamore@288 135 /**
mcimadamore@304 136 * Sets the type/symbol printer used by this formatter.
mcimadamore@304 137 * @param printer the rich printer to be set
mcimadamore@304 138 */
mcimadamore@304 139 protected void setRichPrinter(RichPrinter printer) {
mcimadamore@304 140 this.printer = printer;
mcimadamore@304 141 formatter.setPrinter(printer);
mcimadamore@304 142 }
mcimadamore@304 143
mcimadamore@304 144 /**
mcimadamore@304 145 * Gets the type/symbol printer used by this formatter.
mcimadamore@304 146 * @return type/symbol rich printer
mcimadamore@304 147 */
mcimadamore@304 148 protected RichPrinter getRichPrinter() {
mcimadamore@304 149 return printer;
mcimadamore@304 150 }
mcimadamore@304 151
mcimadamore@304 152 /**
mcimadamore@288 153 * Preprocess a given diagnostic by looking both into its arguments and into
mcimadamore@288 154 * its subdiagnostics (if any). This preprocessing is responsible for
mcimadamore@288 155 * generating info corresponding to features like where clauses, name
mcimadamore@288 156 * simplification, etc.
mcimadamore@288 157 *
mcimadamore@288 158 * @param diag the diagnostic to be preprocessed
mcimadamore@288 159 */
mcimadamore@288 160 protected void preprocessDiagnostic(JCDiagnostic diag) {
mcimadamore@288 161 for (Object o : diag.getArgs()) {
mcimadamore@288 162 if (o != null) {
mcimadamore@288 163 preprocessArgument(o);
mcimadamore@288 164 }
mcimadamore@288 165 }
mcimadamore@288 166 if (diag.isMultiline()) {
mcimadamore@288 167 for (JCDiagnostic d : diag.getSubdiagnostics())
mcimadamore@288 168 preprocessDiagnostic(d);
mcimadamore@288 169 }
mcimadamore@288 170 }
mcimadamore@288 171
mcimadamore@288 172 /**
mcimadamore@288 173 * Preprocess a diagnostic argument. A type/symbol argument is
mcimadamore@288 174 * preprocessed by specialized type/symbol preprocessors.
mcimadamore@288 175 *
mcimadamore@288 176 * @param arg the argument to be translated
mcimadamore@288 177 */
mcimadamore@288 178 protected void preprocessArgument(Object arg) {
mcimadamore@288 179 if (arg instanceof Type) {
mcimadamore@288 180 preprocessType((Type)arg);
mcimadamore@288 181 }
mcimadamore@288 182 else if (arg instanceof Symbol) {
mcimadamore@288 183 preprocessSymbol((Symbol)arg);
mcimadamore@288 184 }
mcimadamore@288 185 else if (arg instanceof JCDiagnostic) {
mcimadamore@288 186 preprocessDiagnostic((JCDiagnostic)arg);
mcimadamore@288 187 }
mcimadamore@288 188 else if (arg instanceof Iterable<?>) {
mcimadamore@288 189 for (Object o : (Iterable<?>)arg) {
mcimadamore@288 190 preprocessArgument(o);
mcimadamore@288 191 }
mcimadamore@288 192 }
mcimadamore@288 193 }
mcimadamore@288 194
mcimadamore@288 195 /**
mcimadamore@288 196 * Build a list of multiline diagnostics containing detailed info about
mcimadamore@288 197 * type-variables, captured types, and intersection types
mcimadamore@288 198 *
mcimadamore@288 199 * @return where clause list
mcimadamore@288 200 */
mcimadamore@288 201 protected List<JCDiagnostic> getWhereClauses() {
mcimadamore@288 202 List<JCDiagnostic> clauses = List.nil();
mcimadamore@288 203 for (WhereClauseKind kind : WhereClauseKind.values()) {
mcimadamore@288 204 List<JCDiagnostic> lines = List.nil();
mcimadamore@288 205 for (Map.Entry<Type, JCDiagnostic> entry : whereClauses.get(kind).entrySet()) {
mcimadamore@288 206 lines = lines.prepend(entry.getValue());
mcimadamore@288 207 }
mcimadamore@288 208 if (!lines.isEmpty()) {
mcimadamore@288 209 String key = kind.key();
mcimadamore@288 210 if (lines.size() > 1)
mcimadamore@288 211 key += ".1";
mcimadamore@288 212 JCDiagnostic d = diags.fragment(key, whereClauses.get(kind).keySet());
mcimadamore@288 213 d = new JCDiagnostic.MultilineDiagnostic(d, lines.reverse());
mcimadamore@288 214 clauses = clauses.prepend(d);
mcimadamore@288 215 }
mcimadamore@288 216 }
mcimadamore@288 217 return clauses.reverse();
mcimadamore@288 218 }
mcimadamore@342 219
mcimadamore@342 220 private int indexOf(Type type, WhereClauseKind kind) {
mcimadamore@342 221 int index = 1;
mcimadamore@342 222 for (Type t : whereClauses.get(kind).keySet()) {
mcimadamore@342 223 if (t.tsym == type.tsym) {
mcimadamore@342 224 return index;
mcimadamore@342 225 }
mcimadamore@342 226 if (kind != WhereClauseKind.TYPEVAR ||
mcimadamore@342 227 t.toString().equals(type.toString())) {
mcimadamore@342 228 index++;
mcimadamore@342 229 }
mcimadamore@342 230 }
mcimadamore@342 231 return -1;
mcimadamore@342 232 }
mcimadamore@342 233
mcimadamore@342 234 private boolean unique(TypeVar typevar) {
mcimadamore@342 235 int found = 0;
mcimadamore@342 236 for (Type t : whereClauses.get(WhereClauseKind.TYPEVAR).keySet()) {
mcimadamore@342 237 if (t.toString().equals(typevar.toString())) {
mcimadamore@342 238 found++;
mcimadamore@342 239 }
mcimadamore@342 240 }
mcimadamore@342 241 if (found < 1)
mcimadamore@342 242 throw new AssertionError("Missing type variable in where clause " + typevar);
mcimadamore@342 243 return found == 1;
mcimadamore@342 244 }
mcimadamore@288 245 //where
mcimadamore@288 246 /**
mcimadamore@288 247 * This enum defines all posssible kinds of where clauses that can be
mcimadamore@288 248 * attached by a rich diagnostic formatter to a given diagnostic
mcimadamore@288 249 */
mcimadamore@288 250 enum WhereClauseKind {
mcimadamore@288 251
mcimadamore@288 252 /** where clause regarding a type variable */
mcimadamore@288 253 TYPEVAR("where.description.typevar"),
mcimadamore@288 254 /** where clause regarding a captured type */
mcimadamore@288 255 CAPTURED("where.description.captured"),
mcimadamore@288 256 /** where clause regarding an intersection type */
mcimadamore@288 257 INTERSECTION("where.description.intersection");
mcimadamore@288 258
mcimadamore@288 259 /** resource key for this where clause kind */
vromero@1442 260 private final String key;
mcimadamore@288 261
mcimadamore@288 262 WhereClauseKind(String key) {
mcimadamore@288 263 this.key = key;
mcimadamore@288 264 }
mcimadamore@288 265
mcimadamore@288 266 String key() {
mcimadamore@288 267 return key;
mcimadamore@288 268 }
mcimadamore@288 269 }
mcimadamore@288 270
mcimadamore@288 271 // <editor-fold defaultstate="collapsed" desc="name simplifier">
mcimadamore@288 272 /**
mcimadamore@288 273 * A name simplifier keeps track of class names usages in order to determine
mcimadamore@288 274 * whether a class name can be compacted or not. Short names are not used
mcimadamore@288 275 * if a conflict is detected, e.g. when two classes with the same simple
mcimadamore@288 276 * name belong to different packages - in this case the formatter reverts
mcimadamore@288 277 * to fullnames as compact names might lead to a confusing diagnostic.
mcimadamore@288 278 */
mcimadamore@304 279 protected class ClassNameSimplifier {
mcimadamore@288 280
mcimadamore@288 281 /* table for keeping track of all short name usages */
mcimadamore@288 282 Map<Name, List<Symbol>> nameClashes = new HashMap<Name, List<Symbol>>();
mcimadamore@288 283
mcimadamore@288 284 /**
mcimadamore@288 285 * Add a name usage to the simplifier's internal cache
mcimadamore@288 286 */
mcimadamore@288 287 protected void addUsage(Symbol sym) {
mcimadamore@288 288 Name n = sym.getSimpleName();
mcimadamore@288 289 List<Symbol> conflicts = nameClashes.get(n);
mcimadamore@288 290 if (conflicts == null) {
mcimadamore@288 291 conflicts = List.nil();
mcimadamore@288 292 }
mcimadamore@288 293 if (!conflicts.contains(sym))
mcimadamore@288 294 nameClashes.put(n, conflicts.append(sym));
mcimadamore@288 295 }
mcimadamore@288 296
mcimadamore@288 297 public String simplify(Symbol s) {
mcimadamore@288 298 String name = s.getQualifiedName().toString();
mcimadamore@1497 299 if (!s.type.isCompound() && !s.type.isPrimitive()) {
mcimadamore@288 300 List<Symbol> conflicts = nameClashes.get(s.getSimpleName());
mcimadamore@288 301 if (conflicts == null ||
mcimadamore@288 302 (conflicts.size() == 1 &&
mcimadamore@288 303 conflicts.contains(s))) {
mcimadamore@288 304 List<Name> l = List.nil();
mcimadamore@288 305 Symbol s2 = s;
mcimadamore@1887 306 while (s2.type.hasTag(CLASS) &&
mcimadamore@1887 307 s2.type.getEnclosingType().hasTag(CLASS) &&
mcimadamore@1887 308 s2.owner.kind == Kinds.TYP) {
mcimadamore@288 309 l = l.prepend(s2.getSimpleName());
mcimadamore@288 310 s2 = s2.owner;
mcimadamore@288 311 }
mcimadamore@288 312 l = l.prepend(s2.getSimpleName());
mcimadamore@288 313 StringBuilder buf = new StringBuilder();
mcimadamore@288 314 String sep = "";
mcimadamore@288 315 for (Name n2 : l) {
mcimadamore@288 316 buf.append(sep);
mcimadamore@288 317 buf.append(n2);
mcimadamore@288 318 sep = ".";
mcimadamore@288 319 }
mcimadamore@288 320 name = buf.toString();
mcimadamore@288 321 }
mcimadamore@288 322 }
mcimadamore@288 323 return name;
mcimadamore@288 324 }
mcimadamore@288 325 };
mcimadamore@288 326 // </editor-fold>
mcimadamore@288 327
mcimadamore@288 328 // <editor-fold defaultstate="collapsed" desc="rich printer">
mcimadamore@288 329 /**
mcimadamore@288 330 * Enhanced type/symbol printer that provides support for features like simple names
mcimadamore@288 331 * and type variable disambiguation. This enriched printer exploits the info
mcimadamore@288 332 * discovered during type/symbol preprocessing. This printer is set on the delegate
mcimadamore@288 333 * formatter so that rich type/symbol info can be properly rendered.
mcimadamore@288 334 */
mcimadamore@304 335 protected class RichPrinter extends Printer {
mcimadamore@288 336
mcimadamore@288 337 @Override
mcimadamore@288 338 public String localize(Locale locale, String key, Object... args) {
mcimadamore@288 339 return formatter.localize(locale, key, args);
mcimadamore@288 340 }
mcimadamore@288 341
mcimadamore@288 342 @Override
mcimadamore@288 343 public String capturedVarId(CapturedType t, Locale locale) {
mcimadamore@288 344 return indexOf(t, WhereClauseKind.CAPTURED) + "";
mcimadamore@288 345 }
mcimadamore@288 346
mcimadamore@288 347 @Override
mcimadamore@288 348 public String visitType(Type t, Locale locale) {
mcimadamore@288 349 String s = super.visitType(t, locale);
mcimadamore@288 350 if (t == syms.botType)
mcimadamore@288 351 s = localize(locale, "compiler.misc.type.null");
mcimadamore@288 352 return s;
mcimadamore@288 353 }
mcimadamore@288 354
mcimadamore@288 355 @Override
mcimadamore@288 356 public String visitCapturedType(CapturedType t, Locale locale) {
mcimadamore@288 357 if (getConfiguration().isEnabled(RichFormatterFeature.WHERE_CLAUSES)) {
mcimadamore@288 358 return localize(locale,
mcimadamore@288 359 "compiler.misc.captured.type",
mcimadamore@288 360 indexOf(t, WhereClauseKind.CAPTURED));
mcimadamore@288 361 }
mcimadamore@288 362 else
mcimadamore@288 363 return super.visitCapturedType(t, locale);
mcimadamore@288 364 }
mcimadamore@288 365
mcimadamore@288 366 @Override
mcimadamore@288 367 public String visitClassType(ClassType t, Locale locale) {
mcimadamore@288 368 if (t.isCompound() &&
mcimadamore@288 369 getConfiguration().isEnabled(RichFormatterFeature.WHERE_CLAUSES)) {
mcimadamore@288 370 return localize(locale,
mcimadamore@288 371 "compiler.misc.intersection.type",
mcimadamore@288 372 indexOf(t, WhereClauseKind.INTERSECTION));
mcimadamore@288 373 }
mcimadamore@288 374 else
mcimadamore@288 375 return super.visitClassType(t, locale);
mcimadamore@288 376 }
mcimadamore@288 377
mcimadamore@288 378 @Override
mcimadamore@288 379 protected String className(ClassType t, boolean longform, Locale locale) {
mcimadamore@288 380 Symbol sym = t.tsym;
mcimadamore@288 381 if (sym.name.length() == 0 ||
mcimadamore@288 382 !getConfiguration().isEnabled(RichFormatterFeature.SIMPLE_NAMES)) {
mcimadamore@288 383 return super.className(t, longform, locale);
mcimadamore@288 384 }
mcimadamore@288 385 else if (longform)
mcimadamore@288 386 return nameSimplifier.simplify(sym).toString();
mcimadamore@288 387 else
mcimadamore@288 388 return sym.name.toString();
mcimadamore@288 389 }
mcimadamore@288 390
mcimadamore@288 391 @Override
mcimadamore@288 392 public String visitTypeVar(TypeVar t, Locale locale) {
mcimadamore@288 393 if (unique(t) ||
mcimadamore@288 394 !getConfiguration().isEnabled(RichFormatterFeature.UNIQUE_TYPEVAR_NAMES)) {
mcimadamore@288 395 return t.toString();
mcimadamore@288 396 }
mcimadamore@288 397 else {
mcimadamore@288 398 return localize(locale,
mcimadamore@288 399 "compiler.misc.type.var",
mcimadamore@288 400 t.toString(), indexOf(t, WhereClauseKind.TYPEVAR));
mcimadamore@288 401 }
mcimadamore@288 402 }
mcimadamore@288 403
mcimadamore@288 404 @Override
mcimadamore@288 405 public String visitClassSymbol(ClassSymbol s, Locale locale) {
mcimadamore@1678 406 if (s.type.isCompound()) {
mcimadamore@1678 407 return visit(s.type, locale);
mcimadamore@1678 408 }
mcimadamore@288 409 String name = nameSimplifier.simplify(s);
mcimadamore@288 410 if (name.length() == 0 ||
mcimadamore@288 411 !getConfiguration().isEnabled(RichFormatterFeature.SIMPLE_NAMES)) {
mcimadamore@288 412 return super.visitClassSymbol(s, locale);
mcimadamore@288 413 }
mcimadamore@288 414 else {
mcimadamore@288 415 return name;
mcimadamore@288 416 }
mcimadamore@288 417 }
mcimadamore@288 418
mcimadamore@288 419 @Override
mcimadamore@288 420 public String visitMethodSymbol(MethodSymbol s, Locale locale) {
mcimadamore@288 421 String ownerName = visit(s.owner, locale);
mcimadamore@1085 422 if (s.isStaticOrInstanceInit()) {
mcimadamore@288 423 return ownerName;
mcimadamore@288 424 } else {
mcimadamore@288 425 String ms = (s.name == s.name.table.names.init)
mcimadamore@288 426 ? ownerName
mcimadamore@288 427 : s.name.toString();
mcimadamore@288 428 if (s.type != null) {
jjg@1374 429 if (s.type.hasTag(FORALL)) {
mcimadamore@288 430 ms = "<" + visitTypes(s.type.getTypeArguments(), locale) + ">" + ms;
mcimadamore@288 431 }
mcimadamore@288 432 ms += "(" + printMethodArgs(
mcimadamore@288 433 s.type.getParameterTypes(),
mcimadamore@288 434 (s.flags() & VARARGS) != 0,
mcimadamore@288 435 locale) + ")";
mcimadamore@288 436 }
mcimadamore@288 437 return ms;
mcimadamore@288 438 }
mcimadamore@288 439 }
mcimadamore@288 440 };
mcimadamore@288 441 // </editor-fold>
mcimadamore@288 442
mcimadamore@288 443 // <editor-fold defaultstate="collapsed" desc="type scanner">
mcimadamore@288 444 /**
mcimadamore@288 445 * Preprocess a given type looking for (i) additional info (where clauses) to be
mcimadamore@288 446 * added to the main diagnostic (ii) names to be compacted.
mcimadamore@288 447 */
mcimadamore@288 448 protected void preprocessType(Type t) {
mcimadamore@288 449 typePreprocessor.visit(t);
mcimadamore@288 450 }
mcimadamore@288 451 //where
mcimadamore@288 452 protected Types.UnaryVisitor<Void> typePreprocessor =
mcimadamore@288 453 new Types.UnaryVisitor<Void>() {
mcimadamore@288 454
mcimadamore@288 455 public Void visit(List<Type> ts) {
mcimadamore@288 456 for (Type t : ts)
mcimadamore@288 457 visit(t);
mcimadamore@288 458 return null;
mcimadamore@288 459 }
mcimadamore@288 460
mcimadamore@288 461 @Override
mcimadamore@288 462 public Void visitForAll(ForAll t, Void ignored) {
mcimadamore@288 463 visit(t.tvars);
mcimadamore@288 464 visit(t.qtype);
mcimadamore@288 465 return null;
mcimadamore@288 466 }
mcimadamore@288 467
mcimadamore@288 468 @Override
mcimadamore@288 469 public Void visitMethodType(MethodType t, Void ignored) {
mcimadamore@288 470 visit(t.argtypes);
mcimadamore@288 471 visit(t.restype);
mcimadamore@288 472 return null;
mcimadamore@288 473 }
mcimadamore@288 474
mcimadamore@288 475 @Override
mcimadamore@288 476 public Void visitErrorType(ErrorType t, Void ignored) {
mcimadamore@288 477 Type ot = t.getOriginalType();
mcimadamore@288 478 if (ot != null)
mcimadamore@288 479 visit(ot);
mcimadamore@288 480 return null;
mcimadamore@288 481 }
mcimadamore@288 482
mcimadamore@288 483 @Override
mcimadamore@288 484 public Void visitArrayType(ArrayType t, Void ignored) {
mcimadamore@288 485 visit(t.elemtype);
mcimadamore@288 486 return null;
mcimadamore@288 487 }
mcimadamore@288 488
mcimadamore@288 489 @Override
mcimadamore@288 490 public Void visitWildcardType(WildcardType t, Void ignored) {
mcimadamore@288 491 visit(t.type);
mcimadamore@288 492 return null;
mcimadamore@288 493 }
mcimadamore@288 494
mcimadamore@288 495 public Void visitType(Type t, Void ignored) {
mcimadamore@288 496 return null;
mcimadamore@288 497 }
mcimadamore@288 498
mcimadamore@288 499 @Override
mcimadamore@288 500 public Void visitCapturedType(CapturedType t, Void ignored) {
mcimadamore@342 501 if (indexOf(t, WhereClauseKind.CAPTURED) == -1) {
mcimadamore@288 502 String suffix = t.lower == syms.botType ? ".1" : "";
mcimadamore@288 503 JCDiagnostic d = diags.fragment("where.captured"+ suffix, t, t.bound, t.lower, t.wildcard);
mcimadamore@288 504 whereClauses.get(WhereClauseKind.CAPTURED).put(t, d);
mcimadamore@288 505 visit(t.wildcard);
mcimadamore@288 506 visit(t.lower);
mcimadamore@288 507 visit(t.bound);
mcimadamore@288 508 }
mcimadamore@288 509 return null;
mcimadamore@288 510 }
mcimadamore@288 511
mcimadamore@288 512 @Override
mcimadamore@288 513 public Void visitClassType(ClassType t, Void ignored) {
mcimadamore@288 514 if (t.isCompound()) {
mcimadamore@342 515 if (indexOf(t, WhereClauseKind.INTERSECTION) == -1) {
mcimadamore@288 516 Type supertype = types.supertype(t);
mcimadamore@288 517 List<Type> interfaces = types.interfaces(t);
mcimadamore@288 518 JCDiagnostic d = diags.fragment("where.intersection", t, interfaces.prepend(supertype));
mcimadamore@288 519 whereClauses.get(WhereClauseKind.INTERSECTION).put(t, d);
mcimadamore@288 520 visit(supertype);
mcimadamore@288 521 visit(interfaces);
mcimadamore@288 522 }
mcimadamore@1656 523 } else if (t.tsym.name.isEmpty()) {
mcimadamore@1656 524 //anon class
mcimadamore@1656 525 ClassType norm = (ClassType) t.tsym.type;
mcimadamore@1656 526 if (norm != null) {
mcimadamore@1656 527 if (norm.interfaces_field != null && norm.interfaces_field.nonEmpty()) {
mcimadamore@1656 528 visit(norm.interfaces_field.head);
mcimadamore@1656 529 } else {
mcimadamore@1656 530 visit(norm.supertype_field);
mcimadamore@1656 531 }
mcimadamore@1656 532 }
mcimadamore@288 533 }
mcimadamore@288 534 nameSimplifier.addUsage(t.tsym);
mcimadamore@288 535 visit(t.getTypeArguments());
mcimadamore@288 536 if (t.getEnclosingType() != Type.noType)
mcimadamore@288 537 visit(t.getEnclosingType());
mcimadamore@288 538 return null;
mcimadamore@288 539 }
mcimadamore@288 540
mcimadamore@288 541 @Override
mcimadamore@288 542 public Void visitTypeVar(TypeVar t, Void ignored) {
mcimadamore@342 543 if (indexOf(t, WhereClauseKind.TYPEVAR) == -1) {
mcimadamore@343 544 //access the bound type and skip error types
mcimadamore@288 545 Type bound = t.bound;
mcimadamore@288 546 while ((bound instanceof ErrorType))
mcimadamore@288 547 bound = ((ErrorType)bound).getOriginalType();
mcimadamore@343 548 //retrieve the bound list - if the type variable
mcimadamore@343 549 //has not been attributed the bound is not set
mcimadamore@1415 550 List<Type> bounds = (bound != null) &&
mcimadamore@1415 551 (bound.hasTag(CLASS) || bound.hasTag(TYPEVAR)) ?
mcimadamore@343 552 types.getBounds(t) :
mcimadamore@343 553 List.<Type>nil();
mcimadamore@343 554
mcimadamore@288 555 nameSimplifier.addUsage(t.tsym);
mcimadamore@288 556
mcimadamore@288 557 boolean boundErroneous = bounds.head == null ||
jjg@1374 558 bounds.head.hasTag(NONE) ||
jjg@1374 559 bounds.head.hasTag(ERROR);
mcimadamore@288 560
mcimadamore@1251 561 if ((t.tsym.flags() & SYNTHETIC) == 0) {
mcimadamore@1251 562 //this is a true typevar
mcimadamore@1251 563 JCDiagnostic d = diags.fragment("where.typevar" +
mcimadamore@288 564 (boundErroneous ? ".1" : ""), t, bounds,
mcimadamore@288 565 Kinds.kindName(t.tsym.location()), t.tsym.location());
mcimadamore@1251 566 whereClauses.get(WhereClauseKind.TYPEVAR).put(t, d);
mcimadamore@1251 567 symbolPreprocessor.visit(t.tsym.location(), null);
mcimadamore@1251 568 visit(bounds);
mcimadamore@1251 569 } else {
mcimadamore@1251 570 Assert.check(!boundErroneous);
mcimadamore@1251 571 //this is a fresh (synthetic) tvar
mcimadamore@1251 572 JCDiagnostic d = diags.fragment("where.fresh.typevar", t, bounds);
mcimadamore@1251 573 whereClauses.get(WhereClauseKind.TYPEVAR).put(t, d);
mcimadamore@1251 574 visit(bounds);
mcimadamore@1251 575 }
mcimadamore@1251 576
mcimadamore@288 577 }
mcimadamore@288 578 return null;
mcimadamore@288 579 }
mcimadamore@288 580 };
mcimadamore@288 581 // </editor-fold>
mcimadamore@288 582
mcimadamore@288 583 // <editor-fold defaultstate="collapsed" desc="symbol scanner">
mcimadamore@288 584 /**
mcimadamore@288 585 * Preprocess a given symbol looking for (i) additional info (where clauses) to be
mcimadamore@1656 586 * added to the main diagnostic (ii) names to be compacted
mcimadamore@288 587 */
mcimadamore@288 588 protected void preprocessSymbol(Symbol s) {
mcimadamore@288 589 symbolPreprocessor.visit(s, null);
mcimadamore@288 590 }
mcimadamore@288 591 //where
mcimadamore@288 592 protected Types.DefaultSymbolVisitor<Void, Void> symbolPreprocessor =
mcimadamore@288 593 new Types.DefaultSymbolVisitor<Void, Void>() {
mcimadamore@288 594
mcimadamore@288 595 @Override
mcimadamore@288 596 public Void visitClassSymbol(ClassSymbol s, Void ignored) {
mcimadamore@1678 597 if (s.type.isCompound()) {
mcimadamore@1678 598 typePreprocessor.visit(s.type);
mcimadamore@1678 599 } else {
mcimadamore@1678 600 nameSimplifier.addUsage(s);
mcimadamore@1678 601 }
mcimadamore@288 602 return null;
mcimadamore@288 603 }
mcimadamore@288 604
mcimadamore@288 605 @Override
mcimadamore@288 606 public Void visitSymbol(Symbol s, Void ignored) {
mcimadamore@288 607 return null;
mcimadamore@288 608 }
mcimadamore@288 609
mcimadamore@288 610 @Override
mcimadamore@288 611 public Void visitMethodSymbol(MethodSymbol s, Void ignored) {
mcimadamore@288 612 visit(s.owner, null);
mcimadamore@326 613 if (s.type != null)
mcimadamore@326 614 typePreprocessor.visit(s.type);
mcimadamore@288 615 return null;
mcimadamore@288 616 }
mcimadamore@288 617 };
mcimadamore@288 618 // </editor-fold>
mcimadamore@288 619
mcimadamore@288 620 @Override
mcimadamore@288 621 public RichConfiguration getConfiguration() {
mcimadamore@288 622 //the following cast is always safe - see init
mcimadamore@288 623 return (RichConfiguration)configuration;
mcimadamore@288 624 }
mcimadamore@288 625
mcimadamore@288 626 /**
mcimadamore@288 627 * Configuration object provided by the rich formatter.
mcimadamore@288 628 */
mcimadamore@288 629 public static class RichConfiguration extends ForwardingDiagnosticFormatter.ForwardingConfiguration {
mcimadamore@288 630
mcimadamore@288 631 /** set of enabled rich formatter's features */
mcimadamore@288 632 protected java.util.EnumSet<RichFormatterFeature> features;
mcimadamore@288 633
mcimadamore@288 634 @SuppressWarnings("fallthrough")
mcimadamore@288 635 public RichConfiguration(Options options, AbstractDiagnosticFormatter formatter) {
mcimadamore@288 636 super(formatter.getConfiguration());
mcimadamore@288 637 features = formatter.isRaw() ? EnumSet.noneOf(RichFormatterFeature.class) :
mcimadamore@288 638 EnumSet.of(RichFormatterFeature.SIMPLE_NAMES,
mcimadamore@288 639 RichFormatterFeature.WHERE_CLAUSES,
mcimadamore@288 640 RichFormatterFeature.UNIQUE_TYPEVAR_NAMES);
mcimadamore@288 641 String diagOpts = options.get("diags");
mcimadamore@288 642 if (diagOpts != null) {
mcimadamore@288 643 for (String args: diagOpts.split(",")) {
mcimadamore@288 644 if (args.equals("-where")) {
mcimadamore@288 645 features.remove(RichFormatterFeature.WHERE_CLAUSES);
mcimadamore@288 646 }
mcimadamore@288 647 else if (args.equals("where")) {
mcimadamore@288 648 features.add(RichFormatterFeature.WHERE_CLAUSES);
mcimadamore@288 649 }
mcimadamore@288 650 if (args.equals("-simpleNames")) {
mcimadamore@288 651 features.remove(RichFormatterFeature.SIMPLE_NAMES);
mcimadamore@288 652 }
mcimadamore@288 653 else if (args.equals("simpleNames")) {
mcimadamore@288 654 features.add(RichFormatterFeature.SIMPLE_NAMES);
mcimadamore@288 655 }
mcimadamore@288 656 if (args.equals("-disambiguateTvars")) {
mcimadamore@288 657 features.remove(RichFormatterFeature.UNIQUE_TYPEVAR_NAMES);
mcimadamore@288 658 }
mcimadamore@288 659 else if (args.equals("disambiguateTvars")) {
mcimadamore@288 660 features.add(RichFormatterFeature.UNIQUE_TYPEVAR_NAMES);
mcimadamore@288 661 }
mcimadamore@288 662 }
mcimadamore@288 663 }
mcimadamore@288 664 }
mcimadamore@288 665
mcimadamore@288 666 /**
mcimadamore@288 667 * Returns a list of all the features supported by the rich formatter.
mcimadamore@288 668 * @return list of supported features
mcimadamore@288 669 */
mcimadamore@288 670 public RichFormatterFeature[] getAvailableFeatures() {
mcimadamore@288 671 return RichFormatterFeature.values();
mcimadamore@288 672 }
mcimadamore@288 673
mcimadamore@288 674 /**
mcimadamore@288 675 * Enable a specific feature on this rich formatter.
mcimadamore@288 676 * @param feature feature to be enabled
mcimadamore@288 677 */
mcimadamore@288 678 public void enable(RichFormatterFeature feature) {
mcimadamore@288 679 features.add(feature);
mcimadamore@288 680 }
mcimadamore@288 681
mcimadamore@288 682 /**
mcimadamore@288 683 * Disable a specific feature on this rich formatter.
mcimadamore@288 684 * @param feature feature to be disabled
mcimadamore@288 685 */
mcimadamore@288 686 public void disable(RichFormatterFeature feature) {
mcimadamore@288 687 features.remove(feature);
mcimadamore@288 688 }
mcimadamore@288 689
mcimadamore@288 690 /**
mcimadamore@288 691 * Is a given feature enabled on this formatter?
mcimadamore@288 692 * @param feature feature to be tested
mcimadamore@288 693 */
mcimadamore@288 694 public boolean isEnabled(RichFormatterFeature feature) {
mcimadamore@288 695 return features.contains(feature);
mcimadamore@288 696 }
mcimadamore@288 697
mcimadamore@288 698 /**
mcimadamore@288 699 * The advanced formatting features provided by the rich formatter
mcimadamore@288 700 */
mcimadamore@288 701 public enum RichFormatterFeature {
mcimadamore@288 702 /** a list of additional info regarding a given type/symbol */
mcimadamore@288 703 WHERE_CLAUSES,
mcimadamore@288 704 /** full class names simplification (where possible) */
mcimadamore@288 705 SIMPLE_NAMES,
mcimadamore@288 706 /** type-variable names disambiguation */
mcimadamore@288 707 UNIQUE_TYPEVAR_NAMES;
mcimadamore@288 708 }
mcimadamore@288 709 }
mcimadamore@288 710 }

mercurial