001: /*
002: * Copyright 2005-2006 Sun Microsystems, Inc. All Rights Reserved.
003: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004: *
005: * This code is free software; you can redistribute it and/or modify it
006: * under the terms of the GNU General Public License version 2 only, as
007: * published by the Free Software Foundation. Sun designates this
008: * particular file as subject to the "Classpath" exception as provided
009: * by Sun in the LICENSE file that accompanied this code.
010: *
011: * This code is distributed in the hope that it will be useful, but WITHOUT
012: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
014: * version 2 for more details (a copy is included in the LICENSE file that
015: * accompanied this code).
016: *
017: * You should have received a copy of the GNU General Public License version
018: * 2 along with this work; if not, write to the Free Software Foundation,
019: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
020: *
021: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
022: * CA 95054 USA or visit www.sun.com if you need additional information or
023: * have any questions.
024: */
025:
026: package com.sun.tools.javac.util;
027:
028: import javax.tools.JavaFileObject;
029:
030: import com.sun.tools.javac.util.JCDiagnostic.DiagnosticSource;
031: import com.sun.tools.javac.util.JCDiagnostic.DiagnosticType;
032:
033: /**
034: * A formatter for diagnostic messages.
035: * The formatter will format a diagnostic according to one of two format strings, depending on whether
036: * or not the source name and position are set. The format is a printf-like string,
037: * with the following special characters:
038: * <ul>
039: * <li>%b: the base of the source name, or "-" if not set
040: * <li>%f: the source name, or "-" if not set
041: * <li>%l: the line number of the diagnostic, derived from the character offset if set, or "-" otherwise
042: * <li>%c: the column number of the diagnostic, derived from the character offset if set, or "-" otherwise
043: * <li>%o: the character offset of the diagnostic if set, or "-" otherwise
044: * <li>%p: the prefix for the diagnostic, derived from the diagnostic type
045: * <li>%t: the prefix as it normally appears in standard diagnostics. In this case, no prefix is
046: * shown if the type is ERROR and if a source name is set
047: * <li>%m: the text or the diagnostic, including any appropriate arguments
048: * </ul>
049: */
050: @Version("@(#)DiagnosticFormatter.java 1.19 07/05/05")
051: public class DiagnosticFormatter {
052: /**
053: * A format string to be used for diagnostics with a given position.
054: */
055: protected String posFormat;
056:
057: /**
058: * A format string to be used for diagnostics regarding classfiles
059: */
060: protected String classFormat = DEFAULT_CLASS_FORMAT;
061:
062: /**
063: * A format string to be used for diagnostics without a given position.
064: */
065: protected String noPosFormat;
066:
067: /**
068: * A value to indicate whether to output the i18n key and args, instead of
069: * the derived l10n message.
070: */
071: protected boolean raw;
072:
073: /** The context key for the formatter. */
074: protected static final Context.Key<DiagnosticFormatter> formatterKey = new Context.Key<DiagnosticFormatter>();
075:
076: /** Get the DiagnosticFormatter instance for this context. */
077: public static DiagnosticFormatter instance(Context context) {
078: DiagnosticFormatter instance = context.get(formatterKey);
079: if (instance == null)
080: instance = new DiagnosticFormatter(context);
081: return instance;
082: }
083:
084: /**
085: * Create a formatter based on the supplied options.
086: */
087: protected DiagnosticFormatter(Context context) {
088: Options options = Options.instance(context);
089: raw = options.get("rawDiagnostics") != null;
090: String fmt = options.get("diags");
091: if (fmt != null) {
092: int sep = fmt.indexOf('|');
093: if (sep == -1)
094: posFormat = noPosFormat = fmt;
095: else {
096: posFormat = fmt.substring(0, sep);
097: noPosFormat = fmt.substring(sep + 1);
098: }
099: } else {
100: posFormat = DEFAULT_POS_FORMAT;
101: noPosFormat = DEFAULT_NO_POS_FORMAT;
102: }
103: }
104:
105: public static final String DEFAULT_POS_FORMAT = "%f:%l: %t%m";
106: public static final String DEFAULT_CLASS_FORMAT = "%f: %t%m";
107: public static final String DEFAULT_NO_POS_FORMAT = "%p%m";
108:
109: public DiagnosticFormatter() {
110: posFormat = DEFAULT_POS_FORMAT;
111: noPosFormat = DEFAULT_NO_POS_FORMAT;
112: raw = false;
113: }
114:
115: public DiagnosticFormatter(String pos, String noPos) {
116: posFormat = pos;
117: noPosFormat = noPos;
118: raw = false;
119: }
120:
121: String format(JCDiagnostic d) {
122: return (raw ? format_raw(d) : format_std(d));
123: }
124:
125: private String format_raw(JCDiagnostic d) {
126: DiagnosticSource source = d.getDiagnosticSource();
127: int position = d.getIntPosition();
128:
129: StringBuilder sb = new StringBuilder();
130: if (position == Position.NOPOS)
131: sb.append("-");
132: else {
133: sb.append(source.getName() + ":"
134: + source.getLineNumber(position) + ":"
135: + source.getColumnNumber(position) + ":");
136: }
137: sb.append(" ");
138: sb.append(d.getCode());
139: String sep = ": ";
140: for (Object arg : d.getArgs()) {
141: sb.append(sep);
142: if (arg instanceof JCDiagnostic) {
143: sb.append('(');
144: sb.append(format_raw((JCDiagnostic) arg));
145: sb.append(')');
146: } else if (arg instanceof JavaFileObject)
147: sb.append(JavacFileManager
148: .getJavacBaseFileName((JavaFileObject) arg));
149: else
150: sb.append(arg);
151: sep = ", ";
152: }
153: return sb.toString();
154: }
155:
156: private String format_std(JCDiagnostic d) {
157: DiagnosticSource source = d.getDiagnosticSource();
158: DiagnosticType type = d.getType();
159: int position = d.getIntPosition();
160:
161: String format = noPosFormat;
162: if (source != null) {
163: if (position != Position.NOPOS) {
164: format = posFormat;
165: } else if (source.getFile() != null
166: && source.getFile().getKind() == JavaFileObject.Kind.CLASS) {
167: format = classFormat;
168: }
169: }
170:
171: StringBuilder sb = new StringBuilder();
172:
173: for (int i = 0; i < format.length(); i++) {
174: char c = format.charAt(i);
175: if (c == '%' && i < format.length() - 1) {
176: c = format.charAt(++i);
177: switch (c) {
178: case 'b':
179: sb.append(source == null ? "-" : source.getName());
180: break;
181:
182: case 'e':
183: sb.append(position == Position.NOPOS ? "-" : String
184: .valueOf(d.getEndPosition()));
185: break;
186:
187: case 'f':
188: sb.append(source == null ? "-" : d.getSourceName());
189: break;
190:
191: case 'l':
192: sb.append(position == Position.NOPOS ? "-" : String
193: .valueOf(d.getLineNumber()));
194: break;
195:
196: case 'c':
197: sb.append(position == Position.NOPOS ? "-" : String
198: .valueOf(d.getColumnNumber()));
199: break;
200:
201: case 'o':
202: sb.append(position == Position.NOPOS ? "-" : String
203: .valueOf(position));
204: break;
205:
206: case 'p':
207: sb.append(d.getPrefix());
208: break;
209:
210: case 's':
211: sb.append(position == Position.NOPOS ? "-" : String
212: .valueOf(d.getStartPosition()));
213: break;
214:
215: case 't': {
216: boolean usePrefix;
217: switch (type) {
218: case FRAGMENT:
219: usePrefix = false;
220: break;
221:
222: case ERROR:
223: usePrefix = (position == Position.NOPOS);
224: break;
225:
226: default:
227: usePrefix = true;
228: }
229:
230: if (usePrefix)
231: sb.append(d.getPrefix());
232: break;
233: }
234:
235: case 'm':
236: sb.append(d.getMessage(null));
237: break;
238:
239: case '_':
240: sb.append(' ');
241: break;
242:
243: case '%':
244: sb.append('%');
245: break;
246:
247: default:
248: sb.append(c);
249: break;
250: }
251: } else
252: sb.append(c);
253: }
254: return sb.toString();
255: }
256: }
|