src/share/classes/com/sun/tools/javac/util/JCDiagnostic.java

Tue, 04 Mar 2008 15:45:20 +0000

author
mcimadamore
date
Tue, 04 Mar 2008 15:45:20 +0000
changeset 8
38bd6375f37d
parent 1
9a66ca7c79fa
child 50
b9bcea8bbe24
permissions
-rw-r--r--

6663588: Compiler goes into infinite loop for Cyclic Inheritance test case
Summary: interplay between cyclic inheritance and tvar bounds hangs javac
Reviewed-by: jjg

     1 /*
     2  * Copyright 2003-2006 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.net.URI;
    29 import java.text.MessageFormat;
    30 import java.util.Locale;
    31 import java.util.Map;
    32 import java.util.MissingResourceException;
    33 import java.util.ResourceBundle;
    35 import javax.tools.Diagnostic;
    36 import javax.tools.FileObject;
    37 import javax.tools.JavaFileObject;
    39 import com.sun.tools.javac.tree.JCTree;
    41 import static com.sun.tools.javac.util.JCDiagnostic.DiagnosticType.*;
    43 /** An abstraction of a diagnostic message generated by the compiler.
    44  *
    45  *  <p><b>This is NOT part of any API supported by Sun Microsystems.  If
    46  *  you write code that depends on this, you do so at your own risk.
    47  *  This code and its internal interfaces are subject to change or
    48  *  deletion without notice.</b>
    49  */
    50 public class JCDiagnostic implements Diagnostic<JavaFileObject> {
    51     /** A factory for creating diagnostic objects. */
    52     public static class Factory {
    53         /** The context key for the diagnostic factory. */
    54         protected static final Context.Key<JCDiagnostic.Factory> diagnosticFactoryKey =
    55             new Context.Key<JCDiagnostic.Factory>();
    57         /** Get the Factory instance for this context. */
    58         public static Factory instance(Context context) {
    59             Factory instance = context.get(diagnosticFactoryKey);
    60             if (instance == null)
    61                 instance = new Factory(context);
    62             return instance;
    63         }
    65         final Messages messages;
    66         final String prefix;
    68         /** Create a new diagnostic factory. */
    69         protected Factory(Context context) {
    70             context.put(diagnosticFactoryKey, this);
    71             messages = Messages.instance(context);
    72             prefix = "compiler";
    73         }
    75         /** Create a new diagnostic factory. */
    76         public Factory(Messages messages, String prefix) {
    77             this.messages = messages;
    78             this.prefix = prefix;
    79         }
    81         /**
    82          * Create an error diagnostic.
    83          *  @param source The source of the compilation unit, if any, in which to report the error.
    84          *  @param pos    The source position at which to report the error.
    85          *  @param key    The key for the localized error message.
    86          *  @param args   Fields of the error message.
    87          */
    88         public JCDiagnostic error(
    89                 DiagnosticSource source, DiagnosticPosition pos, String key, Object... args) {
    90             return new JCDiagnostic(messages, ERROR, true, source, pos, qualify(ERROR, key), args);
    91         }
    93         /**
    94          * Create a warning diagnostic that will not be hidden by the -nowarn or -Xlint:none options.
    95          *  @param source The source of the compilation unit, if any, in which to report the warning.
    96          *  @param pos    The source position at which to report the warning.
    97          *  @param key    The key for the localized error message.
    98          *  @param args   Fields of the error message.
    99          *  @see MandatoryWarningHandler
   100          */
   101         public JCDiagnostic mandatoryWarning(
   102                  DiagnosticSource source, DiagnosticPosition pos, String key, Object... args) {
   103             return new JCDiagnostic(messages, WARNING, true, source, pos, qualify(WARNING, key), args);
   104         }
   106         /**
   107          * Create a warning diagnostic.
   108          *  @param source The source of the compilation unit, if any, in which to report the warning.
   109          *  @param pos    The source position at which to report the warning.
   110          *  @param key    The key for the localized error message.
   111          *  @param args   Fields of the error message.
   112          */
   113         public JCDiagnostic warning(
   114                 DiagnosticSource source, DiagnosticPosition pos, String key, Object... args) {
   115             return new JCDiagnostic(messages, WARNING, false, source, pos, qualify(WARNING, key), args);
   116         }
   118         /**
   119          * Create a note diagnostic that will not be hidden by the -nowarn or -Xlint:none options.
   120          *  @param key    The key for the localized error message.
   121          *  @param args   Fields of the error message.
   122          *  @see MandatoryWarningHandler
   123          */
   124         public JCDiagnostic mandatoryNote(DiagnosticSource source, String key, Object... args) {
   125             return new JCDiagnostic(messages, NOTE, true, source, null, qualify(NOTE, key), args);
   126         }
   128         /**
   129          * Create a note diagnostic.
   130          *  @param key    The key for the localized error message.
   131          *  @param args   Fields of the error message.
   132          */
   133         public JCDiagnostic note(String key, Object... args) {
   134             return note(null, null, key, args);
   135         }
   137         /**
   138          * Create a note diagnostic.
   139          *  @param source The source of the compilation unit, if any, in which to report the note.
   140          *  @param pos    The source position at which to report the note.
   141          *  @param key    The key for the localized error message.
   142          *  @param args   Fields of the error message.
   143          */
   144         public JCDiagnostic note(
   145                 DiagnosticSource source, DiagnosticPosition pos, String key, Object... args) {
   146             return new JCDiagnostic(messages, NOTE, false, source, pos, qualify(NOTE, key), args);
   147         }
   149         /**
   150          * Create a fragment diagnostic, for use as an argument in other diagnostics
   151          *  @param key    The key for the localized error message.
   152          *  @param args   Fields of the error message.
   153          */
   154         public JCDiagnostic fragment(String key, Object... args) {
   155             return new JCDiagnostic(messages, FRAGMENT, false, null, null, qualify(FRAGMENT, key), args);
   156         }
   158         protected String qualify(DiagnosticType t, String key) {
   159             return prefix + "." + t.key + "." + key;
   160         }
   161     }
   165     /**
   166      * Create a fragment diagnostic, for use as an argument in other diagnostics
   167      *  @param key    The key for the localized error message.
   168      *  @param args   Fields of the error message.
   169      */
   170     // should be deprecated
   171     public static JCDiagnostic fragment(String key, Object... args) {
   172         return new JCDiagnostic(Messages.getDefaultMessages(),
   173                               FRAGMENT,
   174                               false,
   175                               null,
   176                               null,
   177                               "compiler." + FRAGMENT.key + "." + key,
   178                               args);
   179     }
   181     /**
   182      * A simple abstraction of a source file, as needed for use in a diagnostic message.
   183      */
   184     // Note: This class may be superceded by a more general abstraction
   185     public interface DiagnosticSource {
   186         JavaFileObject getFile();
   187         CharSequence getName();
   188         int getLineNumber(int pos);
   189         int getColumnNumber(int pos);
   190         Map<JCTree, Integer> getEndPosTable();
   191     };
   193     /**
   194      * A DiagnosticType defines the type of the diagnostic.
   195      **/
   196     public enum DiagnosticType {
   197         /** A fragment of an enclosing diagnostic. */
   198         FRAGMENT("misc"),
   199         /** A note: similar to, but less serious than, a warning. */
   200         NOTE("note"),
   201         /** A warning. */
   202         WARNING("warn"),
   203         /** An error. */
   204         ERROR("err");
   206         final String key;
   208         /** Create a DiagnosticType.
   209          * @param key A string used to create the resource key for the diagnostic.
   210          */
   211         DiagnosticType(String key) {
   212             this.key = key;
   213         }
   214     };
   216     /**
   217      * A DiagnosticPosition provides information about the positions in a file
   218      * that gave rise to a diagnostic. It always defines a "preferred" position
   219      * that most accurately defines the location of the diagnostic, it may also
   220      * provide a related tree node that spans that location.
   221      */
   222     public static interface DiagnosticPosition {
   223         /** Gets the tree node, if any, to which the diagnostic applies. */
   224         JCTree getTree();
   225         /** If there is a tree node, get the start position of the tree node.
   226          *  Otherwise, just returns the same as getPreferredPosition(). */
   227         int getStartPosition();
   228         /** Get the position within the file that most accurately defines the
   229          *  location for the diagnostic. */
   230         int getPreferredPosition();
   231         /** If there is a tree node, and if endPositions are available, get
   232          *  the end position of the tree node. Otherwise, just returns the
   233          *  same as getPreferredPosition(). */
   234         int getEndPosition(Map<JCTree, Integer> endPosTable);
   235     }
   237     /**
   238      * A DiagnosticPosition that simply identifies a position, but no related
   239      * tree node, as the location for a diagnostic. Used for scanner and parser
   240      * diagnostics. */
   241     public static class SimpleDiagnosticPosition implements DiagnosticPosition {
   242         public SimpleDiagnosticPosition(int pos) {
   243             this.pos = pos;
   244         }
   246         public JCTree getTree() {
   247             return null;
   248         }
   250         public int getStartPosition() {
   251             return pos;
   252         }
   254         public int getPreferredPosition() {
   255             return pos;
   256         }
   258         public int getEndPosition(Map<JCTree, Integer> endPosTable) {
   259             return pos;
   260         }
   262         private final int pos;
   263     }
   265     private final Messages messages;
   266     private final DiagnosticType type;
   267     private final DiagnosticSource source;
   268     private final DiagnosticPosition position;
   269     private final int line;
   270     private final int column;
   271     private final String key;
   272     private final Object[] args;
   273     private boolean mandatory;
   275     /**
   276      * Create a diagnostic object.
   277      * @param messages the resource for localized messages
   278      * @param dt the type of diagnostic
   279      * @param name the name of the source file, or null if none.
   280      * @param pos the character offset within the source file, if given.
   281      * @param key a resource key to identify the text of the diagnostic
   282      * @param args arguments to be included in the text of the diagnostic
   283      */
   284     protected JCDiagnostic(Messages messages,
   285                        DiagnosticType dt,
   286                        boolean mandatory,
   287                        DiagnosticSource source,
   288                        DiagnosticPosition pos,
   289                        String key,
   290                        Object ... args) {
   291         if (source == null && pos != null && pos.getPreferredPosition() != Position.NOPOS)
   292             throw new IllegalArgumentException();
   294         this.messages = messages;
   295         this.type = dt;
   296         this.mandatory = mandatory;
   297         this.source = source;
   298         this.position = pos;
   299         this.key = key;
   300         this.args = args;
   302         int n = (pos == null ? Position.NOPOS : pos.getPreferredPosition());
   303         if (n == Position.NOPOS || source == null)
   304             line = column = -1;
   305         else {
   306             line = source.getLineNumber(n);
   307             column = source.getColumnNumber(n);
   308         }
   309     }
   311     /**
   312      * Get the type of this diagnostic.
   313      * @return the type of this diagnostic
   314      */
   315     public DiagnosticType getType() {
   316         return type;
   317     }
   319     /**
   320      * Check whether or not this diagnostic is required to be shown.
   321      * @return true if this diagnostic is required to be shown.
   322      */
   323     public boolean isMandatory() {
   324         return mandatory;
   325     }
   327     /**
   328      * Get the name of the source file referred to by this diagnostic.
   329      * @return the name of the source referred to with this diagnostic, or null if none
   330      */
   331     public JavaFileObject getSource() {
   332         if (source == null)
   333             return null;
   334         else
   335             return source.getFile();
   336     }
   338     /**
   339      * Get the name of the source file referred to by this diagnostic.
   340      * @return the name of the source referred to with this diagnostic, or null if none
   341      */
   342     public String getSourceName() {
   343         JavaFileObject s = getSource();
   344         return s == null ? null : JavacFileManager.getJavacFileName(s);
   345     }
   347     /**
   348      * Get the source referred to by this diagnostic.
   349      * @return the source referred to with this diagnostic, or null if none
   350      */
   351     public DiagnosticSource getDiagnosticSource() {
   352         return source;
   353     }
   355     protected int getIntStartPosition() {
   356         return (position == null ? Position.NOPOS : position.getStartPosition());
   357     }
   359     protected int getIntPosition() {
   360         return (position == null ? Position.NOPOS : position.getPreferredPosition());
   361     }
   363     protected int getIntEndPosition() {
   364         return (position == null ? Position.NOPOS : position.getEndPosition(source.getEndPosTable()));
   365     }
   367     public long getStartPosition() {
   368         return getIntStartPosition();
   369     }
   371     public long getPosition() {
   372         return getIntPosition();
   373     }
   375     public long getEndPosition() {
   376         return getIntEndPosition();
   377     }
   379     /**
   380      * Get the line number within the source referred to by this diagnostic.
   381      * @return  the line number within the source referred to by this diagnostic
   382      */
   383     public long getLineNumber() {
   384         return line;
   385     }
   387     /**
   388      * Get the column number within the line of source referred to by this diagnostic.
   389      * @return  the column number within the line of source referred to by this diagnostic
   390      */
   391     public long getColumnNumber() {
   392         return column;
   393     }
   395     /**
   396      * Get the arguments to be included in the text of the diagnostic.
   397      * @return  the arguments to be included in the text of the diagnostic
   398      */
   399     public Object[] getArgs() {
   400         return args;
   401     }
   403     /**
   404      * Get the prefix string associated with this type of diagnostic.
   405      * @return the prefix string associated with this type of diagnostic
   406      */
   407     public String getPrefix() {
   408         return getPrefix(type);
   409     }
   411     /**
   412      * Get the prefix string associated with a particular type of diagnostic.
   413      * @return the prefix string associated with a particular type of diagnostic
   414      */
   415     public String getPrefix(DiagnosticType dt) {
   416         switch (dt) {
   417         case FRAGMENT: return "";
   418         case NOTE:     return getLocalizedString("compiler.note.note");
   419         case WARNING:  return getLocalizedString("compiler.warn.warning");
   420         case ERROR:    return getLocalizedString("compiler.err.error");
   421         default:
   422             throw new AssertionError("Unknown diagnostic type: " + dt);
   423         }
   424     }
   426     /**
   427      * Return the standard presentation of this diagnostic.
   428      */
   429     public String toString() {
   430         if (defaultFormatter == null) {
   431             defaultFormatter =
   432                 new DiagnosticFormatter();
   433         }
   434         return defaultFormatter.format(this);
   435     }
   437     private static DiagnosticFormatter defaultFormatter;
   439     private static final String messageBundleName =
   440         "com.sun.tools.javac.resources.compiler";
   442     private String getLocalizedString(String key, Object... args) {
   443         String[] strings = new String[args.length];
   444         for (int i = 0; i < strings.length; i++) {
   445             Object arg = args[i];
   446             if (arg == null)
   447                 strings[i] = null;
   448             else if (arg instanceof JCDiagnostic)
   449                 strings[i] = ((JCDiagnostic) arg).getMessage(null);
   450             else
   451                 strings[i] = arg.toString();
   452         }
   454         return messages.getLocalizedString(key, (Object[]) strings);
   455     }
   457     // Methods for javax.tools.Diagnostic
   459     public Diagnostic.Kind getKind() {
   460         switch (type) {
   461         case NOTE:
   462             return Diagnostic.Kind.NOTE;
   463         case WARNING:
   464             return mandatory ? Diagnostic.Kind.MANDATORY_WARNING
   465                              : Diagnostic.Kind.WARNING;
   466         case ERROR:
   467             return Diagnostic.Kind.ERROR;
   468         default:
   469             return Diagnostic.Kind.OTHER;
   470         }
   471     }
   473     public String getCode() {
   474         return key;
   475     }
   477     public String getMessage(Locale locale) {
   478         // RFE 6406133: JCDiagnostic.getMessage ignores locale argument
   479         return getLocalizedString(key, args);
   480     }
   482 }

mercurial