duke@1: /* xdono@54: * Copyright 2005-2008 Sun Microsystems, Inc. All Rights Reserved. duke@1: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. duke@1: * duke@1: * This code is free software; you can redistribute it and/or modify it duke@1: * under the terms of the GNU General Public License version 2 only, as duke@1: * published by the Free Software Foundation. Sun designates this duke@1: * particular file as subject to the "Classpath" exception as provided duke@1: * by Sun in the LICENSE file that accompanied this code. duke@1: * duke@1: * This code is distributed in the hope that it will be useful, but WITHOUT duke@1: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or duke@1: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License duke@1: * version 2 for more details (a copy is included in the LICENSE file that duke@1: * accompanied this code). duke@1: * duke@1: * You should have received a copy of the GNU General Public License version duke@1: * 2 along with this work; if not, write to the Free Software Foundation, duke@1: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. duke@1: * duke@1: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, duke@1: * CA 95054 USA or visit www.sun.com if you need additional information or duke@1: * have any questions. duke@1: */ duke@1: duke@1: package com.sun.tools.javac.util; duke@1: mcimadamore@80: import java.util.Collection; duke@1: import javax.tools.JavaFileObject; duke@1: jjg@50: import com.sun.tools.javac.file.JavacFileManager; duke@1: import com.sun.tools.javac.util.JCDiagnostic.DiagnosticType; duke@1: duke@1: /** duke@1: * A formatter for diagnostic messages. duke@1: * The formatter will format a diagnostic according to one of two format strings, depending on whether duke@1: * or not the source name and position are set. The format is a printf-like string, duke@1: * with the following special characters: duke@1: * duke@1: */ duke@1: public class DiagnosticFormatter { duke@1: /** duke@1: * A format string to be used for diagnostics with a given position. duke@1: */ duke@1: protected String posFormat; duke@1: duke@1: /** duke@1: * A format string to be used for diagnostics regarding classfiles duke@1: */ duke@1: protected String classFormat = DEFAULT_CLASS_FORMAT; duke@1: duke@1: /** duke@1: * A format string to be used for diagnostics without a given position. duke@1: */ duke@1: protected String noPosFormat; duke@1: duke@1: /** duke@1: * A value to indicate whether to output the i18n key and args, instead of duke@1: * the derived l10n message. duke@1: */ duke@1: protected boolean raw; duke@1: duke@1: /** The context key for the formatter. */ duke@1: protected static final Context.Key formatterKey = duke@1: new Context.Key(); duke@1: duke@1: /** Get the DiagnosticFormatter instance for this context. */ duke@1: public static DiagnosticFormatter instance(Context context) { duke@1: DiagnosticFormatter instance = context.get(formatterKey); duke@1: if (instance == null) duke@1: instance = new DiagnosticFormatter(context); duke@1: return instance; duke@1: } duke@1: duke@1: /** duke@1: * Create a formatter based on the supplied options. duke@1: */ duke@1: protected DiagnosticFormatter(Context context) { duke@1: Options options = Options.instance(context); duke@1: raw = options.get("rawDiagnostics") != null; duke@1: String fmt = options.get("diags"); duke@1: if (fmt != null) { duke@1: int sep = fmt.indexOf('|'); duke@1: if (sep == -1) duke@1: posFormat = noPosFormat = fmt; duke@1: else { duke@1: posFormat = fmt.substring(0, sep); duke@1: noPosFormat = fmt.substring(sep + 1); duke@1: } duke@1: } duke@1: else { duke@1: posFormat = DEFAULT_POS_FORMAT; duke@1: noPosFormat = DEFAULT_NO_POS_FORMAT; duke@1: } duke@1: } duke@1: duke@1: public static final String DEFAULT_POS_FORMAT = "%f:%l: %t%m"; duke@1: public static final String DEFAULT_CLASS_FORMAT = "%f: %t%m"; duke@1: public static final String DEFAULT_NO_POS_FORMAT = "%p%m"; duke@1: duke@1: public DiagnosticFormatter() { duke@1: posFormat = DEFAULT_POS_FORMAT; duke@1: noPosFormat = DEFAULT_NO_POS_FORMAT; duke@1: raw = false; duke@1: } duke@1: duke@1: public DiagnosticFormatter(String pos, String noPos) { duke@1: posFormat = pos; duke@1: noPosFormat = noPos; duke@1: raw = false; duke@1: } duke@1: duke@1: String format(JCDiagnostic d) { duke@1: return (raw ? format_raw(d) : format_std(d)); duke@1: } duke@1: duke@1: private String format_raw(JCDiagnostic d) { duke@1: DiagnosticSource source = d.getDiagnosticSource(); duke@1: int position = d.getIntPosition(); duke@1: duke@1: StringBuilder sb = new StringBuilder(); duke@1: if (position == Position.NOPOS) duke@1: sb.append("-"); duke@1: else { duke@1: sb.append(source.getName() + ":" + source.getLineNumber(position) + ":" + source.getColumnNumber(position) + ":"); duke@1: } duke@1: sb.append(" "); duke@1: sb.append(d.getCode()); duke@1: String sep = ": "; duke@1: for (Object arg: d.getArgs()) { duke@1: sb.append(sep); duke@1: if (arg instanceof JCDiagnostic) { duke@1: sb.append('('); duke@1: sb.append(format_raw((JCDiagnostic) arg)); duke@1: sb.append(')'); duke@1: } duke@1: else if (arg instanceof JavaFileObject) duke@1: sb.append(JavacFileManager.getJavacBaseFileName((JavaFileObject) arg)); mcimadamore@80: else if (arg instanceof Collection) mcimadamore@80: sb.append(convert((Collection)arg)); duke@1: else duke@1: sb.append(arg); duke@1: sep = ", "; duke@1: } duke@1: return sb.toString(); duke@1: } duke@1: mcimadamore@80: static List convert(Collection c) { mcimadamore@80: if (c instanceof List) mcimadamore@80: return (List)c; mcimadamore@80: else { mcimadamore@80: List l = List.nil(); mcimadamore@80: for (T t : c) { mcimadamore@80: l = l.prepend(t); mcimadamore@80: } mcimadamore@80: return l.reverse(); mcimadamore@80: } mcimadamore@80: } mcimadamore@80: duke@1: private String format_std(JCDiagnostic d) { duke@1: DiagnosticSource source = d.getDiagnosticSource(); duke@1: DiagnosticType type = d.getType(); duke@1: int position = d.getIntPosition(); duke@1: duke@1: duke@1: String format = noPosFormat; duke@1: if (source != null) { duke@1: if (position != Position.NOPOS) { duke@1: format = posFormat; duke@1: } else if (source.getFile() != null && duke@1: source.getFile().getKind() == JavaFileObject.Kind.CLASS) { duke@1: format = classFormat; duke@1: } duke@1: } duke@1: duke@1: StringBuilder sb = new StringBuilder(); duke@1: duke@1: for (int i = 0; i < format.length(); i++) { duke@1: char c = format.charAt(i); duke@1: if (c == '%' && i < format.length() - 1) { duke@1: c = format.charAt(++i); duke@1: switch (c) { duke@1: case 'b': duke@1: sb.append(source == null ? "-" : source.getName()); duke@1: break; duke@1: duke@1: case 'e': duke@1: sb.append(position == Position.NOPOS ? "-" : String.valueOf(d.getEndPosition())); duke@1: break; duke@1: duke@1: case 'f': duke@1: sb.append(source == null ? "-" : d.getSourceName()); duke@1: break; duke@1: duke@1: case 'l': duke@1: sb.append(position == Position.NOPOS ? "-" : String.valueOf(d.getLineNumber())); duke@1: break; duke@1: duke@1: case 'c': duke@1: sb.append(position == Position.NOPOS ? "-" : String.valueOf(d.getColumnNumber())); duke@1: break; duke@1: duke@1: case 'o': duke@1: sb.append(position == Position.NOPOS ? "-" : String.valueOf(position)); duke@1: break; duke@1: duke@1: case 'p': duke@1: sb.append(d.getPrefix()); duke@1: break; duke@1: duke@1: case 's': duke@1: sb.append(position == Position.NOPOS ? "-" : String.valueOf(d.getStartPosition())); duke@1: break; duke@1: duke@1: case 't': { duke@1: boolean usePrefix; duke@1: switch (type) { duke@1: case FRAGMENT: duke@1: usePrefix = false; duke@1: break; duke@1: duke@1: case ERROR: duke@1: usePrefix = (position == Position.NOPOS); duke@1: break; duke@1: duke@1: default: duke@1: usePrefix = true; duke@1: } duke@1: duke@1: if (usePrefix) duke@1: sb.append(d.getPrefix()); duke@1: break; duke@1: } duke@1: duke@1: case 'm': duke@1: sb.append(d.getMessage(null)); duke@1: break; duke@1: duke@1: case '_': duke@1: sb.append(' '); duke@1: break; duke@1: duke@1: case '%': duke@1: sb.append('%'); duke@1: break; duke@1: duke@1: default: duke@1: sb.append(c); duke@1: break; duke@1: } duke@1: } duke@1: else duke@1: sb.append(c); duke@1: } duke@1: return sb.toString(); duke@1: } duke@1: }