Thu, 24 Jul 2008 19:06:57 +0100
6717241: some diagnostic argument is prematurely converted into a String object
Summary: removed early toString() conversions applied to diagnostic arguments
Reviewed-by: jjg
1 /*
2 * Copyright 2005-2008 Sun Microsystems, Inc. All Rights Reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Sun designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Sun in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
22 * CA 95054 USA or visit www.sun.com if you need additional information or
23 * have any questions.
24 */
26 package com.sun.tools.javac.util;
28 import java.util.Collection;
29 import javax.tools.JavaFileObject;
31 import com.sun.tools.javac.file.JavacFileManager;
32 import com.sun.tools.javac.util.JCDiagnostic.DiagnosticType;
34 /**
35 * A formatter for diagnostic messages.
36 * The formatter will format a diagnostic according to one of two format strings, depending on whether
37 * or not the source name and position are set. The format is a printf-like string,
38 * with the following special characters:
39 * <ul>
40 * <li>%b: the base of the source name, or "-" if not set
41 * <li>%f: the source name, or "-" if not set
42 * <li>%l: the line number of the diagnostic, derived from the character offset if set, or "-" otherwise
43 * <li>%c: the column number of the diagnostic, derived from the character offset if set, or "-" otherwise
44 * <li>%o: the character offset of the diagnostic if set, or "-" otherwise
45 * <li>%p: the prefix for the diagnostic, derived from the diagnostic type
46 * <li>%t: the prefix as it normally appears in standard diagnostics. In this case, no prefix is
47 * shown if the type is ERROR and if a source name is set
48 * <li>%m: the text or the diagnostic, including any appropriate arguments
49 * </ul>
50 */
51 public class DiagnosticFormatter {
52 /**
53 * A format string to be used for diagnostics with a given position.
54 */
55 protected String posFormat;
57 /**
58 * A format string to be used for diagnostics regarding classfiles
59 */
60 protected String classFormat = DEFAULT_CLASS_FORMAT;
62 /**
63 * A format string to be used for diagnostics without a given position.
64 */
65 protected String noPosFormat;
67 /**
68 * A value to indicate whether to output the i18n key and args, instead of
69 * the derived l10n message.
70 */
71 protected boolean raw;
73 /** The context key for the formatter. */
74 protected static final Context.Key<DiagnosticFormatter> formatterKey =
75 new Context.Key<DiagnosticFormatter>();
77 /** Get the DiagnosticFormatter instance for this context. */
78 public static DiagnosticFormatter instance(Context context) {
79 DiagnosticFormatter instance = context.get(formatterKey);
80 if (instance == null)
81 instance = new DiagnosticFormatter(context);
82 return instance;
83 }
85 /**
86 * Create a formatter based on the supplied options.
87 */
88 protected DiagnosticFormatter(Context context) {
89 Options options = Options.instance(context);
90 raw = options.get("rawDiagnostics") != null;
91 String fmt = options.get("diags");
92 if (fmt != null) {
93 int sep = fmt.indexOf('|');
94 if (sep == -1)
95 posFormat = noPosFormat = fmt;
96 else {
97 posFormat = fmt.substring(0, sep);
98 noPosFormat = fmt.substring(sep + 1);
99 }
100 }
101 else {
102 posFormat = DEFAULT_POS_FORMAT;
103 noPosFormat = DEFAULT_NO_POS_FORMAT;
104 }
105 }
107 public static final String DEFAULT_POS_FORMAT = "%f:%l: %t%m";
108 public static final String DEFAULT_CLASS_FORMAT = "%f: %t%m";
109 public static final String DEFAULT_NO_POS_FORMAT = "%p%m";
111 public DiagnosticFormatter() {
112 posFormat = DEFAULT_POS_FORMAT;
113 noPosFormat = DEFAULT_NO_POS_FORMAT;
114 raw = false;
115 }
117 public DiagnosticFormatter(String pos, String noPos) {
118 posFormat = pos;
119 noPosFormat = noPos;
120 raw = false;
121 }
123 String format(JCDiagnostic d) {
124 return (raw ? format_raw(d) : format_std(d));
125 }
127 private String format_raw(JCDiagnostic d) {
128 DiagnosticSource source = d.getDiagnosticSource();
129 int position = d.getIntPosition();
131 StringBuilder sb = new StringBuilder();
132 if (position == Position.NOPOS)
133 sb.append("-");
134 else {
135 sb.append(source.getName() + ":" + source.getLineNumber(position) + ":" + 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 }
147 else if (arg instanceof JavaFileObject)
148 sb.append(JavacFileManager.getJavacBaseFileName((JavaFileObject) arg));
149 else if (arg instanceof Collection<?>)
150 sb.append(convert((Collection<?>)arg));
151 else
152 sb.append(arg);
153 sep = ", ";
154 }
155 return sb.toString();
156 }
158 static <T> List<T> convert(Collection<T> c) {
159 if (c instanceof List<?>)
160 return (List<T>)c;
161 else {
162 List<T> l = List.<T>nil();
163 for (T t : c) {
164 l = l.prepend(t);
165 }
166 return l.reverse();
167 }
168 }
170 private String format_std(JCDiagnostic d) {
171 DiagnosticSource source = d.getDiagnosticSource();
172 DiagnosticType type = d.getType();
173 int position = d.getIntPosition();
176 String format = noPosFormat;
177 if (source != null) {
178 if (position != Position.NOPOS) {
179 format = posFormat;
180 } else if (source.getFile() != null &&
181 source.getFile().getKind() == JavaFileObject.Kind.CLASS) {
182 format = classFormat;
183 }
184 }
186 StringBuilder sb = new StringBuilder();
188 for (int i = 0; i < format.length(); i++) {
189 char c = format.charAt(i);
190 if (c == '%' && i < format.length() - 1) {
191 c = format.charAt(++i);
192 switch (c) {
193 case 'b':
194 sb.append(source == null ? "-" : source.getName());
195 break;
197 case 'e':
198 sb.append(position == Position.NOPOS ? "-" : String.valueOf(d.getEndPosition()));
199 break;
201 case 'f':
202 sb.append(source == null ? "-" : d.getSourceName());
203 break;
205 case 'l':
206 sb.append(position == Position.NOPOS ? "-" : String.valueOf(d.getLineNumber()));
207 break;
209 case 'c':
210 sb.append(position == Position.NOPOS ? "-" : String.valueOf(d.getColumnNumber()));
211 break;
213 case 'o':
214 sb.append(position == Position.NOPOS ? "-" : String.valueOf(position));
215 break;
217 case 'p':
218 sb.append(d.getPrefix());
219 break;
221 case 's':
222 sb.append(position == Position.NOPOS ? "-" : String.valueOf(d.getStartPosition()));
223 break;
225 case 't': {
226 boolean usePrefix;
227 switch (type) {
228 case FRAGMENT:
229 usePrefix = false;
230 break;
232 case ERROR:
233 usePrefix = (position == Position.NOPOS);
234 break;
236 default:
237 usePrefix = true;
238 }
240 if (usePrefix)
241 sb.append(d.getPrefix());
242 break;
243 }
245 case 'm':
246 sb.append(d.getMessage(null));
247 break;
249 case '_':
250 sb.append(' ');
251 break;
253 case '%':
254 sb.append('%');
255 break;
257 default:
258 sb.append(c);
259 break;
260 }
261 }
262 else
263 sb.append(c);
264 }
265 return sb.toString();
266 }
267 }