Tue, 16 Jun 2009 10:46:37 +0100
6638712: Inference with wildcard types causes selection of inapplicable method
Summary: Added global sanity check in order to make sure that return type inference does not violate bounds constraints
Reviewed-by: jjg
1 /*
2 * Copyright 2003-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.Locale;
29 import java.util.Map;
31 import javax.tools.Diagnostic;
32 import javax.tools.JavaFileObject;
34 import com.sun.tools.javac.api.DiagnosticFormatter;
35 import com.sun.tools.javac.file.JavacFileManager;
36 import com.sun.tools.javac.tree.JCTree;
38 import static com.sun.tools.javac.util.JCDiagnostic.DiagnosticType.*;
40 /** An abstraction of a diagnostic message generated by the compiler.
41 *
42 * <p><b>This is NOT part of any API supported by Sun Microsystems. If
43 * you write code that depends on this, you do so at your own risk.
44 * This code and its internal interfaces are subject to change or
45 * deletion without notice.</b>
46 */
47 public class JCDiagnostic implements Diagnostic<JavaFileObject> {
48 /** A factory for creating diagnostic objects. */
49 public static class Factory {
50 /** The context key for the diagnostic factory. */
51 protected static final Context.Key<JCDiagnostic.Factory> diagnosticFactoryKey =
52 new Context.Key<JCDiagnostic.Factory>();
54 /** Get the Factory instance for this context. */
55 public static Factory instance(Context context) {
56 Factory instance = context.get(diagnosticFactoryKey);
57 if (instance == null)
58 instance = new Factory(context);
59 return instance;
60 }
62 DiagnosticFormatter<JCDiagnostic> formatter;
63 final String prefix;
65 /** Create a new diagnostic factory. */
66 protected Factory(Context context) {
67 this(JavacMessages.instance(context), "compiler");
68 context.put(diagnosticFactoryKey, this);
69 }
71 /** Create a new diagnostic factory. */
72 public Factory(JavacMessages messages, String prefix) {
73 this.prefix = prefix;
74 this.formatter = new BasicDiagnosticFormatter(messages);
75 }
77 /**
78 * Create an error diagnostic.
79 * @param source The source of the compilation unit, if any, in which to report the error.
80 * @param pos The source position at which to report the error.
81 * @param key The key for the localized error message.
82 * @param args Fields of the error message.
83 */
84 public JCDiagnostic error(
85 DiagnosticSource source, DiagnosticPosition pos, String key, Object... args) {
86 return new JCDiagnostic(formatter, ERROR, true, source, pos, qualify(ERROR, key), args);
87 }
89 /**
90 * Create a warning diagnostic that will not be hidden by the -nowarn or -Xlint:none options.
91 * @param source The source of the compilation unit, if any, in which to report the warning.
92 * @param pos The source position at which to report the warning.
93 * @param key The key for the localized error message.
94 * @param args Fields of the error message.
95 * @see MandatoryWarningHandler
96 */
97 public JCDiagnostic mandatoryWarning(
98 DiagnosticSource source, DiagnosticPosition pos, String key, Object... args) {
99 return new JCDiagnostic(formatter, WARNING, true, source, pos, qualify(WARNING, key), args);
100 }
102 /**
103 * Create a warning diagnostic.
104 * @param source The source of the compilation unit, if any, in which to report the warning.
105 * @param pos The source position at which to report the warning.
106 * @param key The key for the localized error message.
107 * @param args Fields of the error message.
108 */
109 public JCDiagnostic warning(
110 DiagnosticSource source, DiagnosticPosition pos, String key, Object... args) {
111 return new JCDiagnostic(formatter, WARNING, false, source, pos, qualify(WARNING, key), args);
112 }
114 /**
115 * Create a note diagnostic that will not be hidden by the -nowarn or -Xlint:none options.
116 * @param key The key for the localized error message.
117 * @param args Fields of the error message.
118 * @see MandatoryWarningHandler
119 */
120 public JCDiagnostic mandatoryNote(DiagnosticSource source, String key, Object... args) {
121 return new JCDiagnostic(formatter, NOTE, true, source, null, qualify(NOTE, key), args);
122 }
124 /**
125 * Create a note diagnostic.
126 * @param key The key for the localized error message.
127 * @param args Fields of the error message.
128 */
129 public JCDiagnostic note(String key, Object... args) {
130 return note(null, null, key, args);
131 }
133 /**
134 * Create a note diagnostic.
135 * @param source The source of the compilation unit, if any, in which to report the note.
136 * @param pos The source position at which to report the note.
137 * @param key The key for the localized error message.
138 * @param args Fields of the error message.
139 */
140 public JCDiagnostic note(
141 DiagnosticSource source, DiagnosticPosition pos, String key, Object... args) {
142 return new JCDiagnostic(formatter, NOTE, false, source, pos, qualify(NOTE, key), args);
143 }
145 /**
146 * Create a fragment diagnostic, for use as an argument in other diagnostics
147 * @param key The key for the localized error message.
148 * @param args Fields of the error message.
149 */
150 public JCDiagnostic fragment(String key, Object... args) {
151 return new JCDiagnostic(formatter, FRAGMENT, false, null, null, qualify(FRAGMENT, key), args);
152 }
154 protected String qualify(DiagnosticType t, String key) {
155 return prefix + "." + t.key + "." + key;
156 }
157 }
161 /**
162 * Create a fragment diagnostic, for use as an argument in other diagnostics
163 * @param key The key for the localized error message.
164 * @param args Fields of the error message.
165 *
166 */
167 @Deprecated
168 public static JCDiagnostic fragment(String key, Object... args) {
169 return new JCDiagnostic(getFragmentFormatter(),
170 FRAGMENT,
171 false,
172 null,
173 null,
174 "compiler." + FRAGMENT.key + "." + key,
175 args);
176 }
177 //where
178 @Deprecated
179 public static DiagnosticFormatter<JCDiagnostic> getFragmentFormatter() {
180 if (fragmentFormatter == null) {
181 fragmentFormatter = new BasicDiagnosticFormatter(JavacMessages.getDefaultMessages());
182 }
183 return fragmentFormatter;
184 }
186 /**
187 * A DiagnosticType defines the type of the diagnostic.
188 **/
189 public enum DiagnosticType {
190 /** A fragment of an enclosing diagnostic. */
191 FRAGMENT("misc"),
192 /** A note: similar to, but less serious than, a warning. */
193 NOTE("note"),
194 /** A warning. */
195 WARNING("warn"),
196 /** An error. */
197 ERROR("err");
199 final String key;
201 /** Create a DiagnosticType.
202 * @param key A string used to create the resource key for the diagnostic.
203 */
204 DiagnosticType(String key) {
205 this.key = key;
206 }
207 };
209 /**
210 * A DiagnosticPosition provides information about the positions in a file
211 * that gave rise to a diagnostic. It always defines a "preferred" position
212 * that most accurately defines the location of the diagnostic, it may also
213 * provide a related tree node that spans that location.
214 */
215 public static interface DiagnosticPosition {
216 /** Gets the tree node, if any, to which the diagnostic applies. */
217 JCTree getTree();
218 /** If there is a tree node, get the start position of the tree node.
219 * Otherwise, just returns the same as getPreferredPosition(). */
220 int getStartPosition();
221 /** Get the position within the file that most accurately defines the
222 * location for the diagnostic. */
223 int getPreferredPosition();
224 /** If there is a tree node, and if endPositions are available, get
225 * the end position of the tree node. Otherwise, just returns the
226 * same as getPreferredPosition(). */
227 int getEndPosition(Map<JCTree, Integer> endPosTable);
228 }
230 /**
231 * A DiagnosticPosition that simply identifies a position, but no related
232 * tree node, as the location for a diagnostic. Used for scanner and parser
233 * diagnostics. */
234 public static class SimpleDiagnosticPosition implements DiagnosticPosition {
235 public SimpleDiagnosticPosition(int pos) {
236 this.pos = pos;
237 }
239 public JCTree getTree() {
240 return null;
241 }
243 public int getStartPosition() {
244 return pos;
245 }
247 public int getPreferredPosition() {
248 return pos;
249 }
251 public int getEndPosition(Map<JCTree, Integer> endPosTable) {
252 return pos;
253 }
255 private final int pos;
256 }
258 private final DiagnosticType type;
259 private final DiagnosticSource source;
260 private final DiagnosticPosition position;
261 private final int line;
262 private final int column;
263 private final String key;
264 protected Object[] args;
265 private boolean mandatory;
267 /**
268 * Create a diagnostic object.
269 * @param messages the resource for localized messages
270 * @param dt the type of diagnostic
271 * @param name the name of the source file, or null if none.
272 * @param pos the character offset within the source file, if given.
273 * @param key a resource key to identify the text of the diagnostic
274 * @param args arguments to be included in the text of the diagnostic
275 */
276 protected JCDiagnostic(DiagnosticFormatter<JCDiagnostic> formatter,
277 DiagnosticType dt,
278 boolean mandatory,
279 DiagnosticSource source,
280 DiagnosticPosition pos,
281 String key,
282 Object ... args) {
283 if (source == null && pos != null && pos.getPreferredPosition() != Position.NOPOS)
284 throw new IllegalArgumentException();
286 this.defaultFormatter = formatter;
287 this.type = dt;
288 this.mandatory = mandatory;
289 this.source = source;
290 this.position = pos;
291 this.key = key;
292 this.args = args;
294 int n = (pos == null ? Position.NOPOS : pos.getPreferredPosition());
295 if (n == Position.NOPOS || source == null)
296 line = column = -1;
297 else {
298 line = source.getLineNumber(n);
299 column = source.getColumnNumber(n, true);
300 }
301 }
303 /**
304 * Get the type of this diagnostic.
305 * @return the type of this diagnostic
306 */
307 public DiagnosticType getType() {
308 return type;
309 }
311 /**
312 * Get the subdiagnostic list
313 * @return subdiagnostic list
314 */
315 public List<JCDiagnostic> getSubdiagnostics() {
316 return List.nil();
317 }
319 public boolean isMultiline() {
320 return false;
321 }
323 /**
324 * Check whether or not this diagnostic is required to be shown.
325 * @return true if this diagnostic is required to be shown.
326 */
327 public boolean isMandatory() {
328 return mandatory;
329 }
331 /**
332 * Get the name of the source file referred to by this diagnostic.
333 * @return the name of the source referred to with this diagnostic, or null if none
334 */
335 public JavaFileObject getSource() {
336 if (source == null)
337 return null;
338 else
339 return source.getFile();
340 }
342 /**
343 * Get the name of the source file referred to by this diagnostic.
344 * @return the name of the source referred to with this diagnostic, or null if none
345 */
346 public String getSourceName() {
347 JavaFileObject s = getSource();
348 return s == null ? null : JavacFileManager.getJavacFileName(s);
349 }
351 /**
352 * Get the source referred to by this diagnostic.
353 * @return the source referred to with this diagnostic, or null if none
354 */
355 public DiagnosticSource getDiagnosticSource() {
356 return source;
357 }
359 protected int getIntStartPosition() {
360 return (position == null ? Position.NOPOS : position.getStartPosition());
361 }
363 protected int getIntPosition() {
364 return (position == null ? Position.NOPOS : position.getPreferredPosition());
365 }
367 protected int getIntEndPosition() {
368 return (position == null ? Position.NOPOS : position.getEndPosition(source.getEndPosTable()));
369 }
371 public long getStartPosition() {
372 return getIntStartPosition();
373 }
375 public long getPosition() {
376 return getIntPosition();
377 }
379 public long getEndPosition() {
380 return getIntEndPosition();
381 }
383 /**
384 * Get the line number within the source referred to by this diagnostic.
385 * @return the line number within the source referred to by this diagnostic
386 */
387 public long getLineNumber() {
388 return line;
389 }
391 /**
392 * Get the column number within the line of source referred to by this diagnostic.
393 * @return the column number within the line of source referred to by this diagnostic
394 */
395 public long getColumnNumber() {
396 return column;
397 }
399 /**
400 * Get the arguments to be included in the text of the diagnostic.
401 * @return the arguments to be included in the text of the diagnostic
402 */
403 public Object[] getArgs() {
404 return args;
405 }
407 /**
408 * Get the prefix string associated with this type of diagnostic.
409 * @return the prefix string associated with this type of diagnostic
410 */
411 public String getPrefix() {
412 return getPrefix(type);
413 }
415 /**
416 * Get the prefix string associated with a particular type of diagnostic.
417 * @return the prefix string associated with a particular type of diagnostic
418 */
419 public String getPrefix(DiagnosticType dt) {
420 return defaultFormatter.formatKind(this, Locale.getDefault());
421 }
423 /**
424 * Return the standard presentation of this diagnostic.
425 */
426 public String toString() {
427 return defaultFormatter.format(this,Locale.getDefault());
428 }
430 private DiagnosticFormatter<JCDiagnostic> defaultFormatter;
431 @Deprecated
432 private static DiagnosticFormatter<JCDiagnostic> fragmentFormatter;
434 // Methods for javax.tools.Diagnostic
436 public Diagnostic.Kind getKind() {
437 switch (type) {
438 case NOTE:
439 return Diagnostic.Kind.NOTE;
440 case WARNING:
441 return mandatory ? Diagnostic.Kind.MANDATORY_WARNING
442 : Diagnostic.Kind.WARNING;
443 case ERROR:
444 return Diagnostic.Kind.ERROR;
445 default:
446 return Diagnostic.Kind.OTHER;
447 }
448 }
450 public String getCode() {
451 return key;
452 }
454 public String getMessage(Locale locale) {
455 return defaultFormatter.formatMessage(this, locale);
456 }
458 public static class MultilineDiagnostic extends JCDiagnostic {
460 private final List<JCDiagnostic> subdiagnostics;
462 public MultilineDiagnostic(JCDiagnostic other, List<JCDiagnostic> subdiagnostics) {
463 super(other.defaultFormatter,
464 other.getType(),
465 other.isMandatory(),
466 other.getDiagnosticSource(),
467 other.position,
468 other.getCode(),
469 other.getArgs());
470 this.subdiagnostics = subdiagnostics;
471 }
473 @Override
474 public List<JCDiagnostic> getSubdiagnostics() {
475 return subdiagnostics;
476 }
478 @Override
479 public boolean isMultiline() {
480 return true;
481 }
482 }
483 }