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

Mon, 09 Mar 2009 23:53:41 -0700

author
tbell
date
Mon, 09 Mar 2009 23:53:41 -0700
changeset 240
8c55d5b0ed71
parent 229
03bcd66bd8e7
parent 238
86b60aa941c6
child 288
d402db1005ad
permissions
-rw-r--r--

Merge

     1 /*
     2  * Copyright 2005-2009 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 java.util.EnumSet;
    30 import java.util.HashMap;
    31 import java.util.Locale;
    32 import java.util.Map;
    33 import java.util.regex.Matcher;
    34 import javax.tools.JavaFileObject;
    36 import com.sun.tools.javac.util.AbstractDiagnosticFormatter.SimpleConfiguration;
    37 import com.sun.tools.javac.util.BasicDiagnosticFormatter.BasicConfiguration;
    39 import static com.sun.tools.javac.api.DiagnosticFormatter.PositionKind.*;
    40 import static com.sun.tools.javac.util.BasicDiagnosticFormatter.BasicConfiguration.*;
    41 import static com.sun.tools.javac.util.LayoutCharacters.*;
    43 /**
    44  * A basic formatter for diagnostic messages.
    45  * The basic formatter will format a diagnostic according to one of three format patterns, depending on whether
    46  * or not the source name and position are set. The formatter supports a printf-like string for patterns
    47  * with the following special characters:
    48  * <ul>
    49  * <li>%b: the base of the source name
    50  * <li>%f: the source name (full absolute path)
    51  * <li>%l: the line number of the diagnostic, derived from the character offset
    52  * <li>%c: the column number of the diagnostic, derived from the character offset
    53  * <li>%o: the character offset of the diagnostic if set
    54  * <li>%p: the prefix for the diagnostic, derived from the diagnostic type
    55  * <li>%t: the prefix as it normally appears in standard diagnostics. In this case, no prefix is
    56  *        shown if the type is ERROR and if a source name is set
    57  * <li>%m: the text or the diagnostic, including any appropriate arguments
    58  * <li>%_: space delimiter, useful for formatting purposes
    59  * </ul>
    60  */
    61 public class BasicDiagnosticFormatter extends AbstractDiagnosticFormatter {
    63     protected int currentIndentation = 0;
    65     /**
    66      * Create a basic formatter based on the supplied options.
    67      *
    68      * @param opts list of command-line options
    69      * @param msgs JavacMessages object used for i18n
    70      */
    71     @SuppressWarnings("fallthrough")
    72     public BasicDiagnosticFormatter(Options options, JavacMessages msgs) {
    73         super(msgs, new BasicConfiguration(options));
    74     }
    76     /**
    77      * Create a standard basic formatter
    78      *
    79      * @param msgs JavacMessages object used for i18n
    80      */
    81     public BasicDiagnosticFormatter(JavacMessages msgs) {
    82         super(msgs, new BasicConfiguration());
    83     }
    85     public String formatDiagnostic(JCDiagnostic d, Locale l) {
    86         if (l == null)
    87             l = messages.getCurrentLocale();
    88         String format = selectFormat(d);
    89         StringBuilder buf = new StringBuilder();
    90         for (int i = 0; i < format.length(); i++) {
    91             char c = format.charAt(i);
    92             boolean meta = false;
    93             if (c == '%' && i < format.length() - 1) {
    94                 meta = true;
    95                 c = format.charAt(++i);
    96             }
    97             buf.append(meta ? formatMeta(c, d, l) : String.valueOf(c));
    98         }
    99         if (depth == 0)
   100             return addSourceLineIfNeeded(d, buf.toString());
   101         else
   102             return buf.toString();
   103     }
   105     public String formatMessage(JCDiagnostic d, Locale l) {
   106         int prevIndentation = currentIndentation;
   107         try {
   108             StringBuilder buf = new StringBuilder();
   109             Collection<String> args = formatArguments(d, l);
   110             String msg = localize(l, d.getCode(), args.toArray());
   111             String[] lines = msg.split("\n");
   112             if (getConfiguration().getVisible().contains(DiagnosticPart.SUMMARY)) {
   113                 currentIndentation += getConfiguration().getIndentation(DiagnosticPart.SUMMARY);
   114                 buf.append(indent(lines[0], currentIndentation)); //summary
   115             }
   116             if (lines.length > 1 && getConfiguration().getVisible().contains(DiagnosticPart.DETAILS)) {
   117                 currentIndentation += getConfiguration().getIndentation(DiagnosticPart.DETAILS);
   118                 for (int i = 1;i < lines.length; i++) {
   119                     buf.append("\n" + indent(lines[i], currentIndentation));
   120                 }
   121             }
   122             if (d.isMultiline() && getConfiguration().getVisible().contains(DiagnosticPart.SUBDIAGNOSTICS)) {
   123                 currentIndentation += getConfiguration().getIndentation(DiagnosticPart.SUBDIAGNOSTICS);
   124                 for (String sub : formatSubdiagnostics(d, l)) {
   125                     buf.append("\n" + sub);
   126                 }
   127             }
   128             return buf.toString();
   129         }
   130         finally {
   131             currentIndentation = prevIndentation;
   132         }
   133     }
   135     protected String addSourceLineIfNeeded(JCDiagnostic d, String msg) {
   136         if (!displaySource(d))
   137             return msg;
   138         else {
   139             BasicConfiguration conf = getConfiguration();
   140             int indentSource = conf.getIndentation(DiagnosticPart.SOURCE);
   141             String sourceLine = "\n" + formatSourceLine(d, indentSource);
   142             boolean singleLine = msg.indexOf("\n") == -1;
   143             if (singleLine || getConfiguration().getSourcePosition() == SourcePosition.BOTTOM)
   144                 return msg + sourceLine;
   145             else
   146                 return msg.replaceFirst("\n", Matcher.quoteReplacement(sourceLine) + "\n");
   147         }
   148     }
   150     protected String formatMeta(char c, JCDiagnostic d, Locale l) {
   151         switch (c) {
   152             case 'b':
   153                 return formatSource(d, false, l);
   154             case 'e':
   155                 return formatPosition(d, END, l);
   156             case 'f':
   157                 return formatSource(d, true, l);
   158             case 'l':
   159                 return formatPosition(d, LINE, l);
   160             case 'c':
   161                 return formatPosition(d, COLUMN, l);
   162             case 'o':
   163                 return formatPosition(d, OFFSET, l);
   164             case 'p':
   165                 return formatKind(d, l);
   166             case 's':
   167                 return formatPosition(d, START, l);
   168             case 't': {
   169                 boolean usePrefix;
   170                 switch (d.getType()) {
   171                 case FRAGMENT:
   172                     usePrefix = false;
   173                     break;
   174                 case ERROR:
   175                     usePrefix = (d.getIntPosition() == Position.NOPOS);
   176                     break;
   177                 default:
   178                     usePrefix = true;
   179                 }
   180                 if (usePrefix)
   181                     return formatKind(d, l);
   182                 else
   183                     return "";
   184             }
   185             case 'm':
   186                 return formatMessage(d, l);
   187             case '_':
   188                 return " ";
   189             case '%':
   190                 return "%";
   191             default:
   192                 return String.valueOf(c);
   193         }
   194     }
   196     private String selectFormat(JCDiagnostic d) {
   197         DiagnosticSource source = d.getDiagnosticSource();
   198         String format = getConfiguration().getFormat(BasicFormatKind.DEFAULT_NO_POS_FORMAT);
   199         if (source != null) {
   200             if (d.getIntPosition() != Position.NOPOS) {
   201                 format = getConfiguration().getFormat(BasicFormatKind.DEFAULT_POS_FORMAT);
   202             } else if (source.getFile() != null &&
   203                        source.getFile().getKind() == JavaFileObject.Kind.CLASS) {
   204                 format = getConfiguration().getFormat(BasicFormatKind.DEFAULT_CLASS_FORMAT);
   205             }
   206         }
   207         return format;
   208     }
   210     @Override
   211     public BasicConfiguration getConfiguration() {
   212         return (BasicConfiguration)super.getConfiguration();
   213     }
   215     static public class BasicConfiguration extends SimpleConfiguration {
   217         protected Map<DiagnosticPart, Integer> indentationLevels;
   218         protected Map<BasicFormatKind, String> availableFormats;
   219         protected SourcePosition sourcePosition;
   221         @SuppressWarnings("fallthrough")
   222         public BasicConfiguration(Options options) {
   223             super(options, EnumSet.of(DiagnosticPart.SUMMARY,
   224                             DiagnosticPart.DETAILS,
   225                             DiagnosticPart.SUBDIAGNOSTICS,
   226                             DiagnosticPart.SOURCE));
   227             initFormat();
   228             initIndentation();
   229             String fmt = options.get("diagsFormat");
   230             if (fmt != null) {
   231                 String[] formats = fmt.split("\\|");
   232                 switch (formats.length) {
   233                     case 3:
   234                         setFormat(BasicFormatKind.DEFAULT_CLASS_FORMAT, formats[2]);
   235                     case 2:
   236                         setFormat(BasicFormatKind.DEFAULT_NO_POS_FORMAT, formats[1]);
   237                     default:
   238                         setFormat(BasicFormatKind.DEFAULT_POS_FORMAT, formats[0]);
   239                 }
   240             }
   241             String sourcePosition = null;
   242             if ((((sourcePosition = options.get("sourcePosition")) != null)) &&
   243                     sourcePosition.equals("bottom"))
   244                     setSourcePosition(SourcePosition.BOTTOM);
   245             else
   246                 setSourcePosition(SourcePosition.AFTER_SUMMARY);
   247             String indent = options.get("diagsIndentation");
   248             if (indent != null) {
   249                 String[] levels = indent.split("\\|");
   250                 try {
   251                     switch (levels.length) {
   252                         case 5:
   253                             setIndentation(DiagnosticPart.JLS,
   254                                     Integer.parseInt(levels[4]));
   255                         case 4:
   256                             setIndentation(DiagnosticPart.SUBDIAGNOSTICS,
   257                                     Integer.parseInt(levels[3]));
   258                         case 3:
   259                             setIndentation(DiagnosticPart.SOURCE,
   260                                     Integer.parseInt(levels[2]));
   261                         case 2:
   262                             setIndentation(DiagnosticPart.DETAILS,
   263                                     Integer.parseInt(levels[1]));
   264                         default:
   265                             setIndentation(DiagnosticPart.SUMMARY,
   266                                     Integer.parseInt(levels[0]));
   267                     }
   268                 }
   269                 catch (NumberFormatException ex) {
   270                     initIndentation();
   271                 }
   272             }
   273         }
   275         public BasicConfiguration() {
   276             super(EnumSet.of(DiagnosticPart.SUMMARY,
   277                   DiagnosticPart.DETAILS,
   278                   DiagnosticPart.SUBDIAGNOSTICS,
   279                   DiagnosticPart.SOURCE));
   280             initFormat();
   281             initIndentation();
   282         }
   283         //where
   284         private void initFormat() {
   285             availableFormats = new HashMap<BasicFormatKind, String>();
   286             setFormat(BasicFormatKind.DEFAULT_POS_FORMAT, "%f:%l:%_%t%m");
   287             setFormat(BasicFormatKind.DEFAULT_NO_POS_FORMAT, "%p%m");
   288             setFormat(BasicFormatKind.DEFAULT_CLASS_FORMAT, "%f:%_%t%m");
   289         }
   290         //where
   291         private void initIndentation() {
   292             indentationLevels = new HashMap<DiagnosticPart, Integer>();
   293             setIndentation(DiagnosticPart.SUMMARY, 0);
   294             setIndentation(DiagnosticPart.DETAILS, DetailsInc);
   295             setIndentation(DiagnosticPart.SUBDIAGNOSTICS, DiagInc);
   296             setIndentation(DiagnosticPart.SOURCE, 0);
   297         }
   299         /**
   300          * Get the amount of spaces for a given indentation kind
   301          * @param diagPart the diagnostic part for which the indentation is
   302          * to be retrieved
   303          * @return the amount of spaces used for the specified indentation kind
   304          */
   305         public int getIndentation(DiagnosticPart diagPart) {
   306             return indentationLevels.get(diagPart);
   307         }
   309         /**
   310          * Set the indentation level for various element of a given diagnostic -
   311          * this might lead to more readable diagnostics
   312          *
   313          * @param indentationKind kind of indentation to be set
   314          * @param nSpaces amount of spaces for the specified diagnostic part
   315          */
   316         public void setIndentation(DiagnosticPart diagPart, int nSpaces) {
   317             indentationLevels.put(diagPart, nSpaces);
   318         }
   320         /**
   321          * Set the source line positioning used by this formatter
   322          *
   323          * @param sourcePos a positioning value for source line
   324          */
   325         public void setSourcePosition(SourcePosition sourcePos) {
   326             sourcePosition = sourcePos;
   327         }
   329         /**
   330          * Get the source line positioning used by this formatter
   331          *
   332          * @return the positioning value used by this formatter
   333          */
   334         public SourcePosition getSourcePosition() {
   335             return sourcePosition;
   336         }
   337         //where
   338         /**
   339          * A source positioning value controls the position (within a given
   340          * diagnostic message) in which the source line the diagnostic refers to
   341          * should be displayed (if applicable)
   342          */
   343         public enum SourcePosition {
   344             /**
   345              * Source line is displayed after the diagnostic message
   346              */
   347             BOTTOM,
   348             /**
   349              * Source line is displayed after the first line of the diagnostic
   350              * message
   351              */
   352             AFTER_SUMMARY;
   353         }
   355         /**
   356          * Set a metachar string for a specific format
   357          *
   358          * @param kind the format kind to be set
   359          * @param s the metachar string specifying the format
   360          */
   361         public void setFormat(BasicFormatKind kind, String s) {
   362             availableFormats.put(kind, s);
   363         }
   365         /**
   366          * Get a metachar string for a specific format
   367          *
   368          * @param sourcePos a positioning value for source line
   369          */
   370         public String getFormat(BasicFormatKind kind) {
   371             return availableFormats.get(kind);
   372         }
   373         //where
   374         /**
   375          * This enum contains all the kinds of formatting patterns supported
   376          * by a basic diagnostic formatter.
   377          */
   378         public enum BasicFormatKind {
   379             /**
   380             * A format string to be used for diagnostics with a given position.
   381             */
   382             DEFAULT_POS_FORMAT,
   383             /**
   384             * A format string to be used for diagnostics without a given position.
   385             */
   386             DEFAULT_NO_POS_FORMAT,
   387             /**
   388             * A format string to be used for diagnostics regarding classfiles
   389             */
   390             DEFAULT_CLASS_FORMAT;
   391         }
   392     }
   393 }

mercurial