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