]> git.lizzy.rs Git - rust.git/blob - src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/tests.rs
Rollup merge of #98301 - ortem:pretty-printers-nonzero, r=wesleywiser
[rust.git] / src / tools / rust-analyzer / crates / ide / src / syntax_highlighting / tests.rs
1 use std::time::Instant;
2
3 use expect_test::{expect_file, ExpectFile};
4 use ide_db::SymbolKind;
5 use test_utils::{bench, bench_fixture, skip_slow_tests, AssertLinear};
6
7 use crate::{fixture, FileRange, HlTag, TextRange};
8
9 #[test]
10 fn attributes() {
11     check_highlighting(
12         r#"
13 //- proc_macros: identity
14 //- minicore: derive, copy
15 #[allow(dead_code)]
16 #[rustfmt::skip]
17 #[proc_macros::identity]
18 #[derive(Copy)]
19 /// This is a doc comment
20 // This is a normal comment
21 /// This is a doc comment
22 #[derive(Copy)]
23 // This is another normal comment
24 /// This is another doc comment
25 // This is another normal comment
26 #[derive(Copy)]
27 // The reason for these being here is to test AttrIds
28 struct Foo;
29 "#,
30         expect_file!["./test_data/highlight_attributes.html"],
31         false,
32     );
33 }
34
35 #[test]
36 fn macros() {
37     check_highlighting(
38         r#"
39 //- proc_macros: mirror
40 proc_macros::mirror! {
41     {
42         ,i32 :x pub
43         ,i32 :y pub
44     } Foo struct
45 }
46 macro_rules! def_fn {
47     ($($tt:tt)*) => {$($tt)*}
48 }
49
50 def_fn! {
51     fn bar() -> u32 {
52         100
53     }
54 }
55
56 macro_rules! dont_color_me_braces {
57     () => {0}
58 }
59
60 macro_rules! noop {
61     ($expr:expr) => {
62         $expr
63     }
64 }
65
66 /// textually shadow previous definition
67 macro_rules! noop {
68     ($expr:expr) => {
69         $expr
70     }
71 }
72
73 macro_rules! keyword_frag {
74     ($type:ty) => ($type)
75 }
76
77 macro with_args($i:ident) {
78     $i
79 }
80
81 macro without_args {
82     ($i:ident) => {
83         $i
84     }
85 }
86
87 fn main() {
88     println!("Hello, {}!", 92);
89     dont_color_me_braces!();
90     noop!(noop!(1));
91 }
92 "#,
93         expect_file!["./test_data/highlight_macros.html"],
94         false,
95     );
96 }
97
98 /// If what you want to test feels like a specific entity consider making a new test instead,
99 /// this test fixture here in fact should shrink instead of grow ideally.
100 #[test]
101 fn test_highlighting() {
102     check_highlighting(
103         r#"
104 //- minicore: derive, copy
105 //- /main.rs crate:main deps:foo
106 use inner::{self as inner_mod};
107 mod inner {}
108
109 pub mod ops {
110     #[lang = "fn_once"]
111     pub trait FnOnce<Args> {}
112
113     #[lang = "fn_mut"]
114     pub trait FnMut<Args>: FnOnce<Args> {}
115
116     #[lang = "fn"]
117     pub trait Fn<Args>: FnMut<Args> {}
118 }
119
120 struct Foo {
121     x: u32,
122 }
123
124 trait Bar {
125     fn bar(&self) -> i32;
126 }
127
128 impl Bar for Foo {
129     fn bar(&self) -> i32 {
130         self.x
131     }
132 }
133
134 impl Foo {
135     fn baz(mut self, f: Foo) -> i32 {
136         f.baz(self)
137     }
138
139     fn qux(&mut self) {
140         self.x = 0;
141     }
142
143     fn quop(&self) -> i32 {
144         self.x
145     }
146 }
147
148 use self::FooCopy::{self as BarCopy};
149
150 #[derive(Copy)]
151 struct FooCopy {
152     x: u32,
153 }
154
155 impl FooCopy {
156     fn baz(self, f: FooCopy) -> u32 {
157         f.baz(self)
158     }
159
160     fn qux(&mut self) {
161         self.x = 0;
162     }
163
164     fn quop(&self) -> u32 {
165         self.x
166     }
167 }
168
169 fn str() {
170     str();
171 }
172
173 fn foo<'a, T>() -> T {
174     foo::<'a, i32>()
175 }
176
177 fn never() -> ! {
178     loop {}
179 }
180
181 fn const_param<const FOO: usize>() -> usize {
182     const_param::<{ FOO }>();
183     FOO
184 }
185
186 use ops::Fn;
187 fn baz<F: Fn() -> ()>(f: F) {
188     f()
189 }
190
191 fn foobar() -> impl Copy {}
192
193 fn foo() {
194     let bar = foobar();
195 }
196
197 // comment
198 fn main() {
199     let mut x = 42;
200     x += 1;
201     let y = &mut x;
202     let z = &y;
203
204     let Foo { x: z, y } = Foo { x: z, y };
205
206     y;
207
208     let mut foo = Foo { x, y: x };
209     let foo2 = Foo { x, y: x };
210     foo.quop();
211     foo.qux();
212     foo.baz(foo2);
213
214     let mut copy = FooCopy { x };
215     copy.quop();
216     copy.qux();
217     copy.baz(copy);
218
219     let a = |x| x;
220     let bar = Foo::baz;
221
222     let baz = (-42,);
223     let baz = -baz.0;
224
225     let _ = !true;
226
227     'foo: loop {
228         break 'foo;
229         continue 'foo;
230     }
231 }
232
233 enum Option<T> {
234     Some(T),
235     None,
236 }
237 use Option::*;
238
239 impl<T> Option<T> {
240     fn and<U>(self, other: Option<U>) -> Option<(T, U)> {
241         match other {
242             None => unimplemented!(),
243             Nope => Nope,
244         }
245     }
246 }
247
248 async fn learn_and_sing() {
249     let song = learn_song().await;
250     sing_song(song).await;
251 }
252
253 async fn async_main() {
254     let f1 = learn_and_sing();
255     let f2 = dance();
256     futures::join!(f1, f2);
257 }
258
259 fn use_foo_items() {
260     let bob = foo::Person {
261         name: "Bob",
262         age: foo::consts::NUMBER,
263     };
264
265     let control_flow = foo::identity(foo::ControlFlow::Continue);
266
267     if control_flow.should_die() {
268         foo::die!();
269     }
270 }
271
272 pub enum Bool { True, False }
273
274 impl Bool {
275     pub const fn to_primitive(self) -> bool {
276         true
277     }
278 }
279 const USAGE_OF_BOOL:bool = Bool::True.to_primitive();
280
281 trait Baz {
282     type Qux;
283 }
284
285 fn baz<T>(t: T)
286 where
287     T: Baz,
288     <T as Baz>::Qux: Bar {}
289
290 fn gp_shadows_trait<Baz: Bar>() {
291     Baz::bar;
292 }
293
294 //- /foo.rs crate:foo
295 pub struct Person {
296     pub name: &'static str,
297     pub age: u8,
298 }
299
300 pub enum ControlFlow {
301     Continue,
302     Die,
303 }
304
305 impl ControlFlow {
306     pub fn should_die(self) -> bool {
307         matches!(self, ControlFlow::Die)
308     }
309 }
310
311 pub fn identity<T>(x: T) -> T { x }
312
313 pub mod consts {
314     pub const NUMBER: i64 = 92;
315 }
316
317 macro_rules! die {
318     () => {
319         panic!();
320     };
321 }
322 "#,
323         expect_file!["./test_data/highlight_general.html"],
324         false,
325     );
326 }
327
328 #[test]
329 fn test_lifetime_highlighting() {
330     check_highlighting(
331         r#"
332 //- minicore: derive
333
334 #[derive()]
335 struct Foo<'a, 'b, 'c> where 'a: 'a, 'static: 'static {
336     field: &'a (),
337     field2: &'static (),
338 }
339 impl<'a> Foo<'_, 'a, 'static>
340 where
341     'a: 'a,
342     'static: 'static
343 {}
344 "#,
345         expect_file!["./test_data/highlight_lifetimes.html"],
346         false,
347     );
348 }
349
350 #[test]
351 fn test_keyword_highlighting() {
352     check_highlighting(
353         r#"
354 extern crate self;
355
356 use crate;
357 use self;
358 mod __ {
359     use super::*;
360 }
361
362 macro_rules! void {
363     ($($tt:tt)*) => {}
364 }
365 void!(Self);
366 struct __ where Self:;
367 fn __(_: Self) {}
368 "#,
369         expect_file!["./test_data/highlight_keywords.html"],
370         false,
371     );
372 }
373
374 #[test]
375 fn test_string_highlighting() {
376     // The format string detection is based on macro-expansion,
377     // thus, we have to copy the macro definition from `std`
378     check_highlighting(
379         r#"
380 macro_rules! println {
381     ($($arg:tt)*) => ({
382         $crate::io::_print($crate::format_args_nl!($($arg)*));
383     })
384 }
385 #[rustc_builtin_macro]
386 #[macro_export]
387 macro_rules! format_args {}
388 #[rustc_builtin_macro]
389 #[macro_export]
390 macro_rules! const_format_args {}
391 #[rustc_builtin_macro]
392 #[macro_export]
393 macro_rules! format_args_nl {}
394
395 mod panic {
396     pub macro panic_2015 {
397         () => (
398             $crate::panicking::panic("explicit panic")
399         ),
400         ($msg:literal $(,)?) => (
401             $crate::panicking::panic($msg)
402         ),
403         // Use `panic_str` instead of `panic_display::<&str>` for non_fmt_panic lint.
404         ($msg:expr $(,)?) => (
405             $crate::panicking::panic_str($msg)
406         ),
407         // Special-case the single-argument case for const_panic.
408         ("{}", $arg:expr $(,)?) => (
409             $crate::panicking::panic_display(&$arg)
410         ),
411         ($fmt:expr, $($arg:tt)+) => (
412             $crate::panicking::panic_fmt($crate::const_format_args!($fmt, $($arg)+))
413         ),
414     }
415 }
416
417 #[rustc_builtin_macro(std_panic)]
418 #[macro_export]
419 macro_rules! panic {}
420 #[rustc_builtin_macro]
421 macro_rules! assert {}
422 #[rustc_builtin_macro]
423 macro_rules! asm {}
424
425 macro_rules! toho {
426     () => ($crate::panic!("not yet implemented"));
427     ($($arg:tt)+) => ($crate::panic!("not yet implemented: {}", $crate::format_args!($($arg)+)));
428 }
429
430 fn main() {
431     println!("Hello {{Hello}}");
432     // from https://doc.rust-lang.org/std/fmt/index.html
433     println!("Hello");                 // => "Hello"
434     println!("Hello, {}!", "world");   // => "Hello, world!"
435     println!("The number is {}", 1);   // => "The number is 1"
436     println!("{:?}", (3, 4));          // => "(3, 4)"
437     println!("{value}", value=4);      // => "4"
438     println!("{} {}", 1, 2);           // => "1 2"
439     println!("{:04}", 42);             // => "0042" with leading zerosV
440     println!("{1} {} {0} {}", 1, 2);   // => "2 1 1 2"
441     println!("{argument}", argument = "test");   // => "test"
442     println!("{name} {}", 1, name = 2);          // => "2 1"
443     println!("{a} {c} {b}", a="a", b='b', c=3);  // => "a 3 b"
444     println!("{{{}}}", 2);                       // => "{2}"
445     println!("Hello {:5}!", "x");
446     println!("Hello {:1$}!", "x", 5);
447     println!("Hello {1:0$}!", 5, "x");
448     println!("Hello {:width$}!", "x", width = 5);
449     println!("Hello {:<5}!", "x");
450     println!("Hello {:-<5}!", "x");
451     println!("Hello {:^5}!", "x");
452     println!("Hello {:>5}!", "x");
453     println!("Hello {:+}!", 5);
454     println!("{:#x}!", 27);
455     println!("Hello {:05}!", 5);
456     println!("Hello {:05}!", -5);
457     println!("{:#010x}!", 27);
458     println!("Hello {0} is {1:.5}", "x", 0.01);
459     println!("Hello {1} is {2:.0$}", 5, "x", 0.01);
460     println!("Hello {0} is {2:.1$}", "x", 5, 0.01);
461     println!("Hello {} is {:.*}",    "x", 5, 0.01);
462     println!("Hello {} is {2:.*}",   "x", 5, 0.01);
463     println!("Hello {} is {number:.prec$}", "x", prec = 5, number = 0.01);
464     println!("{}, `{name:.*}` has 3 fractional digits", "Hello", 3, name=1234.56);
465     println!("{}, `{name:.*}` has 3 characters", "Hello", 3, name="1234.56");
466     println!("{}, `{name:>8.*}` has 3 right-aligned characters", "Hello", 3, name="1234.56");
467
468     let _ = "{}"
469     let _ = "{{}}";
470
471     println!("Hello {{}}");
472     println!("{{ Hello");
473     println!("Hello }}");
474     println!("{{Hello}}");
475     println!("{{ Hello }}");
476     println!("{{Hello }}");
477     println!("{{ Hello}}");
478
479     println!(r"Hello, {}!", "world");
480
481     // escape sequences
482     println!("Hello\nWorld");
483     println!("\u{48}\x65\x6C\x6C\x6F World");
484
485     let _ = "\x28\x28\x00\x63\n";
486     let _ = b"\x28\x28\x00\x63\n";
487
488     println!("{\x41}", A = 92);
489     println!("{ничоси}", ничоси = 92);
490
491     println!("{:x?} {} ", thingy, n2);
492     panic!("{}", 0);
493     panic!("more {}", 1);
494     assert!(true, "{}", 1);
495     assert!(true, "{} asdasd", 1);
496     toho!("{}fmt", 0);
497     asm!("mov eax, {0}");
498     format_args!(concat!("{}"), "{}");
499 }"#,
500         expect_file!["./test_data/highlight_strings.html"],
501         false,
502     );
503 }
504
505 #[test]
506 fn test_unsafe_highlighting() {
507     check_highlighting(
508         r#"
509 macro_rules! id {
510     ($($tt:tt)*) => {
511         $($tt)*
512     };
513 }
514 macro_rules! unsafe_deref {
515     () => {
516         *(&() as *const ())
517     };
518 }
519 static mut MUT_GLOBAL: Struct = Struct { field: 0 };
520 static GLOBAL: Struct = Struct { field: 0 };
521 unsafe fn unsafe_fn() {}
522
523 union Union {
524     a: u32,
525     b: f32,
526 }
527
528 struct Struct { field: i32 }
529 impl Struct {
530     unsafe fn unsafe_method(&self) {}
531 }
532
533 #[repr(packed)]
534 struct Packed {
535     a: u16,
536 }
537
538 unsafe trait UnsafeTrait {}
539 unsafe impl UnsafeTrait for Packed {}
540 impl !UnsafeTrait for () {}
541
542 fn unsafe_trait_bound<T: UnsafeTrait>(_: T) {}
543
544 trait DoTheAutoref {
545     fn calls_autoref(&self);
546 }
547
548 impl DoTheAutoref for u16 {
549     fn calls_autoref(&self) {}
550 }
551
552 fn main() {
553     let x = &5 as *const _ as *const usize;
554     let u = Union { b: 0 };
555
556     id! {
557         unsafe { unsafe_deref!() }
558     };
559
560     unsafe {
561         unsafe_deref!();
562         id! { unsafe_deref!() };
563
564         // unsafe fn and method calls
565         unsafe_fn();
566         let b = u.b;
567         match u {
568             Union { b: 0 } => (),
569             Union { a } => (),
570         }
571         Struct { field: 0 }.unsafe_method();
572
573         // unsafe deref
574         *x;
575
576         // unsafe access to a static mut
577         MUT_GLOBAL.field;
578         GLOBAL.field;
579
580         // unsafe ref of packed fields
581         let packed = Packed { a: 0 };
582         let a = &packed.a;
583         let ref a = packed.a;
584         let Packed { ref a } = packed;
585         let Packed { a: ref _a } = packed;
586
587         // unsafe auto ref of packed field
588         packed.a.calls_autoref();
589     }
590 }
591 "#,
592         expect_file!["./test_data/highlight_unsafe.html"],
593         false,
594     );
595 }
596
597 #[test]
598 fn test_highlight_doc_comment() {
599     check_highlighting(
600         r#"
601 //- /main.rs
602 //! This is a module to test doc injection.
603 //! ```
604 //! fn test() {}
605 //! ```
606
607 mod outline_module;
608
609 /// ```
610 /// let _ = "early doctests should not go boom";
611 /// ```
612 struct Foo {
613     bar: bool,
614 }
615
616 /// This is an impl with a code block.
617 ///
618 /// ```
619 /// fn foo() {
620 ///
621 /// }
622 /// ```
623 impl Foo {
624     /// ```
625     /// let _ = "Call me
626     //    KILLER WHALE
627     ///     Ishmael.";
628     /// ```
629     pub const bar: bool = true;
630
631     /// Constructs a new `Foo`.
632     ///
633     /// # Examples
634     ///
635     /// ```
636     /// # #![allow(unused_mut)]
637     /// let mut foo: Foo = Foo::new();
638     /// ```
639     pub const fn new() -> Foo {
640         Foo { bar: true }
641     }
642
643     /// `bar` method on `Foo`.
644     ///
645     /// # Examples
646     ///
647     /// ```
648     /// use x::y;
649     ///
650     /// let foo = Foo::new();
651     ///
652     /// // calls bar on foo
653     /// assert!(foo.bar());
654     ///
655     /// let bar = foo.bar || Foo::bar;
656     ///
657     /// /* multi-line
658     ///        comment */
659     ///
660     /// let multi_line_string = "Foo
661     ///   bar\n
662     ///          ";
663     ///
664     /// ```
665     ///
666     /// ```rust,no_run
667     /// let foobar = Foo::new().bar();
668     /// ```
669     ///
670     /// ~~~rust,no_run
671     /// // code block with tilde.
672     /// let foobar = Foo::new().bar();
673     /// ~~~
674     ///
675     /// ```
676     /// // functions
677     /// fn foo<T, const X: usize>(arg: i32) {
678     ///     let x: T = X;
679     /// }
680     /// ```
681     ///
682     /// ```sh
683     /// echo 1
684     /// ```
685     pub fn foo(&self) -> bool {
686         true
687     }
688 }
689
690 /// [`Foo`](Foo) is a struct
691 /// This function is > [`all_the_links`](all_the_links) <
692 /// [`noop`](noop) is a macro below
693 /// [`Item`] is a struct in the module [`module`]
694 ///
695 /// [`Item`]: module::Item
696 /// [mix_and_match]: ThisShouldntResolve
697 pub fn all_the_links() {}
698
699 pub mod module {
700     pub struct Item;
701 }
702
703 /// ```
704 /// macro_rules! noop { ($expr:expr) => { $expr }}
705 /// noop!(1);
706 /// ```
707 macro_rules! noop {
708     ($expr:expr) => {
709         $expr
710     }
711 }
712
713 /// ```rust
714 /// let _ = example(&[1, 2, 3]);
715 /// ```
716 ///
717 /// ```
718 /// loop {}
719 #[cfg_attr(not(feature = "false"), doc = "loop {}")]
720 #[doc = "loop {}"]
721 /// ```
722 ///
723 #[cfg_attr(feature = "alloc", doc = "```rust")]
724 #[cfg_attr(not(feature = "alloc"), doc = "```ignore")]
725 /// let _ = example(&alloc::vec![1, 2, 3]);
726 /// ```
727 pub fn mix_and_match() {}
728
729 /**
730 It is beyond me why you'd use these when you got ///
731 ```rust
732 let _ = example(&[1, 2, 3]);
733 ```
734 [`block_comments2`] tests these with indentation
735  */
736 pub fn block_comments() {}
737
738 /**
739     Really, I don't get it
740     ```rust
741     let _ = example(&[1, 2, 3]);
742     ```
743     [`block_comments`] tests these without indentation
744 */
745 pub fn block_comments2() {}
746
747 //- /outline_module.rs
748 //! This is an outline module whose purpose is to test that its inline attribute injection does not
749 //! spill into its parent.
750 //! ```
751 //! fn test() {}
752 //! ```
753 "#,
754         expect_file!["./test_data/highlight_doctest.html"],
755         false,
756     );
757 }
758
759 #[test]
760 fn test_extern_crate() {
761     check_highlighting(
762         r#"
763 //- /main.rs crate:main deps:std,alloc
764 extern crate std;
765 extern crate alloc as abc;
766 //- /std/lib.rs crate:std
767 pub struct S;
768 //- /alloc/lib.rs crate:alloc
769 pub struct A
770 "#,
771         expect_file!["./test_data/highlight_extern_crate.html"],
772         false,
773     );
774 }
775
776 #[test]
777 fn test_crate_root() {
778     check_highlighting(
779         r#"
780 //- minicore: iterators
781 //- /main.rs crate:main deps:foo
782 extern crate foo;
783 use core::iter;
784
785 pub const NINETY_TWO: u8 = 92;
786
787 use foo as foooo;
788
789 pub(crate) fn main() {
790     let baz = iter::repeat(92);
791 }
792
793 mod bar {
794     pub(in super) const FORTY_TWO: u8 = 42;
795
796     mod baz {
797         use super::super::NINETY_TWO;
798         use crate::foooo::Point;
799
800         pub(in super::super) const TWENTY_NINE: u8 = 29;
801     }
802 }
803 //- /foo.rs crate:foo
804 struct Point {
805     x: u8,
806     y: u8,
807 }
808
809 mod inner {
810     pub(super) fn swap(p: crate::Point) -> crate::Point {
811         crate::Point { x: p.y, y: p.x }
812     }
813 }
814 "#,
815         expect_file!["./test_data/highlight_crate_root.html"],
816         false,
817     );
818 }
819
820 #[test]
821 fn test_default_library() {
822     check_highlighting(
823         r#"
824 //- minicore: option, iterators
825 use core::iter;
826
827 fn main() {
828     let foo = Some(92);
829     let nums = iter::repeat(foo.unwrap());
830 }
831 "#,
832         expect_file!["./test_data/highlight_default_library.html"],
833         false,
834     );
835 }
836
837 #[test]
838 fn test_associated_function() {
839     check_highlighting(
840         r#"
841 fn not_static() {}
842
843 struct foo {}
844
845 impl foo {
846     pub fn is_static() {}
847     pub fn is_not_static(&self) {}
848 }
849
850 trait t {
851     fn t_is_static() {}
852     fn t_is_not_static(&self) {}
853 }
854
855 impl t for foo {
856     pub fn is_static() {}
857     pub fn is_not_static(&self) {}
858 }
859 "#,
860         expect_file!["./test_data/highlight_assoc_functions.html"],
861         false,
862     )
863 }
864
865 #[test]
866 fn test_injection() {
867     check_highlighting(
868         r##"
869 fn fixture(ra_fixture: &str) {}
870
871 fn main() {
872     fixture(r#"
873 trait Foo {
874     fn foo() {
875         println!("2 + 2 = {}", 4);
876     }
877 }"#
878     );
879     fixture(r"
880 fn foo() {
881     foo(\$0{
882         92
883     }\$0)
884 }"
885     );
886 }
887 "##,
888         expect_file!["./test_data/highlight_injection.html"],
889         false,
890     );
891 }
892
893 #[test]
894 fn test_operators() {
895     check_highlighting(
896         r##"
897 fn main() {
898     1 + 1 - 1 * 1 / 1 % 1 | 1 & 1 ! 1 ^ 1 >> 1 << 1;
899     let mut a = 0;
900     a += 1;
901     a -= 1;
902     a *= 1;
903     a /= 1;
904     a %= 1;
905     a |= 1;
906     a &= 1;
907     a ^= 1;
908     a >>= 1;
909     a <<= 1;
910 }
911 "##,
912         expect_file!["./test_data/highlight_operators.html"],
913         false,
914     );
915 }
916
917 #[test]
918 fn test_mod_hl_injection() {
919     check_highlighting(
920         r##"
921 //- /foo.rs
922 //! [Struct]
923 //! This is an intra doc injection test for modules
924 //! [Struct]
925 //! This is an intra doc injection test for modules
926
927 pub struct Struct;
928 //- /lib.rs crate:foo
929 /// [crate::foo::Struct]
930 /// This is an intra doc injection test for modules
931 /// [crate::foo::Struct]
932 /// This is an intra doc injection test for modules
933 mod foo;
934 "##,
935         expect_file!["./test_data/highlight_module_docs_inline.html"],
936         false,
937     );
938     check_highlighting(
939         r##"
940 //- /lib.rs crate:foo
941 /// [crate::foo::Struct]
942 /// This is an intra doc injection test for modules
943 /// [crate::foo::Struct]
944 /// This is an intra doc injection test for modules
945 mod foo;
946 //- /foo.rs
947 //! [Struct]
948 //! This is an intra doc injection test for modules
949 //! [Struct]
950 //! This is an intra doc injection test for modules
951
952 pub struct Struct;
953 "##,
954         expect_file!["./test_data/highlight_module_docs_outline.html"],
955         false,
956     );
957 }
958
959 #[test]
960 #[cfg_attr(
961     not(all(unix, target_pointer_width = "64")),
962     ignore = "depends on `DefaultHasher` outputs"
963 )]
964 fn test_rainbow_highlighting() {
965     check_highlighting(
966         r#"
967 fn main() {
968     let hello = "hello";
969     let x = hello.to_string();
970     let y = hello.to_string();
971
972     let x = "other color please!";
973     let y = x.to_string();
974 }
975
976 fn bar() {
977     let mut hello = "hello";
978 }
979 "#,
980         expect_file!["./test_data/highlight_rainbow.html"],
981         true,
982     );
983 }
984
985 #[test]
986 fn test_ranges() {
987     let (analysis, file_id) = fixture::file(
988         r#"
989 #[derive(Clone, Debug)]
990 struct Foo {
991     pub x: i32,
992     pub y: i32,
993 }
994 "#,
995     );
996
997     // The "x"
998     let highlights = &analysis
999         .highlight_range(FileRange { file_id, range: TextRange::at(45.into(), 1.into()) })
1000         .unwrap();
1001
1002     assert_eq!(&highlights[0].highlight.to_string(), "field.declaration.public");
1003 }
1004
1005 #[test]
1006 fn ranges_sorted() {
1007     let (analysis, file_id) = fixture::file(
1008         r#"
1009 #[foo(bar = "bar")]
1010 macro_rules! test {}
1011 }"#
1012         .trim(),
1013     );
1014     let _ = analysis.highlight(file_id).unwrap();
1015 }
1016
1017 /// Highlights the code given by the `ra_fixture` argument, renders the
1018 /// result as HTML, and compares it with the HTML file given as `snapshot`.
1019 /// Note that the `snapshot` file is overwritten by the rendered HTML.
1020 fn check_highlighting(ra_fixture: &str, expect: ExpectFile, rainbow: bool) {
1021     let (analysis, file_id) = fixture::file(ra_fixture.trim());
1022     let actual_html = &analysis.highlight_as_html(file_id, rainbow).unwrap();
1023     expect.assert_eq(actual_html)
1024 }
1025
1026 #[test]
1027 fn benchmark_syntax_highlighting_long_struct() {
1028     if skip_slow_tests() {
1029         return;
1030     }
1031
1032     let fixture = bench_fixture::big_struct();
1033     let (analysis, file_id) = fixture::file(&fixture);
1034
1035     let hash = {
1036         let _pt = bench("syntax highlighting long struct");
1037         analysis
1038             .highlight(file_id)
1039             .unwrap()
1040             .iter()
1041             .filter(|it| it.highlight.tag == HlTag::Symbol(SymbolKind::Struct))
1042             .count()
1043     };
1044     assert_eq!(hash, 2001);
1045 }
1046
1047 #[test]
1048 fn syntax_highlighting_not_quadratic() {
1049     if skip_slow_tests() {
1050         return;
1051     }
1052
1053     let mut al = AssertLinear::default();
1054     while al.next_round() {
1055         for i in 6..=10 {
1056             let n = 1 << i;
1057
1058             let fixture = bench_fixture::big_struct_n(n);
1059             let (analysis, file_id) = fixture::file(&fixture);
1060
1061             let time = Instant::now();
1062
1063             let hash = analysis
1064                 .highlight(file_id)
1065                 .unwrap()
1066                 .iter()
1067                 .filter(|it| it.highlight.tag == HlTag::Symbol(SymbolKind::Struct))
1068                 .count();
1069             assert!(hash > n as usize);
1070
1071             let elapsed = time.elapsed();
1072             al.sample(n as f64, elapsed.as_millis() as f64);
1073         }
1074     }
1075 }
1076
1077 #[test]
1078 fn benchmark_syntax_highlighting_parser() {
1079     if skip_slow_tests() {
1080         return;
1081     }
1082
1083     let fixture = bench_fixture::glorious_old_parser();
1084     let (analysis, file_id) = fixture::file(&fixture);
1085
1086     let hash = {
1087         let _pt = bench("syntax highlighting parser");
1088         analysis
1089             .highlight(file_id)
1090             .unwrap()
1091             .iter()
1092             .filter(|it| it.highlight.tag == HlTag::Symbol(SymbolKind::Function))
1093             .count()
1094     };
1095     assert_eq!(hash, 1609);
1096 }