Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/hir/src/lib.rs')
| -rw-r--r-- | crates/hir/src/lib.rs | 87 |
1 files changed, 87 insertions, 0 deletions
diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs index 2ff5f0d538..58340c74fe 100644 --- a/crates/hir/src/lib.rs +++ b/crates/hir/src/lib.rs @@ -78,6 +78,7 @@ use hir_ty::{ use itertools::Itertools; use nameres::diagnostics::DefDiagnosticKind; use rustc_hash::FxHashSet; +use smallvec::SmallVec; use span::{Edition, EditionedFileId, FileId, MacroCallId, SyntaxContextId}; use stdx::{impl_from, never}; use syntax::{ @@ -4113,6 +4114,15 @@ impl ClosureCapture { Local { parent: self.owner, binding_id: self.capture.local() } } + /// Returns whether this place has any field (aka. non-deref) projections. + pub fn has_field_projections(&self) -> bool { + self.capture.has_field_projections() + } + + pub fn usages(&self) -> CaptureUsages { + CaptureUsages { parent: self.owner, spans: self.capture.spans() } + } + pub fn kind(&self) -> CaptureKind { match self.capture.kind() { hir_ty::CaptureKind::ByRef( @@ -4128,6 +4138,15 @@ impl ClosureCapture { } } + /// Converts the place to a name that can be inserted into source code. + pub fn place_to_name(&self, db: &dyn HirDatabase) -> String { + self.capture.place_to_name(self.owner, db) + } + + pub fn display_place_source_code(&self, db: &dyn HirDatabase) -> String { + self.capture.display_place_source_code(self.owner, db) + } + pub fn display_place(&self, db: &dyn HirDatabase) -> String { self.capture.display_place(self.owner, db) } @@ -4141,6 +4160,74 @@ pub enum CaptureKind { Move, } +#[derive(Debug, Clone)] +pub struct CaptureUsages { + parent: DefWithBodyId, + spans: SmallVec<[mir::MirSpan; 3]>, +} + +impl CaptureUsages { + pub fn sources(&self, db: &dyn HirDatabase) -> Vec<CaptureUsageSource> { + let (body, source_map) = db.body_with_source_map(self.parent); + let mut result = Vec::with_capacity(self.spans.len()); + for &span in self.spans.iter() { + let is_ref = span.is_ref_span(&body); + match span { + mir::MirSpan::ExprId(expr) => { + if let Ok(expr) = source_map.expr_syntax(expr) { + result.push(CaptureUsageSource { + is_ref, + source: expr.map(AstPtr::wrap_left), + }) + } + } + mir::MirSpan::PatId(pat) => { + if let Ok(pat) = source_map.pat_syntax(pat) { + result.push(CaptureUsageSource { + is_ref, + source: pat.map(AstPtr::wrap_right), + }); + } + } + mir::MirSpan::BindingId(binding) => result.extend( + source_map + .patterns_for_binding(binding) + .iter() + .filter_map(|&pat| source_map.pat_syntax(pat).ok()) + .map(|pat| CaptureUsageSource { + is_ref, + source: pat.map(AstPtr::wrap_right), + }), + ), + mir::MirSpan::SelfParam | mir::MirSpan::Unknown => { + unreachable!("invalid capture usage span") + } + } + } + result + } +} + +#[derive(Debug)] +pub struct CaptureUsageSource { + is_ref: bool, + source: InFile<AstPtr<Either<ast::Expr, ast::Pat>>>, +} + +impl CaptureUsageSource { + pub fn source(&self) -> AstPtr<Either<ast::Expr, ast::Pat>> { + self.source.value + } + + pub fn file_id(&self) -> HirFileId { + self.source.file_id + } + + pub fn is_ref(&self) -> bool { + self.is_ref + } +} + #[derive(Clone, PartialEq, Eq, Debug, Hash)] pub struct Type { env: Arc<TraitEnvironment>, |