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

Tue, 28 Dec 2010 15:54:52 -0800

author
ohair
date
Tue, 28 Dec 2010 15:54:52 -0800
changeset 798
4868a36f6fd8
parent 689
77cc34d5e548
child 929
e2890b8369f7
permissions
-rw-r--r--

6962318: Update copyright year
Reviewed-by: xdono

     1 /*
     2  * Copyright (c) 2005, 2010, 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.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  * <p><b>This is NOT part of any supported API.
    62  * If you write code that depends on this, you do so at your own risk.
    63  * This code and its internal interfaces are subject to change or
    64  * deletion without notice.</b>
    65  */
    66 public class BasicDiagnosticFormatter extends AbstractDiagnosticFormatter {
    68     /**
    69      * Create a basic formatter based on the supplied options.
    70      *
    71      * @param opts list of command-line options
    72      * @param msgs JavacMessages object used for i18n
    73      */
    74     public BasicDiagnosticFormatter(Options options, JavacMessages msgs) {
    75         super(msgs, new BasicConfiguration(options));
    76     }
    78     /**
    79      * Create a standard basic formatter
    80      *
    81      * @param msgs JavacMessages object used for i18n
    82      */
    83     public BasicDiagnosticFormatter(JavacMessages msgs) {
    84         super(msgs, new BasicConfiguration());
    85     }
    87     public String formatDiagnostic(JCDiagnostic d, Locale l) {
    88         if (l == null)
    89             l = messages.getCurrentLocale();
    90         String format = selectFormat(d);
    91         StringBuilder buf = new StringBuilder();
    92         for (int i = 0; i < format.length(); i++) {
    93             char c = format.charAt(i);
    94             boolean meta = false;
    95             if (c == '%' && i < format.length() - 1) {
    96                 meta = true;
    97                 c = format.charAt(++i);
    98             }
    99             buf.append(meta ? formatMeta(c, d, l) : String.valueOf(c));
   100         }
   101         if (depth == 0)
   102             return addSourceLineIfNeeded(d, buf.toString());
   103         else
   104             return buf.toString();
   105     }
   107     public String formatMessage(JCDiagnostic d, Locale l) {
   108         int currentIndentation = 0;
   109         StringBuilder buf = new StringBuilder();
   110         Collection<String> args = formatArguments(d, l);
   111         String msg = localize(l, d.getCode(), args.toArray());
   112         String[] lines = msg.split("\n");
   113         if (getConfiguration().getVisible().contains(DiagnosticPart.SUMMARY)) {
   114             currentIndentation += getConfiguration().getIndentation(DiagnosticPart.SUMMARY);
   115             buf.append(indent(lines[0], currentIndentation)); //summary
   116         }
   117         if (lines.length > 1 && getConfiguration().getVisible().contains(DiagnosticPart.DETAILS)) {
   118             currentIndentation += getConfiguration().getIndentation(DiagnosticPart.DETAILS);
   119             for (int i = 1;i < lines.length; i++) {
   120                 buf.append("\n" + indent(lines[i], currentIndentation));
   121             }
   122         }
   123         if (d.isMultiline() && getConfiguration().getVisible().contains(DiagnosticPart.SUBDIAGNOSTICS)) {
   124             currentIndentation += getConfiguration().getIndentation(DiagnosticPart.SUBDIAGNOSTICS);
   125                 for (String sub : formatSubdiagnostics(d, l)) {
   126                     buf.append("\n" + indent(sub, currentIndentation));
   127             }
   128         }
   129         return buf.toString();
   130     }
   132     protected String addSourceLineIfNeeded(JCDiagnostic d, String msg) {
   133         if (!displaySource(d))
   134             return msg;
   135         else {
   136             BasicConfiguration conf = getConfiguration();
   137             int indentSource = conf.getIndentation(DiagnosticPart.SOURCE);
   138             String sourceLine = "\n" + formatSourceLine(d, indentSource);
   139             boolean singleLine = msg.indexOf("\n") == -1;
   140             if (singleLine || getConfiguration().getSourcePosition() == SourcePosition.BOTTOM)
   141                 return msg + sourceLine;
   142             else
   143                 return msg.replaceFirst("\n", Matcher.quoteReplacement(sourceLine) + "\n");
   144         }
   145     }
   147     protected String formatMeta(char c, JCDiagnostic d, Locale l) {
   148         switch (c) {
   149             case 'b':
   150                 return formatSource(d, false, l);
   151             case 'e':
   152                 return formatPosition(d, END, l);
   153             case 'f':
   154                 return formatSource(d, true, l);
   155             case 'l':
   156                 return formatPosition(d, LINE, l);
   157             case 'c':
   158                 return formatPosition(d, COLUMN, l);
   159             case 'o':
   160                 return formatPosition(d, OFFSET, l);
   161             case 'p':
   162                 return formatKind(d, l);
   163             case 's':
   164                 return formatPosition(d, START, l);
   165             case 't': {
   166                 boolean usePrefix;
   167                 switch (d.getType()) {
   168                 case FRAGMENT:
   169                     usePrefix = false;
   170                     break;
   171                 case ERROR:
   172                     usePrefix = (d.getIntPosition() == Position.NOPOS);
   173                     break;
   174                 default:
   175                     usePrefix = true;
   176                 }
   177                 if (usePrefix)
   178                     return formatKind(d, l);
   179                 else
   180                     return "";
   181             }
   182             case 'm':
   183                 return formatMessage(d, l);
   184             case 'L':
   185                 return formatLintCategory(d, l);
   186             case '_':
   187                 return " ";
   188             case '%':
   189                 return "%";
   190             default:
   191                 return String.valueOf(c);
   192         }
   193     }
   195     private String selectFormat(JCDiagnostic d) {
   196         DiagnosticSource source = d.getDiagnosticSource();
   197         String format = getConfiguration().getFormat(BasicFormatKind.DEFAULT_NO_POS_FORMAT);
   198         if (source != null && source != DiagnosticSource.NO_SOURCE) {
   199             if (d.getIntPosition() != Position.NOPOS) {
   200                 format = getConfiguration().getFormat(BasicFormatKind.DEFAULT_POS_FORMAT);
   201             } else if (source.getFile() != null &&
   202                        source.getFile().getKind() == JavaFileObject.Kind.CLASS) {
   203                 format = getConfiguration().getFormat(BasicFormatKind.DEFAULT_CLASS_FORMAT);
   204             }
   205         }
   206         return format;
   207     }
   209     @Override
   210     public BasicConfiguration getConfiguration() {
   211         //the following cast is always safe - see init
   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 srcPos = null;
   242             if ((((srcPos = options.get("sourcePosition")) != null)) &&
   243                     srcPos.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%L%m");
   287             setFormat(BasicFormatKind.DEFAULT_NO_POS_FORMAT, "%p%L%m");
   288             setFormat(BasicFormatKind.DEFAULT_CLASS_FORMAT, "%f:%_%t%L%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