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: * - %b: the base of the source name, or "-" if not set
duke@1: *
- %f: the source name, or "-" if not set
duke@1: *
- %l: the line number of the diagnostic, derived from the character offset if set, or "-" otherwise
duke@1: *
- %c: the column number of the diagnostic, derived from the character offset if set, or "-" otherwise
duke@1: *
- %o: the character offset of the diagnostic if set, or "-" otherwise
duke@1: *
- %p: the prefix for the diagnostic, derived from the diagnostic type
duke@1: *
- %t: the prefix as it normally appears in standard diagnostics. In this case, no prefix is
duke@1: * shown if the type is ERROR and if a source name is set
duke@1: *
- %m: the text or the diagnostic, including any appropriate arguments
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: }