mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-11-15 09:27:27 +00:00
replace a chain of if let
by macro
This commit is contained in:
parent
d6ae1b5f0f
commit
0b5d0a41fd
3 changed files with 87 additions and 255 deletions
|
@ -12,8 +12,7 @@ use crate::{
|
||||||
ids::{AstItemDef, LocationCtx},
|
ids::{AstItemDef, LocationCtx},
|
||||||
name::AsName,
|
name::AsName,
|
||||||
AssocItem, Const, Crate, Enum, EnumVariant, FieldSource, Function, HasSource, ImplBlock,
|
AssocItem, Const, Crate, Enum, EnumVariant, FieldSource, Function, HasSource, ImplBlock,
|
||||||
Module, ModuleDef, ModuleSource, Source, Static, Struct, StructField, Trait, TypeAlias, Union,
|
Module, ModuleSource, Source, Static, Struct, StructField, Trait, TypeAlias, Union, VariantDef,
|
||||||
VariantDef,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
pub trait FromSource: Sized {
|
pub trait FromSource: Sized {
|
||||||
|
@ -148,43 +147,6 @@ impl FromSource for AssocItem {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// not fully matched
|
|
||||||
impl FromSource for ModuleDef {
|
|
||||||
type Ast = ast::ModuleItem;
|
|
||||||
fn from_source(db: &(impl DefDatabase + AstDatabase), src: Source<Self::Ast>) -> Option<Self> {
|
|
||||||
macro_rules! def {
|
|
||||||
($kind:ident, $ast:ident) => {
|
|
||||||
$kind::from_source(db, Source { file_id: src.file_id, ast: $ast })
|
|
||||||
.and_then(|it| Some(ModuleDef::from(it)))
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
match src.ast {
|
|
||||||
ast::ModuleItem::FnDef(f) => def!(Function, f),
|
|
||||||
ast::ModuleItem::ConstDef(c) => def!(Const, c),
|
|
||||||
ast::ModuleItem::TypeAliasDef(a) => def!(TypeAlias, a),
|
|
||||||
ast::ModuleItem::TraitDef(t) => def!(Trait, t),
|
|
||||||
ast::ModuleItem::StaticDef(s) => def!(Static, s),
|
|
||||||
ast::ModuleItem::StructDef(s) => {
|
|
||||||
let src = Source { file_id: src.file_id, ast: s };
|
|
||||||
let s = Struct::from_source(db, src)?;
|
|
||||||
Some(ModuleDef::Adt(s.into()))
|
|
||||||
}
|
|
||||||
ast::ModuleItem::EnumDef(e) => {
|
|
||||||
let src = Source { file_id: src.file_id, ast: e };
|
|
||||||
let e = Enum::from_source(db, src)?;
|
|
||||||
Some(ModuleDef::Adt(e.into()))
|
|
||||||
}
|
|
||||||
ast::ModuleItem::Module(ref m) if !m.has_semi() => {
|
|
||||||
let src = Source { file_id: src.file_id, ast: ModuleSource::Module(m.clone()) };
|
|
||||||
let module = Module::from_definition(db, src)?;
|
|
||||||
Some(ModuleDef::Module(module))
|
|
||||||
}
|
|
||||||
_ => None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// FIXME: simplify it
|
// FIXME: simplify it
|
||||||
impl ModuleSource {
|
impl ModuleSource {
|
||||||
pub fn from_position(
|
pub fn from_position(
|
||||||
|
|
|
@ -102,36 +102,92 @@ pub(crate) fn classify_name(
|
||||||
let parent = name.syntax().parent()?;
|
let parent = name.syntax().parent()?;
|
||||||
let file_id = file_id.into();
|
let file_id = file_id.into();
|
||||||
|
|
||||||
if let Some(pat) = ast::BindPat::cast(parent.clone()) {
|
macro_rules! match_ast {
|
||||||
return Some(Pat(AstPtr::new(&pat)));
|
(match $node:ident {
|
||||||
|
$( ast::$ast:ident($it:ident) => $res:block, )*
|
||||||
|
_ => $catch_all:expr,
|
||||||
|
}) => {{
|
||||||
|
$( if let Some($it) = ast::$ast::cast($node.clone()) $res else )*
|
||||||
|
{ $catch_all }
|
||||||
|
}};
|
||||||
}
|
}
|
||||||
if let Some(var) = ast::EnumVariant::cast(parent.clone()) {
|
|
||||||
let src = hir::Source { file_id, ast: var };
|
|
||||||
let var = hir::EnumVariant::from_source(db, src)?;
|
|
||||||
return Some(Def(var.into()));
|
|
||||||
}
|
|
||||||
if let Some(field) = ast::RecordFieldDef::cast(parent.clone()) {
|
|
||||||
let src = hir::Source { file_id, ast: hir::FieldSource::Named(field) };
|
|
||||||
let field = hir::StructField::from_source(db, src)?;
|
|
||||||
return Some(FieldAccess(field));
|
|
||||||
}
|
|
||||||
if let Some(field) = ast::TupleFieldDef::cast(parent.clone()) {
|
|
||||||
let src = hir::Source { file_id, ast: hir::FieldSource::Pos(field) };
|
|
||||||
let field = hir::StructField::from_source(db, src)?;
|
|
||||||
return Some(FieldAccess(field));
|
|
||||||
}
|
|
||||||
if let Some(_) = parent.parent().and_then(ast::ItemList::cast) {
|
|
||||||
let ast = ast::ImplItem::cast(parent.clone())?;
|
|
||||||
let src = hir::Source { file_id, ast };
|
|
||||||
let item = hir::AssocItem::from_source(db, src)?;
|
|
||||||
return Some(AssocItem(item));
|
|
||||||
}
|
|
||||||
if let Some(item) = ast::ModuleItem::cast(parent.clone()) {
|
|
||||||
let src = hir::Source { file_id, ast: item };
|
|
||||||
let def = hir::ModuleDef::from_source(db, src)?;
|
|
||||||
return Some(Def(def));
|
|
||||||
}
|
|
||||||
// FIXME: TYPE_PARAM, ALIAS, MACRO_CALL; Union
|
|
||||||
|
|
||||||
None
|
// FIXME: add ast::MacroCall(it)
|
||||||
|
match_ast! {
|
||||||
|
match parent {
|
||||||
|
ast::BindPat(it) => {
|
||||||
|
let pat = AstPtr::new(&it);
|
||||||
|
Some(Pat(pat))
|
||||||
|
},
|
||||||
|
ast::RecordFieldDef(it) => {
|
||||||
|
let src = hir::Source { file_id, ast: hir::FieldSource::Named(it) };
|
||||||
|
let field = hir::StructField::from_source(db, src)?;
|
||||||
|
Some(FieldAccess(field))
|
||||||
|
},
|
||||||
|
ast::FnDef(it) => {
|
||||||
|
if parent.parent().and_then(ast::ItemList::cast).is_some() {
|
||||||
|
let src = hir::Source { file_id, ast: ast::ImplItem::from(it) };
|
||||||
|
let item = hir::AssocItem::from_source(db, src)?;
|
||||||
|
Some(AssocItem(item))
|
||||||
|
} else {
|
||||||
|
let src = hir::Source { file_id, ast: it };
|
||||||
|
let def = hir::Function::from_source(db, src)?;
|
||||||
|
Some(Def(def.into()))
|
||||||
|
}
|
||||||
|
},
|
||||||
|
ast::ConstDef(it) => {
|
||||||
|
if parent.parent().and_then(ast::ItemList::cast).is_some() {
|
||||||
|
let src = hir::Source { file_id, ast: ast::ImplItem::from(it) };
|
||||||
|
let item = hir::AssocItem::from_source(db, src)?;
|
||||||
|
Some(AssocItem(item))
|
||||||
|
} else {
|
||||||
|
let src = hir::Source { file_id, ast: it };
|
||||||
|
let def = hir::Const::from_source(db, src)?;
|
||||||
|
Some(Def(def.into()))
|
||||||
|
}
|
||||||
|
},
|
||||||
|
ast::TypeAliasDef(it) => {
|
||||||
|
if parent.parent().and_then(ast::ItemList::cast).is_some() {
|
||||||
|
let src = hir::Source { file_id, ast: ast::ImplItem::from(it) };
|
||||||
|
let item = hir::AssocItem::from_source(db, src)?;
|
||||||
|
Some(AssocItem(item))
|
||||||
|
} else {
|
||||||
|
let src = hir::Source { file_id, ast: it };
|
||||||
|
let def = hir::TypeAlias::from_source(db, src)?;
|
||||||
|
Some(Def(def.into()))
|
||||||
|
}
|
||||||
|
},
|
||||||
|
ast::Module(it) => {
|
||||||
|
let src = hir::Source { file_id, ast: hir::ModuleSource::Module(it) };
|
||||||
|
let def = hir::Module::from_definition(db, src)?;
|
||||||
|
Some(Def(def.into()))
|
||||||
|
},
|
||||||
|
ast::StructDef(it) => {
|
||||||
|
let src = hir::Source { file_id, ast: it };
|
||||||
|
let def = hir::Struct::from_source(db, src)?;
|
||||||
|
Some(Def(def.into()))
|
||||||
|
},
|
||||||
|
ast::EnumDef(it) => {
|
||||||
|
let src = hir::Source { file_id, ast: it };
|
||||||
|
let def = hir::Enum::from_source(db, src)?;
|
||||||
|
Some(Def(def.into()))
|
||||||
|
},
|
||||||
|
ast::TraitDef(it) => {
|
||||||
|
let src = hir::Source { file_id, ast: it };
|
||||||
|
let def = hir::Trait::from_source(db, src)?;
|
||||||
|
Some(Def(def.into()))
|
||||||
|
},
|
||||||
|
ast::StaticDef(it) => {
|
||||||
|
let src = hir::Source { file_id, ast: it };
|
||||||
|
let def = hir::Static::from_source(db, src)?;
|
||||||
|
Some(Def(def.into()))
|
||||||
|
},
|
||||||
|
ast::EnumVariant(it) => {
|
||||||
|
let src = hir::Source { file_id, ast: it };
|
||||||
|
let def = hir::EnumVariant::from_source(db, src)?;
|
||||||
|
Some(Def(def.into()))
|
||||||
|
},
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,186 +0,0 @@
|
||||||
pub enum SearchScope {
|
|
||||||
Function(hir::Function),
|
|
||||||
Module(hir::Module),
|
|
||||||
Crate(hir::Crate),
|
|
||||||
Crates(Vec<hir::Crate>),
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct SearchScope{
|
|
||||||
pub scope: Vec<SyntaxNode>
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn find_all_refs(db: &RootDatabase, decl: NameKind) -> Vec<ReferenceDescriptor> {
|
|
||||||
let (module, visibility) = match decl {
|
|
||||||
FieldAccess(field) => {
|
|
||||||
let parent = field.parent_def(db);
|
|
||||||
let module = parent.module(db);
|
|
||||||
let visibility = match parent {
|
|
||||||
VariantDef::Struct(s) => s.source(db).ast.visibility(),
|
|
||||||
VariantDef::EnumVariant(v) => v.parent_enum(db).source(db).ast.visibility(),
|
|
||||||
};
|
|
||||||
(module, visibility)
|
|
||||||
}
|
|
||||||
AssocItem(item) => {
|
|
||||||
let parent = item.parent_trait(db)?;
|
|
||||||
let module = parent.module(db);
|
|
||||||
let visibility = parent.source(db).ast.visibility();
|
|
||||||
(module, visibility)
|
|
||||||
}
|
|
||||||
Def(def) => {
|
|
||||||
let (module, visibility) = match def {
|
|
||||||
ModuleDef::Module(m) => (m, ),
|
|
||||||
ModuleDef::Function(f) => (f.module(db), f.source(db).ast.visibility()),
|
|
||||||
ModuleDef::Adt::Struct(s) => (s.module(db), s.source(db).ast.visibility()),
|
|
||||||
ModuleDef::Adt::Union(u) => (u.module(db), u.source(db).ast.visibility()),
|
|
||||||
ModuleDef::Adt::Enum(e) => (e.module(db), e.source(db).ast.visibility()),
|
|
||||||
ModuleDef::EnumVariant(v) => (v.module(db), v.source(db).ast.visibility()),
|
|
||||||
ModuleDef::Const(c) => (c.module(db), c.source(db).ast.visibility()),
|
|
||||||
ModuleDef::Static(s) => (s.module(db), s.source(db).ast.visibility()),
|
|
||||||
ModuleDef::Trait(t) => (t.module(db), t.source(db).ast.visibility()),
|
|
||||||
ModuleDef::TypeAlias(a) => (a.module(db), a.source(db).ast.visibility()),
|
|
||||||
ModuleDef::BuiltinType(_) => return vec![];
|
|
||||||
};
|
|
||||||
(module, visibility)
|
|
||||||
}
|
|
||||||
// FIXME: add missing kinds
|
|
||||||
_ => return vec![];
|
|
||||||
};
|
|
||||||
let scope = scope(db, module, visibility);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn scope(db: &RootDatabase, module: hir::Module, item_vis: Option<ast::Visibility>) -> SearchScope {
|
|
||||||
if let Some(v) = item_vis {
|
|
||||||
let krate = module.krate(db)?;
|
|
||||||
|
|
||||||
if v.syntax().text() == "pub" {
|
|
||||||
SearchScope::Crate(krate)
|
|
||||||
}
|
|
||||||
if v.syntax().text() == "pub(crate)" {
|
|
||||||
let crate_graph = db.crate_graph();
|
|
||||||
let crates = crate_graph.iter().filter(|id| {
|
|
||||||
crate_graph.dependencies(id).any(|d| d.crate_id() == krate.crate_id())
|
|
||||||
}).map(|id| Crate { id }).collect::<Vec<_>>();
|
|
||||||
crates.insert(0, krate);
|
|
||||||
SearchScope::Crates(crates)
|
|
||||||
}
|
|
||||||
// FIXME: "pub(super)", "pub(in path)"
|
|
||||||
SearchScope::Module(module)
|
|
||||||
}
|
|
||||||
SearchScope::Module(module)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn process_one(db, scope: SearchScope, pat) {
|
|
||||||
match scope {
|
|
||||||
SearchScope::Crate(krate) => {
|
|
||||||
let text = db.file_text(position.file_id).as_str();
|
|
||||||
let parse = SourceFile::parse(text);
|
|
||||||
for (offset, name) in text.match_indices(pat) {
|
|
||||||
if let Some() = find_node_at_offset<ast::NameRef>(parse, offset) {
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
use crate::{
|
|
||||||
mock_analysis::analysis_and_position, mock_analysis::single_file_with_position, FileId,
|
|
||||||
ReferenceSearchResult,
|
|
||||||
};
|
|
||||||
use insta::assert_debug_snapshot;
|
|
||||||
use test_utils::assert_eq_text;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_find_all_refs_for_local() {
|
|
||||||
let code = r#"
|
|
||||||
fn main() {
|
|
||||||
let mut i = 1;
|
|
||||||
let j = 1;
|
|
||||||
i = i<|> + j;
|
|
||||||
|
|
||||||
{
|
|
||||||
i = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
i = 5;
|
|
||||||
}
|
|
||||||
"#;
|
|
||||||
|
|
||||||
let refs = get_all_refs(code);
|
|
||||||
assert_eq!(refs.len(), 5);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_find_all_refs_for_param_inside() {
|
|
||||||
let code = r#"
|
|
||||||
fn foo(i : u32) -> u32 {
|
|
||||||
i<|>
|
|
||||||
}"#;
|
|
||||||
|
|
||||||
let refs = get_all_refs(code);
|
|
||||||
assert_eq!(refs.len(), 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_find_all_refs_for_fn_param() {
|
|
||||||
let code = r#"
|
|
||||||
fn foo(i<|> : u32) -> u32 {
|
|
||||||
i
|
|
||||||
}"#;
|
|
||||||
|
|
||||||
let refs = get_all_refs(code);
|
|
||||||
assert_eq!(refs.len(), 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_find_all_refs_field_name() {
|
|
||||||
let code = r#"
|
|
||||||
//- /lib.rs
|
|
||||||
struct Foo {
|
|
||||||
spam<|>: u32,
|
|
||||||
}
|
|
||||||
"#;
|
|
||||||
|
|
||||||
let refs = get_all_refs(code);
|
|
||||||
assert_eq!(refs.len(), 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_find_all_refs_methods() {
|
|
||||||
let code = r#"
|
|
||||||
//- /lib.rs
|
|
||||||
struct Foo;
|
|
||||||
impl Foo {
|
|
||||||
pub fn a() {
|
|
||||||
self.b()
|
|
||||||
}
|
|
||||||
fn b(&self) {}
|
|
||||||
}
|
|
||||||
"#;
|
|
||||||
|
|
||||||
let refs = get_all_refs(code);
|
|
||||||
assert_eq!(refs.len(), 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_find_all_refs_pub_enum() {
|
|
||||||
let code = r#"
|
|
||||||
//- /lib.rs
|
|
||||||
pub enum Foo {
|
|
||||||
A,
|
|
||||||
B<|>,
|
|
||||||
C,
|
|
||||||
}
|
|
||||||
"#;
|
|
||||||
|
|
||||||
let refs = get_all_refs(code);
|
|
||||||
assert_eq!(refs.len(), 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_all_refs(text: &str) -> ReferenceSearchResult {
|
|
||||||
let (analysis, position) = single_file_with_position(text);
|
|
||||||
analysis.find_all_refs(position).unwrap().unwrap()
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in a new issue