mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-09-27 12:29:21 +00:00
Track labels in the HIR
This commit is contained in:
parent
fd1fcf2c2e
commit
262b9c3982
9 changed files with 167 additions and 68 deletions
|
@ -9,7 +9,7 @@ use hir_def::{
|
|||
adt::StructKind,
|
||||
adt::VariantData,
|
||||
builtin_type::BuiltinType,
|
||||
expr::{BindingAnnotation, Pat, PatId},
|
||||
expr::{BindingAnnotation, LabelId, Pat, PatId},
|
||||
import_map,
|
||||
item_tree::ItemTreeNode,
|
||||
lang_item::LangItemTarget,
|
||||
|
@ -1205,6 +1205,34 @@ impl Local {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
||||
pub struct Label {
|
||||
pub(crate) parent: DefWithBodyId,
|
||||
pub(crate) label_id: LabelId,
|
||||
}
|
||||
|
||||
impl Label {
|
||||
pub fn module(self, db: &dyn HirDatabase) -> Module {
|
||||
self.parent(db).module(db)
|
||||
}
|
||||
|
||||
pub fn parent(self, _db: &dyn HirDatabase) -> DefWithBody {
|
||||
self.parent.into()
|
||||
}
|
||||
|
||||
pub fn name(self, db: &dyn HirDatabase) -> Name {
|
||||
let body = db.body(self.parent.into());
|
||||
body[self.label_id].name.clone()
|
||||
}
|
||||
|
||||
pub fn source(self, db: &dyn HirDatabase) -> InFile<ast::Label> {
|
||||
let (_body, source_map) = db.body_with_source_map(self.parent.into());
|
||||
let src = source_map.label_syntax(self.label_id);
|
||||
let root = src.file_syntax(db.upcast());
|
||||
src.map(|ast| ast.to_node(&root))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
||||
pub enum GenericParam {
|
||||
TypeParam(TypeParam),
|
||||
|
|
|
@ -4,12 +4,15 @@
|
|||
//! are splitting the hir.
|
||||
|
||||
use hir_def::{
|
||||
expr::PatId, item_scope::ItemInNs, AdtId, AssocItemId, DefWithBodyId, EnumVariantId, FieldId,
|
||||
GenericDefId, ModuleDefId, VariantId,
|
||||
expr::{LabelId, PatId},
|
||||
item_scope::ItemInNs,
|
||||
AdtId, AssocItemId, DefWithBodyId, EnumVariantId, FieldId, GenericDefId, ModuleDefId,
|
||||
VariantId,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
Adt, AssocItem, DefWithBody, Field, GenericDef, Local, MacroDef, ModuleDef, Variant, VariantDef,
|
||||
Adt, AssocItem, DefWithBody, Field, GenericDef, Label, Local, MacroDef, ModuleDef, Variant,
|
||||
VariantDef,
|
||||
};
|
||||
|
||||
macro_rules! from_id {
|
||||
|
@ -228,6 +231,12 @@ impl From<(DefWithBodyId, PatId)> for Local {
|
|||
}
|
||||
}
|
||||
|
||||
impl From<(DefWithBodyId, LabelId)> for Label {
|
||||
fn from((parent, label_id): (DefWithBodyId, LabelId)) -> Self {
|
||||
Label { parent, label_id }
|
||||
}
|
||||
}
|
||||
|
||||
impl From<MacroDef> for ItemInNs {
|
||||
fn from(macro_def: MacroDef) -> Self {
|
||||
ItemInNs::Macros(macro_def.into())
|
||||
|
|
|
@ -35,8 +35,8 @@ pub use crate::{
|
|||
code_model::{
|
||||
Access, Adt, AsAssocItem, AssocItem, AssocItemContainer, Callable, CallableKind, Const,
|
||||
Crate, CrateDependency, DefWithBody, Enum, Field, FieldSource, Function, GenericDef,
|
||||
HasVisibility, Impl, LifetimeParam, Local, MacroDef, Module, ModuleDef, ScopeDef, Static,
|
||||
Struct, Trait, Type, TypeAlias, TypeParam, Union, Variant, VariantDef,
|
||||
HasVisibility, Impl, Label, LifetimeParam, Local, MacroDef, Module, ModuleDef, ScopeDef,
|
||||
Static, Struct, Trait, Type, TypeAlias, TypeParam, Union, Variant, VariantDef,
|
||||
},
|
||||
has_source::HasSource,
|
||||
semantics::{PathResolution, Semantics, SemanticsScope},
|
||||
|
|
|
@ -15,7 +15,7 @@ use itertools::Itertools;
|
|||
use rustc_hash::{FxHashMap, FxHashSet};
|
||||
use syntax::{
|
||||
algo::find_node_at_offset,
|
||||
ast::{self, GenericParamsOwner},
|
||||
ast::{self, GenericParamsOwner, LoopBodyOwner},
|
||||
match_ast, AstNode, SyntaxNode, SyntaxToken, TextSize,
|
||||
};
|
||||
|
||||
|
@ -25,8 +25,8 @@ use crate::{
|
|||
diagnostics::Diagnostic,
|
||||
semantics::source_to_def::{ChildContainer, SourceToDefCache, SourceToDefCtx},
|
||||
source_analyzer::{resolve_hir_path, SourceAnalyzer},
|
||||
AssocItem, Callable, Crate, Field, Function, HirFileId, Impl, InFile, LifetimeParam, Local,
|
||||
MacroDef, Module, ModuleDef, Name, Path, ScopeDef, Trait, Type, TypeAlias, TypeParam,
|
||||
AssocItem, Callable, Crate, Field, Function, HirFileId, Impl, InFile, Label, LifetimeParam,
|
||||
Local, MacroDef, Module, ModuleDef, Name, Path, ScopeDef, Trait, Type, TypeAlias, TypeParam,
|
||||
VariantDef,
|
||||
};
|
||||
|
||||
|
@ -182,6 +182,10 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> {
|
|||
self.imp.resolve_lifetime_param(lifetime)
|
||||
}
|
||||
|
||||
pub fn resolve_label(&self, lifetime: &ast::Lifetime) -> Option<Label> {
|
||||
self.imp.resolve_label(lifetime)
|
||||
}
|
||||
|
||||
pub fn type_of_expr(&self, expr: &ast::Expr) -> Option<Type> {
|
||||
self.imp.type_of_expr(expr)
|
||||
}
|
||||
|
@ -425,6 +429,28 @@ impl<'db> SemanticsImpl<'db> {
|
|||
ToDef::to_def(self, src)
|
||||
}
|
||||
|
||||
fn resolve_label(&self, lifetime: &ast::Lifetime) -> Option<Label> {
|
||||
let text = lifetime.text();
|
||||
let label = lifetime.syntax().ancestors().find_map(|syn| {
|
||||
let label = match_ast! {
|
||||
match syn {
|
||||
ast::ForExpr(it) => it.label(),
|
||||
ast::WhileExpr(it) => it.label(),
|
||||
ast::LoopExpr(it) => it.label(),
|
||||
ast::EffectExpr(it) => it.label(),
|
||||
_ => None,
|
||||
}
|
||||
};
|
||||
label.filter(|l| {
|
||||
l.lifetime()
|
||||
.and_then(|lt| lt.lifetime_ident_token())
|
||||
.map_or(false, |lt| lt.text() == text)
|
||||
})
|
||||
})?;
|
||||
let src = self.find_file(label.syntax().clone()).with_value(label);
|
||||
ToDef::to_def(self, src)
|
||||
}
|
||||
|
||||
fn type_of_expr(&self, expr: &ast::Expr) -> Option<Type> {
|
||||
self.analyze(expr.syntax()).type_of_expr(self.db, expr)
|
||||
}
|
||||
|
@ -720,6 +746,7 @@ to_def_impls![
|
|||
(crate::LifetimeParam, ast::LifetimeParam, lifetime_param_to_def),
|
||||
(crate::MacroDef, ast::MacroRules, macro_rules_to_def),
|
||||
(crate::Local, ast::IdentPat, bind_pat_to_def),
|
||||
(crate::Label, ast::Label, label_to_def),
|
||||
];
|
||||
|
||||
fn find_root(node: &SyntaxNode) -> SyntaxNode {
|
||||
|
|
|
@ -4,7 +4,7 @@ use base_db::FileId;
|
|||
use hir_def::{
|
||||
child_by_source::ChildBySource,
|
||||
dyn_map::DynMap,
|
||||
expr::PatId,
|
||||
expr::{LabelId, PatId},
|
||||
keys::{self, Key},
|
||||
ConstId, DefWithBodyId, EnumId, EnumVariantId, FieldId, FunctionId, GenericDefId, ImplId,
|
||||
LifetimeParamId, ModuleId, StaticId, StructId, TraitId, TypeAliasId, TypeParamId, UnionId,
|
||||
|
@ -108,12 +108,21 @@ impl SourceToDefCtx<'_, '_> {
|
|||
&mut self,
|
||||
src: InFile<ast::IdentPat>,
|
||||
) -> Option<(DefWithBodyId, PatId)> {
|
||||
let container = self.find_pat_container(src.as_ref().map(|it| it.syntax()))?;
|
||||
let container = self.find_pat_or_label_container(src.as_ref().map(|it| it.syntax()))?;
|
||||
let (_body, source_map) = self.db.body_with_source_map(container);
|
||||
let src = src.map(ast::Pat::from);
|
||||
let pat_id = source_map.node_pat(src.as_ref())?;
|
||||
Some((container, pat_id))
|
||||
}
|
||||
pub(super) fn label_to_def(
|
||||
&mut self,
|
||||
src: InFile<ast::Label>,
|
||||
) -> Option<(DefWithBodyId, LabelId)> {
|
||||
let container = self.find_pat_or_label_container(src.as_ref().map(|it| it.syntax()))?;
|
||||
let (_body, source_map) = self.db.body_with_source_map(container);
|
||||
let label_id = source_map.node_label(src.as_ref())?;
|
||||
Some((container, label_id))
|
||||
}
|
||||
|
||||
fn to_def<Ast: AstNode + 'static, ID: Copy + 'static>(
|
||||
&mut self,
|
||||
|
@ -237,7 +246,7 @@ impl SourceToDefCtx<'_, '_> {
|
|||
None
|
||||
}
|
||||
|
||||
fn find_pat_container(&mut self, src: InFile<&SyntaxNode>) -> Option<DefWithBodyId> {
|
||||
fn find_pat_or_label_container(&mut self, src: InFile<&SyntaxNode>) -> Option<DefWithBodyId> {
|
||||
for container in src.cloned().ancestors_with_macros(self.db.upcast()).skip(1) {
|
||||
let res: DefWithBodyId = match_ast! {
|
||||
match (container.value) {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue