test/langtools/tools/javac/Diagnostics/6769027/T6769027.java
changeset 47216 71c04702a3d5
parent 39812 6272642715a1
--- /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");
+        }
+    }
+
+}