--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/Diagnostics/6769027/T6769027.java Tue Sep 12 19:03:39 2017 +0200
@@ -0,0 +1,488 @@
+/*
+ * 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");
+ }
+ }
+
+}