From 185da286d26ea7f892097c48b79a28acd7e5f172 Mon Sep 17 00:00:00 2001 From: ivan770 Date: Sat, 13 Feb 2021 13:07:47 +0200 Subject: Moved CodeLens to ide crate --- crates/ide/src/annotations.rs | 142 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 142 insertions(+) create mode 100644 crates/ide/src/annotations.rs (limited to 'crates/ide/src/annotations.rs') diff --git a/crates/ide/src/annotations.rs b/crates/ide/src/annotations.rs new file mode 100644 index 000000000..6d54b6b57 --- /dev/null +++ b/crates/ide/src/annotations.rs @@ -0,0 +1,142 @@ +use hir::Semantics; +use ide_db::{ + base_db::{FileId, FilePosition, FileRange, SourceDatabase}, + RootDatabase, SymbolKind, +}; +use syntax::TextRange; + +use crate::{ + file_structure::file_structure, + fn_references::find_all_methods, + goto_implementation::goto_implementation, + references::find_all_refs, + runnables::{runnables, Runnable}, + NavigationTarget, RunnableKind, +}; + +// Feature: Annotations +// +// Provides user with annotations above items for looking up references or impl blocks +// and running/debugging binaries. +pub struct Annotation { + pub range: TextRange, + pub kind: AnnotationKind, +} + +pub enum AnnotationKind { + Runnable { debug: bool, runnable: Runnable }, + HasImpls { position: FilePosition, data: Option> }, + HasReferences { position: FilePosition, data: Option> }, +} + +pub struct AnnotationConfig { + pub binary_target: bool, + pub annotate_runnables: bool, + pub annotate_impls: bool, + pub annotate_references: bool, + pub annotate_method_references: bool, + pub run: bool, + pub debug: bool, +} + +pub(crate) fn annotations( + db: &RootDatabase, + file_id: FileId, + config: AnnotationConfig, +) -> Vec { + let mut annotations = Vec::default(); + + if config.annotate_runnables { + for runnable in runnables(db, file_id) { + if !matches!(runnable.kind, RunnableKind::Bin) || !config.binary_target { + continue; + } + + let action = runnable.action(); + let range = runnable.nav.full_range; + + if config.run { + annotations.push(Annotation { + range, + // FIXME: This one allocates without reason if run is enabled, but debug is disabled + kind: AnnotationKind::Runnable { debug: false, runnable: runnable.clone() }, + }); + } + + if action.debugee && config.debug { + annotations.push(Annotation { + range, + kind: AnnotationKind::Runnable { debug: true, runnable }, + }); + } + } + } + + file_structure(&db.parse(file_id).tree()) + .into_iter() + .filter(|node| { + matches!( + node.kind, + SymbolKind::Trait + | SymbolKind::Struct + | SymbolKind::Enum + | SymbolKind::Union + | SymbolKind::Const + ) + }) + .for_each(|node| { + if config.annotate_impls && node.kind != SymbolKind::Const { + annotations.push(Annotation { + range: node.node_range, + kind: AnnotationKind::HasImpls { + position: FilePosition { file_id, offset: node.navigation_range.start() }, + data: None, + }, + }); + } + + if config.annotate_references { + annotations.push(Annotation { + range: node.node_range, + kind: AnnotationKind::HasReferences { + position: FilePosition { file_id, offset: node.navigation_range.start() }, + data: None, + }, + }); + } + }); + + if config.annotate_method_references { + annotations.extend(find_all_methods(db, file_id).into_iter().map(|method| Annotation { + range: method.range, + kind: AnnotationKind::HasReferences { + position: FilePosition { file_id, offset: method.range.start() }, + data: None, + }, + })); + } + + annotations +} + +pub(crate) fn resolve_annotation(db: &RootDatabase, mut annotation: Annotation) -> Annotation { + match annotation.kind { + AnnotationKind::HasImpls { position, ref mut data } => { + *data = goto_implementation(db, position).map(|range| range.info); + } + AnnotationKind::HasReferences { position, ref mut data } => { + *data = find_all_refs(&Semantics::new(db), position, None).map(|result| { + result + .references + .into_iter() + .map(|(_, access)| access.into_iter()) + .flatten() + .map(|(range, _)| FileRange { file_id: position.file_id, range }) + .collect() + }); + } + _ => {} + }; + + annotation +} -- cgit v1.2.3 From 02ad828c6dc544ac2fb20b85d85ccf6ea495df9c Mon Sep 17 00:00:00 2001 From: ivan770 Date: Sat, 13 Feb 2021 13:22:12 +0200 Subject: Fix incorrect references annotation --- crates/ide/src/annotations.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'crates/ide/src/annotations.rs') diff --git a/crates/ide/src/annotations.rs b/crates/ide/src/annotations.rs index 6d54b6b57..a6f093ad7 100644 --- a/crates/ide/src/annotations.rs +++ b/crates/ide/src/annotations.rs @@ -129,9 +129,10 @@ pub(crate) fn resolve_annotation(db: &RootDatabase, mut annotation: Annotation) result .references .into_iter() - .map(|(_, access)| access.into_iter()) + .map(|(file_id, access)| { + access.into_iter().map(move |(range, _)| FileRange { file_id, range }) + }) .flatten() - .map(|(range, _)| FileRange { file_id: position.file_id, range }) .collect() }); } -- cgit v1.2.3 From c46b32c44987de02559f7ec5898765722fa45166 Mon Sep 17 00:00:00 2001 From: ivan770 Date: Sat, 13 Feb 2021 15:27:04 +0200 Subject: Added annotation tests --- crates/ide/src/annotations.rs | 267 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 267 insertions(+) (limited to 'crates/ide/src/annotations.rs') diff --git a/crates/ide/src/annotations.rs b/crates/ide/src/annotations.rs index a6f093ad7..97a361194 100644 --- a/crates/ide/src/annotations.rs +++ b/crates/ide/src/annotations.rs @@ -18,11 +18,13 @@ use crate::{ // // Provides user with annotations above items for looking up references or impl blocks // and running/debugging binaries. +#[derive(Debug)] pub struct Annotation { pub range: TextRange, pub kind: AnnotationKind, } +#[derive(Debug)] pub enum AnnotationKind { Runnable { debug: bool, runnable: Runnable }, HasImpls { position: FilePosition, data: Option> }, @@ -141,3 +143,268 @@ pub(crate) fn resolve_annotation(db: &RootDatabase, mut annotation: Annotation) annotation } + +#[cfg(test)] +mod tests { + use ide_db::base_db::{FileId, FileRange}; + use syntax::{TextRange, TextSize}; + + use crate::{fixture, Annotation, AnnotationConfig, AnnotationKind, RunnableKind}; + + fn get_annotations( + ra_fixture: &str, + annotation_config: AnnotationConfig, + ) -> (FileId, Vec) { + let (analysis, file_id) = fixture::file(ra_fixture); + + let annotations: Vec = analysis + .annotations(file_id, annotation_config) + .unwrap() + .into_iter() + .map(move |annotation| analysis.resolve_annotation(annotation).unwrap()) + .collect(); + + if annotations.len() == 0 { + panic!("unresolved annotations") + } + + (file_id, annotations) + } + + macro_rules! check_annotation { + ( $ra_fixture:expr, $config:expr, $item_positions:expr, $pattern:pat, $checker:expr ) => { + let (file_id, annotations) = get_annotations($ra_fixture, $config); + + annotations.into_iter().for_each(|annotation| { + assert!($item_positions.contains(&annotation.range)); + + match annotation.kind { + $pattern => $checker(file_id), + _ => panic!("Unexpected annotation kind"), + } + }); + }; + } + + #[test] + fn const_annotations() { + check_annotation!( + r#" +const DEMO: i32 = 123; + +fn main() { + let hello = DEMO; +} + "#, + AnnotationConfig { + binary_target: false, + annotate_runnables: false, + annotate_impls: false, + annotate_references: true, + annotate_method_references: false, + run: false, + debug: false, + }, + &[TextRange::new(TextSize::from(0), TextSize::from(22))], + AnnotationKind::HasReferences { data: Some(ranges), .. }, + |file_id| assert_eq!( + *ranges.first().unwrap(), + FileRange { + file_id, + range: TextRange::new(TextSize::from(52), TextSize::from(56)) + } + ) + ); + } + + #[test] + fn unused_const_annotations() { + check_annotation!( + r#" +const DEMO: i32 = 123; + +fn main() {} + "#, + AnnotationConfig { + binary_target: false, + annotate_runnables: false, + annotate_impls: false, + annotate_references: true, + annotate_method_references: false, + run: false, + debug: false, + }, + &[TextRange::new(TextSize::from(0), TextSize::from(22))], + AnnotationKind::HasReferences { data: Some(ranges), .. }, + |_| assert_eq!(ranges.len(), 0) + ); + } + + #[test] + fn struct_references_annotations() { + check_annotation!( + r#" +struct Test; + +fn main() { + let test = Test; +} + "#, + AnnotationConfig { + binary_target: false, + annotate_runnables: false, + annotate_impls: false, + annotate_references: true, + annotate_method_references: false, + run: false, + debug: false, + }, + &[TextRange::new(TextSize::from(0), TextSize::from(12))], + AnnotationKind::HasReferences { data: Some(ranges), .. }, + |file_id| assert_eq!( + *ranges.first().unwrap(), + FileRange { + file_id, + range: TextRange::new(TextSize::from(41), TextSize::from(45)) + } + ) + ); + } + + #[test] + fn struct_and_trait_impls_annotations() { + check_annotation!( + r#" +struct Test; + +trait MyCoolTrait {} + +impl MyCoolTrait for Test {} + +fn main() { + let test = Test; +} + "#, + AnnotationConfig { + binary_target: false, + annotate_runnables: false, + annotate_impls: true, + annotate_references: false, + annotate_method_references: false, + run: false, + debug: false, + }, + &[ + TextRange::new(TextSize::from(0), TextSize::from(12)), + TextRange::new(TextSize::from(14), TextSize::from(34)) + ], + AnnotationKind::HasImpls { data: Some(ranges), .. }, + |_| assert_eq!( + ranges.first().unwrap().full_range, + TextRange::new(TextSize::from(36), TextSize::from(64)) + ) + ); + } + + #[test] + fn run_annotation() { + check_annotation!( + r#" +fn main() {} + "#, + AnnotationConfig { + binary_target: true, + annotate_runnables: true, + annotate_impls: false, + annotate_references: false, + annotate_method_references: false, + run: true, + debug: false, + }, + &[TextRange::new(TextSize::from(0), TextSize::from(12))], + AnnotationKind::Runnable { debug: false, runnable }, + |_| { + assert!(matches!(runnable.kind, RunnableKind::Bin)); + assert!(runnable.action().run_title.contains("Run")); + } + ); + } + + #[test] + fn debug_annotation() { + check_annotation!( + r#" +fn main() {} + "#, + AnnotationConfig { + binary_target: true, + annotate_runnables: true, + annotate_impls: false, + annotate_references: false, + annotate_method_references: false, + run: false, + debug: true, + }, + &[TextRange::new(TextSize::from(0), TextSize::from(12))], + AnnotationKind::Runnable { debug: true, runnable }, + |_| { + assert!(matches!(runnable.kind, RunnableKind::Bin)); + assert!(runnable.action().debugee); + } + ); + } + + #[test] + fn method_annotations() { + // We actually want to skip `fn main` annotation, as it has no references in it + // but just ignoring empty reference slices would lead to false-positive if something + // goes wrong in annotation resolving mechanism. By tracking if we iterated before finding + // an empty slice we can track if everything is settled. + let mut iterated_once = false; + + check_annotation!( + r#" +struct Test; + +impl Test { + fn self_by_ref(&self) {} +} + +fn main() { + Test.self_by_ref(); +} + "#, + AnnotationConfig { + binary_target: false, + annotate_runnables: false, + annotate_impls: false, + annotate_references: false, + annotate_method_references: true, + run: false, + debug: false, + }, + &[ + TextRange::new(TextSize::from(33), TextSize::from(44)), + TextRange::new(TextSize::from(61), TextSize::from(65)) + ], + AnnotationKind::HasReferences { data: Some(ranges), .. }, + |file_id| { + match ranges.as_slice() { + [first, ..] => { + assert_eq!( + *first, + FileRange { + file_id, + range: TextRange::new(TextSize::from(79), TextSize::from(90)) + } + ); + + iterated_once = true; + } + [] if iterated_once => {} + [] => panic!("One reference was expected but not found"), + } + } + ); + } +} -- cgit v1.2.3 From ee049b256a7718fb346a7172a34f0fc324b3269b Mon Sep 17 00:00:00 2001 From: ivan770 Date: Sat, 13 Feb 2021 15:47:53 +0200 Subject: Improve runnable annotations order, fix incorrect ignore detection --- crates/ide/src/annotations.rs | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) (limited to 'crates/ide/src/annotations.rs') diff --git a/crates/ide/src/annotations.rs b/crates/ide/src/annotations.rs index 97a361194..43250bf5d 100644 --- a/crates/ide/src/annotations.rs +++ b/crates/ide/src/annotations.rs @@ -50,25 +50,26 @@ pub(crate) fn annotations( if config.annotate_runnables { for runnable in runnables(db, file_id) { - if !matches!(runnable.kind, RunnableKind::Bin) || !config.binary_target { + if should_skip_runnable(&runnable.kind, config.binary_target) { continue; } let action = runnable.action(); let range = runnable.nav.full_range; - if config.run { + if action.debugee && config.debug { annotations.push(Annotation { range, + // FIXME: This one allocates without reason if run is enabled, but debug is disabled - kind: AnnotationKind::Runnable { debug: false, runnable: runnable.clone() }, + kind: AnnotationKind::Runnable { debug: true, runnable: runnable.clone() }, }); } - if action.debugee && config.debug { + if config.run { annotations.push(Annotation { range, - kind: AnnotationKind::Runnable { debug: true, runnable }, + kind: AnnotationKind::Runnable { debug: false, runnable }, }); } } @@ -144,6 +145,13 @@ pub(crate) fn resolve_annotation(db: &RootDatabase, mut annotation: Annotation) annotation } +fn should_skip_runnable(kind: &RunnableKind, binary_target: bool) -> bool { + match kind { + RunnableKind::Bin => !binary_target, + _ => false, + } +} + #[cfg(test)] mod tests { use ide_db::base_db::{FileId, FileRange}; -- cgit v1.2.3 From 4c2b201b7d836c3978665c6ed955fafea90cb3dd Mon Sep 17 00:00:00 2001 From: ivan770 Date: Sat, 13 Feb 2021 19:18:13 +0200 Subject: Make annotations tests similar to those in runnables --- crates/ide/src/annotations.rs | 895 +++++++++++++++++++++++++++++++++--------- 1 file changed, 707 insertions(+), 188 deletions(-) (limited to 'crates/ide/src/annotations.rs') diff --git a/crates/ide/src/annotations.rs b/crates/ide/src/annotations.rs index 43250bf5d..414a60bed 100644 --- a/crates/ide/src/annotations.rs +++ b/crates/ide/src/annotations.rs @@ -154,103 +154,143 @@ fn should_skip_runnable(kind: &RunnableKind, binary_target: bool) -> bool { #[cfg(test)] mod tests { - use ide_db::base_db::{FileId, FileRange}; - use syntax::{TextRange, TextSize}; + use expect_test::{expect, Expect}; - use crate::{fixture, Annotation, AnnotationConfig, AnnotationKind, RunnableKind}; + use crate::{fixture, Annotation, AnnotationConfig}; - fn get_annotations( - ra_fixture: &str, - annotation_config: AnnotationConfig, - ) -> (FileId, Vec) { + fn check(ra_fixture: &str, expect: Expect) { let (analysis, file_id) = fixture::file(ra_fixture); let annotations: Vec = analysis - .annotations(file_id, annotation_config) + .annotations( + file_id, + AnnotationConfig { + binary_target: true, + annotate_runnables: true, + annotate_impls: true, + annotate_references: true, + annotate_method_references: true, + run: true, + debug: true, + }, + ) .unwrap() .into_iter() - .map(move |annotation| analysis.resolve_annotation(annotation).unwrap()) + .map(|annotation| analysis.resolve_annotation(annotation).unwrap()) .collect(); - if annotations.len() == 0 { - panic!("unresolved annotations") - } - - (file_id, annotations) - } - - macro_rules! check_annotation { - ( $ra_fixture:expr, $config:expr, $item_positions:expr, $pattern:pat, $checker:expr ) => { - let (file_id, annotations) = get_annotations($ra_fixture, $config); - - annotations.into_iter().for_each(|annotation| { - assert!($item_positions.contains(&annotation.range)); - - match annotation.kind { - $pattern => $checker(file_id), - _ => panic!("Unexpected annotation kind"), - } - }); - }; + expect.assert_debug_eq(&annotations); } #[test] fn const_annotations() { - check_annotation!( + check( r#" const DEMO: i32 = 123; +const UNUSED: i32 = 123; + fn main() { let hello = DEMO; } "#, - AnnotationConfig { - binary_target: false, - annotate_runnables: false, - annotate_impls: false, - annotate_references: true, - annotate_method_references: false, - run: false, - debug: false, - }, - &[TextRange::new(TextSize::from(0), TextSize::from(22))], - AnnotationKind::HasReferences { data: Some(ranges), .. }, - |file_id| assert_eq!( - *ranges.first().unwrap(), - FileRange { - file_id, - range: TextRange::new(TextSize::from(52), TextSize::from(56)) - } - ) - ); - } - - #[test] - fn unused_const_annotations() { - check_annotation!( - r#" -const DEMO: i32 = 123; - -fn main() {} - "#, - AnnotationConfig { - binary_target: false, - annotate_runnables: false, - annotate_impls: false, - annotate_references: true, - annotate_method_references: false, - run: false, - debug: false, - }, - &[TextRange::new(TextSize::from(0), TextSize::from(22))], - AnnotationKind::HasReferences { data: Some(ranges), .. }, - |_| assert_eq!(ranges.len(), 0) + expect![[r#" + [ + Annotation { + range: 50..85, + kind: Runnable { + debug: true, + runnable: Runnable { + nav: NavigationTarget { + file_id: FileId( + 0, + ), + full_range: 50..85, + focus_range: 53..57, + name: "main", + kind: Function, + }, + kind: Bin, + cfg: None, + }, + }, + }, + Annotation { + range: 50..85, + kind: Runnable { + debug: false, + runnable: Runnable { + nav: NavigationTarget { + file_id: FileId( + 0, + ), + full_range: 50..85, + focus_range: 53..57, + name: "main", + kind: Function, + }, + kind: Bin, + cfg: None, + }, + }, + }, + Annotation { + range: 0..22, + kind: HasReferences { + position: FilePosition { + file_id: FileId( + 0, + ), + offset: 6, + }, + data: Some( + [ + FileRange { + file_id: FileId( + 0, + ), + range: 78..82, + }, + ], + ), + }, + }, + Annotation { + range: 24..48, + kind: HasReferences { + position: FilePosition { + file_id: FileId( + 0, + ), + offset: 30, + }, + data: Some( + [], + ), + }, + }, + Annotation { + range: 53..57, + kind: HasReferences { + position: FilePosition { + file_id: FileId( + 0, + ), + offset: 53, + }, + data: Some( + [], + ), + }, + }, + ] + "#]], ); } #[test] fn struct_references_annotations() { - check_annotation!( + check( r#" struct Test; @@ -258,30 +298,103 @@ fn main() { let test = Test; } "#, - AnnotationConfig { - binary_target: false, - annotate_runnables: false, - annotate_impls: false, - annotate_references: true, - annotate_method_references: false, - run: false, - debug: false, - }, - &[TextRange::new(TextSize::from(0), TextSize::from(12))], - AnnotationKind::HasReferences { data: Some(ranges), .. }, - |file_id| assert_eq!( - *ranges.first().unwrap(), - FileRange { - file_id, - range: TextRange::new(TextSize::from(41), TextSize::from(45)) - } - ) + expect![[r#" + [ + Annotation { + range: 14..48, + kind: Runnable { + debug: true, + runnable: Runnable { + nav: NavigationTarget { + file_id: FileId( + 0, + ), + full_range: 14..48, + focus_range: 17..21, + name: "main", + kind: Function, + }, + kind: Bin, + cfg: None, + }, + }, + }, + Annotation { + range: 14..48, + kind: Runnable { + debug: false, + runnable: Runnable { + nav: NavigationTarget { + file_id: FileId( + 0, + ), + full_range: 14..48, + focus_range: 17..21, + name: "main", + kind: Function, + }, + kind: Bin, + cfg: None, + }, + }, + }, + Annotation { + range: 0..12, + kind: HasImpls { + position: FilePosition { + file_id: FileId( + 0, + ), + offset: 7, + }, + data: Some( + [], + ), + }, + }, + Annotation { + range: 0..12, + kind: HasReferences { + position: FilePosition { + file_id: FileId( + 0, + ), + offset: 7, + }, + data: Some( + [ + FileRange { + file_id: FileId( + 0, + ), + range: 41..45, + }, + ], + ), + }, + }, + Annotation { + range: 17..21, + kind: HasReferences { + position: FilePosition { + file_id: FileId( + 0, + ), + offset: 17, + }, + data: Some( + [], + ), + }, + }, + ] + "#]], ); } #[test] fn struct_and_trait_impls_annotations() { - check_annotation!( + check( r#" struct Test; @@ -293,84 +406,229 @@ fn main() { let test = Test; } "#, - AnnotationConfig { - binary_target: false, - annotate_runnables: false, - annotate_impls: true, - annotate_references: false, - annotate_method_references: false, - run: false, - debug: false, - }, - &[ - TextRange::new(TextSize::from(0), TextSize::from(12)), - TextRange::new(TextSize::from(14), TextSize::from(34)) - ], - AnnotationKind::HasImpls { data: Some(ranges), .. }, - |_| assert_eq!( - ranges.first().unwrap().full_range, - TextRange::new(TextSize::from(36), TextSize::from(64)) - ) - ); - } - - #[test] - fn run_annotation() { - check_annotation!( - r#" -fn main() {} - "#, - AnnotationConfig { - binary_target: true, - annotate_runnables: true, - annotate_impls: false, - annotate_references: false, - annotate_method_references: false, - run: true, - debug: false, - }, - &[TextRange::new(TextSize::from(0), TextSize::from(12))], - AnnotationKind::Runnable { debug: false, runnable }, - |_| { - assert!(matches!(runnable.kind, RunnableKind::Bin)); - assert!(runnable.action().run_title.contains("Run")); - } + expect![[r#" + [ + Annotation { + range: 66..100, + kind: Runnable { + debug: true, + runnable: Runnable { + nav: NavigationTarget { + file_id: FileId( + 0, + ), + full_range: 66..100, + focus_range: 69..73, + name: "main", + kind: Function, + }, + kind: Bin, + cfg: None, + }, + }, + }, + Annotation { + range: 66..100, + kind: Runnable { + debug: false, + runnable: Runnable { + nav: NavigationTarget { + file_id: FileId( + 0, + ), + full_range: 66..100, + focus_range: 69..73, + name: "main", + kind: Function, + }, + kind: Bin, + cfg: None, + }, + }, + }, + Annotation { + range: 0..12, + kind: HasImpls { + position: FilePosition { + file_id: FileId( + 0, + ), + offset: 7, + }, + data: Some( + [ + NavigationTarget { + file_id: FileId( + 0, + ), + full_range: 36..64, + focus_range: 57..61, + name: "impl", + kind: Impl, + }, + ], + ), + }, + }, + Annotation { + range: 0..12, + kind: HasReferences { + position: FilePosition { + file_id: FileId( + 0, + ), + offset: 7, + }, + data: Some( + [ + FileRange { + file_id: FileId( + 0, + ), + range: 57..61, + }, + FileRange { + file_id: FileId( + 0, + ), + range: 93..97, + }, + ], + ), + }, + }, + Annotation { + range: 14..34, + kind: HasImpls { + position: FilePosition { + file_id: FileId( + 0, + ), + offset: 20, + }, + data: Some( + [ + NavigationTarget { + file_id: FileId( + 0, + ), + full_range: 36..64, + focus_range: 57..61, + name: "impl", + kind: Impl, + }, + ], + ), + }, + }, + Annotation { + range: 14..34, + kind: HasReferences { + position: FilePosition { + file_id: FileId( + 0, + ), + offset: 20, + }, + data: Some( + [ + FileRange { + file_id: FileId( + 0, + ), + range: 41..52, + }, + ], + ), + }, + }, + Annotation { + range: 69..73, + kind: HasReferences { + position: FilePosition { + file_id: FileId( + 0, + ), + offset: 69, + }, + data: Some( + [], + ), + }, + }, + ] + "#]], ); } #[test] - fn debug_annotation() { - check_annotation!( + fn runnable_annotation() { + check( r#" fn main() {} "#, - AnnotationConfig { - binary_target: true, - annotate_runnables: true, - annotate_impls: false, - annotate_references: false, - annotate_method_references: false, - run: false, - debug: true, - }, - &[TextRange::new(TextSize::from(0), TextSize::from(12))], - AnnotationKind::Runnable { debug: true, runnable }, - |_| { - assert!(matches!(runnable.kind, RunnableKind::Bin)); - assert!(runnable.action().debugee); - } + expect![[r#" + [ + Annotation { + range: 0..12, + kind: Runnable { + debug: true, + runnable: Runnable { + nav: NavigationTarget { + file_id: FileId( + 0, + ), + full_range: 0..12, + focus_range: 3..7, + name: "main", + kind: Function, + }, + kind: Bin, + cfg: None, + }, + }, + }, + Annotation { + range: 0..12, + kind: Runnable { + debug: false, + runnable: Runnable { + nav: NavigationTarget { + file_id: FileId( + 0, + ), + full_range: 0..12, + focus_range: 3..7, + name: "main", + kind: Function, + }, + kind: Bin, + cfg: None, + }, + }, + }, + Annotation { + range: 3..7, + kind: HasReferences { + position: FilePosition { + file_id: FileId( + 0, + ), + offset: 3, + }, + data: Some( + [], + ), + }, + }, + ] + "#]], ); } #[test] fn method_annotations() { - // We actually want to skip `fn main` annotation, as it has no references in it - // but just ignoring empty reference slices would lead to false-positive if something - // goes wrong in annotation resolving mechanism. By tracking if we iterated before finding - // an empty slice we can track if everything is settled. - let mut iterated_once = false; - - check_annotation!( + check( r#" struct Test; @@ -382,37 +640,298 @@ fn main() { Test.self_by_ref(); } "#, - AnnotationConfig { - binary_target: false, - annotate_runnables: false, - annotate_impls: false, - annotate_references: false, - annotate_method_references: true, - run: false, - debug: false, - }, - &[ - TextRange::new(TextSize::from(33), TextSize::from(44)), - TextRange::new(TextSize::from(61), TextSize::from(65)) - ], - AnnotationKind::HasReferences { data: Some(ranges), .. }, - |file_id| { - match ranges.as_slice() { - [first, ..] => { - assert_eq!( - *first, - FileRange { - file_id, - range: TextRange::new(TextSize::from(79), TextSize::from(90)) - } - ); - - iterated_once = true; - } - [] if iterated_once => {} - [] => panic!("One reference was expected but not found"), - } - } + expect![[r#" + [ + Annotation { + range: 58..95, + kind: Runnable { + debug: true, + runnable: Runnable { + nav: NavigationTarget { + file_id: FileId( + 0, + ), + full_range: 58..95, + focus_range: 61..65, + name: "main", + kind: Function, + }, + kind: Bin, + cfg: None, + }, + }, + }, + Annotation { + range: 58..95, + kind: Runnable { + debug: false, + runnable: Runnable { + nav: NavigationTarget { + file_id: FileId( + 0, + ), + full_range: 58..95, + focus_range: 61..65, + name: "main", + kind: Function, + }, + kind: Bin, + cfg: None, + }, + }, + }, + Annotation { + range: 0..12, + kind: HasImpls { + position: FilePosition { + file_id: FileId( + 0, + ), + offset: 7, + }, + data: Some( + [ + NavigationTarget { + file_id: FileId( + 0, + ), + full_range: 14..56, + focus_range: 19..23, + name: "impl", + kind: Impl, + }, + ], + ), + }, + }, + Annotation { + range: 0..12, + kind: HasReferences { + position: FilePosition { + file_id: FileId( + 0, + ), + offset: 7, + }, + data: Some( + [ + FileRange { + file_id: FileId( + 0, + ), + range: 19..23, + }, + FileRange { + file_id: FileId( + 0, + ), + range: 74..78, + }, + ], + ), + }, + }, + Annotation { + range: 33..44, + kind: HasReferences { + position: FilePosition { + file_id: FileId( + 0, + ), + offset: 33, + }, + data: Some( + [ + FileRange { + file_id: FileId( + 0, + ), + range: 79..90, + }, + ], + ), + }, + }, + Annotation { + range: 61..65, + kind: HasReferences { + position: FilePosition { + file_id: FileId( + 0, + ), + offset: 61, + }, + data: Some( + [], + ), + }, + }, + ] + "#]], + ); + } + + #[test] + fn test_annotations() { + check( + r#" +fn main() {} + +mod tests { + #[test] + fn my_cool_test() {} +} + "#, + expect![[r#" + [ + Annotation { + range: 0..12, + kind: Runnable { + debug: true, + runnable: Runnable { + nav: NavigationTarget { + file_id: FileId( + 0, + ), + full_range: 0..12, + focus_range: 3..7, + name: "main", + kind: Function, + }, + kind: Bin, + cfg: None, + }, + }, + }, + Annotation { + range: 0..12, + kind: Runnable { + debug: false, + runnable: Runnable { + nav: NavigationTarget { + file_id: FileId( + 0, + ), + full_range: 0..12, + focus_range: 3..7, + name: "main", + kind: Function, + }, + kind: Bin, + cfg: None, + }, + }, + }, + Annotation { + range: 14..64, + kind: Runnable { + debug: true, + runnable: Runnable { + nav: NavigationTarget { + file_id: FileId( + 0, + ), + full_range: 14..64, + focus_range: 18..23, + name: "tests", + kind: Module, + }, + kind: TestMod { + path: "tests", + }, + cfg: None, + }, + }, + }, + Annotation { + range: 14..64, + kind: Runnable { + debug: false, + runnable: Runnable { + nav: NavigationTarget { + file_id: FileId( + 0, + ), + full_range: 14..64, + focus_range: 18..23, + name: "tests", + kind: Module, + }, + kind: TestMod { + path: "tests", + }, + cfg: None, + }, + }, + }, + Annotation { + range: 30..62, + kind: Runnable { + debug: true, + runnable: Runnable { + nav: NavigationTarget { + file_id: FileId( + 0, + ), + full_range: 30..62, + focus_range: 45..57, + name: "my_cool_test", + kind: Function, + }, + kind: Test { + test_id: Path( + "tests::my_cool_test", + ), + attr: TestAttr { + ignore: false, + }, + }, + cfg: None, + }, + }, + }, + Annotation { + range: 30..62, + kind: Runnable { + debug: false, + runnable: Runnable { + nav: NavigationTarget { + file_id: FileId( + 0, + ), + full_range: 30..62, + focus_range: 45..57, + name: "my_cool_test", + kind: Function, + }, + kind: Test { + test_id: Path( + "tests::my_cool_test", + ), + attr: TestAttr { + ignore: false, + }, + }, + cfg: None, + }, + }, + }, + Annotation { + range: 3..7, + kind: HasReferences { + position: FilePosition { + file_id: FileId( + 0, + ), + offset: 3, + }, + data: Some( + [], + ), + }, + }, + ] + "#]], ); } } -- cgit v1.2.3