blob: 5baaab58408515fc09e165bf6d0cee66234b55f6 [file] [log] [blame]
/*
* Copyright (c) 2009, 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/**
* @test
* @bug 6769027 8006694
* @summary Source line should be displayed immediately after the first diagnostic line
* @modules jdk.compiler/com.sun.tools.javac.api
* jdk.compiler/com.sun.tools.javac.util
* @run main/othervm T6769027
*/
// use /othervm to avoid locale issues
import java.net.URI;
import java.util.ResourceBundle;
import java.util.regex.Matcher;
import javax.tools.*;
import com.sun.tools.javac.util.*;
public class T6769027 {
enum OutputKind {
RAW("rawDiagnostics","rawDiagnostics"),
BASIC("","");
String key;
String value;
void init(Options opts) {
opts.put(key, value);
}
OutputKind(String key, String value) {
this.key = key;
this.value = value;
}
}
enum CaretKind {
DEFAULT("", ""),
SHOW("diags.showCaret","true"),
HIDE("diags.showCaret","false");
String key;
String value;
void init(Options opts) {
opts.put(key, value);
}
CaretKind(String key, String value) {
this.key = key;
this.value = value;
}
boolean isEnabled() {
return this == DEFAULT || this == SHOW;
}
}
enum SourceLineKind {
DEFAULT("", ""),
AFTER_SUMMARY("diags.sourcePosition", "top"),
BOTTOM("diags.sourcePosition", "bottom");
String key;
String value;
void init(Options opts) {
opts.put(key, value);
}
SourceLineKind(String key, String value) {
this.key = key;
this.value = value;
}
boolean isAfterSummary() {
return this == DEFAULT || this == AFTER_SUMMARY;
}
}
enum XDiagsSource {
DEFAULT(""),
SOURCE("source"),
NO_SOURCE("-source");
String flag;
void init(Options opts) {
if (this != DEFAULT) {
String flags = opts.get("diags.formatterOptions");
flags = flags == null ? flag : flags + "," + flag;
opts.put("diags.formatterOptions", flags);
}
}
XDiagsSource(String flag) {
this.flag = flag;
}
String getOutput(CaretKind caretKind, IndentKind indent, OutputKind outKind) {
String spaces = (outKind == OutputKind.BASIC) ? indent.string : "";
return "\n" + spaces + "This is a source line" +
(caretKind.isEnabled() ? "\n" + spaces + " ^" : "");
}
}
enum XDiagsCompact {
DEFAULT(""),
COMPACT("short"),
NO_COMPACT("-short");
String flag;
void init(Options opts) {
if (this != DEFAULT) {
String flags = opts.get("diags.formatterOptions");
flags = flags == null ? flag : flags + "," + flag;
opts.put("diags.formatterOptions", flags);
}
}
XDiagsCompact(String flag) {
this.flag = flag;
}
}
enum ErrorKind {
SINGLE("single",
"compiler.err.single: Hello!",
"KXThis is a test error message Hello!"),
DOUBLE("double",
"compiler.err.double: Hello!",
"KXThis is a test error message.\n" +
"KXYThis is another line of the above error message Hello!");
String key;
String rawOutput;
String nonRawOutput;
String key() {
return key;
}
ErrorKind(String key, String rawOutput, String nonRawOutput) {
this.key = key;
this.rawOutput = rawOutput;
this.nonRawOutput = nonRawOutput;
}
String getOutput(OutputKind outKind, IndentKind summaryIndent, IndentKind detailsIndent) {
return outKind == OutputKind.RAW ?
rawOutput :
nonRawOutput.replace("X", summaryIndent.string).replace("Y", detailsIndent.string).replace("K", "");
}
String getOutput(OutputKind outKind, IndentKind summaryIndent, IndentKind detailsIndent, String indent) {
return outKind == OutputKind.RAW ?
rawOutput :
nonRawOutput.replace("X", summaryIndent.string).replace("Y", detailsIndent.string).replace("K", indent);
}
}
enum MultilineKind {
NONE(0),
DOUBLE(1),
NESTED(2),
DOUBLE_NESTED(3);
static String[][] rawTemplates = {
{"", ",{(E),(E)}", ",{(E,{(E)})}", ",{(E,{(E)}),(E,{(E)})}"}, //ENABLED
{"", "", "", "",""}, //DISABLED
{"", ",{(E)}", ",{(E,{(E)})}", ",{(E,{(E)})}"}, //LIMIT_LENGTH
{"", ",{(E),(E)}", ",{(E)}", ",{(E),(E)}"}, //LIMIT_DEPTH
{"", ",{(E)}", ",{(E)}", ",{(E)}"}}; //LIMIT_BOTH
static String[][] basicTemplates = {
{"", "\nE\nE", "\nE\nQ", "\nE\nQ\nE\nQ"}, //ENABLED
{"", "", "", "",""}, //DISABLED
{"", "\nE", "\nE\nQ", "\nE\nQ"}, //LIMIT_LENGTH
{"", "\nE\nE", "\nE", "\nE\nE"}, //LIMIT_DEPTH
{"", "\nE", "\nE", "\nE"}}; //LIMIT_BOTH
int index;
MultilineKind (int index) {
this.index = index;
}
boolean isDouble() {
return this == DOUBLE || this == DOUBLE_NESTED;
}
boolean isNested() {
return this == NESTED || this == DOUBLE_NESTED;
}
String getOutput(OutputKind outKind, ErrorKind errKind, MultilinePolicy policy,
IndentKind summaryIndent, IndentKind detailsIndent, IndentKind multiIndent) {
String constIndent = (errKind == ErrorKind.DOUBLE) ?
summaryIndent.string + detailsIndent.string :
summaryIndent.string;
constIndent += multiIndent.string;
String errMsg1 = errKind.getOutput(outKind, summaryIndent, detailsIndent, constIndent);
String errMsg2 = errKind.getOutput(outKind, summaryIndent, detailsIndent, constIndent + constIndent);
errMsg1 = errMsg1.replaceAll("compiler.err", "compiler.misc");
errMsg1 = errMsg1.replaceAll("error message", "subdiagnostic");
errMsg2 = errMsg2.replaceAll("compiler.err", "compiler.misc");
errMsg2 = errMsg2.replaceAll("error message", "subdiagnostic");
String template = outKind == OutputKind.RAW ?
rawTemplates[policy.index][index] :
basicTemplates[policy.index][index];
template = template.replaceAll("E", errMsg1);
return template.replaceAll("Q", errMsg2);
}
}
enum MultilinePolicy {
ENABLED(0, "diags.multilinePolicy", "enabled"),
DISABLED(1, "diags.multilinePolicy", "disabled"),
LIMIT_LENGTH(2, "diags.multilinePolicy", "limit:1:*"),
LIMIT_DEPTH(3, "diags.multilinePolicy", "limit:*:1"),
LIMIT_BOTH(4, "diags.multilinePolicy", "limit:1:1");
String name;
String value;
int index;
MultilinePolicy(int index, String name, String value) {
this.name = name;
this.value = value;
this.index = index;
}
void init(Options options) {
options.put(name, value);
}
}
enum PositionKind {
NOPOS(Position.NOPOS, "- ", "error: "),
POS(5, "Test.java:1:6: ", "/Test.java:1: error: ");
int pos;
String rawOutput;
String nonRawOutput;
PositionKind(int pos, String rawOutput, String nonRawOutput) {
this.pos = pos;
this.rawOutput = rawOutput;
this.nonRawOutput = nonRawOutput;
}
JCDiagnostic.DiagnosticPosition pos() {
return new JCDiagnostic.SimpleDiagnosticPosition(pos);
}
String getOutput(OutputKind outputKind) {
return outputKind == OutputKind.RAW ?
rawOutput :
nonRawOutput;
}
}
static class MyFileObject extends SimpleJavaFileObject {
private String text;
public MyFileObject(String text) {
super(URI.create("myfo:/Test.java"), JavaFileObject.Kind.SOURCE);
this.text = text;
}
@Override
public CharSequence getCharContent(boolean ignoreEncodingErrors) {
return text;
}
}
enum IndentKind {
NONE(""),
CUSTOM(" ");
String string;
IndentKind(String indent) {
string = indent;
}
}
class MyLog extends Log {
MyLog(Context ctx) {
super(ctx);
}
@Override
protected boolean shouldReport(JavaFileObject jfo, int pos) {
return true;
}
}
OutputKind outputKind;
ErrorKind errorKind;
MultilineKind multiKind;
MultilinePolicy multiPolicy;
PositionKind posKind;
XDiagsSource xdiagsSource;
XDiagsCompact xdiagsCompact;
CaretKind caretKind;
SourceLineKind sourceLineKind;
IndentKind summaryIndent;
IndentKind detailsIndent;
IndentKind sourceIndent;
IndentKind subdiagsIndent;
T6769027(OutputKind outputKind, ErrorKind errorKind, MultilineKind multiKind,
MultilinePolicy multiPolicy, PositionKind posKind, XDiagsSource xdiagsSource,
XDiagsCompact xdiagsCompact, CaretKind caretKind, SourceLineKind sourceLineKind,
IndentKind summaryIndent, IndentKind detailsIndent, IndentKind sourceIndent,
IndentKind subdiagsIndent) {
this.outputKind = outputKind;
this.errorKind = errorKind;
this.multiKind = multiKind;
this.multiPolicy = multiPolicy;
this.posKind = posKind;
this.xdiagsSource = xdiagsSource;
this.xdiagsCompact = xdiagsCompact;
this.caretKind = caretKind;
this.sourceLineKind = sourceLineKind;
this.summaryIndent = summaryIndent;
this.detailsIndent = detailsIndent;
this.sourceIndent = sourceIndent;
this.subdiagsIndent = subdiagsIndent;
}
public void run() {
Context ctx = new Context();
Options options = Options.instance(ctx);
outputKind.init(options);
multiPolicy.init(options);
xdiagsSource.init(options);
xdiagsCompact.init(options);
caretKind.init(options);
sourceLineKind.init(options);
String indentString = "";
indentString = (summaryIndent == IndentKind.CUSTOM) ? "3" : "0";
indentString += (detailsIndent == IndentKind.CUSTOM) ? "|3" : "|0";
indentString += (sourceIndent == IndentKind.CUSTOM) ? "|3" : "|0";
indentString += (subdiagsIndent == IndentKind.CUSTOM) ? "|3" : "|0";
options.put("diags.indent", indentString);
MyLog log = new MyLog(ctx);
JavacMessages messages = JavacMessages.instance(ctx);
messages.add(locale -> ResourceBundle.getBundle("tester", locale));
JCDiagnostic.Factory diags = JCDiagnostic.Factory.instance(ctx);
log.useSource(new MyFileObject("This is a source line"));
JCDiagnostic d = diags.error(null, log.currentSource(),
posKind.pos(),
errorKind.key(), "Hello!");
if (multiKind != MultilineKind.NONE) {
JCDiagnostic sub = diags.fragment(errorKind.key(), "Hello!");
if (multiKind.isNested())
sub = new JCDiagnostic.MultilineDiagnostic(sub, List.of(sub));
List<JCDiagnostic> subdiags = multiKind.isDouble() ?
List.of(sub, sub) :
List.of(sub);
d = new JCDiagnostic.MultilineDiagnostic(d, subdiags);
}
String diag = log.getDiagnosticFormatter().format(d, messages.getCurrentLocale());
checkOutput(diag);
}
public static void main(String[] args) throws Exception {
for (OutputKind outputKind : OutputKind.values()) {
for (ErrorKind errKind : ErrorKind.values()) {
for (MultilineKind multiKind : MultilineKind.values()) {
for (MultilinePolicy multiPolicy : MultilinePolicy.values()) {
for (PositionKind posKind : PositionKind.values()) {
for (XDiagsSource xdiagsSource : XDiagsSource.values()) {
for (XDiagsCompact xdiagsCompact : XDiagsCompact.values()) {
for (CaretKind caretKind : CaretKind.values()) {
for (SourceLineKind sourceLineKind : SourceLineKind.values()) {
for (IndentKind summaryIndent : IndentKind.values()) {
for (IndentKind detailsIndent : IndentKind.values()) {
for (IndentKind sourceIndent : IndentKind.values()) {
for (IndentKind subdiagsIndent : IndentKind.values()) {
new T6769027(outputKind,
errKind,
multiKind,
multiPolicy,
posKind,
xdiagsSource,
xdiagsCompact,
caretKind,
sourceLineKind,
summaryIndent,
detailsIndent,
sourceIndent,
subdiagsIndent).run();
}
}
}
}
}
}
}
}
}
}
}
}
}
}
void printInfo(String msg, String errorLine) {
String sep = "*********************************************************";
String desc = "raw=" + outputKind + " pos=" + posKind + " key=" + errorKind.key() +
" multiline=" + multiKind +" multiPolicy=" + multiPolicy.value +
" diags= " + java.util.Arrays.asList(xdiagsSource.flag, xdiagsCompact.flag) +
" caret=" + caretKind + " sourcePosition=" + sourceLineKind +
" summaryIndent=" + summaryIndent + " detailsIndent=" + detailsIndent +
" sourceIndent=" + sourceIndent + " subdiagsIndent=" + subdiagsIndent;
System.err.println(sep);
System.err.println(desc);
System.err.println(sep);
System.err.println(msg);
System.err.println("Diagnostic formatting problem - expected diagnostic...\n" + errorLine);
}
void checkOutput(String msg) {
boolean shouldPrintSource = posKind == PositionKind.POS &&
xdiagsSource != XDiagsSource.NO_SOURCE &&
(xdiagsSource == XDiagsSource.SOURCE ||
outputKind == OutputKind.BASIC);
String errorLine = posKind.getOutput(outputKind) +
errorKind.getOutput(outputKind, summaryIndent, detailsIndent);
if (xdiagsCompact != XDiagsCompact.COMPACT)
errorLine += multiKind.getOutput(outputKind, errorKind, multiPolicy,
summaryIndent, detailsIndent, subdiagsIndent);
String[] lines = errorLine.split("\n");
if (xdiagsCompact == XDiagsCompact.COMPACT) {
errorLine = lines[0];
lines = new String[] {errorLine};
}
if (shouldPrintSource) {
if (sourceLineKind.isAfterSummary()) {
String sep = "\n";
if (lines.length == 1) {
errorLine += "\n";
sep = "";
}
errorLine = errorLine.replaceFirst("\n",
Matcher.quoteReplacement(xdiagsSource.getOutput(caretKind, sourceIndent, outputKind) + sep));
}
else
errorLine += xdiagsSource.getOutput(caretKind, sourceIndent, outputKind);
}
if (!msg.equals(errorLine)) {
printInfo(msg, errorLine);
throw new AssertionError("errors were found");
}
}
}