1 //! This module implements a methods and free functions search in the specified file.
2 //! We have to skip tests, so cannot reuse file_structure module.
5 use ide_db::RootDatabase;
6 use syntax::{ast, ast::NameOwner, AstNode, SyntaxNode};
8 use crate::{runnables::has_test_related_attribute, FileId, FileRange};
10 pub(crate) fn find_all_methods(db: &RootDatabase, file_id: FileId) -> Vec<FileRange> {
11 let sema = Semantics::new(db);
12 let source_file = sema.parse(file_id);
13 source_file.syntax().descendants().filter_map(|it| method_range(it, file_id)).collect()
16 fn method_range(item: SyntaxNode, file_id: FileId) -> Option<FileRange> {
17 ast::Fn::cast(item).and_then(|fn_def| {
18 if has_test_related_attribute(&fn_def) {
21 fn_def.name().map(|name| FileRange { file_id, range: name.syntax().text_range() })
29 use crate::{FileRange, TextSize};
30 use std::ops::RangeInclusive;
33 fn test_find_all_methods() {
34 let (analysis, pos) = fixture::position(
40 pub fn generic_fn<T>(arg: T) {}
44 let refs = analysis.find_all_methods(pos.file_id).unwrap();
45 check_result(&refs, &[3..=13, 27..=33, 47..=57]);
49 fn test_find_trait_methods() {
50 let (analysis, pos) = fixture::position(
59 let refs = analysis.find_all_methods(pos.file_id).unwrap();
60 check_result(&refs, &[19..=22, 35..=38]);
64 fn test_skip_tests() {
65 let (analysis, pos) = fixture::position(
80 let refs = analysis.find_all_methods(pos.file_id).unwrap();
81 check_result(&refs, &[28..=34]);
84 fn check_result(refs: &[FileRange], expected: &[RangeInclusive<u32>]) {
85 assert_eq!(refs.len(), expected.len());
87 for (i, item) in refs.iter().enumerate() {
88 let range = &expected[i];
89 assert_eq!(TextSize::from(*range.start()), item.range.start());
90 assert_eq!(TextSize::from(*range.end()), item.range.end());