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