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

Mon, 08 Apr 2013 15:59:29 +0100

author
mcimadamore
date
Mon, 08 Apr 2013 15:59:29 +0100
changeset 1678
c635a966ce84
parent 1656
5da12e8a59ba
child 1798
5cd3cb69c8b3
permissions
-rw-r--r--

8010822: Intersection type cast for functional expressions does not follow spec EDR
Summary: Remove support for marker interfaces; redefine intersection type casts to be order-independent
Reviewed-by: jjg

mcimadamore@288 1 /*
jjh@1305 2 * Copyright (c) 2009, 2012, 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@288 128 /**
mcimadamore@304 129 * Sets the type/symbol printer used by this formatter.
mcimadamore@304 130 * @param printer the rich printer to be set
mcimadamore@304 131 */
mcimadamore@304 132 protected void setRichPrinter(RichPrinter printer) {
mcimadamore@304 133 this.printer = printer;
mcimadamore@304 134 formatter.setPrinter(printer);
mcimadamore@304 135 }
mcimadamore@304 136
mcimadamore@304 137 /**
mcimadamore@304 138 * Gets the type/symbol printer used by this formatter.
mcimadamore@304 139 * @return type/symbol rich printer
mcimadamore@304 140 */
mcimadamore@304 141 protected RichPrinter getRichPrinter() {
mcimadamore@304 142 return printer;
mcimadamore@304 143 }
mcimadamore@304 144
mcimadamore@304 145 /**
mcimadamore@288 146 * Preprocess a given diagnostic by looking both into its arguments and into
mcimadamore@288 147 * its subdiagnostics (if any). This preprocessing is responsible for
mcimadamore@288 148 * generating info corresponding to features like where clauses, name
mcimadamore@288 149 * simplification, etc.
mcimadamore@288 150 *
mcimadamore@288 151 * @param diag the diagnostic to be preprocessed
mcimadamore@288 152 */
mcimadamore@288 153 protected void preprocessDiagnostic(JCDiagnostic diag) {
mcimadamore@288 154 for (Object o : diag.getArgs()) {
mcimadamore@288 155 if (o != null) {
mcimadamore@288 156 preprocessArgument(o);
mcimadamore@288 157 }
mcimadamore@288 158 }
mcimadamore@288 159 if (diag.isMultiline()) {
mcimadamore@288 160 for (JCDiagnostic d : diag.getSubdiagnostics())
mcimadamore@288 161 preprocessDiagnostic(d);
mcimadamore@288 162 }
mcimadamore@288 163 }
mcimadamore@288 164
mcimadamore@288 165 /**
mcimadamore@288 166 * Preprocess a diagnostic argument. A type/symbol argument is
mcimadamore@288 167 * preprocessed by specialized type/symbol preprocessors.
mcimadamore@288 168 *
mcimadamore@288 169 * @param arg the argument to be translated
mcimadamore@288 170 */
mcimadamore@288 171 protected void preprocessArgument(Object arg) {
mcimadamore@288 172 if (arg instanceof Type) {
mcimadamore@288 173 preprocessType((Type)arg);
mcimadamore@288 174 }
mcimadamore@288 175 else if (arg instanceof Symbol) {
mcimadamore@288 176 preprocessSymbol((Symbol)arg);
mcimadamore@288 177 }
mcimadamore@288 178 else if (arg instanceof JCDiagnostic) {
mcimadamore@288 179 preprocessDiagnostic((JCDiagnostic)arg);
mcimadamore@288 180 }
mcimadamore@288 181 else if (arg instanceof Iterable<?>) {
mcimadamore@288 182 for (Object o : (Iterable<?>)arg) {
mcimadamore@288 183 preprocessArgument(o);
mcimadamore@288 184 }
mcimadamore@288 185 }
mcimadamore@288 186 }
mcimadamore@288 187
mcimadamore@288 188 /**
mcimadamore@288 189 * Build a list of multiline diagnostics containing detailed info about
mcimadamore@288 190 * type-variables, captured types, and intersection types
mcimadamore@288 191 *
mcimadamore@288 192 * @return where clause list
mcimadamore@288 193 */
mcimadamore@288 194 protected List<JCDiagnostic> getWhereClauses() {
mcimadamore@288 195 List<JCDiagnostic> clauses = List.nil();
mcimadamore@288 196 for (WhereClauseKind kind : WhereClauseKind.values()) {
mcimadamore@288 197 List<JCDiagnostic> lines = List.nil();
mcimadamore@288 198 for (Map.Entry<Type, JCDiagnostic> entry : whereClauses.get(kind).entrySet()) {
mcimadamore@288 199 lines = lines.prepend(entry.getValue());
mcimadamore@288 200 }
mcimadamore@288 201 if (!lines.isEmpty()) {
mcimadamore@288 202 String key = kind.key();
mcimadamore@288 203 if (lines.size() > 1)
mcimadamore@288 204 key += ".1";
mcimadamore@288 205 JCDiagnostic d = diags.fragment(key, whereClauses.get(kind).keySet());
mcimadamore@288 206 d = new JCDiagnostic.MultilineDiagnostic(d, lines.reverse());
mcimadamore@288 207 clauses = clauses.prepend(d);
mcimadamore@288 208 }
mcimadamore@288 209 }
mcimadamore@288 210 return clauses.reverse();
mcimadamore@288 211 }
mcimadamore@342 212
mcimadamore@342 213 private int indexOf(Type type, WhereClauseKind kind) {
mcimadamore@342 214 int index = 1;
mcimadamore@342 215 for (Type t : whereClauses.get(kind).keySet()) {
mcimadamore@342 216 if (t.tsym == type.tsym) {
mcimadamore@342 217 return index;
mcimadamore@342 218 }
mcimadamore@342 219 if (kind != WhereClauseKind.TYPEVAR ||
mcimadamore@342 220 t.toString().equals(type.toString())) {
mcimadamore@342 221 index++;
mcimadamore@342 222 }
mcimadamore@342 223 }
mcimadamore@342 224 return -1;
mcimadamore@342 225 }
mcimadamore@342 226
mcimadamore@342 227 private boolean unique(TypeVar typevar) {
mcimadamore@342 228 int found = 0;
mcimadamore@342 229 for (Type t : whereClauses.get(WhereClauseKind.TYPEVAR).keySet()) {
mcimadamore@342 230 if (t.toString().equals(typevar.toString())) {
mcimadamore@342 231 found++;
mcimadamore@342 232 }
mcimadamore@342 233 }
mcimadamore@342 234 if (found < 1)
mcimadamore@342 235 throw new AssertionError("Missing type variable in where clause " + typevar);
mcimadamore@342 236 return found == 1;
mcimadamore@342 237 }
mcimadamore@288 238 //where
mcimadamore@288 239 /**
mcimadamore@288 240 * This enum defines all posssible kinds of where clauses that can be
mcimadamore@288 241 * attached by a rich diagnostic formatter to a given diagnostic
mcimadamore@288 242 */
mcimadamore@288 243 enum WhereClauseKind {
mcimadamore@288 244
mcimadamore@288 245 /** where clause regarding a type variable */
mcimadamore@288 246 TYPEVAR("where.description.typevar"),
mcimadamore@288 247 /** where clause regarding a captured type */
mcimadamore@288 248 CAPTURED("where.description.captured"),
mcimadamore@288 249 /** where clause regarding an intersection type */
mcimadamore@288 250 INTERSECTION("where.description.intersection");
mcimadamore@288 251
mcimadamore@288 252 /** resource key for this where clause kind */
vromero@1442 253 private final String key;
mcimadamore@288 254
mcimadamore@288 255 WhereClauseKind(String key) {
mcimadamore@288 256 this.key = key;
mcimadamore@288 257 }
mcimadamore@288 258
mcimadamore@288 259 String key() {
mcimadamore@288 260 return key;
mcimadamore@288 261 }
mcimadamore@288 262 }
mcimadamore@288 263
mcimadamore@288 264 // <editor-fold defaultstate="collapsed" desc="name simplifier">
mcimadamore@288 265 /**
mcimadamore@288 266 * A name simplifier keeps track of class names usages in order to determine
mcimadamore@288 267 * whether a class name can be compacted or not. Short names are not used
mcimadamore@288 268 * if a conflict is detected, e.g. when two classes with the same simple
mcimadamore@288 269 * name belong to different packages - in this case the formatter reverts
mcimadamore@288 270 * to fullnames as compact names might lead to a confusing diagnostic.
mcimadamore@288 271 */
mcimadamore@304 272 protected class ClassNameSimplifier {
mcimadamore@288 273
mcimadamore@288 274 /* table for keeping track of all short name usages */
mcimadamore@288 275 Map<Name, List<Symbol>> nameClashes = new HashMap<Name, List<Symbol>>();
mcimadamore@288 276
mcimadamore@288 277 /**
mcimadamore@288 278 * Add a name usage to the simplifier's internal cache
mcimadamore@288 279 */
mcimadamore@288 280 protected void addUsage(Symbol sym) {
mcimadamore@288 281 Name n = sym.getSimpleName();
mcimadamore@288 282 List<Symbol> conflicts = nameClashes.get(n);
mcimadamore@288 283 if (conflicts == null) {
mcimadamore@288 284 conflicts = List.nil();
mcimadamore@288 285 }
mcimadamore@288 286 if (!conflicts.contains(sym))
mcimadamore@288 287 nameClashes.put(n, conflicts.append(sym));
mcimadamore@288 288 }
mcimadamore@288 289
mcimadamore@288 290 public String simplify(Symbol s) {
mcimadamore@288 291 String name = s.getQualifiedName().toString();
mcimadamore@1497 292 if (!s.type.isCompound() && !s.type.isPrimitive()) {
mcimadamore@288 293 List<Symbol> conflicts = nameClashes.get(s.getSimpleName());
mcimadamore@288 294 if (conflicts == null ||
mcimadamore@288 295 (conflicts.size() == 1 &&
mcimadamore@288 296 conflicts.contains(s))) {
mcimadamore@288 297 List<Name> l = List.nil();
mcimadamore@288 298 Symbol s2 = s;
jjg@1374 299 while (s2.type.getEnclosingType().hasTag(CLASS)
mcimadamore@288 300 && s2.owner.kind == Kinds.TYP) {
mcimadamore@288 301 l = l.prepend(s2.getSimpleName());
mcimadamore@288 302 s2 = s2.owner;
mcimadamore@288 303 }
mcimadamore@288 304 l = l.prepend(s2.getSimpleName());
mcimadamore@288 305 StringBuilder buf = new StringBuilder();
mcimadamore@288 306 String sep = "";
mcimadamore@288 307 for (Name n2 : l) {
mcimadamore@288 308 buf.append(sep);
mcimadamore@288 309 buf.append(n2);
mcimadamore@288 310 sep = ".";
mcimadamore@288 311 }
mcimadamore@288 312 name = buf.toString();
mcimadamore@288 313 }
mcimadamore@288 314 }
mcimadamore@288 315 return name;
mcimadamore@288 316 }
mcimadamore@288 317 };
mcimadamore@288 318 // </editor-fold>
mcimadamore@288 319
mcimadamore@288 320 // <editor-fold defaultstate="collapsed" desc="rich printer">
mcimadamore@288 321 /**
mcimadamore@288 322 * Enhanced type/symbol printer that provides support for features like simple names
mcimadamore@288 323 * and type variable disambiguation. This enriched printer exploits the info
mcimadamore@288 324 * discovered during type/symbol preprocessing. This printer is set on the delegate
mcimadamore@288 325 * formatter so that rich type/symbol info can be properly rendered.
mcimadamore@288 326 */
mcimadamore@304 327 protected class RichPrinter extends Printer {
mcimadamore@288 328
mcimadamore@288 329 @Override
mcimadamore@288 330 public String localize(Locale locale, String key, Object... args) {
mcimadamore@288 331 return formatter.localize(locale, key, args);
mcimadamore@288 332 }
mcimadamore@288 333
mcimadamore@288 334 @Override
mcimadamore@288 335 public String capturedVarId(CapturedType t, Locale locale) {
mcimadamore@288 336 return indexOf(t, WhereClauseKind.CAPTURED) + "";
mcimadamore@288 337 }
mcimadamore@288 338
mcimadamore@288 339 @Override
mcimadamore@288 340 public String visitType(Type t, Locale locale) {
mcimadamore@288 341 String s = super.visitType(t, locale);
mcimadamore@288 342 if (t == syms.botType)
mcimadamore@288 343 s = localize(locale, "compiler.misc.type.null");
mcimadamore@288 344 return s;
mcimadamore@288 345 }
mcimadamore@288 346
mcimadamore@288 347 @Override
mcimadamore@288 348 public String visitCapturedType(CapturedType t, Locale locale) {
mcimadamore@288 349 if (getConfiguration().isEnabled(RichFormatterFeature.WHERE_CLAUSES)) {
mcimadamore@288 350 return localize(locale,
mcimadamore@288 351 "compiler.misc.captured.type",
mcimadamore@288 352 indexOf(t, WhereClauseKind.CAPTURED));
mcimadamore@288 353 }
mcimadamore@288 354 else
mcimadamore@288 355 return super.visitCapturedType(t, locale);
mcimadamore@288 356 }
mcimadamore@288 357
mcimadamore@288 358 @Override
mcimadamore@288 359 public String visitClassType(ClassType t, Locale locale) {
mcimadamore@288 360 if (t.isCompound() &&
mcimadamore@288 361 getConfiguration().isEnabled(RichFormatterFeature.WHERE_CLAUSES)) {
mcimadamore@288 362 return localize(locale,
mcimadamore@288 363 "compiler.misc.intersection.type",
mcimadamore@288 364 indexOf(t, WhereClauseKind.INTERSECTION));
mcimadamore@288 365 }
mcimadamore@288 366 else
mcimadamore@288 367 return super.visitClassType(t, locale);
mcimadamore@288 368 }
mcimadamore@288 369
mcimadamore@288 370 @Override
mcimadamore@288 371 protected String className(ClassType t, boolean longform, Locale locale) {
mcimadamore@288 372 Symbol sym = t.tsym;
mcimadamore@288 373 if (sym.name.length() == 0 ||
mcimadamore@288 374 !getConfiguration().isEnabled(RichFormatterFeature.SIMPLE_NAMES)) {
mcimadamore@288 375 return super.className(t, longform, locale);
mcimadamore@288 376 }
mcimadamore@288 377 else if (longform)
mcimadamore@288 378 return nameSimplifier.simplify(sym).toString();
mcimadamore@288 379 else
mcimadamore@288 380 return sym.name.toString();
mcimadamore@288 381 }
mcimadamore@288 382
mcimadamore@288 383 @Override
mcimadamore@288 384 public String visitTypeVar(TypeVar t, Locale locale) {
mcimadamore@288 385 if (unique(t) ||
mcimadamore@288 386 !getConfiguration().isEnabled(RichFormatterFeature.UNIQUE_TYPEVAR_NAMES)) {
mcimadamore@288 387 return t.toString();
mcimadamore@288 388 }
mcimadamore@288 389 else {
mcimadamore@288 390 return localize(locale,
mcimadamore@288 391 "compiler.misc.type.var",
mcimadamore@288 392 t.toString(), indexOf(t, WhereClauseKind.TYPEVAR));
mcimadamore@288 393 }
mcimadamore@288 394 }
mcimadamore@288 395
mcimadamore@288 396 @Override
mcimadamore@288 397 public String visitClassSymbol(ClassSymbol s, Locale locale) {
mcimadamore@1678 398 if (s.type.isCompound()) {
mcimadamore@1678 399 return visit(s.type, locale);
mcimadamore@1678 400 }
mcimadamore@288 401 String name = nameSimplifier.simplify(s);
mcimadamore@288 402 if (name.length() == 0 ||
mcimadamore@288 403 !getConfiguration().isEnabled(RichFormatterFeature.SIMPLE_NAMES)) {
mcimadamore@288 404 return super.visitClassSymbol(s, locale);
mcimadamore@288 405 }
mcimadamore@288 406 else {
mcimadamore@288 407 return name;
mcimadamore@288 408 }
mcimadamore@288 409 }
mcimadamore@288 410
mcimadamore@288 411 @Override
mcimadamore@288 412 public String visitMethodSymbol(MethodSymbol s, Locale locale) {
mcimadamore@288 413 String ownerName = visit(s.owner, locale);
mcimadamore@1085 414 if (s.isStaticOrInstanceInit()) {
mcimadamore@288 415 return ownerName;
mcimadamore@288 416 } else {
mcimadamore@288 417 String ms = (s.name == s.name.table.names.init)
mcimadamore@288 418 ? ownerName
mcimadamore@288 419 : s.name.toString();
mcimadamore@288 420 if (s.type != null) {
jjg@1374 421 if (s.type.hasTag(FORALL)) {
mcimadamore@288 422 ms = "<" + visitTypes(s.type.getTypeArguments(), locale) + ">" + ms;
mcimadamore@288 423 }
mcimadamore@288 424 ms += "(" + printMethodArgs(
mcimadamore@288 425 s.type.getParameterTypes(),
mcimadamore@288 426 (s.flags() & VARARGS) != 0,
mcimadamore@288 427 locale) + ")";
mcimadamore@288 428 }
mcimadamore@288 429 return ms;
mcimadamore@288 430 }
mcimadamore@288 431 }
mcimadamore@288 432 };
mcimadamore@288 433 // </editor-fold>
mcimadamore@288 434
mcimadamore@288 435 // <editor-fold defaultstate="collapsed" desc="type scanner">
mcimadamore@288 436 /**
mcimadamore@288 437 * Preprocess a given type looking for (i) additional info (where clauses) to be
mcimadamore@288 438 * added to the main diagnostic (ii) names to be compacted.
mcimadamore@288 439 */
mcimadamore@288 440 protected void preprocessType(Type t) {
mcimadamore@288 441 typePreprocessor.visit(t);
mcimadamore@288 442 }
mcimadamore@288 443 //where
mcimadamore@288 444 protected Types.UnaryVisitor<Void> typePreprocessor =
mcimadamore@288 445 new Types.UnaryVisitor<Void>() {
mcimadamore@288 446
mcimadamore@288 447 public Void visit(List<Type> ts) {
mcimadamore@288 448 for (Type t : ts)
mcimadamore@288 449 visit(t);
mcimadamore@288 450 return null;
mcimadamore@288 451 }
mcimadamore@288 452
mcimadamore@288 453 @Override
mcimadamore@288 454 public Void visitForAll(ForAll t, Void ignored) {
mcimadamore@288 455 visit(t.tvars);
mcimadamore@288 456 visit(t.qtype);
mcimadamore@288 457 return null;
mcimadamore@288 458 }
mcimadamore@288 459
mcimadamore@288 460 @Override
mcimadamore@288 461 public Void visitMethodType(MethodType t, Void ignored) {
mcimadamore@288 462 visit(t.argtypes);
mcimadamore@288 463 visit(t.restype);
mcimadamore@288 464 return null;
mcimadamore@288 465 }
mcimadamore@288 466
mcimadamore@288 467 @Override
mcimadamore@288 468 public Void visitErrorType(ErrorType t, Void ignored) {
mcimadamore@288 469 Type ot = t.getOriginalType();
mcimadamore@288 470 if (ot != null)
mcimadamore@288 471 visit(ot);
mcimadamore@288 472 return null;
mcimadamore@288 473 }
mcimadamore@288 474
mcimadamore@288 475 @Override
mcimadamore@288 476 public Void visitArrayType(ArrayType t, Void ignored) {
mcimadamore@288 477 visit(t.elemtype);
mcimadamore@288 478 return null;
mcimadamore@288 479 }
mcimadamore@288 480
mcimadamore@288 481 @Override
mcimadamore@288 482 public Void visitWildcardType(WildcardType t, Void ignored) {
mcimadamore@288 483 visit(t.type);
mcimadamore@288 484 return null;
mcimadamore@288 485 }
mcimadamore@288 486
mcimadamore@288 487 public Void visitType(Type t, Void ignored) {
mcimadamore@288 488 return null;
mcimadamore@288 489 }
mcimadamore@288 490
mcimadamore@288 491 @Override
mcimadamore@288 492 public Void visitCapturedType(CapturedType t, Void ignored) {
mcimadamore@342 493 if (indexOf(t, WhereClauseKind.CAPTURED) == -1) {
mcimadamore@288 494 String suffix = t.lower == syms.botType ? ".1" : "";
mcimadamore@288 495 JCDiagnostic d = diags.fragment("where.captured"+ suffix, t, t.bound, t.lower, t.wildcard);
mcimadamore@288 496 whereClauses.get(WhereClauseKind.CAPTURED).put(t, d);
mcimadamore@288 497 visit(t.wildcard);
mcimadamore@288 498 visit(t.lower);
mcimadamore@288 499 visit(t.bound);
mcimadamore@288 500 }
mcimadamore@288 501 return null;
mcimadamore@288 502 }
mcimadamore@288 503
mcimadamore@288 504 @Override
mcimadamore@288 505 public Void visitClassType(ClassType t, Void ignored) {
mcimadamore@288 506 if (t.isCompound()) {
mcimadamore@342 507 if (indexOf(t, WhereClauseKind.INTERSECTION) == -1) {
mcimadamore@288 508 Type supertype = types.supertype(t);
mcimadamore@288 509 List<Type> interfaces = types.interfaces(t);
mcimadamore@288 510 JCDiagnostic d = diags.fragment("where.intersection", t, interfaces.prepend(supertype));
mcimadamore@288 511 whereClauses.get(WhereClauseKind.INTERSECTION).put(t, d);
mcimadamore@288 512 visit(supertype);
mcimadamore@288 513 visit(interfaces);
mcimadamore@288 514 }
mcimadamore@1656 515 } else if (t.tsym.name.isEmpty()) {
mcimadamore@1656 516 //anon class
mcimadamore@1656 517 ClassType norm = (ClassType) t.tsym.type;
mcimadamore@1656 518 if (norm != null) {
mcimadamore@1656 519 if (norm.interfaces_field != null && norm.interfaces_field.nonEmpty()) {
mcimadamore@1656 520 visit(norm.interfaces_field.head);
mcimadamore@1656 521 } else {
mcimadamore@1656 522 visit(norm.supertype_field);
mcimadamore@1656 523 }
mcimadamore@1656 524 }
mcimadamore@288 525 }
mcimadamore@288 526 nameSimplifier.addUsage(t.tsym);
mcimadamore@288 527 visit(t.getTypeArguments());
mcimadamore@288 528 if (t.getEnclosingType() != Type.noType)
mcimadamore@288 529 visit(t.getEnclosingType());
mcimadamore@288 530 return null;
mcimadamore@288 531 }
mcimadamore@288 532
mcimadamore@288 533 @Override
mcimadamore@288 534 public Void visitTypeVar(TypeVar t, Void ignored) {
mcimadamore@342 535 if (indexOf(t, WhereClauseKind.TYPEVAR) == -1) {
mcimadamore@343 536 //access the bound type and skip error types
mcimadamore@288 537 Type bound = t.bound;
mcimadamore@288 538 while ((bound instanceof ErrorType))
mcimadamore@288 539 bound = ((ErrorType)bound).getOriginalType();
mcimadamore@343 540 //retrieve the bound list - if the type variable
mcimadamore@343 541 //has not been attributed the bound is not set
mcimadamore@1415 542 List<Type> bounds = (bound != null) &&
mcimadamore@1415 543 (bound.hasTag(CLASS) || bound.hasTag(TYPEVAR)) ?
mcimadamore@343 544 types.getBounds(t) :
mcimadamore@343 545 List.<Type>nil();
mcimadamore@343 546
mcimadamore@288 547 nameSimplifier.addUsage(t.tsym);
mcimadamore@288 548
mcimadamore@288 549 boolean boundErroneous = bounds.head == null ||
jjg@1374 550 bounds.head.hasTag(NONE) ||
jjg@1374 551 bounds.head.hasTag(ERROR);
mcimadamore@288 552
mcimadamore@1251 553 if ((t.tsym.flags() & SYNTHETIC) == 0) {
mcimadamore@1251 554 //this is a true typevar
mcimadamore@1251 555 JCDiagnostic d = diags.fragment("where.typevar" +
mcimadamore@288 556 (boundErroneous ? ".1" : ""), t, bounds,
mcimadamore@288 557 Kinds.kindName(t.tsym.location()), t.tsym.location());
mcimadamore@1251 558 whereClauses.get(WhereClauseKind.TYPEVAR).put(t, d);
mcimadamore@1251 559 symbolPreprocessor.visit(t.tsym.location(), null);
mcimadamore@1251 560 visit(bounds);
mcimadamore@1251 561 } else {
mcimadamore@1251 562 Assert.check(!boundErroneous);
mcimadamore@1251 563 //this is a fresh (synthetic) tvar
mcimadamore@1251 564 JCDiagnostic d = diags.fragment("where.fresh.typevar", t, bounds);
mcimadamore@1251 565 whereClauses.get(WhereClauseKind.TYPEVAR).put(t, d);
mcimadamore@1251 566 visit(bounds);
mcimadamore@1251 567 }
mcimadamore@1251 568
mcimadamore@288 569 }
mcimadamore@288 570 return null;
mcimadamore@288 571 }
mcimadamore@288 572 };
mcimadamore@288 573 // </editor-fold>
mcimadamore@288 574
mcimadamore@288 575 // <editor-fold defaultstate="collapsed" desc="symbol scanner">
mcimadamore@288 576 /**
mcimadamore@288 577 * Preprocess a given symbol looking for (i) additional info (where clauses) to be
mcimadamore@1656 578 * added to the main diagnostic (ii) names to be compacted
mcimadamore@288 579 */
mcimadamore@288 580 protected void preprocessSymbol(Symbol s) {
mcimadamore@288 581 symbolPreprocessor.visit(s, null);
mcimadamore@288 582 }
mcimadamore@288 583 //where
mcimadamore@288 584 protected Types.DefaultSymbolVisitor<Void, Void> symbolPreprocessor =
mcimadamore@288 585 new Types.DefaultSymbolVisitor<Void, Void>() {
mcimadamore@288 586
mcimadamore@288 587 @Override
mcimadamore@288 588 public Void visitClassSymbol(ClassSymbol s, Void ignored) {
mcimadamore@1678 589 if (s.type.isCompound()) {
mcimadamore@1678 590 typePreprocessor.visit(s.type);
mcimadamore@1678 591 } else {
mcimadamore@1678 592 nameSimplifier.addUsage(s);
mcimadamore@1678 593 }
mcimadamore@288 594 return null;
mcimadamore@288 595 }
mcimadamore@288 596
mcimadamore@288 597 @Override
mcimadamore@288 598 public Void visitSymbol(Symbol s, Void ignored) {
mcimadamore@288 599 return null;
mcimadamore@288 600 }
mcimadamore@288 601
mcimadamore@288 602 @Override
mcimadamore@288 603 public Void visitMethodSymbol(MethodSymbol s, Void ignored) {
mcimadamore@288 604 visit(s.owner, null);
mcimadamore@326 605 if (s.type != null)
mcimadamore@326 606 typePreprocessor.visit(s.type);
mcimadamore@288 607 return null;
mcimadamore@288 608 }
mcimadamore@288 609 };
mcimadamore@288 610 // </editor-fold>
mcimadamore@288 611
mcimadamore@288 612 @Override
mcimadamore@288 613 public RichConfiguration getConfiguration() {
mcimadamore@288 614 //the following cast is always safe - see init
mcimadamore@288 615 return (RichConfiguration)configuration;
mcimadamore@288 616 }
mcimadamore@288 617
mcimadamore@288 618 /**
mcimadamore@288 619 * Configuration object provided by the rich formatter.
mcimadamore@288 620 */
mcimadamore@288 621 public static class RichConfiguration extends ForwardingDiagnosticFormatter.ForwardingConfiguration {
mcimadamore@288 622
mcimadamore@288 623 /** set of enabled rich formatter's features */
mcimadamore@288 624 protected java.util.EnumSet<RichFormatterFeature> features;
mcimadamore@288 625
mcimadamore@288 626 @SuppressWarnings("fallthrough")
mcimadamore@288 627 public RichConfiguration(Options options, AbstractDiagnosticFormatter formatter) {
mcimadamore@288 628 super(formatter.getConfiguration());
mcimadamore@288 629 features = formatter.isRaw() ? EnumSet.noneOf(RichFormatterFeature.class) :
mcimadamore@288 630 EnumSet.of(RichFormatterFeature.SIMPLE_NAMES,
mcimadamore@288 631 RichFormatterFeature.WHERE_CLAUSES,
mcimadamore@288 632 RichFormatterFeature.UNIQUE_TYPEVAR_NAMES);
mcimadamore@288 633 String diagOpts = options.get("diags");
mcimadamore@288 634 if (diagOpts != null) {
mcimadamore@288 635 for (String args: diagOpts.split(",")) {
mcimadamore@288 636 if (args.equals("-where")) {
mcimadamore@288 637 features.remove(RichFormatterFeature.WHERE_CLAUSES);
mcimadamore@288 638 }
mcimadamore@288 639 else if (args.equals("where")) {
mcimadamore@288 640 features.add(RichFormatterFeature.WHERE_CLAUSES);
mcimadamore@288 641 }
mcimadamore@288 642 if (args.equals("-simpleNames")) {
mcimadamore@288 643 features.remove(RichFormatterFeature.SIMPLE_NAMES);
mcimadamore@288 644 }
mcimadamore@288 645 else if (args.equals("simpleNames")) {
mcimadamore@288 646 features.add(RichFormatterFeature.SIMPLE_NAMES);
mcimadamore@288 647 }
mcimadamore@288 648 if (args.equals("-disambiguateTvars")) {
mcimadamore@288 649 features.remove(RichFormatterFeature.UNIQUE_TYPEVAR_NAMES);
mcimadamore@288 650 }
mcimadamore@288 651 else if (args.equals("disambiguateTvars")) {
mcimadamore@288 652 features.add(RichFormatterFeature.UNIQUE_TYPEVAR_NAMES);
mcimadamore@288 653 }
mcimadamore@288 654 }
mcimadamore@288 655 }
mcimadamore@288 656 }
mcimadamore@288 657
mcimadamore@288 658 /**
mcimadamore@288 659 * Returns a list of all the features supported by the rich formatter.
mcimadamore@288 660 * @return list of supported features
mcimadamore@288 661 */
mcimadamore@288 662 public RichFormatterFeature[] getAvailableFeatures() {
mcimadamore@288 663 return RichFormatterFeature.values();
mcimadamore@288 664 }
mcimadamore@288 665
mcimadamore@288 666 /**
mcimadamore@288 667 * Enable a specific feature on this rich formatter.
mcimadamore@288 668 * @param feature feature to be enabled
mcimadamore@288 669 */
mcimadamore@288 670 public void enable(RichFormatterFeature feature) {
mcimadamore@288 671 features.add(feature);
mcimadamore@288 672 }
mcimadamore@288 673
mcimadamore@288 674 /**
mcimadamore@288 675 * Disable a specific feature on this rich formatter.
mcimadamore@288 676 * @param feature feature to be disabled
mcimadamore@288 677 */
mcimadamore@288 678 public void disable(RichFormatterFeature feature) {
mcimadamore@288 679 features.remove(feature);
mcimadamore@288 680 }
mcimadamore@288 681
mcimadamore@288 682 /**
mcimadamore@288 683 * Is a given feature enabled on this formatter?
mcimadamore@288 684 * @param feature feature to be tested
mcimadamore@288 685 */
mcimadamore@288 686 public boolean isEnabled(RichFormatterFeature feature) {
mcimadamore@288 687 return features.contains(feature);
mcimadamore@288 688 }
mcimadamore@288 689
mcimadamore@288 690 /**
mcimadamore@288 691 * The advanced formatting features provided by the rich formatter
mcimadamore@288 692 */
mcimadamore@288 693 public enum RichFormatterFeature {
mcimadamore@288 694 /** a list of additional info regarding a given type/symbol */
mcimadamore@288 695 WHERE_CLAUSES,
mcimadamore@288 696 /** full class names simplification (where possible) */
mcimadamore@288 697 SIMPLE_NAMES,
mcimadamore@288 698 /** type-variable names disambiguation */
mcimadamore@288 699 UNIQUE_TYPEVAR_NAMES;
mcimadamore@288 700 }
mcimadamore@288 701 }
mcimadamore@288 702 }

mercurial