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

Wed, 12 Nov 2008 14:17:03 +0000

author
mcimadamore
date
Wed, 12 Nov 2008 14:17:03 +0000
changeset 168
4cdaaf4c5dca
parent 137
e4eaddca54b7
child 221
6ada6122dd4f
permissions
-rw-r--r--

6768932: Add support for multiline diagnostics
Summary: Added basic support for multiline/tabular diagnostics
Reviewed-by: jjg

     1 /*
     2  * Copyright 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  */
    25 package com.sun.tools.javac.util;
    27 import java.util.Collection;
    28 import java.util.Locale;
    29 import javax.tools.JavaFileObject;
    31 import com.sun.tools.javac.api.DiagnosticFormatter;
    32 import com.sun.tools.javac.api.Formattable;
    33 import com.sun.tools.javac.api.DiagnosticFormatter.PositionKind;
    34 import com.sun.tools.javac.file.JavacFileManager;
    35 import static com.sun.tools.javac.util.JCDiagnostic.DiagnosticType.*;
    36 import static com.sun.tools.javac.util.LayoutCharacters.*;
    38 /**
    39  * This abstract class provides a basic implementation of the functionalities that should be provided
    40  * by any formatter used by javac. Among the main features provided by AbstractDiagnosticFormatter are:
    41  *
    42  * <ul>
    43  *  <li> Provides a standard implementation of the visitor-like methods defined in the interface DiagnisticFormatter.
    44  *  Those implementations are specifically targeting JCDiagnostic objects.
    45  *  <li> Provides basic support for i18n and a method for executing all locale-dependent conversions
    46  *  <li> Provides the formatting logic for rendering the arguments of a JCDiagnostic object.
    47  * <ul>
    48  *
    49  */
    50 public abstract class AbstractDiagnosticFormatter implements DiagnosticFormatter<JCDiagnostic> {
    52     /**
    53      * JavacMessages object used by this formatter for i18n
    54      */
    55     protected JavacMessages messages;
    56     protected boolean showSource;
    58     /**
    59      * Initialize an AbstractDiagnosticFormatter by setting its JavacMessages object
    60      * @param messages
    61      */
    62     protected AbstractDiagnosticFormatter(JavacMessages messages, Options options, boolean showSource) {
    63         this.messages = messages;
    64         this.showSource = options.get("showSource") == null ? showSource :
    65                           options.get("showSource").equals("true");
    66     }
    68     protected AbstractDiagnosticFormatter(JavacMessages messages, boolean showSource) {
    69         this.messages = messages;
    70         this.showSource = showSource;
    71     }
    73     public String formatMessage(JCDiagnostic d, Locale l) {
    74         //this code should rely on the locale settings but it's not! See RFE 6443132
    75         StringBuilder buf = new StringBuilder();
    76         Collection<String> args = formatArguments(d, l);
    77         buf.append(localize(l, d.getCode(), args.toArray()));
    78         if (d.isMultiline()) {
    79             buf.append(formatSubdiagnostics(d, l));
    80         }
    81         return buf.toString();
    82     }
    84     public String formatKind(JCDiagnostic d, Locale l) {
    85         switch (d.getType()) {
    86             case FRAGMENT: return "";
    87             case NOTE:     return localize(l, "compiler.note.note");
    88             case WARNING:  return localize(l, "compiler.warn.warning");
    89             case ERROR:    return localize(l, "compiler.err.error");
    90             default:
    91                 throw new AssertionError("Unknown diagnostic type: " + d.getType());
    92         }
    93     }
    95     public String formatPosition(JCDiagnostic d, PositionKind pk,Locale l) {
    96         assert (d.getPosition() != Position.NOPOS);
    97         return String.valueOf(getPosition(d, pk));
    98     }
    99     //WHERE
   100     public long getPosition(JCDiagnostic d, PositionKind pk) {
   101         switch (pk) {
   102             case START: return d.getIntStartPosition();
   103             case END: return d.getIntEndPosition();
   104             case LINE: return d.getLineNumber();
   105             case COLUMN: return d.getColumnNumber();
   106             case OFFSET: return d.getIntPosition();
   107             default:
   108                 throw new AssertionError("Unknown diagnostic position: " + pk);
   109         }
   110     }
   112     public String formatSource(JCDiagnostic d, boolean fullname, Locale l) {
   113         assert (d.getSource() != null);
   114         return fullname ? d.getSourceName() : d.getSource().getName();
   115     }
   117     /**
   118      * Format the arguments of a given diagnostic.
   119      *
   120      * @param d diagnostic whose arguments are to be formatted
   121      * @param l locale object to be used for i18n
   122      * @return a Collection whose elements are the formatted arguments of the diagnostic
   123      */
   124     protected Collection<String> formatArguments(JCDiagnostic d, Locale l) {
   125         ListBuffer<String> buf = new ListBuffer<String>();
   126         for (Object o : d.getArgs()) {
   127            buf.append(formatArgument(d, o, l));
   128         }
   129         return buf.toList();
   130     }
   132     /**
   133      * Format a single argument of a given diagnostic.
   134      *
   135      * @param d diagnostic whose argument is to be formatted
   136      * @param arg argument to be formatted
   137      * @param l locale object to be used for i18n
   138      * @return string representation of the diagnostic argument
   139      */
   140     protected String formatArgument(JCDiagnostic d, Object arg, Locale l) {
   141         if (arg instanceof JCDiagnostic)
   142             return format((JCDiagnostic)arg, l);
   143         else if (arg instanceof Iterable<?>) {
   144             return formatIterable(d, (Iterable<?>)arg, l);
   145         }
   146         else if (arg instanceof JavaFileObject)
   147             return JavacFileManager.getJavacBaseFileName((JavaFileObject)arg);
   148         else if (arg instanceof Formattable)
   149             return ((Formattable)arg).toString(l, messages);
   150         else
   151             return String.valueOf(arg);
   152     }
   154     /**
   155      * Format an iterable argument of a given diagnostic.
   156      *
   157      * @param d diagnostic whose argument is to be formatted
   158      * @param it iterable argument to be formatted
   159      * @param l locale object to be used for i18n
   160      * @return string representation of the diagnostic iterable argument
   161      */
   162     protected String formatIterable(JCDiagnostic d, Iterable<?> it, Locale l) {
   163         StringBuilder sbuf = new StringBuilder();
   164         String sep = "";
   165         for (Object o : it) {
   166             sbuf.append(sep);
   167             sbuf.append(formatArgument(d, o, l));
   168             sep = ",";
   169         }
   170         return sbuf.toString();
   171     }
   173     /**
   174      * Format all the subdiagnostics attached to a given diagnostic
   175      *
   176      * @param d diagnostic whose subdiagnostics are to be formatted
   177      * @param l locale object to be used for i18n
   178      * @return string representation of the subdiagnostics
   179      */
   180     protected String formatSubdiagnostics(JCDiagnostic d, Locale l) {
   181         StringBuilder buf = new StringBuilder();
   182         for (JCDiagnostic d2 : d.getSubdiagnostics()) {
   183             buf.append('\n');
   184             String subdiagMsg = format(d2, l);
   185             buf.append(indent(subdiagMsg, DiagInc));
   186         }
   187         return buf.toString();
   188     }
   190     /** Format the faulty source code line and point to the error.
   191      *  @param d The diagnostic for which the error line should be printed
   192      */
   193     protected String formatSourceLine(JCDiagnostic d) {
   194         StringBuilder buf = new StringBuilder();
   195         DiagnosticSource source = d.getDiagnosticSource();
   196         int pos = d.getIntPosition();
   197         if (d.getIntPosition() != Position.NOPOS) {
   198             String line = (source == null ? null : source.getLine(pos));
   199             if (line == null)
   200                 return "";
   201             buf.append(line+"\n");
   202             int col = source.getColumnNumber(pos, false);
   203             for (int i = 0; i < col - 1; i++)  {
   204                 buf.append((line.charAt(i) == '\t') ? "\t" : " ");
   205             }
   206             buf.append("^");
   207          }
   208          return buf.toString();
   209     }
   211     /**
   212      * Converts a String into a locale-dependent representation accordingly to a given locale
   213      *
   214      * @param l locale object to be used for i18n
   215      * @param key locale-independent key used for looking up in a resource file
   216      * @param args localization arguments
   217      * @return a locale-dependent string
   218      */
   219     protected String localize(Locale l, String key, Object... args) {
   220         return messages.getLocalizedString(l, key, args);
   221     }
   223     public boolean displaySource(JCDiagnostic d) {
   224         return showSource && d.getType() != FRAGMENT;
   225     }
   227     /**
   228      * Creates a string with a given amount of empty spaces. Useful for
   229      * indenting the text of a diagnostic message.
   230      *
   231      * @param nSpaces the amount of spaces to be added to the result string
   232      * @return the indentation string
   233      */
   234     protected String indentString(int nSpaces) {
   235         String spaces = "                        ";
   236         if (nSpaces <= spaces.length())
   237             return spaces.substring(0, nSpaces);
   238         else {
   239             StringBuilder buf = new StringBuilder();
   240             for (int i = 0 ; i < nSpaces ; i++)
   241                 buf.append(" ");
   242             return buf.toString();
   243         }
   244     }
   246     /**
   247      * Indent a string by prepending a given amount of empty spaces to each line
   248      * of the string
   249      *
   250      * @param s the string to be indented
   251      * @param nSpaces the amount of spaces that should be prepended to each line
   252      * of the string
   253      * @return an indented string
   254      */
   255     protected String indent(String s, int nSpaces) {
   256         String indent = indentString(nSpaces);
   257         StringBuilder buf = new StringBuilder();
   258         String nl = "";
   259         for (String line : s.split("\n")) {
   260             buf.append(nl);
   261             buf.append(indent + line);
   262             nl = "\n";
   263         }
   264         return buf.toString();
   265     }
   266 }

mercurial