mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-12-28 14:03:35 +00:00
Add hir::Local
This commit is contained in:
parent
5ac4ffbc12
commit
8b7f853cc1
14 changed files with 171 additions and 173 deletions
|
@ -22,7 +22,7 @@ use ra_syntax::ast::{self, NameOwner, TypeAscriptionOwner};
|
||||||
use crate::{
|
use crate::{
|
||||||
adt::VariantDef,
|
adt::VariantDef,
|
||||||
db::{AstDatabase, DefDatabase, HirDatabase},
|
db::{AstDatabase, DefDatabase, HirDatabase},
|
||||||
expr::{validation::ExprValidator, Body, BodySourceMap},
|
expr::{validation::ExprValidator, BindingAnnotation, Body, BodySourceMap, Pat, PatId},
|
||||||
generics::HasGenericParams,
|
generics::HasGenericParams,
|
||||||
ids::{
|
ids::{
|
||||||
AstItemDef, ConstId, EnumId, FunctionId, MacroDefId, StaticId, StructId, TraitId,
|
AstItemDef, ConstId, EnumId, FunctionId, MacroDefId, StaticId, StructId, TraitId,
|
||||||
|
@ -32,7 +32,7 @@ use crate::{
|
||||||
resolve::{Resolver, Scope, TypeNs},
|
resolve::{Resolver, Scope, TypeNs},
|
||||||
traits::TraitData,
|
traits::TraitData,
|
||||||
ty::{InferenceResult, Namespace, TraitRef},
|
ty::{InferenceResult, Namespace, TraitRef},
|
||||||
Either, HasSource, ImportId, Name, ScopeDef, Ty,
|
Either, HasSource, ImportId, Name, ScopeDef, Source, Ty,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// hir::Crate describes a single crate. It's the main interface with which
|
/// hir::Crate describes a single crate. It's the main interface with which
|
||||||
|
@ -1070,3 +1070,54 @@ impl AssocItem {
|
||||||
.expect("AssocItem without container")
|
.expect("AssocItem without container")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
||||||
|
pub struct Local {
|
||||||
|
pub(crate) parent: DefWithBody,
|
||||||
|
pub(crate) pat_id: PatId,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Local {
|
||||||
|
pub fn name(self, db: &impl HirDatabase) -> Option<Name> {
|
||||||
|
let body = db.body_hir(self.parent);
|
||||||
|
match &body[self.pat_id] {
|
||||||
|
Pat::Bind { name, .. } => Some(name.clone()),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_self(self, db: &impl HirDatabase) -> bool {
|
||||||
|
self.name(db) == Some(name::SELF_PARAM)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_mut(self, db: &impl HirDatabase) -> bool {
|
||||||
|
let body = db.body_hir(self.parent);
|
||||||
|
match &body[self.pat_id] {
|
||||||
|
Pat::Bind { mode, .. } => match mode {
|
||||||
|
BindingAnnotation::Mutable | BindingAnnotation::RefMut => true,
|
||||||
|
_ => false,
|
||||||
|
},
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn parent(self, _db: &impl HirDatabase) -> DefWithBody {
|
||||||
|
self.parent
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn module(self, db: &impl HirDatabase) -> Module {
|
||||||
|
self.parent.module(db)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn ty(self, db: &impl HirDatabase) -> Ty {
|
||||||
|
let infer = db.infer(self.parent);
|
||||||
|
infer[self.pat_id].clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn source(self, db: &impl HirDatabase) -> Source<Either<ast::BindPat, ast::SelfParam>> {
|
||||||
|
let (_body, source_map) = db.body_with_source_map(self.parent);
|
||||||
|
let src = source_map.pat_syntax(self.pat_id).unwrap(); // Hmm...
|
||||||
|
let root = src.file_syntax(db);
|
||||||
|
src.map(|ast| ast.map(|it| it.cast().unwrap().to_node(&root), |it| it.to_node(&root)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -17,7 +17,7 @@ impl_arena_id!(ScopeId);
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq)]
|
#[derive(Debug, PartialEq, Eq)]
|
||||||
pub struct ExprScopes {
|
pub struct ExprScopes {
|
||||||
body: Arc<Body>,
|
pub(crate) body: Arc<Body>,
|
||||||
scopes: Arena<ScopeId, ScopeData>,
|
scopes: Arena<ScopeId, ScopeData>,
|
||||||
scope_by_expr: FxHashMap<ExprId, ScopeId>,
|
scope_by_expr: FxHashMap<ExprId, ScopeId>,
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,13 +2,17 @@
|
||||||
|
|
||||||
use hir_def::{StructId, StructOrUnionId, UnionId};
|
use hir_def::{StructId, StructOrUnionId, UnionId};
|
||||||
use hir_expand::name::AsName;
|
use hir_expand::name::AsName;
|
||||||
use ra_syntax::ast::{self, AstNode, NameOwner};
|
use ra_syntax::{
|
||||||
|
ast::{self, AstNode, NameOwner},
|
||||||
|
match_ast,
|
||||||
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
db::{AstDatabase, DefDatabase, HirDatabase},
|
db::{AstDatabase, DefDatabase, HirDatabase},
|
||||||
ids::{AstItemDef, LocationCtx},
|
ids::{AstItemDef, LocationCtx},
|
||||||
AstId, Const, Crate, Enum, EnumVariant, FieldSource, Function, HasSource, ImplBlock, Module,
|
AstId, Const, Crate, DefWithBody, Enum, EnumVariant, FieldSource, Function, HasSource,
|
||||||
ModuleSource, Source, Static, Struct, StructField, Trait, TypeAlias, Union, VariantDef,
|
ImplBlock, Local, Module, ModuleSource, Source, Static, Struct, StructField, Trait, TypeAlias,
|
||||||
|
Union, VariantDef,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub trait FromSource: Sized {
|
pub trait FromSource: Sized {
|
||||||
|
@ -126,6 +130,26 @@ impl FromSource for StructField {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Local {
|
||||||
|
pub fn from_source(db: &impl HirDatabase, src: Source<ast::BindPat>) -> Option<Self> {
|
||||||
|
let file_id = src.file_id;
|
||||||
|
let parent: DefWithBody = src.ast.syntax().ancestors().find_map(|it| {
|
||||||
|
let res = match_ast! {
|
||||||
|
match it {
|
||||||
|
ast::ConstDef(ast) => { Const::from_source(db, Source { ast, file_id})?.into() },
|
||||||
|
ast::StaticDef(ast) => { Static::from_source(db, Source { ast, file_id})?.into() },
|
||||||
|
ast::FnDef(ast) => { Function::from_source(db, Source { ast, file_id})?.into() },
|
||||||
|
_ => return None,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
Some(res)
|
||||||
|
})?;
|
||||||
|
let (_body, source_map) = db.body_with_source_map(parent);
|
||||||
|
let pat_id = source_map.node_pat(&src.ast.into())?;
|
||||||
|
Some(Local { parent, pat_id })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Module {
|
impl Module {
|
||||||
pub fn from_declaration(db: &impl HirDatabase, src: Source<ast::Module>) -> Option<Self> {
|
pub fn from_declaration(db: &impl HirDatabase, src: Source<ast::Module>) -> Option<Self> {
|
||||||
let src_parent = Source {
|
let src_parent = Source {
|
||||||
|
|
|
@ -65,7 +65,7 @@ pub use crate::{
|
||||||
docs::{DocDef, Docs, Documentation},
|
docs::{DocDef, Docs, Documentation},
|
||||||
src::{HasBodySource, HasSource},
|
src::{HasBodySource, HasSource},
|
||||||
Adt, AssocItem, Const, ConstData, Container, Crate, CrateDependency, DefWithBody, Enum,
|
Adt, AssocItem, Const, ConstData, Container, Crate, CrateDependency, DefWithBody, Enum,
|
||||||
EnumVariant, FieldSource, FnData, Function, HasBody, MacroDef, Module, ModuleDef,
|
EnumVariant, FieldSource, FnData, Function, HasBody, Local, MacroDef, Module, ModuleDef,
|
||||||
ModuleSource, Static, Struct, StructField, Trait, TypeAlias, Union,
|
ModuleSource, Static, Struct, StructField, Trait, TypeAlias, Union,
|
||||||
},
|
},
|
||||||
expr::ExprScopes,
|
expr::ExprScopes,
|
||||||
|
|
|
@ -28,7 +28,7 @@ use crate::{
|
||||||
ids::LocationCtx,
|
ids::LocationCtx,
|
||||||
resolve::{ScopeDef, TypeNs, ValueNs},
|
resolve::{ScopeDef, TypeNs, ValueNs},
|
||||||
ty::method_resolution::{self, implements_trait},
|
ty::method_resolution::{self, implements_trait},
|
||||||
AssocItem, Const, DefWithBody, Either, Enum, FromSource, Function, HasBody, HirFileId,
|
AssocItem, Const, DefWithBody, Either, Enum, FromSource, Function, HasBody, HirFileId, Local,
|
||||||
MacroDef, Module, Name, Path, Resolver, Static, Struct, Ty,
|
MacroDef, Module, Name, Path, Resolver, Static, Struct, Ty,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -94,6 +94,7 @@ fn def_with_body_from_child_node(
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct SourceAnalyzer {
|
pub struct SourceAnalyzer {
|
||||||
resolver: Resolver,
|
resolver: Resolver,
|
||||||
|
body_owner: Option<DefWithBody>,
|
||||||
body_source_map: Option<Arc<BodySourceMap>>,
|
body_source_map: Option<Arc<BodySourceMap>>,
|
||||||
infer: Option<Arc<crate::ty::InferenceResult>>,
|
infer: Option<Arc<crate::ty::InferenceResult>>,
|
||||||
scopes: Option<Arc<crate::expr::ExprScopes>>,
|
scopes: Option<Arc<crate::expr::ExprScopes>>,
|
||||||
|
@ -104,7 +105,7 @@ pub enum PathResolution {
|
||||||
/// An item
|
/// An item
|
||||||
Def(crate::ModuleDef),
|
Def(crate::ModuleDef),
|
||||||
/// A local binding (only value namespace)
|
/// A local binding (only value namespace)
|
||||||
LocalBinding(Either<AstPtr<ast::BindPat>, AstPtr<ast::SelfParam>>),
|
Local(Local),
|
||||||
/// A generic parameter
|
/// A generic parameter
|
||||||
GenericParam(u32),
|
GenericParam(u32),
|
||||||
SelfType(crate::ImplBlock),
|
SelfType(crate::ImplBlock),
|
||||||
|
@ -152,6 +153,7 @@ impl SourceAnalyzer {
|
||||||
let resolver = expr::resolver_for_scope(def.body(db), db, scope);
|
let resolver = expr::resolver_for_scope(def.body(db), db, scope);
|
||||||
SourceAnalyzer {
|
SourceAnalyzer {
|
||||||
resolver,
|
resolver,
|
||||||
|
body_owner: Some(def),
|
||||||
body_source_map: Some(source_map),
|
body_source_map: Some(source_map),
|
||||||
infer: Some(def.infer(db)),
|
infer: Some(def.infer(db)),
|
||||||
scopes: Some(scopes),
|
scopes: Some(scopes),
|
||||||
|
@ -162,6 +164,7 @@ impl SourceAnalyzer {
|
||||||
.ancestors()
|
.ancestors()
|
||||||
.find_map(|node| try_get_resolver_for_node(db, file_id, &node))
|
.find_map(|node| try_get_resolver_for_node(db, file_id, &node))
|
||||||
.unwrap_or_default(),
|
.unwrap_or_default(),
|
||||||
|
body_owner: None,
|
||||||
body_source_map: None,
|
body_source_map: None,
|
||||||
infer: None,
|
infer: None,
|
||||||
scopes: None,
|
scopes: None,
|
||||||
|
@ -233,16 +236,9 @@ impl SourceAnalyzer {
|
||||||
});
|
});
|
||||||
let values = self.resolver.resolve_path_in_value_ns_fully(db, &path).and_then(|val| {
|
let values = self.resolver.resolve_path_in_value_ns_fully(db, &path).and_then(|val| {
|
||||||
let res = match val {
|
let res = match val {
|
||||||
ValueNs::LocalBinding(it) => {
|
ValueNs::LocalBinding(pat_id) => {
|
||||||
// We get a `PatId` from resolver, but it actually can only
|
let var = Local { parent: self.body_owner?, pat_id };
|
||||||
// point at `BindPat`, and not at the arbitrary pattern.
|
PathResolution::Local(var)
|
||||||
let pat_ptr = self
|
|
||||||
.body_source_map
|
|
||||||
.as_ref()?
|
|
||||||
.pat_syntax(it)?
|
|
||||||
.ast // FIXME: ignoring file_id here is definitelly wrong
|
|
||||||
.map_a(|ptr| ptr.cast::<ast::BindPat>().unwrap());
|
|
||||||
PathResolution::LocalBinding(pat_ptr)
|
|
||||||
}
|
}
|
||||||
ValueNs::Function(it) => PathResolution::Def(it.into()),
|
ValueNs::Function(it) => PathResolution::Def(it.into()),
|
||||||
ValueNs::Const(it) => PathResolution::Def(it.into()),
|
ValueNs::Const(it) => PathResolution::Def(it.into()),
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
//! FIXME: write short doc here
|
//! FIXME: write short doc here
|
||||||
|
|
||||||
use hir::{AssocItem, FieldSource, HasSource, ModuleSource};
|
use hir::{AssocItem, Either, FieldSource, HasSource, ModuleSource};
|
||||||
use ra_db::{FileId, SourceDatabase};
|
use ra_db::{FileId, SourceDatabase};
|
||||||
use ra_syntax::{
|
use ra_syntax::{
|
||||||
ast::{self, DocCommentsOwner},
|
ast::{self, DocCommentsOwner, NameOwner},
|
||||||
match_ast, AstNode, AstPtr, SmolStr,
|
match_ast, AstNode, SmolStr,
|
||||||
SyntaxKind::{self, NAME},
|
SyntaxKind::{self, BIND_PAT},
|
||||||
SyntaxNode, TextRange,
|
SyntaxNode, TextRange,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -76,42 +76,6 @@ impl NavigationTarget {
|
||||||
self.focus_range
|
self.focus_range
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn from_bind_pat(
|
|
||||||
db: &RootDatabase,
|
|
||||||
file_id: FileId,
|
|
||||||
pat: &ast::BindPat,
|
|
||||||
) -> NavigationTarget {
|
|
||||||
NavigationTarget::from_named(db, file_id.into(), pat, None, None)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn from_pat(
|
|
||||||
db: &RootDatabase,
|
|
||||||
file_id: FileId,
|
|
||||||
pat: AstPtr<ast::BindPat>,
|
|
||||||
) -> NavigationTarget {
|
|
||||||
let parse = db.parse(file_id);
|
|
||||||
let pat = pat.to_node(parse.tree().syntax());
|
|
||||||
NavigationTarget::from_bind_pat(db, file_id, &pat)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn from_self_param(
|
|
||||||
file_id: FileId,
|
|
||||||
par: AstPtr<ast::SelfParam>,
|
|
||||||
) -> NavigationTarget {
|
|
||||||
let (name, full_range) = ("self".into(), par.syntax_node_ptr().range());
|
|
||||||
|
|
||||||
NavigationTarget {
|
|
||||||
file_id,
|
|
||||||
name,
|
|
||||||
full_range,
|
|
||||||
focus_range: None,
|
|
||||||
kind: NAME,
|
|
||||||
container_name: None,
|
|
||||||
description: None, //< No document node for SelfParam
|
|
||||||
docs: None, //< No document node for SelfParam
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn from_module_to_decl(db: &RootDatabase, module: hir::Module) -> NavigationTarget {
|
pub(crate) fn from_module_to_decl(db: &RootDatabase, module: hir::Module) -> NavigationTarget {
|
||||||
let name = module.name(db).map(|it| it.to_string().into()).unwrap_or_default();
|
let name = module.name(db).map(|it| it.to_string().into()).unwrap_or_default();
|
||||||
if let Some(src) = module.declaration_source(db) {
|
if let Some(src) = module.declaration_source(db) {
|
||||||
|
@ -370,6 +334,32 @@ impl ToNav for hir::AssocItem {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl ToNav for hir::Local {
|
||||||
|
fn to_nav(&self, db: &RootDatabase) -> NavigationTarget {
|
||||||
|
let src = self.source(db);
|
||||||
|
let (full_range, focus_range) = match src.ast {
|
||||||
|
Either::A(it) => {
|
||||||
|
(it.syntax().text_range(), it.name().map(|it| it.syntax().text_range()))
|
||||||
|
}
|
||||||
|
Either::B(it) => (it.syntax().text_range(), Some(it.self_kw_token().text_range())),
|
||||||
|
};
|
||||||
|
let name = match self.name(db) {
|
||||||
|
Some(it) => it.to_string().into(),
|
||||||
|
None => "".into(),
|
||||||
|
};
|
||||||
|
NavigationTarget {
|
||||||
|
file_id: src.file_id.original_file(db),
|
||||||
|
name,
|
||||||
|
kind: BIND_PAT,
|
||||||
|
full_range,
|
||||||
|
focus_range,
|
||||||
|
container_name: None,
|
||||||
|
description: None,
|
||||||
|
docs: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn find_range_from_node(
|
fn find_range_from_node(
|
||||||
db: &RootDatabase,
|
db: &RootDatabase,
|
||||||
src: hir::HirFileId,
|
src: hir::HirFileId,
|
||||||
|
|
|
@ -68,8 +68,7 @@ pub(crate) fn reference_definition(
|
||||||
return Exact(adt.to_nav(db));
|
return Exact(adt.to_nav(db));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Some(Pat((_, pat))) => return Exact(NavigationTarget::from_pat(db, file_id, pat)),
|
Some(Local(local)) => return Exact(local.to_nav(db)),
|
||||||
Some(SelfParam(par)) => return Exact(NavigationTarget::from_self_param(file_id, par)),
|
|
||||||
Some(GenericParam(_)) => {
|
Some(GenericParam(_)) => {
|
||||||
// FIXME: go to the generic param def
|
// FIXME: go to the generic param def
|
||||||
}
|
}
|
||||||
|
|
|
@ -143,7 +143,7 @@ pub(crate) fn hover(db: &RootDatabase, position: FilePosition) -> Option<RangeIn
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Some(Pat(_)) | Some(SelfParam(_)) => {
|
Some(Local(_)) => {
|
||||||
// Hover for these shows type names
|
// Hover for these shows type names
|
||||||
no_fallback = true;
|
no_fallback = true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -86,8 +86,7 @@ pub(crate) fn find_all_refs(
|
||||||
Some((adt, _)) => adt.to_nav(db),
|
Some((adt, _)) => adt.to_nav(db),
|
||||||
None => return None,
|
None => return None,
|
||||||
},
|
},
|
||||||
NameKind::Pat((_, pat)) => NavigationTarget::from_pat(db, position.file_id, pat),
|
NameKind::Local(local) => local.to_nav(db),
|
||||||
NameKind::SelfParam(par) => NavigationTarget::from_self_param(position.file_id, par),
|
|
||||||
NameKind::GenericParam(_) => return None,
|
NameKind::GenericParam(_) => return None,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
//! Functions that are used to classify an element from its definition or reference.
|
//! Functions that are used to classify an element from its definition or reference.
|
||||||
|
|
||||||
use hir::{Either, FromSource, Module, ModuleSource, Path, PathResolution, Source, SourceAnalyzer};
|
use hir::{FromSource, Module, ModuleSource, Path, PathResolution, Source, SourceAnalyzer};
|
||||||
use ra_db::FileId;
|
use ra_db::FileId;
|
||||||
use ra_prof::profile;
|
use ra_prof::profile;
|
||||||
use ra_syntax::{ast, match_ast, AstNode, AstPtr};
|
use ra_syntax::{ast, match_ast, AstNode};
|
||||||
use test_utils::tested_by;
|
use test_utils::tested_by;
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
name_definition::{from_assoc_item, from_module_def, from_pat, from_struct_field},
|
name_definition::{from_assoc_item, from_module_def, from_struct_field},
|
||||||
NameDefinition, NameKind,
|
NameDefinition, NameKind,
|
||||||
};
|
};
|
||||||
use crate::db::RootDatabase;
|
use crate::db::RootDatabase;
|
||||||
|
@ -25,7 +25,13 @@ pub(crate) fn classify_name(
|
||||||
match_ast! {
|
match_ast! {
|
||||||
match parent {
|
match parent {
|
||||||
ast::BindPat(it) => {
|
ast::BindPat(it) => {
|
||||||
from_pat(db, file_id, AstPtr::new(&it))
|
let src = hir::Source { file_id, ast: it };
|
||||||
|
let local = hir::Local::from_source(db, src)?;
|
||||||
|
Some(NameDefinition {
|
||||||
|
visibility: None,
|
||||||
|
container: local.module(db),
|
||||||
|
kind: NameKind::Local(local),
|
||||||
|
})
|
||||||
},
|
},
|
||||||
ast::RecordFieldDef(it) => {
|
ast::RecordFieldDef(it) => {
|
||||||
let ast = hir::FieldSource::Named(it);
|
let ast = hir::FieldSource::Named(it);
|
||||||
|
@ -159,10 +165,10 @@ pub(crate) fn classify_name_ref(
|
||||||
match resolved {
|
match resolved {
|
||||||
Def(def) => Some(from_module_def(db, def, Some(container))),
|
Def(def) => Some(from_module_def(db, def, Some(container))),
|
||||||
AssocItem(item) => Some(from_assoc_item(db, item)),
|
AssocItem(item) => Some(from_assoc_item(db, item)),
|
||||||
LocalBinding(Either::A(pat)) => from_pat(db, file_id, pat),
|
Local(local) => {
|
||||||
LocalBinding(Either::B(par)) => {
|
let container = local.module(db);
|
||||||
let kind = NameKind::SelfParam(par);
|
let kind = NameKind::Local(local);
|
||||||
Some(NameDefinition { kind, container, visibility })
|
Some(NameDefinition { kind, container, visibility: None })
|
||||||
}
|
}
|
||||||
GenericParam(par) => {
|
GenericParam(par) => {
|
||||||
// FIXME: get generic param def
|
// FIXME: get generic param def
|
||||||
|
|
|
@ -4,10 +4,9 @@
|
||||||
//! Note that the reference search is possible for not all of the classified items.
|
//! Note that the reference search is possible for not all of the classified items.
|
||||||
|
|
||||||
use hir::{
|
use hir::{
|
||||||
db::AstDatabase, Adt, AssocItem, DefWithBody, FromSource, HasSource, HirFileId, MacroDef,
|
Adt, AssocItem, HasSource, Local, MacroDef, Module, ModuleDef, StructField, Ty, VariantDef,
|
||||||
Module, ModuleDef, StructField, Ty, VariantDef,
|
|
||||||
};
|
};
|
||||||
use ra_syntax::{ast, ast::VisibilityOwner, match_ast, AstNode, AstPtr};
|
use ra_syntax::{ast, ast::VisibilityOwner};
|
||||||
|
|
||||||
use crate::db::RootDatabase;
|
use crate::db::RootDatabase;
|
||||||
|
|
||||||
|
@ -18,8 +17,7 @@ pub enum NameKind {
|
||||||
AssocItem(AssocItem),
|
AssocItem(AssocItem),
|
||||||
Def(ModuleDef),
|
Def(ModuleDef),
|
||||||
SelfType(Ty),
|
SelfType(Ty),
|
||||||
Pat((DefWithBody, AstPtr<ast::BindPat>)),
|
Local(Local),
|
||||||
SelfParam(AstPtr<ast::SelfParam>),
|
|
||||||
GenericParam(u32),
|
GenericParam(u32),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -30,36 +28,6 @@ pub(crate) struct NameDefinition {
|
||||||
pub kind: NameKind,
|
pub kind: NameKind,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn from_pat(
|
|
||||||
db: &RootDatabase,
|
|
||||||
file_id: HirFileId,
|
|
||||||
pat: AstPtr<ast::BindPat>,
|
|
||||||
) -> Option<NameDefinition> {
|
|
||||||
let root = db.parse_or_expand(file_id)?;
|
|
||||||
let def = pat.to_node(&root).syntax().ancestors().find_map(|node| {
|
|
||||||
match_ast! {
|
|
||||||
match node {
|
|
||||||
ast::FnDef(it) => {
|
|
||||||
let src = hir::Source { file_id, ast: it };
|
|
||||||
Some(hir::Function::from_source(db, src)?.into())
|
|
||||||
},
|
|
||||||
ast::ConstDef(it) => {
|
|
||||||
let src = hir::Source { file_id, ast: it };
|
|
||||||
Some(hir::Const::from_source(db, src)?.into())
|
|
||||||
},
|
|
||||||
ast::StaticDef(it) => {
|
|
||||||
let src = hir::Source { file_id, ast: it };
|
|
||||||
Some(hir::Static::from_source(db, src)?.into())
|
|
||||||
},
|
|
||||||
_ => None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})?;
|
|
||||||
let kind = NameKind::Pat((def, pat));
|
|
||||||
let container = def.module(db);
|
|
||||||
Some(NameDefinition { kind, container, visibility: None })
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(super) fn from_assoc_item(db: &RootDatabase, item: AssocItem) -> NameDefinition {
|
pub(super) fn from_assoc_item(db: &RootDatabase, item: AssocItem) -> NameDefinition {
|
||||||
let container = item.module(db);
|
let container = item.module(db);
|
||||||
let visibility = match item {
|
let visibility = match item {
|
||||||
|
|
|
@ -71,13 +71,13 @@ impl NameDefinition {
|
||||||
let module_src = self.container.definition_source(db);
|
let module_src = self.container.definition_source(db);
|
||||||
let file_id = module_src.file_id.original_file(db);
|
let file_id = module_src.file_id.original_file(db);
|
||||||
|
|
||||||
if let NameKind::Pat((def, _)) = self.kind {
|
if let NameKind::Local(var) = self.kind {
|
||||||
let mut res = FxHashMap::default();
|
let range = match var.parent(db) {
|
||||||
let range = match def {
|
|
||||||
DefWithBody::Function(f) => f.source(db).ast.syntax().text_range(),
|
DefWithBody::Function(f) => f.source(db).ast.syntax().text_range(),
|
||||||
DefWithBody::Const(c) => c.source(db).ast.syntax().text_range(),
|
DefWithBody::Const(c) => c.source(db).ast.syntax().text_range(),
|
||||||
DefWithBody::Static(s) => s.source(db).ast.syntax().text_range(),
|
DefWithBody::Static(s) => s.source(db).ast.syntax().text_range(),
|
||||||
};
|
};
|
||||||
|
let mut res = FxHashMap::default();
|
||||||
res.insert(file_id, Some(range));
|
res.insert(file_id, Some(range));
|
||||||
return SearchScope::new(res);
|
return SearchScope::new(res);
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,14 +20,14 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
|
||||||
.keyword\.control { color: #F0DFAF; font-weight: bold; }
|
.keyword\.control { color: #F0DFAF; font-weight: bold; }
|
||||||
</style>
|
</style>
|
||||||
<pre><code><span class="keyword">fn</span> <span class="function">main</span>() {
|
<pre><code><span class="keyword">fn</span> <span class="function">main</span>() {
|
||||||
<span class="keyword">let</span> <span class="variable" data-binding-hash="3888301305669440875" style="color: hsl(242,59%,59%);">hello</span> = <span class="string">"hello"</span>;
|
<span class="keyword">let</span> <span class="variable" data-binding-hash="8723171760279909834" style="color: hsl(307,91%,75%);">hello</span> = <span class="string">"hello"</span>;
|
||||||
<span class="keyword">let</span> <span class="variable" data-binding-hash="5695551762718493399" style="color: hsl(272,48%,45%);">x</span> = <span class="variable" data-binding-hash="3888301305669440875" style="color: hsl(242,59%,59%);">hello</span>.<span class="text">to_string</span>();
|
<span class="keyword">let</span> <span class="variable" data-binding-hash="14702933417323009544" style="color: hsl(108,90%,49%);">x</span> = <span class="variable" data-binding-hash="8723171760279909834" style="color: hsl(307,91%,75%);">hello</span>.<span class="text">to_string</span>();
|
||||||
<span class="keyword">let</span> <span class="variable" data-binding-hash="5435401749617022797" style="color: hsl(353,77%,74%);">y</span> = <span class="variable" data-binding-hash="3888301305669440875" style="color: hsl(242,59%,59%);">hello</span>.<span class="text">to_string</span>();
|
<span class="keyword">let</span> <span class="variable" data-binding-hash="5443150872754369068" style="color: hsl(215,43%,43%);">y</span> = <span class="variable" data-binding-hash="8723171760279909834" style="color: hsl(307,91%,75%);">hello</span>.<span class="text">to_string</span>();
|
||||||
|
|
||||||
<span class="keyword">let</span> <span class="variable" data-binding-hash="1903207544374197704" style="color: hsl(58,61%,61%);">x</span> = <span class="string">"other color please!"</span>;
|
<span class="keyword">let</span> <span class="variable" data-binding-hash="17358108296605513516" style="color: hsl(331,46%,60%);">x</span> = <span class="string">"other color please!"</span>;
|
||||||
<span class="keyword">let</span> <span class="variable" data-binding-hash="14878783531007968800" style="color: hsl(265,73%,83%);">y</span> = <span class="variable" data-binding-hash="1903207544374197704" style="color: hsl(58,61%,61%);">x</span>.<span class="text">to_string</span>();
|
<span class="keyword">let</span> <span class="variable" data-binding-hash="2073121142529774969" style="color: hsl(320,43%,74%);">y</span> = <span class="variable" data-binding-hash="17358108296605513516" style="color: hsl(331,46%,60%);">x</span>.<span class="text">to_string</span>();
|
||||||
}
|
}
|
||||||
|
|
||||||
<span class="keyword">fn</span> <span class="function">bar</span>() {
|
<span class="keyword">fn</span> <span class="function">bar</span>() {
|
||||||
<span class="keyword">let</span> <span class="keyword">mut</span> <span class="variable.mut" data-binding-hash="3888301305669440875" style="color: hsl(242,59%,59%);">hello</span> = <span class="string">"hello"</span>;
|
<span class="keyword">let</span> <span class="keyword">mut</span> <span class="variable.mut" data-binding-hash="8723171760279909834" style="color: hsl(307,91%,75%);">hello</span> = <span class="string">"hello"</span>;
|
||||||
}</code></pre>
|
}</code></pre>
|
|
@ -2,15 +2,10 @@
|
||||||
|
|
||||||
use rustc_hash::{FxHashMap, FxHashSet};
|
use rustc_hash::{FxHashMap, FxHashSet};
|
||||||
|
|
||||||
use hir::{Mutability, Ty};
|
use hir::{Mutability, Name};
|
||||||
use ra_db::SourceDatabase;
|
use ra_db::SourceDatabase;
|
||||||
use ra_prof::profile;
|
use ra_prof::profile;
|
||||||
use ra_syntax::{
|
use ra_syntax::{ast, AstNode, Direction, SyntaxElement, SyntaxKind, SyntaxKind::*, TextRange, T};
|
||||||
ast::{self, NameOwner},
|
|
||||||
AstNode, Direction, SmolStr, SyntaxElement, SyntaxKind,
|
|
||||||
SyntaxKind::*,
|
|
||||||
SyntaxNode, TextRange, T,
|
|
||||||
};
|
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
db::RootDatabase,
|
db::RootDatabase,
|
||||||
|
@ -43,32 +38,12 @@ fn is_control_keyword(kind: SyntaxKind) -> bool {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_variable_mutable(
|
|
||||||
db: &RootDatabase,
|
|
||||||
analyzer: &hir::SourceAnalyzer,
|
|
||||||
pat: ast::BindPat,
|
|
||||||
) -> bool {
|
|
||||||
if pat.is_mutable() {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
let ty = analyzer.type_of_pat(db, &pat.into()).unwrap_or(Ty::Unknown);
|
|
||||||
if let Some((_, mutability)) = ty.as_reference() {
|
|
||||||
match mutability {
|
|
||||||
Mutability::Shared => false,
|
|
||||||
Mutability::Mut => true,
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn highlight(db: &RootDatabase, file_id: FileId) -> Vec<HighlightedRange> {
|
pub(crate) fn highlight(db: &RootDatabase, file_id: FileId) -> Vec<HighlightedRange> {
|
||||||
let _p = profile("highlight");
|
let _p = profile("highlight");
|
||||||
let parse = db.parse(file_id);
|
let parse = db.parse(file_id);
|
||||||
let root = parse.tree().syntax().clone();
|
let root = parse.tree().syntax().clone();
|
||||||
|
|
||||||
fn calc_binding_hash(file_id: FileId, text: &SmolStr, shadow_count: u32) -> u64 {
|
fn calc_binding_hash(file_id: FileId, name: &Name, shadow_count: u32) -> u64 {
|
||||||
fn hash<T: std::hash::Hash + std::fmt::Debug>(x: T) -> u64 {
|
fn hash<T: std::hash::Hash + std::fmt::Debug>(x: T) -> u64 {
|
||||||
use std::{collections::hash_map::DefaultHasher, hash::Hasher};
|
use std::{collections::hash_map::DefaultHasher, hash::Hasher};
|
||||||
|
|
||||||
|
@ -77,13 +52,13 @@ pub(crate) fn highlight(db: &RootDatabase, file_id: FileId) -> Vec<HighlightedRa
|
||||||
hasher.finish()
|
hasher.finish()
|
||||||
}
|
}
|
||||||
|
|
||||||
hash((file_id, text, shadow_count))
|
hash((file_id, name, shadow_count))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Visited nodes to handle highlighting priorities
|
// Visited nodes to handle highlighting priorities
|
||||||
// FIXME: retain only ranges here
|
// FIXME: retain only ranges here
|
||||||
let mut highlighted: FxHashSet<SyntaxElement> = FxHashSet::default();
|
let mut highlighted: FxHashSet<SyntaxElement> = FxHashSet::default();
|
||||||
let mut bindings_shadow_count: FxHashMap<SmolStr, u32> = FxHashMap::default();
|
let mut bindings_shadow_count: FxHashMap<Name, u32> = FxHashMap::default();
|
||||||
|
|
||||||
let mut res = Vec::new();
|
let mut res = Vec::new();
|
||||||
for node in root.descendants_with_tokens() {
|
for node in root.descendants_with_tokens() {
|
||||||
|
@ -107,34 +82,29 @@ pub(crate) fn highlight(db: &RootDatabase, file_id: FileId) -> Vec<HighlightedRa
|
||||||
let name_ref = node.as_node().cloned().and_then(ast::NameRef::cast).unwrap();
|
let name_ref = node.as_node().cloned().and_then(ast::NameRef::cast).unwrap();
|
||||||
let name_kind = classify_name_ref(db, file_id, &name_ref).map(|d| d.kind);
|
let name_kind = classify_name_ref(db, file_id, &name_ref).map(|d| d.kind);
|
||||||
|
|
||||||
if let Some(Pat((_, ptr))) = &name_kind {
|
if let Some(Local(local)) = &name_kind {
|
||||||
let pat = ptr.to_node(&root);
|
if let Some(name) = local.name(db) {
|
||||||
if let Some(name) = pat.name() {
|
let shadow_count = bindings_shadow_count.entry(name.clone()).or_default();
|
||||||
let text = name.text();
|
binding_hash = Some(calc_binding_hash(file_id, &name, *shadow_count))
|
||||||
let shadow_count = bindings_shadow_count.entry(text.clone()).or_default();
|
|
||||||
binding_hash = Some(calc_binding_hash(file_id, &text, *shadow_count))
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
name_kind
|
name_kind.map_or("text", |it| highlight_name(db, it))
|
||||||
.map_or("text", |it| highlight_name(db, file_id, name_ref.syntax(), &root, it))
|
|
||||||
}
|
}
|
||||||
NAME => {
|
NAME => {
|
||||||
let name = node.as_node().cloned().and_then(ast::Name::cast).unwrap();
|
let name = node.as_node().cloned().and_then(ast::Name::cast).unwrap();
|
||||||
let name_kind = classify_name(db, file_id, &name).map(|d| d.kind);
|
let name_kind = classify_name(db, file_id, &name).map(|d| d.kind);
|
||||||
|
|
||||||
if let Some(Pat((_, ptr))) = &name_kind {
|
if let Some(Local(local)) = &name_kind {
|
||||||
let pat = ptr.to_node(&root);
|
if let Some(name) = local.name(db) {
|
||||||
if let Some(name) = pat.name() {
|
let shadow_count = bindings_shadow_count.entry(name.clone()).or_default();
|
||||||
let text = name.text();
|
|
||||||
let shadow_count = bindings_shadow_count.entry(text.clone()).or_default();
|
|
||||||
*shadow_count += 1;
|
*shadow_count += 1;
|
||||||
binding_hash = Some(calc_binding_hash(file_id, &text, *shadow_count))
|
binding_hash = Some(calc_binding_hash(file_id, &name, *shadow_count))
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
match name_kind {
|
match name_kind {
|
||||||
Some(name_kind) => highlight_name(db, file_id, name.syntax(), &root, name_kind),
|
Some(name_kind) => highlight_name(db, name_kind),
|
||||||
None => name.syntax().parent().map_or("function", |x| match x.kind() {
|
None => name.syntax().parent().map_or("function", |x| match x.kind() {
|
||||||
TYPE_PARAM | STRUCT_DEF | ENUM_DEF | TRAIT_DEF | TYPE_ALIAS_DEF => "type",
|
TYPE_PARAM | STRUCT_DEF | ENUM_DEF | TRAIT_DEF | TYPE_ALIAS_DEF => "type",
|
||||||
RECORD_FIELD_DEF => "field",
|
RECORD_FIELD_DEF => "field",
|
||||||
|
@ -237,13 +207,7 @@ pub(crate) fn highlight_as_html(db: &RootDatabase, file_id: FileId, rainbow: boo
|
||||||
buf
|
buf
|
||||||
}
|
}
|
||||||
|
|
||||||
fn highlight_name(
|
fn highlight_name(db: &RootDatabase, name_kind: NameKind) -> &'static str {
|
||||||
db: &RootDatabase,
|
|
||||||
file_id: FileId,
|
|
||||||
node: &SyntaxNode,
|
|
||||||
root: &SyntaxNode,
|
|
||||||
name_kind: NameKind,
|
|
||||||
) -> &'static str {
|
|
||||||
match name_kind {
|
match name_kind {
|
||||||
Macro(_) => "macro",
|
Macro(_) => "macro",
|
||||||
Field(_) => "field",
|
Field(_) => "field",
|
||||||
|
@ -260,14 +224,15 @@ fn highlight_name(
|
||||||
Def(hir::ModuleDef::TypeAlias(_)) => "type",
|
Def(hir::ModuleDef::TypeAlias(_)) => "type",
|
||||||
Def(hir::ModuleDef::BuiltinType(_)) => "type",
|
Def(hir::ModuleDef::BuiltinType(_)) => "type",
|
||||||
SelfType(_) => "type",
|
SelfType(_) => "type",
|
||||||
SelfParam(_) => "type",
|
|
||||||
GenericParam(_) => "type",
|
GenericParam(_) => "type",
|
||||||
Pat((_, ptr)) => {
|
Local(local) => {
|
||||||
let analyzer = hir::SourceAnalyzer::new(db, file_id, node, None);
|
if local.is_mut(db) {
|
||||||
if is_variable_mutable(db, &analyzer, ptr.to_node(&root)) {
|
|
||||||
"variable.mut"
|
"variable.mut"
|
||||||
} else {
|
} else {
|
||||||
"variable"
|
match local.ty(db).as_reference() {
|
||||||
|
Some((_, Mutability::Mut)) => "variable.mut",
|
||||||
|
_ => "variable",
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue