Make syntax highlighting linear
This commit is contained in:
parent
7e70fc22a7
commit
c640c2ea11
4 changed files with 78 additions and 57 deletions
|
@ -8,8 +8,8 @@ use hir_def::{
|
|||
dyn_map::DynMap,
|
||||
keys::{self, Key},
|
||||
resolver::{HasResolver, Resolver},
|
||||
ConstId, DefWithBodyId, EnumId, FunctionId, ImplId, ModuleId, StaticId, StructId, TraitId,
|
||||
UnionId, VariantId,
|
||||
ConstId, DefWithBodyId, EnumId, EnumVariantId, FunctionId, ImplId, ModuleId, StaticId,
|
||||
StructFieldId, StructId, TraitId, TypeAliasId, UnionId, VariantId,
|
||||
};
|
||||
use hir_expand::InFile;
|
||||
use ra_prof::profile;
|
||||
|
@ -166,6 +166,8 @@ to_id_impls![
|
|||
(FunctionId, ast::FnDef, keys::FUNCTION),
|
||||
(StaticId, ast::StaticDef, keys::STATIC),
|
||||
(ConstId, ast::ConstDef, keys::CONST),
|
||||
// (TypeAlias, TypeAliasId, ast::TypeAliasDef, keys::TYPE_ALIAS),
|
||||
(TypeAliasId, ast::TypeAliasDef, keys::TYPE_ALIAS),
|
||||
(ImplId, ast::ImplBlock, keys::IMPL),
|
||||
(StructFieldId, ast::RecordFieldDef, keys::RECORD_FIELD),
|
||||
(EnumVariantId, ast::EnumVariant, keys::ENUM_VARIANT),
|
||||
];
|
||||
|
|
|
@ -29,7 +29,7 @@ use crate::{
|
|||
};
|
||||
|
||||
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},
|
||||
rename::rename,
|
||||
};
|
||||
|
@ -309,7 +309,7 @@ mod tests {
|
|||
}
|
||||
impl Foo {
|
||||
fn f() -> i32 { 42 }
|
||||
}
|
||||
}
|
||||
fn main() {
|
||||
let f: Foo;
|
||||
f = Foo {a: Foo::f()};
|
||||
|
@ -319,7 +319,7 @@ mod tests {
|
|||
check_result(
|
||||
refs,
|
||||
"Foo STRUCT_DEF FileId(1) [5; 39) [12; 15) Other",
|
||||
&["FileId(1) [142; 145) StructLiteral"],
|
||||
&["FileId(1) [138; 141) StructLiteral"],
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
//! 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_syntax::{ast, match_ast, AstNode};
|
||||
use test_utils::tested_by;
|
||||
|
@ -12,6 +12,14 @@ use super::{
|
|||
use crate::db::RootDatabase;
|
||||
|
||||
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 parent = name.value.syntax().parent()?;
|
||||
|
||||
|
@ -19,90 +27,89 @@ pub(crate) fn classify_name(db: &RootDatabase, name: InFile<&ast::Name>) -> Opti
|
|||
match parent {
|
||||
ast::BindPat(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 {
|
||||
visibility: None,
|
||||
container: local.module(db),
|
||||
container: local.module(sb.db),
|
||||
kind: NameKind::Local(local),
|
||||
})
|
||||
},
|
||||
ast::RecordFieldDef(it) => {
|
||||
let ast = hir::FieldSource::Named(it);
|
||||
let src = name.with_value(ast);
|
||||
let field = hir::StructField::from_source(db, src)?;
|
||||
Some(from_struct_field(db, field))
|
||||
let src = name.with_value(it);
|
||||
let field: hir::StructField = sb.to_def(src)?;
|
||||
Some(from_struct_field(sb.db, field))
|
||||
},
|
||||
ast::Module(it) => {
|
||||
let def = {
|
||||
if !it.has_semi() {
|
||||
let ast = hir::ModuleSource::Module(it);
|
||||
let src = name.with_value(ast);
|
||||
hir::Module::from_definition(db, src)
|
||||
hir::Module::from_definition(sb.db, src)
|
||||
} else {
|
||||
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) => {
|
||||
let src = name.with_value(it);
|
||||
let def = hir::Struct::from_source(db, src)?;
|
||||
Some(from_module_def(db, def.into(), None))
|
||||
let def: hir::Struct = sb.to_def(src)?;
|
||||
Some(from_module_def(sb.db, def.into(), None))
|
||||
},
|
||||
ast::EnumDef(it) => {
|
||||
let src = name.with_value(it);
|
||||
let def = hir::Enum::from_source(db, src)?;
|
||||
Some(from_module_def(db, def.into(), None))
|
||||
let def: hir::Enum = sb.to_def(src)?;
|
||||
Some(from_module_def(sb.db, def.into(), None))
|
||||
},
|
||||
ast::TraitDef(it) => {
|
||||
let src = name.with_value(it);
|
||||
let def = hir::Trait::from_source(db, src)?;
|
||||
Some(from_module_def(db, def.into(), None))
|
||||
let def: hir::Trait = sb.to_def(src)?;
|
||||
Some(from_module_def(sb.db, def.into(), None))
|
||||
},
|
||||
ast::StaticDef(it) => {
|
||||
let src = name.with_value(it);
|
||||
let def = hir::Static::from_source(db, src)?;
|
||||
Some(from_module_def(db, def.into(), None))
|
||||
let def: hir::Static = sb.to_def(src)?;
|
||||
Some(from_module_def(sb.db, def.into(), None))
|
||||
},
|
||||
ast::EnumVariant(it) => {
|
||||
let src = name.with_value(it);
|
||||
let def = hir::EnumVariant::from_source(db, src)?;
|
||||
Some(from_module_def(db, def.into(), None))
|
||||
let def: hir::EnumVariant = sb.to_def(src)?;
|
||||
Some(from_module_def(sb.db, def.into(), None))
|
||||
},
|
||||
ast::FnDef(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() {
|
||||
Some(from_assoc_item(db, def.into()))
|
||||
Some(from_assoc_item(sb.db, def.into()))
|
||||
} else {
|
||||
Some(from_module_def(db, def.into(), None))
|
||||
Some(from_module_def(sb.db, def.into(), None))
|
||||
}
|
||||
},
|
||||
ast::ConstDef(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() {
|
||||
Some(from_assoc_item(db, def.into()))
|
||||
Some(from_assoc_item(sb.db, def.into()))
|
||||
} else {
|
||||
Some(from_module_def(db, def.into(), None))
|
||||
Some(from_module_def(sb.db, def.into(), None))
|
||||
}
|
||||
},
|
||||
ast::TypeAliasDef(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() {
|
||||
Some(from_assoc_item(db, def.into()))
|
||||
Some(from_assoc_item(sb.db, def.into()))
|
||||
} else {
|
||||
Some(from_module_def(db, def.into(), None))
|
||||
Some(from_module_def(sb.db, def.into(), None))
|
||||
}
|
||||
},
|
||||
ast::MacroCall(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 = Module::from_definition(db, src.with_value(module_src))?;
|
||||
let module_src = ModuleSource::from_child_node(sb.db, src.as_ref().map(|it| it.syntax()));
|
||||
let module = Module::from_definition(sb.db, src.with_value(module_src))?;
|
||||
|
||||
Some(NameDefinition {
|
||||
visibility: None,
|
||||
|
@ -112,10 +119,10 @@ pub(crate) fn classify_name(db: &RootDatabase, name: InFile<&ast::Name>) -> Opti
|
|||
},
|
||||
ast::TypeParam(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 {
|
||||
visibility: None,
|
||||
container: def.module(db),
|
||||
container: def.module(sb.db),
|
||||
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(
|
||||
db: &RootDatabase,
|
||||
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> {
|
||||
let _p = profile("classify_name_ref");
|
||||
|
||||
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()) {
|
||||
tested_by!(goto_def_for_methods);
|
||||
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()) {
|
||||
tested_by!(goto_def_for_fields);
|
||||
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_field_init_shorthand);
|
||||
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
|
||||
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;
|
||||
|
||||
if let Some(macro_call) = parent.ancestors().find_map(ast::MacroCall::cast) {
|
||||
tested_by!(goto_def_for_macros);
|
||||
if let Some(macro_def) = analyzer.resolve_macro_call(db, name_ref.with_value(¯o_call)) {
|
||||
if let Some(macro_def) =
|
||||
analyzer.resolve_macro_call(sb.db, name_ref.with_value(¯o_call))
|
||||
{
|
||||
let kind = NameKind::Macro(macro_def);
|
||||
return Some(NameDefinition { kind, container, visibility });
|
||||
}
|
||||
}
|
||||
|
||||
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 {
|
||||
PathResolution::Def(def) => Some(from_module_def(db, def, Some(container))),
|
||||
PathResolution::AssocItem(item) => Some(from_assoc_item(db, item)),
|
||||
PathResolution::Def(def) => Some(from_module_def(sb.db, def, Some(container))),
|
||||
PathResolution::AssocItem(item) => Some(from_assoc_item(sb.db, item)),
|
||||
PathResolution::Local(local) => {
|
||||
let container = local.module(db);
|
||||
let container = local.module(sb.db);
|
||||
let kind = NameKind::Local(local);
|
||||
Some(NameDefinition { kind, container, visibility: None })
|
||||
}
|
||||
|
@ -188,7 +205,7 @@ pub(crate) fn classify_name_ref(
|
|||
}
|
||||
PathResolution::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 })
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
use rustc_hash::{FxHashMap, FxHashSet};
|
||||
|
||||
use hir::{InFile, Name};
|
||||
use hir::{InFile, Name, SourceBinder};
|
||||
use ra_db::SourceDatabase;
|
||||
use ra_prof::profile;
|
||||
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::{
|
||||
db::RootDatabase,
|
||||
references::{
|
||||
classify_name, classify_name_ref,
|
||||
classify_name2, classify_name_ref2,
|
||||
NameKind::{self, *},
|
||||
},
|
||||
FileId,
|
||||
|
@ -84,6 +84,8 @@ pub(crate) fn highlight(db: &RootDatabase, file_id: FileId) -> Vec<HighlightedRa
|
|||
hash((file_id, name, shadow_count))
|
||||
}
|
||||
|
||||
let mut sb = SourceBinder::new(db);
|
||||
|
||||
// Visited nodes to handle highlighting priorities
|
||||
// FIXME: retain only ranges here
|
||||
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 => {
|
||||
let name_ref = node.as_node().cloned().and_then(ast::NameRef::cast).unwrap();
|
||||
let name_kind =
|
||||
classify_name_ref(db, InFile::new(file_id.into(), &name_ref)).map(|d| d.kind);
|
||||
let name_kind = classify_name_ref2(&mut sb, InFile::new(file_id.into(), &name_ref))
|
||||
.map(|d| d.kind);
|
||||
match name_kind {
|
||||
Some(name_kind) => {
|
||||
if let Local(local) = &name_kind {
|
||||
|
@ -129,7 +131,7 @@ pub(crate) fn highlight(db: &RootDatabase, file_id: FileId) -> Vec<HighlightedRa
|
|||
NAME => {
|
||||
let name = node.as_node().cloned().and_then(ast::Name::cast).unwrap();
|
||||
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(name) = local.name(db) {
|
||||
|
|
Loading…
Add table
Reference in a new issue