]> git.lizzy.rs Git - rust.git/commitdiff
initial classify_name
authorEkaterina Babshukova <ekaterina.babshukova@yandex.ru>
Sat, 14 Sep 2019 11:38:10 +0000 (14:38 +0300)
committerEkaterina Babshukova <ekaterina.babshukova@yandex.ru>
Tue, 22 Oct 2019 20:47:31 +0000 (23:47 +0300)
crates/ra_hir/src/from_source.rs
crates/ra_ide_api/src/goto_definition.rs
crates/ra_ide_api/src/hover.rs
crates/ra_ide_api/src/name_ref_kind.rs
crates/ra_ide_api/src/references.rs
crates/ra_ide_api/src/search_scope.rs [new file with mode: 0644]
crates/ra_ide_api/src/syntax_highlighting.rs

index f80d8eb5f1ed991ce36c36e293d25d2c0380045f..e09414ca3d6e553c9447a79393ab94918cb4e5e1 100644 (file)
@@ -11,8 +11,9 @@
     db::{AstDatabase, DefDatabase, HirDatabase},
     ids::{AstItemDef, LocationCtx},
     name::AsName,
-    Const, Crate, Enum, EnumVariant, FieldSource, Function, HasSource, ImplBlock, Module,
-    ModuleSource, Source, Static, Struct, StructField, Trait, TypeAlias, Union, VariantDef,
+    AssocItem, Const, Crate, Enum, EnumVariant, FieldSource, Function, HasSource, ImplBlock,
+    Module, ModuleDef, ModuleSource, Source, Static, Struct, StructField, Trait, TypeAlias, Union,
+    VariantDef,
 };
 
 pub trait FromSource: Sized {
@@ -129,6 +130,61 @@ fn from_source(db: &(impl DefDatabase + AstDatabase), src: Source<Self::Ast>) ->
     }
 }
 
+impl FromSource for AssocItem {
+    type Ast = ast::ImplItem;
+    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(AssocItem::from(it)))
+            };
+        }
+
+        match src.ast {
+            ast::ImplItem::FnDef(f) => def!(Function, f),
+            ast::ImplItem::ConstDef(c) => def!(Const, c),
+            ast::ImplItem::TypeAliasDef(a) => def!(TypeAlias, a),
+        }
+    }
+}
+
+// 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
 impl ModuleSource {
     pub fn from_position(
index 41a88314fb287e38ae560c325a26c0d2948d82d7..13e42bb35c1a8b593ced1b1c764ba3edc1fd1b62 100644 (file)
@@ -10,7 +10,7 @@
 use crate::{
     db::RootDatabase,
     display::ShortLabel,
-    name_ref_kind::{classify_name_ref, NameRefKind::*},
+    name_ref_kind::{classify_name_ref, NameKind::*},
     FilePosition, NavigationTarget, RangeInfo,
 };
 
index 24b161c5c114b04bcbae07ce7349ee3cd7e32019..5c2549dc38cc50ab0a76b924706a27d2dad3874b 100644 (file)
@@ -14,7 +14,7 @@
         description_from_symbol, docs_from_symbol, macro_label, rust_code_markup,
         rust_code_markup_with_doc, ShortLabel,
     },
-    name_ref_kind::{classify_name_ref, NameRefKind::*},
+    name_ref_kind::{classify_name_ref, NameKind::*},
     FilePosition, FileRange, RangeInfo,
 };
 
index 149585971e9974641b68a78d6523afcd3ea4f197..eb8caabfe42723103a3cb37a90db12fb836ad582 100644 (file)
@@ -6,7 +6,7 @@
 
 use crate::db::RootDatabase;
 
-pub enum NameRefKind {
+pub enum NameKind {
     Method(hir::Function),
     Macro(hir::MacroDef),
     FieldAccess(hir::StructField),
@@ -22,8 +22,8 @@ pub(crate) fn classify_name_ref(
     db: &RootDatabase,
     analyzer: &hir::SourceAnalyzer,
     name_ref: &ast::NameRef,
-) -> Option<NameRefKind> {
-    use NameRefKind::*;
+) -> Option<NameKind> {
+    use NameKind::*;
 
     // Check if it is a method
     if let Some(method_call) = name_ref.syntax().parent().and_then(ast::MethodCallExpr::cast) {
index 4247c6d90852edddc72aaafa27cbce3c433fa6c7..9335bc8cab248478d2a0d1e5d0afb075fc5a3d4b 100644 (file)
@@ -1,13 +1,18 @@
 //! FIXME: write short doc here
 
-use hir::{Either, ModuleSource};
+use hir::{FromSource, ModuleSource};
 use ra_db::{SourceDatabase, SourceDatabaseExt};
-use ra_syntax::{algo::find_node_at_offset, ast, AstNode, SourceFile, SyntaxNode};
+use ra_syntax::{algo::find_node_at_offset, ast, AstNode, AstPtr, SyntaxNode};
 use relative_path::{RelativePath, RelativePathBuf};
 
 use crate::{
-    db::RootDatabase, FileId, FilePosition, FileRange, FileSystemEdit, NavigationTarget, RangeInfo,
-    SourceChange, SourceFileEdit, TextRange,
+    db::RootDatabase,
+    name_ref_kind::{
+        classify_name_ref,
+        NameKind::{self, *},
+    },
+    FileId, FilePosition, FileRange, FileSystemEdit, NavigationTarget, RangeInfo, SourceChange,
+    SourceFileEdit, TextRange,
 };
 
 #[derive(Debug, Clone)]
@@ -52,41 +57,92 @@ pub(crate) fn find_all_refs(
     position: FilePosition,
 ) -> Option<RangeInfo<ReferenceSearchResult>> {
     let parse = db.parse(position.file_id);
-    let RangeInfo { range, info: (binding, analyzer) } = find_binding(db, &parse.tree(), position)?;
-    let declaration = NavigationTarget::from_bind_pat(position.file_id, &binding);
+    let syntax = parse.tree().syntax().clone();
+    let RangeInfo { range, info: (analyzer, name_kind) } = find_name(db, &syntax, position)?;
+
+    let declaration = match name_kind {
+        Macro(mac) => NavigationTarget::from_macro_def(db, mac),
+        FieldAccess(field) => NavigationTarget::from_field(db, field),
+        AssocItem(assoc) => NavigationTarget::from_assoc_item(db, assoc),
+        Method(func) => NavigationTarget::from_def_source(db, func),
+        Def(def) => NavigationTarget::from_def(db, def)?,
+        SelfType(ref ty) => match ty.as_adt() {
+            Some((def_id, _)) => NavigationTarget::from_adt_def(db, def_id),
+            None => return None,
+        },
+        Pat(pat) => NavigationTarget::from_pat(db, position.file_id, pat),
+        SelfParam(par) => NavigationTarget::from_self_param(position.file_id, par),
+        GenericParam(_) => return None,
+    };
 
-    let references = analyzer
-        .find_all_refs(&binding)
-        .into_iter()
-        .map(move |ref_desc| FileRange { file_id: position.file_id, range: ref_desc.range })
-        .collect::<Vec<_>>();
+    let references = match name_kind {
+        Pat(pat) => analyzer
+            .find_all_refs(&pat.to_node(&syntax))
+            .into_iter()
+            .map(move |ref_desc| FileRange { file_id: position.file_id, range: ref_desc.range })
+            .collect::<Vec<_>>(),
+        _ => vec![],
+    };
 
     return Some(RangeInfo::new(range, ReferenceSearchResult { declaration, references }));
 
-    fn find_binding<'a>(
+    fn find_name<'a>(
         db: &RootDatabase,
-        source_file: &SourceFile,
+        syntax: &SyntaxNode,
         position: FilePosition,
-    ) -> Option<RangeInfo<(ast::BindPat, hir::SourceAnalyzer)>> {
-        let syntax = source_file.syntax();
-        if let Some(binding) = find_node_at_offset::<ast::BindPat>(syntax, position.offset) {
-            let range = binding.syntax().text_range();
-            let analyzer = hir::SourceAnalyzer::new(db, position.file_id, binding.syntax(), None);
-            return Some(RangeInfo::new(range, (binding, analyzer)));
-        };
-        let name_ref = find_node_at_offset::<ast::NameRef>(syntax, position.offset)?;
+    ) -> Option<RangeInfo<(hir::SourceAnalyzer, NameKind)>> {
+        if let Some(name) = find_node_at_offset::<ast::Name>(&syntax, position.offset) {
+            let analyzer = hir::SourceAnalyzer::new(db, position.file_id, name.syntax(), None);
+            let name_kind = classify_name(db, position.file_id, &name)?;
+            let range = name.syntax().text_range();
+            return Some(RangeInfo::new(range, (analyzer, name_kind)));
+        }
+        let name_ref = find_node_at_offset::<ast::NameRef>(&syntax, position.offset)?;
         let range = name_ref.syntax().text_range();
         let analyzer = hir::SourceAnalyzer::new(db, position.file_id, name_ref.syntax(), None);
-        let resolved = analyzer.resolve_local_name(&name_ref)?;
-        if let Either::A(ptr) = resolved.ptr() {
-            if let ast::Pat::BindPat(binding) = ptr.to_node(source_file.syntax()) {
-                return Some(RangeInfo::new(range, (binding, analyzer)));
-            }
-        }
-        None
+        let name_kind = classify_name_ref(db, &analyzer, &name_ref)?;
+        Some(RangeInfo::new(range, (analyzer, name_kind)))
     }
 }
 
+fn classify_name(db: &RootDatabase, file_id: FileId, name: &ast::Name) -> Option<NameKind> {
+    let parent = name.syntax().parent()?;
+    let file_id = file_id.into();
+
+    if let Some(pat) = ast::BindPat::cast(parent.clone()) {
+        return Some(Pat(AstPtr::new(&pat)));
+    }
+    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
+}
+
 pub(crate) fn rename(
     db: &RootDatabase,
     position: FilePosition,
@@ -249,6 +305,48 @@ fn foo(i<|> : u32) -> u32 {
         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_impl_item_name() {
+        let code = r#"
+            //- /lib.rs
+            struct Foo;
+            impl Foo {
+                fn f<|>(&self) {  }
+            }
+        "#;
+
+        let refs = get_all_refs(code);
+        assert_eq!(refs.len(), 1);
+    }
+
+    #[test]
+    fn test_find_all_refs_enum_var_name() {
+        let code = r#"
+            //- /lib.rs
+            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()
diff --git a/crates/ra_ide_api/src/search_scope.rs b/crates/ra_ide_api/src/search_scope.rs
new file mode 100644 (file)
index 0000000..ca1ac2b
--- /dev/null
@@ -0,0 +1,186 @@
+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()
+    }
+}
\ No newline at end of file
index 1d290387c41883dca3753b1d9bcf378f106a35ec..03104e3486cf5913cd459635622693ed623828b1 100644 (file)
@@ -14,7 +14,7 @@
 
 use crate::{
     db::RootDatabase,
-    name_ref_kind::{classify_name_ref, NameRefKind::*},
+    name_ref_kind::{classify_name_ref, NameKind::*},
     FileId,
 };