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

Thu, 21 May 2009 10:56:36 +0100

author
mcimadamore
date
Thu, 21 May 2009 10:56:36 +0100
changeset 288
d402db1005ad
child 304
1d9e61e0a075
permissions
-rw-r--r--

6722234: javac diagnostics need better integration with the type-system
Summary: Added RichDiagnosticFormatter which provides better formatting capabilities for javac types/symbols
Reviewed-by: jjg

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

mercurial