T6769027.java revision 3019:176472b94f2e
1/*
2 * Copyright (c) 2009, 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.
8 *
9 * This code is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12 * version 2 for more details (a copy is included in the LICENSE file that
13 * accompanied this code).
14 *
15 * You should have received a copy of the GNU General Public License version
16 * 2 along with this work; if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20 * or visit www.oracle.com if you need additional information or have any
21 * questions.
22 */
23
24/**
25 * @test
26 * @bug     6769027 8006694
27 * @summary Source line should be displayed immediately after the first diagnostic line
28 * @modules jdk.compiler/com.sun.tools.javac.api
29 *          jdk.compiler/com.sun.tools.javac.util
30 * @run main/othervm T6769027
31 */
32
33// use /othervm to avoid locale issues
34
35import java.net.URI;
36import java.util.regex.Matcher;
37import javax.tools.*;
38import com.sun.tools.javac.util.*;
39
40public class T6769027 {
41
42    enum OutputKind {
43        RAW("rawDiagnostics","rawDiagnostics"),
44        BASIC("","");
45
46        String key;
47        String value;
48
49        void init(Options opts) {
50            opts.put(key, value);
51        }
52
53        OutputKind(String key, String value) {
54            this.key = key;
55            this.value = value;
56        }
57    }
58
59    enum CaretKind {
60        DEFAULT("", ""),
61        SHOW("showCaret","true"),
62        HIDE("showCaret","false");
63
64        String key;
65        String value;
66
67        void init(Options opts) {
68            opts.put(key, value);
69        }
70
71        CaretKind(String key, String value) {
72            this.key = key;
73            this.value = value;
74        }
75
76        boolean isEnabled() {
77            return this == DEFAULT || this == SHOW;
78        }
79    }
80
81    enum SourceLineKind {
82        DEFAULT("", ""),
83        AFTER_SUMMARY("sourcePosition", "top"),
84        BOTTOM("sourcePosition", "bottom");
85
86        String key;
87        String value;
88
89        void init(Options opts) {
90            opts.put(key, value);
91        }
92
93        SourceLineKind(String key, String value) {
94            this.key = key;
95            this.value = value;
96        }
97
98        boolean isAfterSummary() {
99            return this == DEFAULT || this == AFTER_SUMMARY;
100        }
101    }
102
103    enum XDiagsSource {
104        DEFAULT(""),
105        SOURCE("source"),
106        NO_SOURCE("-source");
107
108        String flag;
109
110        void init(Options opts) {
111            if (this != DEFAULT) {
112                String flags = opts.get("diags");
113                flags = flags == null ? flag : flags + "," + flag;
114                opts.put("diags", flags);
115            }
116        }
117
118        XDiagsSource(String flag) {
119            this.flag = flag;
120        }
121
122        String getOutput(CaretKind caretKind, IndentKind indent, OutputKind outKind) {
123            String spaces = (outKind == OutputKind.BASIC) ? indent.string : "";
124            return "\n" + spaces + "This is a source line" +
125                   (caretKind.isEnabled() ? "\n" + spaces + "     ^" : "");
126        }
127    }
128
129    enum XDiagsCompact {
130        DEFAULT(""),
131        COMPACT("short"),
132        NO_COMPACT("-short");
133
134        String flag;
135
136        void init(Options opts) {
137            if (this != DEFAULT) {
138                String flags = opts.get("diags");
139                flags = flags == null ? flag : flags + "," + flag;
140                opts.put("diags", flags);
141            }
142        }
143
144        XDiagsCompact(String flag) {
145            this.flag = flag;
146        }
147    }
148
149    enum ErrorKind {
150        SINGLE("single",
151            "compiler.err.single: Hello!",
152            "KXThis is a test error message Hello!"),
153        DOUBLE("double",
154            "compiler.err.double: Hello!",
155            "KXThis is a test error message.\n" +
156            "KXYThis is another line of the above error message Hello!");
157
158        String key;
159        String rawOutput;
160        String nonRawOutput;
161
162        String key() {
163            return key;
164        }
165
166        ErrorKind(String key, String rawOutput, String nonRawOutput) {
167            this.key = key;
168            this.rawOutput = rawOutput;
169            this.nonRawOutput = nonRawOutput;
170        }
171
172        String getOutput(OutputKind outKind, IndentKind summaryIndent, IndentKind detailsIndent) {
173            return outKind == OutputKind.RAW ?
174                rawOutput :
175                nonRawOutput.replace("X", summaryIndent.string).replace("Y", detailsIndent.string).replace("K", "");
176        }
177
178        String getOutput(OutputKind outKind, IndentKind summaryIndent, IndentKind detailsIndent, String indent) {
179            return outKind == OutputKind.RAW ?
180                rawOutput :
181                nonRawOutput.replace("X", summaryIndent.string).replace("Y", detailsIndent.string).replace("K", indent);
182        }
183    }
184
185    enum MultilineKind {
186        NONE(0),
187        DOUBLE(1),
188        NESTED(2),
189        DOUBLE_NESTED(3);
190
191        static String[][] rawTemplates = {
192            {"", ",{(E),(E)}", ",{(E,{(E)})}", ",{(E,{(E)}),(E,{(E)})}"}, //ENABLED
193            {"", "", "", "",""}, //DISABLED
194            {"", ",{(E)}", ",{(E,{(E)})}", ",{(E,{(E)})}"}, //LIMIT_LENGTH
195            {"", ",{(E),(E)}", ",{(E)}", ",{(E),(E)}"}, //LIMIT_DEPTH
196            {"", ",{(E)}", ",{(E)}", ",{(E)}"}}; //LIMIT_BOTH
197
198        static String[][] basicTemplates = {
199            {"", "\nE\nE", "\nE\nQ", "\nE\nQ\nE\nQ"}, //ENABLED
200            {"", "", "", "",""}, //DISABLED
201            {"", "\nE", "\nE\nQ", "\nE\nQ"}, //LIMIT_LENGTH
202            {"", "\nE\nE", "\nE", "\nE\nE"}, //LIMIT_DEPTH
203            {"", "\nE", "\nE", "\nE"}}; //LIMIT_BOTH
204
205
206        int index;
207
208        MultilineKind (int index) {
209            this.index = index;
210        }
211
212        boolean isDouble() {
213            return this == DOUBLE || this == DOUBLE_NESTED;
214        }
215
216        boolean isNested() {
217            return this == NESTED || this == DOUBLE_NESTED;
218        }
219
220        String getOutput(OutputKind outKind, ErrorKind errKind, MultilinePolicy policy,
221                IndentKind summaryIndent, IndentKind detailsIndent, IndentKind multiIndent) {
222            String constIndent = (errKind == ErrorKind.DOUBLE) ?
223                summaryIndent.string + detailsIndent.string :
224                summaryIndent.string;
225            constIndent += multiIndent.string;
226
227            String errMsg1 = errKind.getOutput(outKind, summaryIndent, detailsIndent, constIndent);
228            String errMsg2 = errKind.getOutput(outKind, summaryIndent, detailsIndent, constIndent + constIndent);
229
230            errMsg1 = errMsg1.replaceAll("compiler.err", "compiler.misc");
231            errMsg1 = errMsg1.replaceAll("error message", "subdiagnostic");
232            errMsg2 = errMsg2.replaceAll("compiler.err", "compiler.misc");
233            errMsg2 = errMsg2.replaceAll("error message", "subdiagnostic");
234
235            String template = outKind == OutputKind.RAW ?
236                rawTemplates[policy.index][index] :
237                basicTemplates[policy.index][index];
238
239            template = template.replaceAll("E", errMsg1);
240            return template.replaceAll("Q", errMsg2);
241        }
242    }
243
244    enum MultilinePolicy {
245        ENABLED(0, "multilinePolicy", "enabled"),
246        DISABLED(1, "multilinePolicy", "disabled"),
247        LIMIT_LENGTH(2, "multilinePolicy", "limit:1:*"),
248        LIMIT_DEPTH(3, "multilinePolicy", "limit:*:1"),
249        LIMIT_BOTH(4, "multilinePolicy", "limit:1:1");
250
251        String name;
252        String value;
253        int index;
254
255        MultilinePolicy(int index, String name, String value) {
256            this.name = name;
257            this.value = value;
258            this.index = index;
259        }
260
261        void init(Options options) {
262            options.put(name, value);
263        }
264    }
265
266    enum PositionKind {
267        NOPOS(Position.NOPOS, "- ", "error: "),
268        POS(5, "Test.java:1:6: ", "/Test.java:1: error: ");
269
270        int pos;
271        String rawOutput;
272        String nonRawOutput;
273
274        PositionKind(int pos, String rawOutput, String nonRawOutput) {
275            this.pos = pos;
276            this.rawOutput = rawOutput;
277            this.nonRawOutput = nonRawOutput;
278        }
279
280        JCDiagnostic.DiagnosticPosition pos() {
281            return new JCDiagnostic.SimpleDiagnosticPosition(pos);
282        }
283
284        String getOutput(OutputKind outputKind) {
285            return outputKind == OutputKind.RAW ?
286                rawOutput :
287                nonRawOutput;
288        }
289    }
290
291    static class MyFileObject extends SimpleJavaFileObject {
292        private String text;
293        public MyFileObject(String text) {
294            super(URI.create("myfo:/Test.java"), JavaFileObject.Kind.SOURCE);
295            this.text = text;
296        }
297        @Override
298        public CharSequence getCharContent(boolean ignoreEncodingErrors) {
299            return text;
300        }
301    }
302
303    enum IndentKind {
304        NONE(""),
305        CUSTOM("   ");
306
307        String string;
308
309        IndentKind(String indent) {
310            string = indent;
311        }
312    }
313
314    class MyLog extends Log {
315        MyLog(Context ctx) {
316            super(ctx);
317        }
318
319        @Override
320        protected boolean shouldReport(JavaFileObject jfo, int pos) {
321            return true;
322        }
323    }
324
325    OutputKind outputKind;
326    ErrorKind errorKind;
327    MultilineKind multiKind;
328    MultilinePolicy multiPolicy;
329    PositionKind posKind;
330    XDiagsSource xdiagsSource;
331    XDiagsCompact xdiagsCompact;
332    CaretKind caretKind;
333    SourceLineKind sourceLineKind;
334    IndentKind summaryIndent;
335    IndentKind detailsIndent;
336    IndentKind sourceIndent;
337    IndentKind subdiagsIndent;
338
339    T6769027(OutputKind outputKind, ErrorKind errorKind, MultilineKind multiKind,
340            MultilinePolicy multiPolicy, PositionKind posKind, XDiagsSource xdiagsSource,
341            XDiagsCompact xdiagsCompact, CaretKind caretKind, SourceLineKind sourceLineKind,
342            IndentKind summaryIndent, IndentKind detailsIndent, IndentKind sourceIndent,
343            IndentKind subdiagsIndent) {
344        this.outputKind = outputKind;
345        this.errorKind = errorKind;
346        this.multiKind = multiKind;
347        this.multiPolicy = multiPolicy;
348        this.posKind = posKind;
349        this.xdiagsSource = xdiagsSource;
350        this.xdiagsCompact = xdiagsCompact;
351        this.caretKind = caretKind;
352        this.sourceLineKind = sourceLineKind;
353        this.summaryIndent = summaryIndent;
354        this.detailsIndent = detailsIndent;
355        this.sourceIndent = sourceIndent;
356        this.subdiagsIndent = subdiagsIndent;
357    }
358
359    public void run() {
360        Context ctx = new Context();
361        Options options = Options.instance(ctx);
362        outputKind.init(options);
363        multiPolicy.init(options);
364        xdiagsSource.init(options);
365        xdiagsCompact.init(options);
366        caretKind.init(options);
367        sourceLineKind.init(options);
368        String indentString = "";
369        indentString = (summaryIndent == IndentKind.CUSTOM) ? "3" : "0";
370        indentString += (detailsIndent == IndentKind.CUSTOM) ? "|3" : "|0";
371        indentString += (sourceIndent == IndentKind.CUSTOM) ? "|3" : "|0";
372        indentString += (subdiagsIndent == IndentKind.CUSTOM) ? "|3" : "|0";
373        options.put("diagsIndentation", indentString);
374        MyLog log = new MyLog(ctx);
375        JavacMessages messages = JavacMessages.instance(ctx);
376        messages.add("tester");
377        JCDiagnostic.Factory diags = JCDiagnostic.Factory.instance(ctx);
378        log.useSource(new MyFileObject("This is a source line"));
379        JCDiagnostic d = diags.error(null, log.currentSource(),
380            posKind.pos(),
381            errorKind.key(), "Hello!");
382        if (multiKind != MultilineKind.NONE) {
383            JCDiagnostic sub = diags.fragment(errorKind.key(), "Hello!");
384            if (multiKind.isNested())
385                sub = new JCDiagnostic.MultilineDiagnostic(sub, List.of(sub));
386            List<JCDiagnostic> subdiags = multiKind.isDouble() ?
387                List.of(sub, sub) :
388                List.of(sub);
389            d = new JCDiagnostic.MultilineDiagnostic(d, subdiags);
390        }
391        String diag = log.getDiagnosticFormatter().format(d, messages.getCurrentLocale());
392        checkOutput(diag);
393    }
394
395    public static void main(String[] args) throws Exception {
396        for (OutputKind outputKind : OutputKind.values()) {
397            for (ErrorKind errKind : ErrorKind.values()) {
398                for (MultilineKind multiKind : MultilineKind.values()) {
399                    for (MultilinePolicy multiPolicy : MultilinePolicy.values()) {
400                        for (PositionKind posKind : PositionKind.values()) {
401                            for (XDiagsSource xdiagsSource : XDiagsSource.values()) {
402                                for (XDiagsCompact xdiagsCompact : XDiagsCompact.values()) {
403                                    for (CaretKind caretKind : CaretKind.values()) {
404                                        for (SourceLineKind sourceLineKind : SourceLineKind.values()) {
405                                            for (IndentKind summaryIndent : IndentKind.values()) {
406                                                for (IndentKind detailsIndent : IndentKind.values()) {
407                                                    for (IndentKind sourceIndent : IndentKind.values()) {
408                                                        for (IndentKind subdiagsIndent : IndentKind.values()) {
409                                                            new T6769027(outputKind,
410                                                                errKind,
411                                                                multiKind,
412                                                                multiPolicy,
413                                                                posKind,
414                                                                xdiagsSource,
415                                                                xdiagsCompact,
416                                                                caretKind,
417                                                                sourceLineKind,
418                                                                summaryIndent,
419                                                                detailsIndent,
420                                                                sourceIndent,
421                                                                subdiagsIndent).run();
422                                                        }
423                                                    }
424                                                }
425                                            }
426                                        }
427                                    }
428                                }
429                            }
430                        }
431                    }
432                }
433            }
434        }
435    }
436
437    void printInfo(String msg, String errorLine) {
438        String sep = "*********************************************************";
439        String desc = "raw=" + outputKind + " pos=" + posKind + " key=" + errorKind.key() +
440                " multiline=" + multiKind +" multiPolicy=" + multiPolicy.value +
441                " diags= " + java.util.Arrays.asList(xdiagsSource.flag, xdiagsCompact.flag) +
442                " caret=" + caretKind + " sourcePosition=" + sourceLineKind +
443                " summaryIndent=" + summaryIndent + " detailsIndent=" + detailsIndent +
444                " sourceIndent=" + sourceIndent + " subdiagsIndent=" + subdiagsIndent;
445        System.err.println(sep);
446        System.err.println(desc);
447        System.err.println(sep);
448        System.err.println(msg);
449        System.err.println("Diagnostic formatting problem - expected diagnostic...\n" + errorLine);
450    }
451
452    void checkOutput(String msg) {
453        boolean shouldPrintSource = posKind == PositionKind.POS &&
454                xdiagsSource != XDiagsSource.NO_SOURCE &&
455                (xdiagsSource == XDiagsSource.SOURCE ||
456                outputKind == OutputKind.BASIC);
457        String errorLine = posKind.getOutput(outputKind) +
458                errorKind.getOutput(outputKind, summaryIndent, detailsIndent);
459        if (xdiagsCompact != XDiagsCompact.COMPACT)
460            errorLine += multiKind.getOutput(outputKind, errorKind, multiPolicy,
461                    summaryIndent, detailsIndent, subdiagsIndent);
462        String[] lines = errorLine.split("\n");
463        if (xdiagsCompact == XDiagsCompact.COMPACT) {
464            errorLine = lines[0];
465            lines = new String[] {errorLine};
466        }
467        if (shouldPrintSource) {
468            if (sourceLineKind.isAfterSummary()) {
469                String sep = "\n";
470                if (lines.length == 1) {
471                    errorLine += "\n";
472                    sep = "";
473                }
474                errorLine = errorLine.replaceFirst("\n",
475                        Matcher.quoteReplacement(xdiagsSource.getOutput(caretKind, sourceIndent, outputKind) + sep));
476            }
477            else
478                errorLine += xdiagsSource.getOutput(caretKind, sourceIndent, outputKind);
479        }
480
481        if (!msg.equals(errorLine)) {
482            printInfo(msg, errorLine);
483            throw new AssertionError("errors were found");
484        }
485    }
486
487}
488