1 /* 2 * Copyright (c) 2008, 2015, 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 */ 25 26 package com.sun.tools.javac.util; 27 28 import java.util.Collection; 29 import java.util.EnumSet; 30 import java.util.Locale; 31 import javax.tools.JavaFileObject; 32 33 import com.sun.tools.javac.api.DiagnosticFormatter.Configuration.*; 34 import com.sun.tools.javac.api.Formattable; 35 import com.sun.tools.javac.file.PathFileObject; 36 import com.sun.tools.javac.tree.JCTree.*; 37 38 import static com.sun.tools.javac.api.DiagnosticFormatter.PositionKind.*; 39 40 /** 41 * A raw formatter for diagnostic messages. 42 * The raw formatter will format a diagnostic according to one of two format patterns, depending on whether 43 * or not the source name and position are set. This formatter provides a standardized, localize-independent 44 * implementation of a diagnostic formatter; as such, this formatter is best suited for testing purposes. 45 * 46 * <p><b>This is NOT part of any supported API. 47 * If you write code that depends on this, you do so at your own risk. 48 * This code and its internal interfaces are subject to change or 49 * deletion without notice.</b> 50 */ 51 public final class RawDiagnosticFormatter extends AbstractDiagnosticFormatter { 52 53 /** 54 * The raw diagnostic helper. 55 */ 56 RawDiagnosticPosHelper rawDiagnosticPosHelper; 57 58 /** 59 * Helper class to generate stable positions for AST nodes occurring in diagnostic arguments. 60 * If the AST node appears in the same line number as the main diagnostic, the line is information is omitted. 61 * Otherwise both line and column information is included, using the format @{code line:col}". 62 * 63 * Note: since subdiagnostics can be created without a diagnostic source, a position helper 64 * should always refer to the toplevel diagnostic source. 65 */ 66 static class RawDiagnosticPosHelper { 67 private final JCDiagnostic diag; 68 69 RawDiagnosticPosHelper(JCDiagnostic diag) { 70 this.diag = diag; 71 } 72 73 String getPosition(JCExpression exp) { 74 DiagnosticSource diagSource = diag.getDiagnosticSource(); 75 long diagLine = diag.getLineNumber(); 76 long expLine = diagSource.getLineNumber(exp.pos); 77 long expCol = diagSource.getColumnNumber(exp.pos, false); 78 return (expLine == diagLine) ? 79 String.valueOf(expCol) : 80 expLine + ":" + expCol; 81 } 82 } 83 84 /** 85 * Create a formatter based on the supplied options. 86 * @param options 87 */ 88 public RawDiagnosticFormatter(Options options) { 89 super(null, new SimpleConfiguration(options, 90 EnumSet.of(DiagnosticPart.SUMMARY, 91 DiagnosticPart.DETAILS, 92 DiagnosticPart.SUBDIAGNOSTICS))); 93 } 94 95 //provide common default formats 96 public String formatDiagnostic(JCDiagnostic d, Locale l) { 97 try { 98 rawDiagnosticPosHelper = new RawDiagnosticPosHelper(d); 99 StringBuilder buf = new StringBuilder(); 100 if (d.getPosition() != Position.NOPOS) { 101 buf.append(formatSource(d, false, null)); 102 buf.append(':'); 103 buf.append(formatPosition(d, LINE, null)); 104 buf.append(':'); 105 buf.append(formatPosition(d, COLUMN, null)); 106 buf.append(':'); 107 } 108 else if (d.getSource() != null && d.getSource().getKind() == JavaFileObject.Kind.CLASS) { 109 buf.append(formatSource(d, false, null)); 110 buf.append(":-:-:"); 111 } 112 else 113 buf.append('-'); 114 buf.append(' '); 115 buf.append(formatMessage(d, null)); 116 if (displaySource(d)) { 117 buf.append("\n"); 118 buf.append(formatSourceLine(d, 0)); 119 } 120 return buf.toString(); 121 } 122 catch (Exception e) { 123 return null; 124 } finally { 125 rawDiagnosticPosHelper = null; 126 } 127 } 128 129 public String formatMessage(JCDiagnostic d, Locale l) { 130 StringBuilder buf = new StringBuilder(); 131 Collection<String> args = formatArguments(d, l); 132 buf.append(localize(null, d.getCode(), args.toArray())); 133 if (d.isMultiline() && getConfiguration().getVisible().contains(DiagnosticPart.SUBDIAGNOSTICS)) { 134 List<String> subDiags = formatSubdiagnostics(d, null); 135 if (subDiags.nonEmpty()) { 136 String sep = ""; 137 buf.append(",{"); 138 for (String sub : formatSubdiagnostics(d, null)) { 139 buf.append(sep); 140 buf.append("("); 141 buf.append(sub); 142 buf.append(")"); 143 sep = ","; 144 } 145 buf.append('}'); 146 } 147 } 148 return buf.toString(); 149 } 150 151 @Override 152 protected String formatArgument(JCDiagnostic diag, Object arg, Locale l) { 153 String s; 154 if (arg instanceof Formattable) { 155 s = arg.toString(); 156 } else if (arg instanceof JCExpression) { 157 Assert.checkNonNull(rawDiagnosticPosHelper); 158 s = "@" + rawDiagnosticPosHelper.getPosition((JCExpression)arg); 159 } else if (arg instanceof PathFileObject) { 160 s = ((PathFileObject) arg).getShortName(); 161 } else if (arg instanceof Tag) { 162 s = "compiler.misc.tree.tag." + StringUtils.toLowerCase(((Tag) arg).name()); 163 } else { 164 s = super.formatArgument(diag, arg, null); 165 } 166 return (arg instanceof JCDiagnostic) ? "(" + s + ")" : s; 167 } 168 169 @Override 170 protected String localize(Locale l, String key, Object... args) { 171 StringBuilder buf = new StringBuilder(); 172 buf.append(key); 173 String sep = ": "; 174 for (Object o : args) { 175 buf.append(sep); 176 buf.append(o); 177 sep = ", "; 178 } 179 return buf.toString(); 180 } 181 182 @Override 183 public boolean isRaw() { 184 return true; 185 } 186 }