aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--crates/ra_hir_ty/src/diagnostics.rs240
-rw-r--r--crates/ra_hir_ty/src/diagnostics/expr.rs2
-rw-r--r--crates/ra_hir_ty/src/diagnostics/match_check.rs2
-rw-r--r--crates/ra_hir_ty/src/diagnostics/unsafe_check.rs50
-rw-r--r--crates/ra_hir_ty/src/test_db.rs50
-rw-r--r--crates/ra_hir_ty/src/tests.rs408
6 files changed, 278 insertions, 474 deletions
diff --git a/crates/ra_hir_ty/src/diagnostics.rs b/crates/ra_hir_ty/src/diagnostics.rs
index 3870c6d9c..d3ee9cf55 100644
--- a/crates/ra_hir_ty/src/diagnostics.rs
+++ b/crates/ra_hir_ty/src/diagnostics.rs
@@ -246,25 +246,233 @@ impl AstDiagnostic for MismatchedArgCount {
246} 246}
247 247
248#[cfg(test)] 248#[cfg(test)]
249fn check_diagnostics(ra_fixture: &str) { 249mod tests {
250 use ra_db::{fixture::WithFixture, FileId}; 250 use hir_def::{db::DefDatabase, AssocItemId, ModuleDefId};
251 use ra_syntax::TextRange; 251 use hir_expand::diagnostics::{Diagnostic, DiagnosticSink};
252 use ra_db::{fixture::WithFixture, FileId, SourceDatabase, SourceDatabaseExt};
253 use ra_syntax::{TextRange, TextSize};
252 use rustc_hash::FxHashMap; 254 use rustc_hash::FxHashMap;
253 255
254 use crate::test_db::TestDB; 256 use crate::{diagnostics::validate_body, test_db::TestDB};
257
258 impl TestDB {
259 fn diagnostics<F: FnMut(&dyn Diagnostic)>(&self, mut cb: F) {
260 let crate_graph = self.crate_graph();
261 for krate in crate_graph.iter() {
262 let crate_def_map = self.crate_def_map(krate);
263
264 let mut fns = Vec::new();
265 for (module_id, _) in crate_def_map.modules.iter() {
266 for decl in crate_def_map[module_id].scope.declarations() {
267 if let ModuleDefId::FunctionId(f) = decl {
268 fns.push(f)
269 }
270 }
271
272 for impl_id in crate_def_map[module_id].scope.impls() {
273 let impl_data = self.impl_data(impl_id);
274 for item in impl_data.items.iter() {
275 if let AssocItemId::FunctionId(f) = item {
276 fns.push(*f)
277 }
278 }
279 }
280 }
281
282 for f in fns {
283 let mut sink = DiagnosticSink::new(&mut cb);
284 validate_body(self, f.into(), &mut sink);
285 }
286 }
287 }
288 }
289
290 pub(crate) fn check_diagnostics(ra_fixture: &str) {
291 let db = TestDB::with_files(ra_fixture);
292 let annotations = db.extract_annotations();
293
294 let mut actual: FxHashMap<FileId, Vec<(TextRange, String)>> = FxHashMap::default();
295 db.diagnostics(|d| {
296 // FXIME: macros...
297 let file_id = d.source().file_id.original_file(&db);
298 let range = d.syntax_node(&db).text_range();
299 let message = d.message().to_owned();
300 actual.entry(file_id).or_default().push((range, message));
301 });
302
303 for (file_id, diags) in actual.iter_mut() {
304 diags.sort_by_key(|it| it.0.start());
305 let text = db.file_text(*file_id);
306 // For multiline spans, place them on line start
307 for (range, content) in diags {
308 if text[*range].contains('\n') {
309 *range = TextRange::new(range.start(), range.start() + TextSize::from(1));
310 *content = format!("... {}", content);
311 }
312 }
313 }
314
315 assert_eq!(annotations, actual);
316 }
317
318 #[test]
319 fn no_such_field_diagnostics() {
320 check_diagnostics(
321 r#"
322struct S { foo: i32, bar: () }
323impl S {
324 fn new() -> S {
325 S {
326 //^... Missing structure fields:
327 //| - bar
328 foo: 92,
329 baz: 62,
330 //^^^^^^^ no such field
331 }
332 }
333}
334"#,
335 );
336 }
337 #[test]
338 fn no_such_field_with_feature_flag_diagnostics() {
339 check_diagnostics(
340 r#"
341//- /lib.rs crate:foo cfg:feature=foo
342struct MyStruct {
343 my_val: usize,
344 #[cfg(feature = "foo")]
345 bar: bool,
346}
347
348impl MyStruct {
349 #[cfg(feature = "foo")]
350 pub(crate) fn new(my_val: usize, bar: bool) -> Self {
351 Self { my_val, bar }
352 }
353 #[cfg(not(feature = "foo"))]
354 pub(crate) fn new(my_val: usize, _bar: bool) -> Self {
355 Self { my_val }
356 }
357}
358"#,
359 );
360 }
361
362 #[test]
363 fn no_such_field_enum_with_feature_flag_diagnostics() {
364 check_diagnostics(
365 r#"
366//- /lib.rs crate:foo cfg:feature=foo
367enum Foo {
368 #[cfg(not(feature = "foo"))]
369 Buz,
370 #[cfg(feature = "foo")]
371 Bar,
372 Baz
373}
374
375fn test_fn(f: Foo) {
376 match f {
377 Foo::Bar => {},
378 Foo::Baz => {},
379 }
380}
381"#,
382 );
383 }
384
385 #[test]
386 fn no_such_field_with_feature_flag_diagnostics_on_struct_lit() {
387 check_diagnostics(
388 r#"
389//- /lib.rs crate:foo cfg:feature=foo
390struct S {
391 #[cfg(feature = "foo")]
392 foo: u32,
393 #[cfg(not(feature = "foo"))]
394 bar: u32,
395}
396
397impl S {
398 #[cfg(feature = "foo")]
399 fn new(foo: u32) -> Self {
400 Self { foo }
401 }
402 #[cfg(not(feature = "foo"))]
403 fn new(bar: u32) -> Self {
404 Self { bar }
405 }
406 fn new2(bar: u32) -> Self {
407 #[cfg(feature = "foo")]
408 { Self { foo: bar } }
409 #[cfg(not(feature = "foo"))]
410 { Self { bar } }
411 }
412 fn new2(val: u32) -> Self {
413 Self {
414 #[cfg(feature = "foo")]
415 foo: val,
416 #[cfg(not(feature = "foo"))]
417 bar: val,
418 }
419 }
420}
421"#,
422 );
423 }
255 424
256 let db = TestDB::with_files(ra_fixture); 425 #[test]
257 let annotations = db.extract_annotations(); 426 fn no_such_field_with_type_macro() {
427 check_diagnostics(
428 r#"
429macro_rules! Type { () => { u32 }; }
430struct Foo { bar: Type![] }
258 431
259 let mut actual: FxHashMap<FileId, Vec<(TextRange, String)>> = FxHashMap::default(); 432impl Foo {
260 db.diag(|d| { 433 fn new() -> Self {
261 // FXIME: macros... 434 Foo { bar: 0 }
262 let file_id = d.source().file_id.original_file(&db); 435 }
263 let range = d.syntax_node(&db).text_range(); 436}
264 let message = d.message().to_owned(); 437"#,
265 actual.entry(file_id).or_default().push((range, message)); 438 );
266 }); 439 }
267 actual.values_mut().for_each(|diags| diags.sort_by_key(|it| it.0.start())); 440
441 #[test]
442 fn missing_record_pat_field_diagnostic() {
443 check_diagnostics(
444 r#"
445struct S { foo: i32, bar: () }
446fn baz(s: S) {
447 let S { foo: _ } = s;
448 //^^^^^^^^^^ Missing structure fields:
449 // | - bar
450}
451"#,
452 );
453 }
268 454
269 assert_eq!(annotations, actual); 455 #[test]
456 fn missing_record_pat_field_no_diagnostic_if_not_exhaustive() {
457 check_diagnostics(
458 r"
459struct S { foo: i32, bar: () }
460fn baz(s: S) -> i32 {
461 match s {
462 S { foo, .. } => foo,
463 }
464}
465",
466 )
467 }
468
469 #[test]
470 fn break_outside_of_loop() {
471 check_diagnostics(
472 r#"
473fn foo() { break; }
474 //^^^^^ break outside of loop
475"#,
476 );
477 }
270} 478}
diff --git a/crates/ra_hir_ty/src/diagnostics/expr.rs b/crates/ra_hir_ty/src/diagnostics/expr.rs
index 277ace180..91caedc3d 100644
--- a/crates/ra_hir_ty/src/diagnostics/expr.rs
+++ b/crates/ra_hir_ty/src/diagnostics/expr.rs
@@ -376,7 +376,7 @@ pub fn record_pattern_missing_fields(
376 376
377#[cfg(test)] 377#[cfg(test)]
378mod tests { 378mod tests {
379 use crate::diagnostics::check_diagnostics; 379 use crate::diagnostics::tests::check_diagnostics;
380 380
381 #[test] 381 #[test]
382 fn simple_free_fn_zero() { 382 fn simple_free_fn_zero() {
diff --git a/crates/ra_hir_ty/src/diagnostics/match_check.rs b/crates/ra_hir_ty/src/diagnostics/match_check.rs
index 95f272811..507edcb7d 100644
--- a/crates/ra_hir_ty/src/diagnostics/match_check.rs
+++ b/crates/ra_hir_ty/src/diagnostics/match_check.rs
@@ -837,7 +837,7 @@ fn enum_variant_matches(cx: &MatchCheckCtx, pat_id: PatId, enum_variant_id: Enum
837 837
838#[cfg(test)] 838#[cfg(test)]
839mod tests { 839mod tests {
840 use crate::diagnostics::check_diagnostics; 840 use crate::diagnostics::tests::check_diagnostics;
841 841
842 #[test] 842 #[test]
843 fn empty_tuple() { 843 fn empty_tuple() {
diff --git a/crates/ra_hir_ty/src/diagnostics/unsafe_check.rs b/crates/ra_hir_ty/src/diagnostics/unsafe_check.rs
index b8ff95ee1..9e4ed9a8b 100644
--- a/crates/ra_hir_ty/src/diagnostics/unsafe_check.rs
+++ b/crates/ra_hir_ty/src/diagnostics/unsafe_check.rs
@@ -121,3 +121,53 @@ fn walk_unsafe(
121 walk_unsafe(unsafe_exprs, db, infer, body, child, inside_unsafe_block); 121 walk_unsafe(unsafe_exprs, db, infer, body, child, inside_unsafe_block);
122 }); 122 });
123} 123}
124
125#[cfg(test)]
126mod tests {
127 use crate::diagnostics::tests::check_diagnostics;
128
129 #[test]
130 fn missing_unsafe_diagnostic_with_raw_ptr() {
131 check_diagnostics(
132 r#"
133fn main() {
134 let x = &5 as *const usize;
135 unsafe { let y = *x; }
136 let z = *x;
137} //^^ This operation is unsafe and requires an unsafe function or block
138"#,
139 )
140 }
141
142 #[test]
143 fn missing_unsafe_diagnostic_with_unsafe_call() {
144 check_diagnostics(
145 r#"
146struct HasUnsafe;
147
148impl HasUnsafe {
149 unsafe fn unsafe_fn(&self) {
150 let x = &5 as *const usize;
151 let y = *x;
152 }
153}
154
155unsafe fn unsafe_fn() {
156 let x = &5 as *const usize;
157 let y = *x;
158}
159
160fn main() {
161 unsafe_fn();
162 //^^^^^^^^^^^ This operation is unsafe and requires an unsafe function or block
163 HasUnsafe.unsafe_fn();
164 //^^^^^^^^^^^^^^^^^^^^^ This operation is unsafe and requires an unsafe function or block
165 unsafe {
166 unsafe_fn();
167 HasUnsafe.unsafe_fn();
168 }
169}
170"#,
171 );
172 }
173}
diff --git a/crates/ra_hir_ty/src/test_db.rs b/crates/ra_hir_ty/src/test_db.rs
index fb8723fb7..a1714ff0f 100644
--- a/crates/ra_hir_ty/src/test_db.rs
+++ b/crates/ra_hir_ty/src/test_db.rs
@@ -5,19 +5,13 @@ use std::{
5 sync::{Arc, Mutex}, 5 sync::{Arc, Mutex},
6}; 6};
7 7
8use hir_def::{db::DefDatabase, AssocItemId, ModuleDefId, ModuleId}; 8use hir_def::{db::DefDatabase, ModuleId};
9use hir_expand::{ 9use hir_expand::db::AstDatabase;
10 db::AstDatabase,
11 diagnostics::{Diagnostic, DiagnosticSink},
12};
13use ra_db::{salsa, CrateId, FileId, FileLoader, FileLoaderDelegate, SourceDatabase, Upcast}; 10use ra_db::{salsa, CrateId, FileId, FileLoader, FileLoaderDelegate, SourceDatabase, Upcast};
14use ra_syntax::TextRange; 11use ra_syntax::TextRange;
15use rustc_hash::{FxHashMap, FxHashSet}; 12use rustc_hash::{FxHashMap, FxHashSet};
16use stdx::format_to;
17use test_utils::extract_annotations; 13use test_utils::extract_annotations;
18 14
19use crate::diagnostics::validate_body;
20
21#[salsa::database( 15#[salsa::database(
22 ra_db::SourceDatabaseExtStorage, 16 ra_db::SourceDatabaseExtStorage,
23 ra_db::SourceDatabaseStorage, 17 ra_db::SourceDatabaseStorage,
@@ -94,46 +88,6 @@ impl TestDB {
94 panic!("Can't find module for file") 88 panic!("Can't find module for file")
95 } 89 }
96 90
97 pub(crate) fn diag<F: FnMut(&dyn Diagnostic)>(&self, mut cb: F) {
98 let crate_graph = self.crate_graph();
99 for krate in crate_graph.iter() {
100 let crate_def_map = self.crate_def_map(krate);
101
102 let mut fns = Vec::new();
103 for (module_id, _) in crate_def_map.modules.iter() {
104 for decl in crate_def_map[module_id].scope.declarations() {
105 if let ModuleDefId::FunctionId(f) = decl {
106 fns.push(f)
107 }
108 }
109
110 for impl_id in crate_def_map[module_id].scope.impls() {
111 let impl_data = self.impl_data(impl_id);
112 for item in impl_data.items.iter() {
113 if let AssocItemId::FunctionId(f) = item {
114 fns.push(*f)
115 }
116 }
117 }
118 }
119
120 for f in fns {
121 let mut sink = DiagnosticSink::new(&mut cb);
122 validate_body(self, f.into(), &mut sink);
123 }
124 }
125 }
126
127 pub(crate) fn diagnostics(&self) -> (String, u32) {
128 let mut buf = String::new();
129 let mut count = 0;
130 self.diag(|d| {
131 format_to!(buf, "{:?}: {}\n", d.syntax_node(self).text(), d.message());
132 count += 1;
133 });
134 (buf, count)
135 }
136
137 pub(crate) fn extract_annotations(&self) -> FxHashMap<FileId, Vec<(TextRange, String)>> { 91 pub(crate) fn extract_annotations(&self) -> FxHashMap<FileId, Vec<(TextRange, String)>> {
138 let mut files = Vec::new(); 92 let mut files = Vec::new();
139 let crate_graph = self.crate_graph(); 93 let crate_graph = self.crate_graph();
diff --git a/crates/ra_hir_ty/src/tests.rs b/crates/ra_hir_ty/src/tests.rs
index 27f5a60bf..d57b3f288 100644
--- a/crates/ra_hir_ty/src/tests.rs
+++ b/crates/ra_hir_ty/src/tests.rs
@@ -20,7 +20,6 @@ use hir_def::{
20 AssocItemId, DefWithBodyId, LocalModuleId, Lookup, ModuleDefId, 20 AssocItemId, DefWithBodyId, LocalModuleId, Lookup, ModuleDefId,
21}; 21};
22use hir_expand::{db::AstDatabase, InFile}; 22use hir_expand::{db::AstDatabase, InFile};
23use insta::assert_snapshot;
24use ra_db::{fixture::WithFixture, FileRange, SourceDatabase, SourceDatabaseExt}; 23use ra_db::{fixture::WithFixture, FileRange, SourceDatabase, SourceDatabaseExt};
25use ra_syntax::{ 24use ra_syntax::{
26 algo, 25 algo,
@@ -341,410 +340,3 @@ fn typing_whitespace_inside_a_function_should_not_invalidate_types() {
341 assert!(!format!("{:?}", events).contains("infer"), "{:#?}", events) 340 assert!(!format!("{:?}", events).contains("infer"), "{:#?}", events)
342 } 341 }
343} 342}
344
345#[test]
346fn no_such_field_diagnostics() {
347 let diagnostics = TestDB::with_files(
348 r"
349 //- /lib.rs
350 struct S { foo: i32, bar: () }
351 impl S {
352 fn new() -> S {
353 S {
354 foo: 92,
355 baz: 62,
356 }
357 }
358 }
359 ",
360 )
361 .diagnostics()
362 .0;
363
364 assert_snapshot!(diagnostics, @r###"
365 "baz: 62": no such field
366 "{\n foo: 92,\n baz: 62,\n }": Missing structure fields:
367 - bar
368 "###
369 );
370}
371
372#[test]
373fn no_such_field_with_feature_flag_diagnostics() {
374 let diagnostics = TestDB::with_files(
375 r#"
376 //- /lib.rs crate:foo cfg:feature=foo
377 struct MyStruct {
378 my_val: usize,
379 #[cfg(feature = "foo")]
380 bar: bool,
381 }
382
383 impl MyStruct {
384 #[cfg(feature = "foo")]
385 pub(crate) fn new(my_val: usize, bar: bool) -> Self {
386 Self { my_val, bar }
387 }
388
389 #[cfg(not(feature = "foo"))]
390 pub(crate) fn new(my_val: usize, _bar: bool) -> Self {
391 Self { my_val }
392 }
393 }
394 "#,
395 )
396 .diagnostics()
397 .0;
398
399 assert_snapshot!(diagnostics, @r###""###);
400}
401
402#[test]
403fn no_such_field_enum_with_feature_flag_diagnostics() {
404 let diagnostics = TestDB::with_files(
405 r#"
406 //- /lib.rs crate:foo cfg:feature=foo
407 enum Foo {
408 #[cfg(not(feature = "foo"))]
409 Buz,
410 #[cfg(feature = "foo")]
411 Bar,
412 Baz
413 }
414
415 fn test_fn(f: Foo) {
416 match f {
417 Foo::Bar => {},
418 Foo::Baz => {},
419 }
420 }
421 "#,
422 )
423 .diagnostics()
424 .0;
425
426 assert_snapshot!(diagnostics, @r###""###);
427}
428
429#[test]
430fn no_such_field_with_feature_flag_diagnostics_on_struct_lit() {
431 let diagnostics = TestDB::with_files(
432 r#"
433 //- /lib.rs crate:foo cfg:feature=foo
434 struct S {
435 #[cfg(feature = "foo")]
436 foo: u32,
437 #[cfg(not(feature = "foo"))]
438 bar: u32,
439 }
440
441 impl S {
442 #[cfg(feature = "foo")]
443 fn new(foo: u32) -> Self {
444 Self { foo }
445 }
446 #[cfg(not(feature = "foo"))]
447 fn new(bar: u32) -> Self {
448 Self { bar }
449 }
450 }
451 "#,
452 )
453 .diagnostics()
454 .0;
455
456 assert_snapshot!(diagnostics, @r###""###);
457}
458
459#[test]
460fn no_such_field_with_feature_flag_diagnostics_on_block_expr() {
461 let diagnostics = TestDB::with_files(
462 r#"
463 //- /lib.rs crate:foo cfg:feature=foo
464 struct S {
465 #[cfg(feature = "foo")]
466 foo: u32,
467 #[cfg(not(feature = "foo"))]
468 bar: u32,
469 }
470
471 impl S {
472 fn new(bar: u32) -> Self {
473 #[cfg(feature = "foo")]
474 {
475 Self { foo: bar }
476 }
477 #[cfg(not(feature = "foo"))]
478 {
479 Self { bar }
480 }
481 }
482 }
483 "#,
484 )
485 .diagnostics()
486 .0;
487
488 assert_snapshot!(diagnostics, @r###""###);
489}
490
491#[test]
492fn no_such_field_with_feature_flag_diagnostics_on_struct_fields() {
493 let diagnostics = TestDB::with_files(
494 r#"
495 //- /lib.rs crate:foo cfg:feature=foo
496 struct S {
497 #[cfg(feature = "foo")]
498 foo: u32,
499 #[cfg(not(feature = "foo"))]
500 bar: u32,
501 }
502
503 impl S {
504 fn new(val: u32) -> Self {
505 Self {
506 #[cfg(feature = "foo")]
507 foo: val,
508 #[cfg(not(feature = "foo"))]
509 bar: val,
510 }
511 }
512 }
513 "#,
514 )
515 .diagnostics()
516 .0;
517
518 assert_snapshot!(diagnostics, @r###""###);
519}
520
521#[test]
522fn no_such_field_with_type_macro() {
523 let diagnostics = TestDB::with_files(
524 r"
525 macro_rules! Type {
526 () => { u32 };
527 }
528
529 struct Foo {
530 bar: Type![],
531 }
532 impl Foo {
533 fn new() -> Self {
534 Foo { bar: 0 }
535 }
536 }
537 ",
538 )
539 .diagnostics()
540 .0;
541
542 assert_snapshot!(diagnostics, @r###""###);
543}
544
545#[test]
546fn missing_record_pat_field_diagnostic() {
547 let diagnostics = TestDB::with_files(
548 r"
549 //- /lib.rs
550 struct S { foo: i32, bar: () }
551 fn baz(s: S) {
552 let S { foo: _ } = s;
553 }
554 ",
555 )
556 .diagnostics()
557 .0;
558
559 assert_snapshot!(diagnostics, @r###"
560 "{ foo: _ }": Missing structure fields:
561 - bar
562 "###
563 );
564}
565
566#[test]
567fn missing_record_pat_field_no_diagnostic_if_not_exhaustive() {
568 let diagnostics = TestDB::with_files(
569 r"
570 //- /lib.rs
571 struct S { foo: i32, bar: () }
572 fn baz(s: S) -> i32 {
573 match s {
574 S { foo, .. } => foo,
575 }
576 }
577 ",
578 )
579 .diagnostics()
580 .0;
581
582 assert_snapshot!(diagnostics, @"");
583}
584
585#[test]
586fn missing_unsafe_diagnostic_with_raw_ptr() {
587 let diagnostics = TestDB::with_files(
588 r"
589//- /lib.rs
590fn missing_unsafe() {
591 let x = &5 as *const usize;
592 let y = *x;
593}
594",
595 )
596 .diagnostics()
597 .0;
598
599 assert_snapshot!(diagnostics, @r#""*x": This operation is unsafe and requires an unsafe function or block"#);
600}
601
602#[test]
603fn missing_unsafe_diagnostic_with_unsafe_call() {
604 let diagnostics = TestDB::with_files(
605 r"
606//- /lib.rs
607unsafe fn unsafe_fn() {
608 let x = &5 as *const usize;
609 let y = *x;
610}
611
612fn missing_unsafe() {
613 unsafe_fn();
614}
615",
616 )
617 .diagnostics()
618 .0;
619
620 assert_snapshot!(diagnostics, @r#""unsafe_fn()": This operation is unsafe and requires an unsafe function or block"#);
621}
622
623#[test]
624fn missing_unsafe_diagnostic_with_unsafe_method_call() {
625 let diagnostics = TestDB::with_files(
626 r"
627struct HasUnsafe;
628
629impl HasUnsafe {
630 unsafe fn unsafe_fn(&self) {
631 let x = &5 as *const usize;
632 let y = *x;
633 }
634}
635
636fn missing_unsafe() {
637 HasUnsafe.unsafe_fn();
638}
639
640",
641 )
642 .diagnostics()
643 .0;
644
645 assert_snapshot!(diagnostics, @r#""HasUnsafe.unsafe_fn()": This operation is unsafe and requires an unsafe function or block"#);
646}
647
648#[test]
649fn no_missing_unsafe_diagnostic_with_raw_ptr_in_unsafe_block() {
650 let diagnostics = TestDB::with_files(
651 r"
652fn nothing_to_see_move_along() {
653 let x = &5 as *const usize;
654 unsafe {
655 let y = *x;
656 }
657}
658",
659 )
660 .diagnostics()
661 .0;
662
663 assert_snapshot!(diagnostics, @"");
664}
665
666#[test]
667fn missing_unsafe_diagnostic_with_raw_ptr_outside_unsafe_block() {
668 let diagnostics = TestDB::with_files(
669 r"
670fn nothing_to_see_move_along() {
671 let x = &5 as *const usize;
672 unsafe {
673 let y = *x;
674 }
675 let z = *x;
676}
677",
678 )
679 .diagnostics()
680 .0;
681
682 assert_snapshot!(diagnostics, @r#""*x": This operation is unsafe and requires an unsafe function or block"#);
683}
684
685#[test]
686fn no_missing_unsafe_diagnostic_with_unsafe_call_in_unsafe_block() {
687 let diagnostics = TestDB::with_files(
688 r"
689unsafe fn unsafe_fn() {
690 let x = &5 as *const usize;
691 let y = *x;
692}
693
694fn nothing_to_see_move_along() {
695 unsafe {
696 unsafe_fn();
697 }
698}
699",
700 )
701 .diagnostics()
702 .0;
703
704 assert_snapshot!(diagnostics, @"");
705}
706
707#[test]
708fn no_missing_unsafe_diagnostic_with_unsafe_method_call_in_unsafe_block() {
709 let diagnostics = TestDB::with_files(
710 r"
711struct HasUnsafe;
712
713impl HasUnsafe {
714 unsafe fn unsafe_fn() {
715 let x = &5 as *const usize;
716 let y = *x;
717 }
718}
719
720fn nothing_to_see_move_along() {
721 unsafe {
722 HasUnsafe.unsafe_fn();
723 }
724}
725
726",
727 )
728 .diagnostics()
729 .0;
730
731 assert_snapshot!(diagnostics, @"");
732}
733
734#[test]
735fn break_outside_of_loop() {
736 let diagnostics = TestDB::with_files(
737 r"
738 //- /lib.rs
739 fn foo() {
740 break;
741 }
742 ",
743 )
744 .diagnostics()
745 .0;
746
747 assert_snapshot!(diagnostics, @r###""break": break outside of loop
748 "###
749 );
750}