]> git.lizzy.rs Git - rust.git/blob - src/libsyntax/test_snippet.rs
Do not show `::constructor` on tuple struct diagnostics
[rust.git] / src / libsyntax / test_snippet.rs
1 // Copyright 2016 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
4 //
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
10
11 use codemap::CodeMap;
12 use errors::Handler;
13 use errors::emitter::EmitterWriter;
14 use std::io;
15 use std::io::prelude::*;
16 use std::rc::Rc;
17 use std::str;
18 use std::sync::{Arc, Mutex};
19 use syntax_pos::{BytePos, NO_EXPANSION, Span, MultiSpan};
20
21 /// Identify a position in the text by the Nth occurrence of a string.
22 struct Position {
23     string: &'static str,
24     count: usize,
25 }
26
27 struct SpanLabel {
28     start: Position,
29     end: Position,
30     label: &'static str,
31 }
32
33 struct Shared<T: Write> {
34     data: Arc<Mutex<T>>,
35 }
36
37 impl<T: Write> Write for Shared<T> {
38     fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
39         self.data.lock().unwrap().write(buf)
40     }
41
42     fn flush(&mut self) -> io::Result<()> {
43         self.data.lock().unwrap().flush()
44     }
45 }
46
47 fn test_harness(file_text: &str, span_labels: Vec<SpanLabel>, expected_output: &str) {
48     let output = Arc::new(Mutex::new(Vec::new()));
49
50     let code_map = Rc::new(CodeMap::new());
51     code_map.new_filemap_and_lines("test.rs", None, &file_text);
52
53     let primary_span = make_span(&file_text, &span_labels[0].start, &span_labels[0].end);
54     let mut msp = MultiSpan::from_span(primary_span);
55     for span_label in span_labels {
56         let span = make_span(&file_text, &span_label.start, &span_label.end);
57         msp.push_span_label(span, span_label.label.to_string());
58         println!("span: {:?} label: {:?}", span, span_label.label);
59         println!("text: {:?}", code_map.span_to_snippet(span));
60     }
61
62     let emitter = EmitterWriter::new(Box::new(Shared { data: output.clone() }),
63                                      Some(code_map.clone()));
64     let handler = Handler::with_emitter(true, false, Box::new(emitter));
65     handler.span_err(msp, "foo");
66
67     assert!(expected_output.chars().next() == Some('\n'),
68             "expected output should begin with newline");
69     let expected_output = &expected_output[1..];
70
71     let bytes = output.lock().unwrap();
72     let actual_output = str::from_utf8(&bytes).unwrap();
73     println!("expected output:\n------\n{}------", expected_output);
74     println!("actual output:\n------\n{}------", actual_output);
75
76     assert!(expected_output == actual_output)
77 }
78
79 fn make_span(file_text: &str, start: &Position, end: &Position) -> Span {
80     let start = make_pos(file_text, start);
81     let end = make_pos(file_text, end) + end.string.len(); // just after matching thing ends
82     assert!(start <= end);
83     Span {
84         lo: BytePos(start as u32),
85         hi: BytePos(end as u32),
86         ctxt: NO_EXPANSION,
87     }
88 }
89
90 fn make_pos(file_text: &str, pos: &Position) -> usize {
91     let mut remainder = file_text;
92     let mut offset = 0;
93     for _ in 0..pos.count {
94         if let Some(n) = remainder.find(&pos.string) {
95             offset += n;
96             remainder = &remainder[n + 1..];
97         } else {
98             panic!("failed to find {} instances of {:?} in {:?}",
99                    pos.count,
100                    pos.string,
101                    file_text);
102         }
103     }
104     offset
105 }
106
107 #[test]
108 fn ends_on_col0() {
109     test_harness(r#"
110 fn foo() {
111 }
112 "#,
113     vec![
114         SpanLabel {
115            start: Position {
116                string: "{",
117                count: 1,
118            },
119            end: Position {
120                string: "}",
121                count: 1,
122            },
123            label: "test",
124        },
125     ],
126     r#"
127 error: foo
128  --> test.rs:2:10
129   |
130 2 |   fn foo() {
131   |  __________^ starting here...
132 3 | | }
133   | |_^ ...ending here: test
134
135 "#);
136 }
137
138 #[test]
139 fn ends_on_col2() {
140     test_harness(r#"
141 fn foo() {
142
143
144   }
145 "#,
146      vec![
147         SpanLabel {
148             start: Position {
149                 string: "{",
150                 count: 1,
151             },
152             end: Position {
153                 string: "}",
154                 count: 1,
155             },
156             label: "test",
157         },
158      ],
159      r#"
160 error: foo
161  --> test.rs:2:10
162   |
163 2 |   fn foo() {
164   |  __________^ starting here...
165 3 | |
166 4 | |
167 5 | |   }
168   | |___^ ...ending here: test
169
170 "#);
171 }
172 #[test]
173 fn non_nested() {
174     test_harness(r#"
175 fn foo() {
176   X0 Y0
177   X1 Y1
178   X2 Y2
179 }
180 "#,
181     vec![
182         SpanLabel {
183             start: Position {
184                 string: "X0",
185                 count: 1,
186             },
187             end: Position {
188                 string: "X2",
189                 count: 1,
190             },
191             label: "`X` is a good letter",
192         },
193         SpanLabel {
194             start: Position {
195                 string: "Y0",
196                 count: 1,
197             },
198             end: Position {
199                 string: "Y2",
200                 count: 1,
201             },
202             label: "`Y` is a good letter too",
203         },
204     ],
205     r#"
206 error: foo
207  --> test.rs:3:3
208   |
209 3 |      X0 Y0
210   |  ____^__- starting here...
211   | | ___|
212   | ||   starting here...
213 4 | ||   X1 Y1
214 5 | ||   X2 Y2
215   | ||____^__- ...ending here: `Y` is a good letter too
216   |  |____|
217   |       ...ending here: `X` is a good letter
218
219 "#);
220 }
221
222 #[test]
223 fn nested() {
224     test_harness(r#"
225 fn foo() {
226   X0 Y0
227   Y1 X1
228 }
229 "#,
230     vec![
231         SpanLabel {
232             start: Position {
233                 string: "X0",
234                 count: 1,
235             },
236             end: Position {
237                 string: "X1",
238                 count: 1,
239             },
240             label: "`X` is a good letter",
241         },
242         SpanLabel {
243             start: Position {
244                 string: "Y0",
245                 count: 1,
246             },
247             end: Position {
248                 string: "Y1",
249                 count: 1,
250             },
251             label: "`Y` is a good letter too",
252         },
253     ],
254 r#"
255 error: foo
256  --> test.rs:3:3
257   |
258 3 |      X0 Y0
259   |  ____^__- starting here...
260   | | ___|
261   | ||   starting here...
262 4 | ||   Y1 X1
263   | ||____-__^ ...ending here: `X` is a good letter
264   | |_____|
265   |       ...ending here: `Y` is a good letter too
266
267 "#);
268 }
269
270 #[test]
271 fn different_overlap() {
272     test_harness(r#"
273 fn foo() {
274   X0 Y0 Z0
275   X1 Y1 Z1
276   X2 Y2 Z2
277   X3 Y3 Z3
278 }
279 "#,
280     vec![
281         SpanLabel {
282             start: Position {
283                 string: "Y0",
284                 count: 1,
285             },
286             end: Position {
287                 string: "X2",
288                 count: 1,
289             },
290             label: "`X` is a good letter",
291         },
292         SpanLabel {
293             start: Position {
294                 string: "Z1",
295                 count: 1,
296             },
297             end: Position {
298                 string: "X3",
299                 count: 1,
300             },
301             label: "`Y` is a good letter too",
302         },
303     ],
304     r#"
305 error: foo
306  --> test.rs:3:6
307   |
308 3 |      X0 Y0 Z0
309   |   ______^ starting here...
310 4 |  |   X1 Y1 Z1
311   |  |_________- starting here...
312 5 | ||   X2 Y2 Z2
313   | ||____^ ...ending here: `X` is a good letter
314 6 | |    X3 Y3 Z3
315   | |_____- ...ending here: `Y` is a good letter too
316
317 "#);
318 }
319
320 #[test]
321 fn triple_overlap() {
322     test_harness(r#"
323 fn foo() {
324   X0 Y0 Z0
325   X1 Y1 Z1
326   X2 Y2 Z2
327 }
328 "#,
329     vec![
330         SpanLabel {
331             start: Position {
332                 string: "X0",
333                 count: 1,
334             },
335             end: Position {
336                 string: "X2",
337                 count: 1,
338             },
339             label: "`X` is a good letter",
340         },
341         SpanLabel {
342             start: Position {
343                 string: "Y0",
344                 count: 1,
345             },
346             end: Position {
347                 string: "Y2",
348                 count: 1,
349             },
350             label: "`Y` is a good letter too",
351         },
352         SpanLabel {
353             start: Position {
354                 string: "Z0",
355                 count: 1,
356             },
357             end: Position {
358                 string: "Z2",
359                 count: 1,
360             },
361             label: "`Z` label",
362         },
363     ],
364     r#"
365 error: foo
366  --> test.rs:3:3
367   |
368 3 |       X0 Y0 Z0
369   |  _____^__-__- starting here...
370   | | ____|__|
371   | || ___|  starting here...
372   | |||   starting here...
373 4 | |||   X1 Y1 Z1
374 5 | |||   X2 Y2 Z2
375   | |||____^__-__- ...ending here: `Z` label
376   |  ||____|__|
377   |   |____|  ...ending here: `Y` is a good letter too
378   |        ...ending here: `X` is a good letter
379
380 "#);
381 }
382
383 #[test]
384 fn minimum_depth() {
385     test_harness(r#"
386 fn foo() {
387   X0 Y0 Z0
388   X1 Y1 Z1
389   X2 Y2 Z2
390   X3 Y3 Z3
391 }
392 "#,
393     vec![
394         SpanLabel {
395             start: Position {
396                 string: "Y0",
397                 count: 1,
398             },
399             end: Position {
400                 string: "X1",
401                 count: 1,
402             },
403             label: "`X` is a good letter",
404         },
405         SpanLabel {
406             start: Position {
407                 string: "Y1",
408                 count: 1,
409             },
410             end: Position {
411                 string: "Z2",
412                 count: 1,
413             },
414             label: "`Y` is a good letter too",
415         },
416         SpanLabel {
417             start: Position {
418                 string: "X2",
419                 count: 1,
420             },
421             end: Position {
422                 string: "Y3",
423                 count: 1,
424             },
425             label: "`Z`",
426         },
427     ],
428     r#"
429 error: foo
430  --> test.rs:3:6
431   |
432 3 |      X0 Y0 Z0
433   |   ______^ starting here...
434 4 |  |   X1 Y1 Z1
435   |  |____^_- starting here...
436   | ||____|
437   | |     ...ending here: `X` is a good letter
438 5 | |    X2 Y2 Z2
439   | |____-______- ...ending here: `Y` is a good letter too
440   |  ____|
441   | |    starting here...
442 6 | |    X3 Y3 Z3
443   | |________- ...ending here: `Z`
444
445 "#);
446 }
447
448 #[test]
449 fn non_overlaping() {
450     test_harness(r#"
451 fn foo() {
452   X0 Y0 Z0
453   X1 Y1 Z1
454   X2 Y2 Z2
455   X3 Y3 Z3
456 }
457 "#,
458     vec![
459         SpanLabel {
460             start: Position {
461                 string: "Y0",
462                 count: 1,
463             },
464             end: Position {
465                 string: "X1",
466                 count: 1,
467             },
468             label: "`X` is a good letter",
469         },
470         SpanLabel {
471             start: Position {
472                 string: "Y2",
473                 count: 1,
474             },
475             end: Position {
476                 string: "Z3",
477                 count: 1,
478             },
479             label: "`Y` is a good letter too",
480         },
481     ],
482     r#"
483 error: foo
484  --> test.rs:3:6
485   |
486 3 |     X0 Y0 Z0
487   |  ______^ starting here...
488 4 | |   X1 Y1 Z1
489   | |____^ ...ending here: `X` is a good letter
490 5 |     X2 Y2 Z2
491   |  ______- starting here...
492 6 | |   X3 Y3 Z3
493   | |__________- ...ending here: `Y` is a good letter too
494
495 "#);
496 }
497
498 #[test]
499 fn overlaping_start_and_end() {
500     test_harness(r#"
501 fn foo() {
502   X0 Y0 Z0
503   X1 Y1 Z1
504   X2 Y2 Z2
505   X3 Y3 Z3
506 }
507 "#,
508     vec![
509         SpanLabel {
510             start: Position {
511                 string: "Y0",
512                 count: 1,
513             },
514             end: Position {
515                 string: "X1",
516                 count: 1,
517             },
518             label: "`X` is a good letter",
519         },
520         SpanLabel {
521             start: Position {
522                 string: "Z1",
523                 count: 1,
524             },
525             end: Position {
526                 string: "Z3",
527                 count: 1,
528             },
529             label: "`Y` is a good letter too",
530         },
531     ],
532     r#"
533 error: foo
534  --> test.rs:3:6
535   |
536 3 |      X0 Y0 Z0
537   |   ______^ starting here...
538 4 |  |   X1 Y1 Z1
539   |  |____^____- starting here...
540   | ||____|
541   | |     ...ending here: `X` is a good letter
542 5 | |    X2 Y2 Z2
543 6 | |    X3 Y3 Z3
544   | |___________- ...ending here: `Y` is a good letter too
545
546 "#);
547 }
548
549 #[test]
550 fn multiple_labels_primary_without_message() {
551     test_harness(r#"
552 fn foo() {
553   a { b { c } d }
554 }
555 "#,
556     vec![
557         SpanLabel {
558             start: Position {
559                 string: "b",
560                 count: 1,
561             },
562             end: Position {
563                 string: "}",
564                 count: 1,
565             },
566             label: "",
567         },
568         SpanLabel {
569             start: Position {
570                 string: "a",
571                 count: 1,
572             },
573             end: Position {
574                 string: "d",
575                 count: 1,
576             },
577             label: "`a` is a good letter",
578         },
579         SpanLabel {
580             start: Position {
581                 string: "c",
582                 count: 1,
583             },
584             end: Position {
585                 string: "c",
586                 count: 1,
587             },
588             label: "",
589         },
590     ],
591     r#"
592 error: foo
593  --> test.rs:3:7
594   |
595 3 |   a { b { c } d }
596   |   ----^^^^-^^-- `a` is a good letter
597
598 "#);
599 }
600
601 #[test]
602 fn multiple_labels_secondary_without_message() {
603     test_harness(r#"
604 fn foo() {
605   a { b { c } d }
606 }
607 "#,
608     vec![
609         SpanLabel {
610             start: Position {
611                 string: "a",
612                 count: 1,
613             },
614             end: Position {
615                 string: "d",
616                 count: 1,
617             },
618             label: "`a` is a good letter",
619         },
620         SpanLabel {
621             start: Position {
622                 string: "b",
623                 count: 1,
624             },
625             end: Position {
626                 string: "}",
627                 count: 1,
628             },
629             label: "",
630         },
631     ],
632     r#"
633 error: foo
634  --> test.rs:3:3
635   |
636 3 |   a { b { c } d }
637   |   ^^^^-------^^ `a` is a good letter
638
639 "#);
640 }
641
642 #[test]
643 fn multiple_labels_primary_without_message_2() {
644     test_harness(r#"
645 fn foo() {
646   a { b { c } d }
647 }
648 "#,
649     vec![
650         SpanLabel {
651             start: Position {
652                 string: "b",
653                 count: 1,
654             },
655             end: Position {
656                 string: "}",
657                 count: 1,
658             },
659             label: "`b` is a good letter",
660         },
661         SpanLabel {
662             start: Position {
663                 string: "a",
664                 count: 1,
665             },
666             end: Position {
667                 string: "d",
668                 count: 1,
669             },
670             label: "",
671         },
672         SpanLabel {
673             start: Position {
674                 string: "c",
675                 count: 1,
676             },
677             end: Position {
678                 string: "c",
679                 count: 1,
680             },
681             label: "",
682         },
683     ],
684     r#"
685 error: foo
686  --> test.rs:3:7
687   |
688 3 |   a { b { c } d }
689   |   ----^^^^-^^--
690   |       |
691   |       `b` is a good letter
692
693 "#);
694 }
695
696 #[test]
697 fn multiple_labels_secondary_without_message_2() {
698     test_harness(r#"
699 fn foo() {
700   a { b { c } d }
701 }
702 "#,
703     vec![
704         SpanLabel {
705             start: Position {
706                 string: "a",
707                 count: 1,
708             },
709             end: Position {
710                 string: "d",
711                 count: 1,
712             },
713             label: "",
714         },
715         SpanLabel {
716             start: Position {
717                 string: "b",
718                 count: 1,
719             },
720             end: Position {
721                 string: "}",
722                 count: 1,
723             },
724             label: "`b` is a good letter",
725         },
726     ],
727     r#"
728 error: foo
729  --> test.rs:3:3
730   |
731 3 |   a { b { c } d }
732   |   ^^^^-------^^
733   |       |
734   |       `b` is a good letter
735
736 "#);
737 }
738
739 #[test]
740 fn multiple_labels_without_message() {
741     test_harness(r#"
742 fn foo() {
743   a { b { c } d }
744 }
745 "#,
746     vec![
747         SpanLabel {
748             start: Position {
749                 string: "a",
750                 count: 1,
751             },
752             end: Position {
753                 string: "d",
754                 count: 1,
755             },
756             label: "",
757         },
758         SpanLabel {
759             start: Position {
760                 string: "b",
761                 count: 1,
762             },
763             end: Position {
764                 string: "}",
765                 count: 1,
766             },
767             label: "",
768         },
769     ],
770     r#"
771 error: foo
772  --> test.rs:3:3
773   |
774 3 |   a { b { c } d }
775   |   ^^^^-------^^
776
777 "#);
778 }
779
780 #[test]
781 fn multiple_labels_without_message_2() {
782     test_harness(r#"
783 fn foo() {
784   a { b { c } d }
785 }
786 "#,
787     vec![
788         SpanLabel {
789             start: Position {
790                 string: "b",
791                 count: 1,
792             },
793             end: Position {
794                 string: "}",
795                 count: 1,
796             },
797             label: "",
798         },
799         SpanLabel {
800             start: Position {
801                 string: "a",
802                 count: 1,
803             },
804             end: Position {
805                 string: "d",
806                 count: 1,
807             },
808             label: "",
809         },
810         SpanLabel {
811             start: Position {
812                 string: "c",
813                 count: 1,
814             },
815             end: Position {
816                 string: "c",
817                 count: 1,
818             },
819             label: "",
820         },
821     ],
822     r#"
823 error: foo
824  --> test.rs:3:7
825   |
826 3 |   a { b { c } d }
827   |   ----^^^^-^^--
828
829 "#);
830 }
831
832 #[test]
833 fn multiple_labels_with_message() {
834     test_harness(r#"
835 fn foo() {
836   a { b { c } d }
837 }
838 "#,
839     vec![
840         SpanLabel {
841             start: Position {
842                 string: "a",
843                 count: 1,
844             },
845             end: Position {
846                 string: "d",
847                 count: 1,
848             },
849             label: "`a` is a good letter",
850         },
851         SpanLabel {
852             start: Position {
853                 string: "b",
854                 count: 1,
855             },
856             end: Position {
857                 string: "}",
858                 count: 1,
859             },
860             label: "`b` is a good letter",
861         },
862     ],
863     r#"
864 error: foo
865  --> test.rs:3:3
866   |
867 3 |   a { b { c } d }
868   |   ^^^^-------^^
869   |   |   |
870   |   |   `b` is a good letter
871   |   `a` is a good letter
872
873 "#);
874 }
875
876 #[test]
877 fn single_label_with_message() {
878     test_harness(r#"
879 fn foo() {
880   a { b { c } d }
881 }
882 "#,
883     vec![
884         SpanLabel {
885             start: Position {
886                 string: "a",
887                 count: 1,
888             },
889             end: Position {
890                 string: "d",
891                 count: 1,
892             },
893             label: "`a` is a good letter",
894         },
895     ],
896     r#"
897 error: foo
898  --> test.rs:3:3
899   |
900 3 |   a { b { c } d }
901   |   ^^^^^^^^^^^^^ `a` is a good letter
902
903 "#);
904 }
905
906 #[test]
907 fn single_label_without_message() {
908     test_harness(r#"
909 fn foo() {
910   a { b { c } d }
911 }
912 "#,
913     vec![
914         SpanLabel {
915             start: Position {
916                 string: "a",
917                 count: 1,
918             },
919             end: Position {
920                 string: "d",
921                 count: 1,
922             },
923             label: "",
924         },
925     ],
926     r#"
927 error: foo
928  --> test.rs:3:3
929   |
930 3 |   a { b { c } d }
931   |   ^^^^^^^^^^^^^
932
933 "#);
934 }
935
936 #[test]
937 fn long_snippet() {
938     test_harness(r#"
939 fn foo() {
940   X0 Y0 Z0
941   X1 Y1 Z1
942 1
943 2
944 3
945 4
946 5
947 6
948 7
949 8
950 9
951 10
952   X2 Y2 Z2
953   X3 Y3 Z3
954 }
955 "#,
956     vec![
957         SpanLabel {
958             start: Position {
959                 string: "Y0",
960                 count: 1,
961             },
962             end: Position {
963                 string: "X1",
964                 count: 1,
965             },
966             label: "`X` is a good letter",
967         },
968         SpanLabel {
969             start: Position {
970                 string: "Z1",
971                 count: 1,
972             },
973             end: Position {
974                 string: "Z3",
975                 count: 1,
976             },
977             label: "`Y` is a good letter too",
978         },
979     ],
980     r#"
981 error: foo
982   --> test.rs:3:6
983    |
984 3  |      X0 Y0 Z0
985    |   ______^ starting here...
986 4  |  |   X1 Y1 Z1
987    |  |____^____- starting here...
988    | ||____|
989    | |     ...ending here: `X` is a good letter
990 5  | |  1
991 6  | |  2
992 7  | |  3
993 ...  |
994 15 | |    X2 Y2 Z2
995 16 | |    X3 Y3 Z3
996    | |___________- ...ending here: `Y` is a good letter too
997
998 "#);
999 }
1000
1001 #[test]
1002 fn long_snippet_multiple_spans() {
1003     test_harness(r#"
1004 fn foo() {
1005   X0 Y0 Z0
1006 1
1007 2
1008 3
1009   X1 Y1 Z1
1010 4
1011 5
1012 6
1013   X2 Y2 Z2
1014 7
1015 8
1016 9
1017 10
1018   X3 Y3 Z3
1019 }
1020 "#,
1021     vec![
1022         SpanLabel {
1023             start: Position {
1024                 string: "Y0",
1025                 count: 1,
1026             },
1027             end: Position {
1028                 string: "Y3",
1029                 count: 1,
1030             },
1031             label: "`Y` is a good letter",
1032         },
1033         SpanLabel {
1034             start: Position {
1035                 string: "Z1",
1036                 count: 1,
1037             },
1038             end: Position {
1039                 string: "Z2",
1040                 count: 1,
1041             },
1042             label: "`Z` is a good letter too",
1043         },
1044     ],
1045     r#"
1046 error: foo
1047   --> test.rs:3:6
1048    |
1049 3  |      X0 Y0 Z0
1050    |   ______^ starting here...
1051 4  |  | 1
1052 5  |  | 2
1053 6  |  | 3
1054 7  |  |   X1 Y1 Z1
1055    |  |_________- starting here...
1056 8  | || 4
1057 9  | || 5
1058 10 | || 6
1059 11 | ||   X2 Y2 Z2
1060    | ||__________- ...ending here: `Z` is a good letter too
1061 ...   |
1062 15 |  | 10
1063 16 |  |   X3 Y3 Z3
1064    |  |_______^ ...ending here: `Y` is a good letter
1065
1066 "#);
1067 }
1068