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

Mon, 14 Nov 2011 15:11:10 -0800

author
ksrini
date
Mon, 14 Nov 2011 15:11:10 -0800
changeset 1138
7375d4979bd3
parent 1135
36553cb94345
child 1280
5c0b3faeb0b0
permissions
-rw-r--r--

7106166: (javac) re-factor EndPos parser
Reviewed-by: jjg

     1 /*
     2  * Copyright (c) 2003, 2011, Oracle and/or its affiliates. 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.  Oracle designates this
     8  * particular file as subject to the "Classpath" exception as provided
     9  * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
    22  * or visit www.oracle.com if you need additional information or have any
    23  * questions.
    24  */
    26 package com.sun.tools.javac.util;
    28 import java.util.EnumSet;
    29 import java.util.Locale;
    30 import java.util.Map;
    31 import java.util.Set;
    33 import javax.tools.Diagnostic;
    34 import javax.tools.JavaFileObject;
    36 import com.sun.tools.javac.api.DiagnosticFormatter;
    37 import com.sun.tools.javac.code.Lint.LintCategory;
    38 import com.sun.tools.javac.parser.EndPosTable;
    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 supported API.
    46  *  If 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         DiagnosticFormatter<JCDiagnostic> formatter;
    66         final String prefix;
    67         final Set<DiagnosticFlag> defaultErrorFlags;
    69         /** Create a new diagnostic factory. */
    70         protected Factory(Context context) {
    71             this(JavacMessages.instance(context), "compiler");
    72             context.put(diagnosticFactoryKey, this);
    74             final Options options = Options.instance(context);
    75             initOptions(options);
    76             options.addListener(new Runnable() {
    77                public void run() {
    78                    initOptions(options);
    79                }
    80             });
    81         }
    83         private void initOptions(Options options) {
    84             if (options.isSet("onlySyntaxErrorsUnrecoverable"))
    85                 defaultErrorFlags.add(DiagnosticFlag.RECOVERABLE);
    86         }
    88         /** Create a new diagnostic factory. */
    89         public Factory(JavacMessages messages, String prefix) {
    90             this.prefix = prefix;
    91             this.formatter = new BasicDiagnosticFormatter(messages);
    92             defaultErrorFlags = EnumSet.of(DiagnosticFlag.MANDATORY);
    93         }
    95         /**
    96          * Create an error diagnostic.
    97          *  @param source The source of the compilation unit, if any, in which to report the error.
    98          *  @param pos    The source position at which to report the error.
    99          *  @param key    The key for the localized error message.
   100          *  @param args   Fields of the error message.
   101          */
   102         public JCDiagnostic error(
   103                 DiagnosticSource source, DiagnosticPosition pos, String key, Object... args) {
   104             return create(ERROR, null, defaultErrorFlags, source, pos, key, args);
   105         }
   107         /**
   108          * Create a warning diagnostic that will not be hidden by the -nowarn or -Xlint:none options.
   109          *  @param source The source of the compilation unit, if any, in which to report the warning.
   110          *  @param pos    The source position at which to report the warning.
   111          *  @param key    The key for the localized warning message.
   112          *  @param args   Fields of the warning message.
   113          *  @see MandatoryWarningHandler
   114          */
   115         public JCDiagnostic mandatoryWarning(
   116                 DiagnosticSource source, DiagnosticPosition pos, String key, Object... args) {
   117             return create(WARNING, null, EnumSet.of(DiagnosticFlag.MANDATORY), source, pos, key, args);
   118         }
   120         /**
   121          * Create a warning diagnostic that will not be hidden by the -nowarn or -Xlint:none options.
   122          *  @param lc     The lint category for the diagnostic
   123          *  @param source The source of the compilation unit, if any, in which to report the warning.
   124          *  @param pos    The source position at which to report the warning.
   125          *  @param key    The key for the localized warning message.
   126          *  @param args   Fields of the warning message.
   127          *  @see MandatoryWarningHandler
   128          */
   129         public JCDiagnostic mandatoryWarning(
   130                 LintCategory lc,
   131                 DiagnosticSource source, DiagnosticPosition pos, String key, Object... args) {
   132             return create(WARNING, lc, EnumSet.of(DiagnosticFlag.MANDATORY), source, pos, key, args);
   133         }
   135         /**
   136          * Create a warning diagnostic.
   137          *  @param lc     The lint category for the diagnostic
   138          *  @param key    The key for the localized error message.
   139          *  @param args   Fields of the warning message.
   140          *  @see MandatoryWarningHandler
   141          */
   142         public JCDiagnostic warning(
   143                  LintCategory lc, String key, Object... args) {
   144             return create(WARNING, lc, EnumSet.noneOf(DiagnosticFlag.class), null, null, key, args);
   145         }
   147         /**
   148          * Create a warning diagnostic.
   149          *  @param source The source of the compilation unit, if any, in which to report the warning.
   150          *  @param pos    The source position at which to report the warning.
   151          *  @param key    The key for the localized warning message.
   152          *  @param args   Fields of the warning message.
   153          */
   154         public JCDiagnostic warning(
   155                 DiagnosticSource source, DiagnosticPosition pos, String key, Object... args) {
   156             return create(WARNING, null, EnumSet.noneOf(DiagnosticFlag.class), source, pos, key, args);
   157         }
   159         /**
   160          * Create a warning diagnostic.
   161          *  @param lc     The lint category for the diagnostic
   162          *  @param source The source of the compilation unit, if any, in which to report the warning.
   163          *  @param pos    The source position at which to report the warning.
   164          *  @param key    The key for the localized warning message.
   165          *  @param args   Fields of the warning message.
   166          *  @see MandatoryWarningHandler
   167          */
   168         public JCDiagnostic warning(
   169                  LintCategory lc, DiagnosticSource source, DiagnosticPosition pos, String key, Object... args) {
   170             return create(WARNING, lc, EnumSet.noneOf(DiagnosticFlag.class), source, pos, key, args);
   171         }
   173         /**
   174          * Create a note diagnostic that will not be hidden by the -nowarn or -Xlint:none options.
   175          *  @param key    The key for the localized message.
   176          *  @param args   Fields of the message.
   177          *  @see MandatoryWarningHandler
   178          */
   179         public JCDiagnostic mandatoryNote(DiagnosticSource source, String key, Object... args) {
   180             return create(NOTE, null, EnumSet.of(DiagnosticFlag.MANDATORY), source, null, key, args);
   181         }
   183         /**
   184          * Create a note diagnostic.
   185          *  @param key    The key for the localized error message.
   186          *  @param args   Fields of the message.
   187          */
   188         public JCDiagnostic note(String key, Object... args) {
   189             return create(NOTE, null, EnumSet.noneOf(DiagnosticFlag.class), null, null, key, args);
   190         }
   192         /**
   193          * Create a note diagnostic.
   194          *  @param source The source of the compilation unit, if any, in which to report the note.
   195          *  @param pos    The source position at which to report the note.
   196          *  @param key    The key for the localized message.
   197          *  @param args   Fields of the message.
   198          */
   199         public JCDiagnostic note(
   200                 DiagnosticSource source, DiagnosticPosition pos, String key, Object... args) {
   201             return create(NOTE, null, EnumSet.noneOf(DiagnosticFlag.class), source, pos, key, args);
   202         }
   204         /**
   205          * Create a fragment diagnostic, for use as an argument in other diagnostics
   206          *  @param key    The key for the localized message.
   207          *  @param args   Fields of the message.
   208          */
   209         public JCDiagnostic fragment(String key, Object... args) {
   210             return create(FRAGMENT, null, EnumSet.noneOf(DiagnosticFlag.class), null, null, key, args);
   211         }
   213         /**
   214          * Create a new diagnostic of the given kind, which is not mandatory and which has
   215          * no lint category.
   216          *  @param kind        The diagnostic kind
   217          *  @param ls          The lint category, if applicable, or null
   218          *  @param source      The source of the compilation unit, if any, in which to report the message.
   219          *  @param pos         The source position at which to report the message.
   220          *  @param key         The key for the localized message.
   221          *  @param args        Fields of the message.
   222          */
   223         public JCDiagnostic create(
   224                 DiagnosticType kind, DiagnosticSource source, DiagnosticPosition pos, String key, Object... args) {
   225             return create(kind, null, EnumSet.noneOf(DiagnosticFlag.class), source, pos, key, args);
   226         }
   228         /**
   229          * Create a new diagnostic of the given kind.
   230          *  @param kind        The diagnostic kind
   231          *  @param lc          The lint category, if applicable, or null
   232          *  @param isMandatory is diagnostic mandatory?
   233          *  @param source      The source of the compilation unit, if any, in which to report the message.
   234          *  @param pos         The source position at which to report the message.
   235          *  @param key         The key for the localized message.
   236          *  @param args        Fields of the message.
   237          */
   238         public JCDiagnostic create(
   239                 DiagnosticType kind, LintCategory lc, Set<DiagnosticFlag> flags, DiagnosticSource source, DiagnosticPosition pos, String key, Object... args) {
   240             return new JCDiagnostic(formatter, kind, lc, flags, source, pos, qualify(kind, key), args);
   241         }
   243         protected String qualify(DiagnosticType t, String key) {
   244             return prefix + "." + t.key + "." + key;
   245         }
   246     }
   250     /**
   251      * Create a fragment diagnostic, for use as an argument in other diagnostics
   252      *  @param key    The key for the localized error message.
   253      *  @param args   Fields of the error message.
   254      *
   255      */
   256     @Deprecated
   257     public static JCDiagnostic fragment(String key, Object... args) {
   258         return new JCDiagnostic(getFragmentFormatter(),
   259                               FRAGMENT,
   260                               null,
   261                               EnumSet.noneOf(DiagnosticFlag.class),
   262                               null,
   263                               null,
   264                               "compiler." + FRAGMENT.key + "." + key,
   265                               args);
   266     }
   267     //where
   268     @Deprecated
   269     public static DiagnosticFormatter<JCDiagnostic> getFragmentFormatter() {
   270         if (fragmentFormatter == null) {
   271             fragmentFormatter = new BasicDiagnosticFormatter(JavacMessages.getDefaultMessages());
   272         }
   273         return fragmentFormatter;
   274     }
   276     /**
   277      * A DiagnosticType defines the type of the diagnostic.
   278      **/
   279     public enum DiagnosticType {
   280         /** A fragment of an enclosing diagnostic. */
   281         FRAGMENT("misc"),
   282         /** A note: similar to, but less serious than, a warning. */
   283         NOTE("note"),
   284         /** A warning. */
   285         WARNING("warn"),
   286         /** An error. */
   287         ERROR("err");
   289         final String key;
   291         /** Create a DiagnosticType.
   292          * @param key A string used to create the resource key for the diagnostic.
   293          */
   294         DiagnosticType(String key) {
   295             this.key = key;
   296         }
   297     };
   299     /**
   300      * A DiagnosticPosition provides information about the positions in a file
   301      * that gave rise to a diagnostic. It always defines a "preferred" position
   302      * that most accurately defines the location of the diagnostic, it may also
   303      * provide a related tree node that spans that location.
   304      */
   305     public static interface DiagnosticPosition {
   306         /** Gets the tree node, if any, to which the diagnostic applies. */
   307         JCTree getTree();
   308         /** If there is a tree node, get the start position of the tree node.
   309          *  Otherwise, just returns the same as getPreferredPosition(). */
   310         int getStartPosition();
   311         /** Get the position within the file that most accurately defines the
   312          *  location for the diagnostic. */
   313         int getPreferredPosition();
   314         /** If there is a tree node, and if endPositions are available, get
   315          *  the end position of the tree node. Otherwise, just returns the
   316          *  same as getPreferredPosition(). */
   317         int getEndPosition(EndPosTable endPosTable);
   318     }
   320     /**
   321      * A DiagnosticPosition that simply identifies a position, but no related
   322      * tree node, as the location for a diagnostic. Used for scanner and parser
   323      * diagnostics. */
   324     public static class SimpleDiagnosticPosition implements DiagnosticPosition {
   325         public SimpleDiagnosticPosition(int pos) {
   326             this.pos = pos;
   327         }
   329         public JCTree getTree() {
   330             return null;
   331         }
   333         public int getStartPosition() {
   334             return pos;
   335         }
   337         public int getPreferredPosition() {
   338             return pos;
   339         }
   341         public int getEndPosition(EndPosTable endPosTable) {
   342             return pos;
   343         }
   345         private final int pos;
   346     }
   348     public enum DiagnosticFlag {
   349         MANDATORY,
   350         RESOLVE_ERROR,
   351         SYNTAX,
   352         RECOVERABLE
   353     }
   355     private final DiagnosticType type;
   356     private final DiagnosticSource source;
   357     private final DiagnosticPosition position;
   358     private final int line;
   359     private final int column;
   360     private final String key;
   361     protected final Object[] args;
   362     private final Set<DiagnosticFlag> flags;
   363     private final LintCategory lintCategory;
   365     /**
   366      * Create a diagnostic object.
   367      * @param fomatter the formatter to use for the diagnostic
   368      * @param dt the type of diagnostic
   369      * @param lc     the lint category for the diagnostic
   370      * @param source the name of the source file, or null if none.
   371      * @param pos the character offset within the source file, if given.
   372      * @param key a resource key to identify the text of the diagnostic
   373      * @param args arguments to be included in the text of the diagnostic
   374      */
   375     protected JCDiagnostic(DiagnosticFormatter<JCDiagnostic> formatter,
   376                        DiagnosticType dt,
   377                        LintCategory lc,
   378                        Set<DiagnosticFlag> flags,
   379                        DiagnosticSource source,
   380                        DiagnosticPosition pos,
   381                        String key,
   382                        Object... args) {
   383         if (source == null && pos != null && pos.getPreferredPosition() != Position.NOPOS)
   384             throw new IllegalArgumentException();
   386         this.defaultFormatter = formatter;
   387         this.type = dt;
   388         this.lintCategory = lc;
   389         this.flags = flags;
   390         this.source = source;
   391         this.position = pos;
   392         this.key = key;
   393             this.args = args;
   395         int n = (pos == null ? Position.NOPOS : pos.getPreferredPosition());
   396         if (n == Position.NOPOS || source == null)
   397             line = column = -1;
   398         else {
   399             line = source.getLineNumber(n);
   400             column = source.getColumnNumber(n, true);
   401         }
   402     }
   404     /**
   405      * Get the type of this diagnostic.
   406      * @return the type of this diagnostic
   407      */
   408     public DiagnosticType getType() {
   409         return type;
   410     }
   412     /**
   413      * Get the subdiagnostic list
   414      * @return subdiagnostic list
   415      */
   416     public List<JCDiagnostic> getSubdiagnostics() {
   417         return List.nil();
   418     }
   420     public boolean isMultiline() {
   421         return false;
   422     }
   424     /**
   425      * Check whether or not this diagnostic is required to be shown.
   426      * @return true if this diagnostic is required to be shown.
   427      */
   428     public boolean isMandatory() {
   429         return flags.contains(DiagnosticFlag.MANDATORY);
   430     }
   432     /**
   433      * Check whether this diagnostic has an associated lint category.
   434      */
   435     public boolean hasLintCategory() {
   436         return (lintCategory != null);
   437     }
   439     /**
   440      * Get the associated lint category, or null if none.
   441      */
   442     public LintCategory getLintCategory() {
   443         return lintCategory;
   444     }
   446     /**
   447      * Get the name of the source file referred to by this diagnostic.
   448      * @return the name of the source referred to with this diagnostic, or null if none
   449      */
   450     public JavaFileObject getSource() {
   451         if (source == null)
   452             return null;
   453         else
   454             return source.getFile();
   455     }
   457     /**
   458      * Get the source referred to by this diagnostic.
   459      * @return the source referred to with this diagnostic, or null if none
   460      */
   461     public DiagnosticSource getDiagnosticSource() {
   462         return source;
   463     }
   465     protected int getIntStartPosition() {
   466         return (position == null ? Position.NOPOS : position.getStartPosition());
   467     }
   469     protected int getIntPosition() {
   470         return (position == null ? Position.NOPOS : position.getPreferredPosition());
   471     }
   473     protected int getIntEndPosition() {
   474         return (position == null ? Position.NOPOS : position.getEndPosition(source.getEndPosTable()));
   475     }
   477     public long getStartPosition() {
   478         return getIntStartPosition();
   479     }
   481     public long getPosition() {
   482         return getIntPosition();
   483     }
   485     public long getEndPosition() {
   486         return getIntEndPosition();
   487     }
   489     /**
   490      * Get the line number within the source referred to by this diagnostic.
   491      * @return  the line number within the source referred to by this diagnostic
   492      */
   493     public long getLineNumber() {
   494         return line;
   495     }
   497     /**
   498      * Get the column number within the line of source referred to by this diagnostic.
   499      * @return  the column number within the line of source referred to by this diagnostic
   500      */
   501     public long getColumnNumber() {
   502         return column;
   503     }
   505     /**
   506      * Get the arguments to be included in the text of the diagnostic.
   507      * @return  the arguments to be included in the text of the diagnostic
   508      */
   509     public Object[] getArgs() {
   510         return args;
   511     }
   513     /**
   514      * Get the prefix string associated with this type of diagnostic.
   515      * @return the prefix string associated with this type of diagnostic
   516      */
   517     public String getPrefix() {
   518         return getPrefix(type);
   519     }
   521     /**
   522      * Get the prefix string associated with a particular type of diagnostic.
   523      * @return the prefix string associated with a particular type of diagnostic
   524      */
   525     public String getPrefix(DiagnosticType dt) {
   526         return defaultFormatter.formatKind(this, Locale.getDefault());
   527     }
   529     /**
   530      * Return the standard presentation of this diagnostic.
   531      */
   532     @Override
   533     public String toString() {
   534         return defaultFormatter.format(this,Locale.getDefault());
   535     }
   537     private DiagnosticFormatter<JCDiagnostic> defaultFormatter;
   538     @Deprecated
   539     private static DiagnosticFormatter<JCDiagnostic> fragmentFormatter;
   541     // Methods for javax.tools.Diagnostic
   543     public Diagnostic.Kind getKind() {
   544         switch (type) {
   545         case NOTE:
   546             return Diagnostic.Kind.NOTE;
   547         case WARNING:
   548             return flags.contains(DiagnosticFlag.MANDATORY)
   549                     ? Diagnostic.Kind.MANDATORY_WARNING
   550                     : Diagnostic.Kind.WARNING;
   551         case ERROR:
   552             return Diagnostic.Kind.ERROR;
   553         default:
   554             return Diagnostic.Kind.OTHER;
   555         }
   556     }
   558     public String getCode() {
   559         return key;
   560     }
   562     public String getMessage(Locale locale) {
   563         return defaultFormatter.formatMessage(this, locale);
   564     }
   566     public void setFlag(DiagnosticFlag flag) {
   567         flags.add(flag);
   569         if (type == DiagnosticType.ERROR) {
   570             switch (flag) {
   571                 case SYNTAX:
   572                     flags.remove(DiagnosticFlag.RECOVERABLE);
   573                     break;
   574                 case RESOLVE_ERROR:
   575                     flags.add(DiagnosticFlag.RECOVERABLE);
   576                     break;
   577             }
   578         }
   579     }
   581     public boolean isFlagSet(DiagnosticFlag flag) {
   582         return flags.contains(flag);
   583     }
   585     public static class MultilineDiagnostic extends JCDiagnostic {
   587         private final List<JCDiagnostic> subdiagnostics;
   589         public MultilineDiagnostic(JCDiagnostic other, List<JCDiagnostic> subdiagnostics) {
   590             super(other.defaultFormatter,
   591                   other.getType(),
   592                   other.getLintCategory(),
   593                   other.flags,
   594                   other.getDiagnosticSource(),
   595                   other.position,
   596                   other.getCode(),
   597                   other.getArgs());
   598             this.subdiagnostics = subdiagnostics;
   599         }
   601         @Override
   602         public List<JCDiagnostic> getSubdiagnostics() {
   603             return subdiagnostics;
   604         }
   606         @Override
   607         public boolean isMultiline() {
   608             return true;
   609         }
   610     }
   611 }

mercurial