wowlab_tidy/languages/rust/rules/api/
support.rs1use ra_ap_syntax::{
2 AstNode,
3 ast::{self, HasAttrs},
4};
5
6pub(super) fn has_derive(item: &impl HasAttrs, target: &str) -> bool {
8 item.attrs().any(|attr| {
9 attr.as_simple_call().is_some_and(|(name, tokens)| {
10 name == "derive"
11 && tokens.syntax().text().to_string().split(',').any(|entry| {
12 entry
13 .trim_matches(|ch: char| ch.is_whitespace() || matches!(ch, '(' | ')'))
14 .rsplit("::")
15 .next()
16 == Some(target)
17 })
18 })
19 })
20}
21
22pub(super) fn type_name(ty: &ast::Type) -> Option<String> {
23 let ast::Type::PathType(path) = ty else {
24 return None;
25 };
26
27 path.path()?
28 .segment()?
29 .name_ref()
30 .map(|name| name.text().to_string())
31}
32
33pub(super) fn path_reachable_from(root: &ast::Type, path: &ast::PathType) -> bool {
34 path.syntax()
35 .ancestors()
36 .take_while(|node| node != root.syntax())
37 .filter_map(ast::Type::cast)
38 .all(|ty| {
39 matches!(
40 ty,
41 ast::Type::PathType(_)
42 | ast::Type::RefType(_)
43 | ast::Type::SliceType(_)
44 | ast::Type::ArrayType(_)
45 | ast::Type::ParenType(_)
46 | ast::Type::TupleType(_)
47 )
48 })
49 && matches!(
50 root,
51 ast::Type::PathType(_)
52 | ast::Type::RefType(_)
53 | ast::Type::SliceType(_)
54 | ast::Type::ArrayType(_)
55 | ast::Type::ParenType(_)
56 | ast::Type::TupleType(_)
57 )
58}