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,
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),
];

View file

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

View file

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

View file

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