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

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