Make syntax highlighting linear

This commit is contained in:
Aleksey Kladov 2020-01-14 17:24:00 +01:00
parent 7e70fc22a7
commit c640c2ea11
4 changed files with 78 additions and 57 deletions

View file

@ -8,8 +8,8 @@ use hir_def::{
dyn_map::DynMap, dyn_map::DynMap,
keys::{self, Key}, keys::{self, Key},
resolver::{HasResolver, Resolver}, resolver::{HasResolver, Resolver},
ConstId, DefWithBodyId, EnumId, FunctionId, ImplId, ModuleId, StaticId, StructId, TraitId, ConstId, DefWithBodyId, EnumId, EnumVariantId, FunctionId, ImplId, ModuleId, StaticId,
UnionId, VariantId, StructFieldId, StructId, TraitId, TypeAliasId, UnionId, VariantId,
}; };
use hir_expand::InFile; use hir_expand::InFile;
use ra_prof::profile; use ra_prof::profile;
@ -166,6 +166,8 @@ to_id_impls![
(FunctionId, ast::FnDef, keys::FUNCTION), (FunctionId, ast::FnDef, keys::FUNCTION),
(StaticId, ast::StaticDef, keys::STATIC), (StaticId, ast::StaticDef, keys::STATIC),
(ConstId, ast::ConstDef, keys::CONST), (ConstId, ast::ConstDef, keys::CONST),
// (TypeAlias, TypeAliasId, ast::TypeAliasDef, keys::TYPE_ALIAS), (TypeAliasId, ast::TypeAliasDef, keys::TYPE_ALIAS),
(ImplId, ast::ImplBlock, keys::IMPL), (ImplId, ast::ImplBlock, keys::IMPL),
(StructFieldId, ast::RecordFieldDef, keys::RECORD_FIELD),
(EnumVariantId, ast::EnumVariant, keys::ENUM_VARIANT),
]; ];

View file

@ -29,7 +29,7 @@ use crate::{
}; };
pub(crate) use self::{ pub(crate) use self::{
classify::{classify_name, classify_name_ref}, classify::{classify_name, classify_name2, classify_name_ref, classify_name_ref2},
name_definition::{NameDefinition, NameKind}, name_definition::{NameDefinition, NameKind},
rename::rename, rename::rename,
}; };
@ -309,7 +309,7 @@ mod tests {
} }
impl Foo { impl Foo {
fn f() -> i32 { 42 } fn f() -> i32 { 42 }
} }
fn main() { fn main() {
let f: Foo; let f: Foo;
f = Foo {a: Foo::f()}; f = Foo {a: Foo::f()};
@ -319,7 +319,7 @@ mod tests {
check_result( check_result(
refs, refs,
"Foo STRUCT_DEF FileId(1) [5; 39) [12; 15) Other", "Foo STRUCT_DEF FileId(1) [5; 39) [12; 15) Other",
&["FileId(1) [142; 145) StructLiteral"], &["FileId(1) [138; 141) StructLiteral"],
); );
} }

View file

@ -1,6 +1,6 @@
//! 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::{FromSource, InFile, Module, ModuleSource, PathResolution, SourceAnalyzer}; use hir::{FromSource, InFile, Module, ModuleSource, PathResolution, SourceBinder};
use ra_prof::profile; use ra_prof::profile;
use ra_syntax::{ast, match_ast, AstNode}; use ra_syntax::{ast, match_ast, AstNode};
use test_utils::tested_by; use test_utils::tested_by;
@ -12,6 +12,14 @@ use super::{
use crate::db::RootDatabase; use crate::db::RootDatabase;
pub(crate) fn classify_name(db: &RootDatabase, name: InFile<&ast::Name>) -> Option<NameDefinition> { pub(crate) fn classify_name(db: &RootDatabase, name: InFile<&ast::Name>) -> Option<NameDefinition> {
let mut sb = SourceBinder::new(db);
classify_name2(&mut sb, name)
}
pub(crate) fn classify_name2(
sb: &mut SourceBinder<RootDatabase>,
name: InFile<&ast::Name>,
) -> Option<NameDefinition> {
let _p = profile("classify_name"); let _p = profile("classify_name");
let parent = name.value.syntax().parent()?; let parent = name.value.syntax().parent()?;
@ -19,90 +27,89 @@ pub(crate) fn classify_name(db: &RootDatabase, name: InFile<&ast::Name>) -> Opti
match parent { match parent {
ast::BindPat(it) => { ast::BindPat(it) => {
let src = name.with_value(it); let src = name.with_value(it);
let local = hir::Local::from_source(db, src)?; let local = hir::Local::from_source(sb.db, src)?;
Some(NameDefinition { Some(NameDefinition {
visibility: None, visibility: None,
container: local.module(db), container: local.module(sb.db),
kind: NameKind::Local(local), kind: NameKind::Local(local),
}) })
}, },
ast::RecordFieldDef(it) => { ast::RecordFieldDef(it) => {
let ast = hir::FieldSource::Named(it); let src = name.with_value(it);
let src = name.with_value(ast); let field: hir::StructField = sb.to_def(src)?;
let field = hir::StructField::from_source(db, src)?; Some(from_struct_field(sb.db, field))
Some(from_struct_field(db, field))
}, },
ast::Module(it) => { ast::Module(it) => {
let def = { let def = {
if !it.has_semi() { if !it.has_semi() {
let ast = hir::ModuleSource::Module(it); let ast = hir::ModuleSource::Module(it);
let src = name.with_value(ast); let src = name.with_value(ast);
hir::Module::from_definition(db, src) hir::Module::from_definition(sb.db, src)
} else { } else {
let src = name.with_value(it); let src = name.with_value(it);
hir::Module::from_declaration(db, src) hir::Module::from_declaration(sb.db, src)
} }
}?; }?;
Some(from_module_def(db, def.into(), None)) Some(from_module_def(sb.db, def.into(), None))
}, },
ast::StructDef(it) => { ast::StructDef(it) => {
let src = name.with_value(it); let src = name.with_value(it);
let def = hir::Struct::from_source(db, src)?; let def: hir::Struct = sb.to_def(src)?;
Some(from_module_def(db, def.into(), None)) Some(from_module_def(sb.db, def.into(), None))
}, },
ast::EnumDef(it) => { ast::EnumDef(it) => {
let src = name.with_value(it); let src = name.with_value(it);
let def = hir::Enum::from_source(db, src)?; let def: hir::Enum = sb.to_def(src)?;
Some(from_module_def(db, def.into(), None)) Some(from_module_def(sb.db, def.into(), None))
}, },
ast::TraitDef(it) => { ast::TraitDef(it) => {
let src = name.with_value(it); let src = name.with_value(it);
let def = hir::Trait::from_source(db, src)?; let def: hir::Trait = sb.to_def(src)?;
Some(from_module_def(db, def.into(), None)) Some(from_module_def(sb.db, def.into(), None))
}, },
ast::StaticDef(it) => { ast::StaticDef(it) => {
let src = name.with_value(it); let src = name.with_value(it);
let def = hir::Static::from_source(db, src)?; let def: hir::Static = sb.to_def(src)?;
Some(from_module_def(db, def.into(), None)) Some(from_module_def(sb.db, def.into(), None))
}, },
ast::EnumVariant(it) => { ast::EnumVariant(it) => {
let src = name.with_value(it); let src = name.with_value(it);
let def = hir::EnumVariant::from_source(db, src)?; let def: hir::EnumVariant = sb.to_def(src)?;
Some(from_module_def(db, def.into(), None)) Some(from_module_def(sb.db, def.into(), None))
}, },
ast::FnDef(it) => { ast::FnDef(it) => {
let src = name.with_value(it); let src = name.with_value(it);
let def = hir::Function::from_source(db, src)?; let def: hir::Function = sb.to_def(src)?;
if parent.parent().and_then(ast::ItemList::cast).is_some() { if parent.parent().and_then(ast::ItemList::cast).is_some() {
Some(from_assoc_item(db, def.into())) Some(from_assoc_item(sb.db, def.into()))
} else { } else {
Some(from_module_def(db, def.into(), None)) Some(from_module_def(sb.db, def.into(), None))
} }
}, },
ast::ConstDef(it) => { ast::ConstDef(it) => {
let src = name.with_value(it); let src = name.with_value(it);
let def = hir::Const::from_source(db, src)?; let def: hir::Const = sb.to_def(src)?;
if parent.parent().and_then(ast::ItemList::cast).is_some() { if parent.parent().and_then(ast::ItemList::cast).is_some() {
Some(from_assoc_item(db, def.into())) Some(from_assoc_item(sb.db, def.into()))
} else { } else {
Some(from_module_def(db, def.into(), None)) Some(from_module_def(sb.db, def.into(), None))
} }
}, },
ast::TypeAliasDef(it) => { ast::TypeAliasDef(it) => {
let src = name.with_value(it); let src = name.with_value(it);
let def = hir::TypeAlias::from_source(db, src)?; let def: hir::TypeAlias = sb.to_def(src)?;
if parent.parent().and_then(ast::ItemList::cast).is_some() { if parent.parent().and_then(ast::ItemList::cast).is_some() {
Some(from_assoc_item(db, def.into())) Some(from_assoc_item(sb.db, def.into()))
} else { } else {
Some(from_module_def(db, def.into(), None)) Some(from_module_def(sb.db, def.into(), None))
} }
}, },
ast::MacroCall(it) => { ast::MacroCall(it) => {
let src = name.with_value(it); let src = name.with_value(it);
let def = hir::MacroDef::from_source(db, src.clone())?; let def = hir::MacroDef::from_source(sb.db, src.clone())?;
let module_src = ModuleSource::from_child_node(db, src.as_ref().map(|it| it.syntax())); let module_src = ModuleSource::from_child_node(sb.db, src.as_ref().map(|it| it.syntax()));
let module = Module::from_definition(db, src.with_value(module_src))?; let module = Module::from_definition(sb.db, src.with_value(module_src))?;
Some(NameDefinition { Some(NameDefinition {
visibility: None, visibility: None,
@ -112,10 +119,10 @@ pub(crate) fn classify_name(db: &RootDatabase, name: InFile<&ast::Name>) -> Opti
}, },
ast::TypeParam(it) => { ast::TypeParam(it) => {
let src = name.with_value(it); let src = name.with_value(it);
let def = hir::TypeParam::from_source(db, src)?; let def = hir::TypeParam::from_source(sb.db, src)?;
Some(NameDefinition { Some(NameDefinition {
visibility: None, visibility: None,
container: def.module(db), container: def.module(sb.db),
kind: NameKind::TypeParam(def), kind: NameKind::TypeParam(def),
}) })
}, },
@ -127,23 +134,31 @@ pub(crate) fn classify_name(db: &RootDatabase, name: InFile<&ast::Name>) -> Opti
pub(crate) fn classify_name_ref( pub(crate) fn classify_name_ref(
db: &RootDatabase, db: &RootDatabase,
name_ref: InFile<&ast::NameRef>, name_ref: InFile<&ast::NameRef>,
) -> Option<NameDefinition> {
let mut sb = SourceBinder::new(db);
classify_name_ref2(&mut sb, name_ref)
}
pub(crate) fn classify_name_ref2(
sb: &mut SourceBinder<RootDatabase>,
name_ref: InFile<&ast::NameRef>,
) -> Option<NameDefinition> { ) -> Option<NameDefinition> {
let _p = profile("classify_name_ref"); let _p = profile("classify_name_ref");
let parent = name_ref.value.syntax().parent()?; let parent = name_ref.value.syntax().parent()?;
let analyzer = SourceAnalyzer::new(db, name_ref.map(|it| it.syntax()), None); let analyzer = sb.analyze(name_ref.map(|it| it.syntax()), None);
if let Some(method_call) = ast::MethodCallExpr::cast(parent.clone()) { if let Some(method_call) = ast::MethodCallExpr::cast(parent.clone()) {
tested_by!(goto_def_for_methods); tested_by!(goto_def_for_methods);
if let Some(func) = analyzer.resolve_method_call(&method_call) { if let Some(func) = analyzer.resolve_method_call(&method_call) {
return Some(from_assoc_item(db, func.into())); return Some(from_assoc_item(sb.db, func.into()));
} }
} }
if let Some(field_expr) = ast::FieldExpr::cast(parent.clone()) { if let Some(field_expr) = ast::FieldExpr::cast(parent.clone()) {
tested_by!(goto_def_for_fields); tested_by!(goto_def_for_fields);
if let Some(field) = analyzer.resolve_field(&field_expr) { if let Some(field) = analyzer.resolve_field(&field_expr) {
return Some(from_struct_field(db, field)); return Some(from_struct_field(sb.db, field));
} }
} }
@ -151,30 +166,32 @@ pub(crate) fn classify_name_ref(
tested_by!(goto_def_for_record_fields); tested_by!(goto_def_for_record_fields);
tested_by!(goto_def_for_field_init_shorthand); tested_by!(goto_def_for_field_init_shorthand);
if let Some(field_def) = analyzer.resolve_record_field(&record_field) { if let Some(field_def) = analyzer.resolve_record_field(&record_field) {
return Some(from_struct_field(db, field_def)); return Some(from_struct_field(sb.db, field_def));
} }
} }
let ast = ModuleSource::from_child_node(db, name_ref.with_value(&parent)); let ast = ModuleSource::from_child_node(sb.db, name_ref.with_value(&parent));
// FIXME: find correct container and visibility for each case // FIXME: find correct container and visibility for each case
let container = Module::from_definition(db, name_ref.with_value(ast))?; let container = Module::from_definition(sb.db, name_ref.with_value(ast))?;
let visibility = None; let visibility = None;
if let Some(macro_call) = parent.ancestors().find_map(ast::MacroCall::cast) { if let Some(macro_call) = parent.ancestors().find_map(ast::MacroCall::cast) {
tested_by!(goto_def_for_macros); tested_by!(goto_def_for_macros);
if let Some(macro_def) = analyzer.resolve_macro_call(db, name_ref.with_value(&macro_call)) { if let Some(macro_def) =
analyzer.resolve_macro_call(sb.db, name_ref.with_value(&macro_call))
{
let kind = NameKind::Macro(macro_def); let kind = NameKind::Macro(macro_def);
return Some(NameDefinition { kind, container, visibility }); return Some(NameDefinition { kind, container, visibility });
} }
} }
let path = name_ref.value.syntax().ancestors().find_map(ast::Path::cast)?; let path = name_ref.value.syntax().ancestors().find_map(ast::Path::cast)?;
let resolved = analyzer.resolve_path(db, &path)?; let resolved = analyzer.resolve_path(sb.db, &path)?;
match resolved { match resolved {
PathResolution::Def(def) => Some(from_module_def(db, def, Some(container))), PathResolution::Def(def) => Some(from_module_def(sb.db, def, Some(container))),
PathResolution::AssocItem(item) => Some(from_assoc_item(db, item)), PathResolution::AssocItem(item) => Some(from_assoc_item(sb.db, item)),
PathResolution::Local(local) => { PathResolution::Local(local) => {
let container = local.module(db); let container = local.module(sb.db);
let kind = NameKind::Local(local); let kind = NameKind::Local(local);
Some(NameDefinition { kind, container, visibility: None }) Some(NameDefinition { kind, container, visibility: None })
} }
@ -188,7 +205,7 @@ pub(crate) fn classify_name_ref(
} }
PathResolution::SelfType(impl_block) => { PathResolution::SelfType(impl_block) => {
let kind = NameKind::SelfType(impl_block); let kind = NameKind::SelfType(impl_block);
let container = impl_block.module(db); let container = impl_block.module(sb.db);
Some(NameDefinition { kind, container, visibility }) Some(NameDefinition { kind, container, visibility })
} }
} }

View file

@ -2,7 +2,7 @@
use rustc_hash::{FxHashMap, FxHashSet}; use rustc_hash::{FxHashMap, FxHashSet};
use hir::{InFile, Name}; use hir::{InFile, Name, SourceBinder};
use ra_db::SourceDatabase; use ra_db::SourceDatabase;
use ra_prof::profile; use ra_prof::profile;
use ra_syntax::{ast, AstNode, Direction, SyntaxElement, SyntaxKind, SyntaxKind::*, TextRange, T}; use ra_syntax::{ast, AstNode, Direction, SyntaxElement, SyntaxKind, SyntaxKind::*, TextRange, T};
@ -10,7 +10,7 @@ use ra_syntax::{ast, AstNode, Direction, SyntaxElement, SyntaxKind, SyntaxKind::
use crate::{ use crate::{
db::RootDatabase, db::RootDatabase,
references::{ references::{
classify_name, classify_name_ref, classify_name2, classify_name_ref2,
NameKind::{self, *}, NameKind::{self, *},
}, },
FileId, FileId,
@ -84,6 +84,8 @@ pub(crate) fn highlight(db: &RootDatabase, file_id: FileId) -> Vec<HighlightedRa
hash((file_id, name, shadow_count)) hash((file_id, name, shadow_count))
} }
let mut sb = SourceBinder::new(db);
// 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();
@ -108,8 +110,8 @@ pub(crate) fn highlight(db: &RootDatabase, file_id: FileId) -> Vec<HighlightedRa
NAME_REF if node.ancestors().any(|it| it.kind() == ATTR) => continue, NAME_REF if node.ancestors().any(|it| it.kind() == ATTR) => continue,
NAME_REF => { NAME_REF => {
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 = let name_kind = classify_name_ref2(&mut sb, InFile::new(file_id.into(), &name_ref))
classify_name_ref(db, InFile::new(file_id.into(), &name_ref)).map(|d| d.kind); .map(|d| d.kind);
match name_kind { match name_kind {
Some(name_kind) => { Some(name_kind) => {
if let Local(local) = &name_kind { if let Local(local) = &name_kind {
@ -129,7 +131,7 @@ pub(crate) fn highlight(db: &RootDatabase, file_id: FileId) -> Vec<HighlightedRa
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 = let name_kind =
classify_name(db, InFile::new(file_id.into(), &name)).map(|d| d.kind); classify_name2(&mut sb, InFile::new(file_id.into(), &name)).map(|d| d.kind);
if let Some(Local(local)) = &name_kind { if let Some(Local(local)) = &name_kind {
if let Some(name) = local.name(db) { if let Some(name) = local.name(db) {