Add hir::Local

This commit is contained in:
Aleksey Kladov 2019-11-10 00:32:00 +03:00
parent 5ac4ffbc12
commit 8b7f853cc1
14 changed files with 171 additions and 173 deletions

View file

@ -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)))
}
}

View file

@ -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>,
}

View file

@ -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 {

View file

@ -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,

View file

@ -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()),

View file

@ -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,

View file

@ -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
}

View file

@ -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;
}

View file

@ -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,
};

View file

@ -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

View file

@ -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 {

View file

@ -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);
}

View file

@ -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>

View file

@ -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",
}
}
}
}