]> git.proxmox.com Git - rustc.git/blob - src/tools/rust-analyzer/crates/ide-db/src/helpers.rs
New upstream version 1.70.0+dfsg1
[rustc.git] / src / tools / rust-analyzer / crates / ide-db / src / helpers.rs
1 //! Random assortment of ide helpers for high-level ide features that don't fit in any other module.
2
3 use std::collections::VecDeque;
4
5 use base_db::{FileId, SourceDatabaseExt};
6 use hir::{Crate, ItemInNs, ModuleDef, Name, Semantics};
7 use syntax::{
8 ast::{self, make},
9 AstToken, SyntaxKind, SyntaxToken, TokenAtOffset,
10 };
11
12 use crate::{defs::Definition, generated, RootDatabase};
13
14 pub fn item_name(db: &RootDatabase, item: ItemInNs) -> Option<Name> {
15 match item {
16 ItemInNs::Types(module_def_id) => module_def_id.name(db),
17 ItemInNs::Values(module_def_id) => module_def_id.name(db),
18 ItemInNs::Macros(macro_def_id) => Some(macro_def_id.name(db)),
19 }
20 }
21
22 /// Picks the token with the highest rank returned by the passed in function.
23 pub fn pick_best_token(
24 tokens: TokenAtOffset<SyntaxToken>,
25 f: impl Fn(SyntaxKind) -> usize,
26 ) -> Option<SyntaxToken> {
27 tokens.max_by_key(move |t| f(t.kind()))
28 }
29 pub fn pick_token<T: AstToken>(mut tokens: TokenAtOffset<SyntaxToken>) -> Option<T> {
30 tokens.find_map(T::cast)
31 }
32
33 /// Converts the mod path struct into its ast representation.
34 pub fn mod_path_to_ast(path: &hir::ModPath) -> ast::Path {
35 let _p = profile::span("mod_path_to_ast");
36
37 let mut segments = Vec::new();
38 let mut is_abs = false;
39 match path.kind {
40 hir::PathKind::Plain => {}
41 hir::PathKind::Super(0) => segments.push(make::path_segment_self()),
42 hir::PathKind::Super(n) => segments.extend((0..n).map(|_| make::path_segment_super())),
43 hir::PathKind::DollarCrate(_) | hir::PathKind::Crate => {
44 segments.push(make::path_segment_crate())
45 }
46 hir::PathKind::Abs => is_abs = true,
47 }
48
49 segments.extend(
50 path.segments()
51 .iter()
52 .map(|segment| make::path_segment(make::name_ref(&segment.to_smol_str()))),
53 );
54 make::path_from_segments(segments, is_abs)
55 }
56
57 /// Iterates all `ModuleDef`s and `Impl` blocks of the given file.
58 pub fn visit_file_defs(
59 sema: &Semantics<'_, RootDatabase>,
60 file_id: FileId,
61 cb: &mut dyn FnMut(Definition),
62 ) {
63 let db = sema.db;
64 let module = match sema.to_module_def(file_id) {
65 Some(it) => it,
66 None => return,
67 };
68 let mut defs: VecDeque<_> = module.declarations(db).into();
69 while let Some(def) = defs.pop_front() {
70 if let ModuleDef::Module(submodule) = def {
71 if let hir::ModuleSource::Module(_) = submodule.definition_source(db).value {
72 defs.extend(submodule.declarations(db));
73 submodule.impl_defs(db).into_iter().for_each(|impl_| cb(impl_.into()));
74 }
75 }
76 cb(def.into());
77 }
78 module.impl_defs(db).into_iter().for_each(|impl_| cb(impl_.into()));
79
80 let is_root = module.is_crate_root(db);
81 module
82 .legacy_macros(db)
83 .into_iter()
84 // don't show legacy macros declared in the crate-root that were already covered in declarations earlier
85 .filter(|it| !(is_root && it.is_macro_export(db)))
86 .for_each(|mac| cb(mac.into()));
87 }
88
89 /// Checks if the given lint is equal or is contained by the other lint which may or may not be a group.
90 pub fn lint_eq_or_in_group(lint: &str, lint_is: &str) -> bool {
91 if lint == lint_is {
92 return true;
93 }
94
95 if let Some(group) = generated::lints::DEFAULT_LINT_GROUPS
96 .iter()
97 .chain(generated::lints::CLIPPY_LINT_GROUPS.iter())
98 .chain(generated::lints::RUSTDOC_LINT_GROUPS.iter())
99 .find(|&check| check.lint.label == lint_is)
100 {
101 group.children.contains(&lint)
102 } else {
103 false
104 }
105 }
106
107 pub fn is_editable_crate(krate: Crate, db: &RootDatabase) -> bool {
108 let root_file = krate.root_file(db);
109 let source_root_id = db.file_source_root(root_file);
110 !db.source_root(source_root_id).is_library
111 }