mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-25 16:24:46 +00:00
Add hir::Local
This commit is contained in:
parent
5ac4ffbc12
commit
8b7f853cc1
@ -22,7 +22,7 @@ use ra_syntax::ast::{self, NameOwner, TypeAscriptionOwner};
|
||||
use crate::{
|
||||
adt::VariantDef,
|
||||
db::{AstDatabase, DefDatabase, HirDatabase},
|
||||
expr::{validation::ExprValidator, Body, BodySourceMap},
|
||||
expr::{validation::ExprValidator, BindingAnnotation, Body, BodySourceMap, Pat, PatId},
|
||||
generics::HasGenericParams,
|
||||
ids::{
|
||||
AstItemDef, ConstId, EnumId, FunctionId, MacroDefId, StaticId, StructId, TraitId,
|
||||
@ -32,7 +32,7 @@ use crate::{
|
||||
resolve::{Resolver, Scope, TypeNs},
|
||||
traits::TraitData,
|
||||
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
|
||||
@ -1070,3 +1070,54 @@ impl AssocItem {
|
||||
.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)]
|
||||
pub struct ExprScopes {
|
||||
body: Arc<Body>,
|
||||
pub(crate) body: Arc<Body>,
|
||||
scopes: Arena<ScopeId, ScopeData>,
|
||||
scope_by_expr: FxHashMap<ExprId, ScopeId>,
|
||||
}
|
||||
|
@ -2,13 +2,17 @@
|
||||
|
||||
use hir_def::{StructId, StructOrUnionId, UnionId};
|
||||
use hir_expand::name::AsName;
|
||||
use ra_syntax::ast::{self, AstNode, NameOwner};
|
||||
use ra_syntax::{
|
||||
ast::{self, AstNode, NameOwner},
|
||||
match_ast,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
db::{AstDatabase, DefDatabase, HirDatabase},
|
||||
ids::{AstItemDef, LocationCtx},
|
||||
AstId, Const, Crate, Enum, EnumVariant, FieldSource, Function, HasSource, ImplBlock, Module,
|
||||
ModuleSource, Source, Static, Struct, StructField, Trait, TypeAlias, Union, VariantDef,
|
||||
AstId, Const, Crate, DefWithBody, Enum, EnumVariant, FieldSource, Function, HasSource,
|
||||
ImplBlock, Local, Module, ModuleSource, Source, Static, Struct, StructField, Trait, TypeAlias,
|
||||
Union, VariantDef,
|
||||
};
|
||||
|
||||
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 {
|
||||
pub fn from_declaration(db: &impl HirDatabase, src: Source<ast::Module>) -> Option<Self> {
|
||||
let src_parent = Source {
|
||||
|
@ -65,7 +65,7 @@ pub use crate::{
|
||||
docs::{DocDef, Docs, Documentation},
|
||||
src::{HasBodySource, HasSource},
|
||||
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,
|
||||
},
|
||||
expr::ExprScopes,
|
||||
|
@ -28,7 +28,7 @@ use crate::{
|
||||
ids::LocationCtx,
|
||||
resolve::{ScopeDef, TypeNs, ValueNs},
|
||||
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,
|
||||
};
|
||||
|
||||
@ -94,6 +94,7 @@ fn def_with_body_from_child_node(
|
||||
#[derive(Debug)]
|
||||
pub struct SourceAnalyzer {
|
||||
resolver: Resolver,
|
||||
body_owner: Option<DefWithBody>,
|
||||
body_source_map: Option<Arc<BodySourceMap>>,
|
||||
infer: Option<Arc<crate::ty::InferenceResult>>,
|
||||
scopes: Option<Arc<crate::expr::ExprScopes>>,
|
||||
@ -104,7 +105,7 @@ pub enum PathResolution {
|
||||
/// An item
|
||||
Def(crate::ModuleDef),
|
||||
/// A local binding (only value namespace)
|
||||
LocalBinding(Either<AstPtr<ast::BindPat>, AstPtr<ast::SelfParam>>),
|
||||
Local(Local),
|
||||
/// A generic parameter
|
||||
GenericParam(u32),
|
||||
SelfType(crate::ImplBlock),
|
||||
@ -152,6 +153,7 @@ impl SourceAnalyzer {
|
||||
let resolver = expr::resolver_for_scope(def.body(db), db, scope);
|
||||
SourceAnalyzer {
|
||||
resolver,
|
||||
body_owner: Some(def),
|
||||
body_source_map: Some(source_map),
|
||||
infer: Some(def.infer(db)),
|
||||
scopes: Some(scopes),
|
||||
@ -162,6 +164,7 @@ impl SourceAnalyzer {
|
||||
.ancestors()
|
||||
.find_map(|node| try_get_resolver_for_node(db, file_id, &node))
|
||||
.unwrap_or_default(),
|
||||
body_owner: None,
|
||||
body_source_map: None,
|
||||
infer: 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 res = match val {
|
||||
ValueNs::LocalBinding(it) => {
|
||||
// We get a `PatId` from resolver, but it actually can only
|
||||
// point at `BindPat`, and not at the arbitrary pattern.
|
||||
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::LocalBinding(pat_id) => {
|
||||
let var = Local { parent: self.body_owner?, pat_id };
|
||||
PathResolution::Local(var)
|
||||
}
|
||||
ValueNs::Function(it) => PathResolution::Def(it.into()),
|
||||
ValueNs::Const(it) => PathResolution::Def(it.into()),
|
||||
|
@ -1,11 +1,11 @@
|
||||
//! 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_syntax::{
|
||||
ast::{self, DocCommentsOwner},
|
||||
match_ast, AstNode, AstPtr, SmolStr,
|
||||
SyntaxKind::{self, NAME},
|
||||
ast::{self, DocCommentsOwner, NameOwner},
|
||||
match_ast, AstNode, SmolStr,
|
||||
SyntaxKind::{self, BIND_PAT},
|
||||
SyntaxNode, TextRange,
|
||||
};
|
||||
|
||||
@ -76,42 +76,6 @@ impl NavigationTarget {
|
||||
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 {
|
||||
let name = module.name(db).map(|it| it.to_string().into()).unwrap_or_default();
|
||||
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(
|
||||
db: &RootDatabase,
|
||||
src: hir::HirFileId,
|
||||
|
@ -68,8 +68,7 @@ pub(crate) fn reference_definition(
|
||||
return Exact(adt.to_nav(db));
|
||||
}
|
||||
}
|
||||
Some(Pat((_, pat))) => return Exact(NavigationTarget::from_pat(db, file_id, pat)),
|
||||
Some(SelfParam(par)) => return Exact(NavigationTarget::from_self_param(file_id, par)),
|
||||
Some(Local(local)) => return Exact(local.to_nav(db)),
|
||||
Some(GenericParam(_)) => {
|
||||
// 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
|
||||
no_fallback = true;
|
||||
}
|
||||
|
@ -86,8 +86,7 @@ pub(crate) fn find_all_refs(
|
||||
Some((adt, _)) => adt.to_nav(db),
|
||||
None => return None,
|
||||
},
|
||||
NameKind::Pat((_, pat)) => NavigationTarget::from_pat(db, position.file_id, pat),
|
||||
NameKind::SelfParam(par) => NavigationTarget::from_self_param(position.file_id, par),
|
||||
NameKind::Local(local) => local.to_nav(db),
|
||||
NameKind::GenericParam(_) => return None,
|
||||
};
|
||||
|
||||
|
@ -1,13 +1,13 @@
|
||||
//! 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_prof::profile;
|
||||
use ra_syntax::{ast, match_ast, AstNode, AstPtr};
|
||||
use ra_syntax::{ast, match_ast, AstNode};
|
||||
use test_utils::tested_by;
|
||||
|
||||
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,
|
||||
};
|
||||
use crate::db::RootDatabase;
|
||||
@ -25,7 +25,13 @@ pub(crate) fn classify_name(
|
||||
match_ast! {
|
||||
match parent {
|
||||
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) => {
|
||||
let ast = hir::FieldSource::Named(it);
|
||||
@ -159,10 +165,10 @@ pub(crate) fn classify_name_ref(
|
||||
match resolved {
|
||||
Def(def) => Some(from_module_def(db, def, Some(container))),
|
||||
AssocItem(item) => Some(from_assoc_item(db, item)),
|
||||
LocalBinding(Either::A(pat)) => from_pat(db, file_id, pat),
|
||||
LocalBinding(Either::B(par)) => {
|
||||
let kind = NameKind::SelfParam(par);
|
||||
Some(NameDefinition { kind, container, visibility })
|
||||
Local(local) => {
|
||||
let container = local.module(db);
|
||||
let kind = NameKind::Local(local);
|
||||
Some(NameDefinition { kind, container, visibility: None })
|
||||
}
|
||||
GenericParam(par) => {
|
||||
// FIXME: get generic param def
|
||||
|
@ -4,10 +4,9 @@
|
||||
//! Note that the reference search is possible for not all of the classified items.
|
||||
|
||||
use hir::{
|
||||
db::AstDatabase, Adt, AssocItem, DefWithBody, FromSource, HasSource, HirFileId, MacroDef,
|
||||
Module, ModuleDef, StructField, Ty, VariantDef,
|
||||
Adt, AssocItem, HasSource, Local, MacroDef, 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;
|
||||
|
||||
@ -18,8 +17,7 @@ pub enum NameKind {
|
||||
AssocItem(AssocItem),
|
||||
Def(ModuleDef),
|
||||
SelfType(Ty),
|
||||
Pat((DefWithBody, AstPtr<ast::BindPat>)),
|
||||
SelfParam(AstPtr<ast::SelfParam>),
|
||||
Local(Local),
|
||||
GenericParam(u32),
|
||||
}
|
||||
|
||||
@ -30,36 +28,6 @@ pub(crate) struct NameDefinition {
|
||||
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 {
|
||||
let container = item.module(db);
|
||||
let visibility = match item {
|
||||
|
@ -71,13 +71,13 @@ impl NameDefinition {
|
||||
let module_src = self.container.definition_source(db);
|
||||
let file_id = module_src.file_id.original_file(db);
|
||||
|
||||
if let NameKind::Pat((def, _)) = self.kind {
|
||||
let mut res = FxHashMap::default();
|
||||
let range = match def {
|
||||
if let NameKind::Local(var) = self.kind {
|
||||
let range = match var.parent(db) {
|
||||
DefWithBody::Function(f) => f.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(),
|
||||
};
|
||||
let mut res = FxHashMap::default();
|
||||
res.insert(file_id, Some(range));
|
||||
return SearchScope::new(res);
|
||||
}
|
||||
|
@ -20,14 +20,14 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
|
||||
.keyword\.control { color: #F0DFAF; font-weight: bold; }
|
||||
</style>
|
||||
<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="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="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="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="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="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="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="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="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">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>
|
@ -2,15 +2,10 @@
|
||||
|
||||
use rustc_hash::{FxHashMap, FxHashSet};
|
||||
|
||||
use hir::{Mutability, Ty};
|
||||
use hir::{Mutability, Name};
|
||||
use ra_db::SourceDatabase;
|
||||
use ra_prof::profile;
|
||||
use ra_syntax::{
|
||||
ast::{self, NameOwner},
|
||||
AstNode, Direction, SmolStr, SyntaxElement, SyntaxKind,
|
||||
SyntaxKind::*,
|
||||
SyntaxNode, TextRange, T,
|
||||
};
|
||||
use ra_syntax::{ast, AstNode, Direction, SyntaxElement, SyntaxKind, SyntaxKind::*, TextRange, T};
|
||||
|
||||
use crate::{
|
||||
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> {
|
||||
let _p = profile("highlight");
|
||||
let parse = db.parse(file_id);
|
||||
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 {
|
||||
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()
|
||||
}
|
||||
|
||||
hash((file_id, text, shadow_count))
|
||||
hash((file_id, name, shadow_count))
|
||||
}
|
||||
|
||||
// Visited nodes to handle highlighting priorities
|
||||
// FIXME: retain only ranges here
|
||||
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();
|
||||
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_kind = classify_name_ref(db, file_id, &name_ref).map(|d| d.kind);
|
||||
|
||||
if let Some(Pat((_, ptr))) = &name_kind {
|
||||
let pat = ptr.to_node(&root);
|
||||
if let Some(name) = pat.name() {
|
||||
let text = name.text();
|
||||
let shadow_count = bindings_shadow_count.entry(text.clone()).or_default();
|
||||
binding_hash = Some(calc_binding_hash(file_id, &text, *shadow_count))
|
||||
if let Some(Local(local)) = &name_kind {
|
||||
if let Some(name) = local.name(db) {
|
||||
let shadow_count = bindings_shadow_count.entry(name.clone()).or_default();
|
||||
binding_hash = Some(calc_binding_hash(file_id, &name, *shadow_count))
|
||||
}
|
||||
};
|
||||
|
||||
name_kind
|
||||
.map_or("text", |it| highlight_name(db, file_id, name_ref.syntax(), &root, it))
|
||||
name_kind.map_or("text", |it| highlight_name(db, it))
|
||||
}
|
||||
NAME => {
|
||||
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);
|
||||
|
||||
if let Some(Pat((_, ptr))) = &name_kind {
|
||||
let pat = ptr.to_node(&root);
|
||||
if let Some(name) = pat.name() {
|
||||
let text = name.text();
|
||||
let shadow_count = bindings_shadow_count.entry(text.clone()).or_default();
|
||||
if let Some(Local(local)) = &name_kind {
|
||||
if let Some(name) = local.name(db) {
|
||||
let shadow_count = bindings_shadow_count.entry(name.clone()).or_default();
|
||||
*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 {
|
||||
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() {
|
||||
TYPE_PARAM | STRUCT_DEF | ENUM_DEF | TRAIT_DEF | TYPE_ALIAS_DEF => "type",
|
||||
RECORD_FIELD_DEF => "field",
|
||||
@ -237,13 +207,7 @@ pub(crate) fn highlight_as_html(db: &RootDatabase, file_id: FileId, rainbow: boo
|
||||
buf
|
||||
}
|
||||
|
||||
fn highlight_name(
|
||||
db: &RootDatabase,
|
||||
file_id: FileId,
|
||||
node: &SyntaxNode,
|
||||
root: &SyntaxNode,
|
||||
name_kind: NameKind,
|
||||
) -> &'static str {
|
||||
fn highlight_name(db: &RootDatabase, name_kind: NameKind) -> &'static str {
|
||||
match name_kind {
|
||||
Macro(_) => "macro",
|
||||
Field(_) => "field",
|
||||
@ -260,14 +224,15 @@ fn highlight_name(
|
||||
Def(hir::ModuleDef::TypeAlias(_)) => "type",
|
||||
Def(hir::ModuleDef::BuiltinType(_)) => "type",
|
||||
SelfType(_) => "type",
|
||||
SelfParam(_) => "type",
|
||||
GenericParam(_) => "type",
|
||||
Pat((_, ptr)) => {
|
||||
let analyzer = hir::SourceAnalyzer::new(db, file_id, node, None);
|
||||
if is_variable_mutable(db, &analyzer, ptr.to_node(&root)) {
|
||||
Local(local) => {
|
||||
if local.is_mut(db) {
|
||||
"variable.mut"
|
||||
} else {
|
||||
"variable"
|
||||
match local.ty(db).as_reference() {
|
||||
Some((_, Mutability::Mut)) => "variable.mut",
|
||||
_ => "variable",
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user