Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/hir/src/semantics.rs')
-rw-r--r--crates/hir/src/semantics.rs38
1 files changed, 38 insertions, 0 deletions
diff --git a/crates/hir/src/semantics.rs b/crates/hir/src/semantics.rs
index b7cc780ae4..38656e1870 100644
--- a/crates/hir/src/semantics.rs
+++ b/crates/hir/src/semantics.rs
@@ -1635,6 +1635,44 @@ impl<'db> SemanticsImpl<'db> {
.kmerge_by(|node1, node2| node1.text_range().len() < node2.text_range().len())
}
+ /// Returns the `return` expressions in this function's body,
+ /// excluding those inside closures or async blocks.
+ pub fn fn_return_points(&self, func: Function) -> Vec<InFile<ast::ReturnExpr>> {
+ let func_id = match func.id {
+ AnyFunctionId::FunctionId(id) => id,
+ _ => return vec![],
+ };
+ let (body, source_map) = Body::with_source_map(self.db, func_id.into());
+
+ fn collect_returns(
+ sema: &SemanticsImpl<'_>,
+ body: &Body,
+ source_map: &hir_def::expr_store::ExpressionStoreSourceMap,
+ expr_id: ExprId,
+ acc: &mut Vec<InFile<ast::ReturnExpr>>,
+ ) {
+ match &body[expr_id] {
+ Expr::Closure { .. } | Expr::Const(_) => return,
+ Expr::Return { .. } => {
+ if let Ok(source) = source_map.expr_syntax(expr_id)
+ && let Some(ret_expr) = source.value.cast::<ast::ReturnExpr>()
+ {
+ let root = sema.parse_or_expand(source.file_id);
+ acc.push(InFile::new(source.file_id, ret_expr.to_node(&root)));
+ }
+ }
+ _ => {}
+ }
+ body.walk_child_exprs(expr_id, |child| {
+ collect_returns(sema, body, source_map, child, acc);
+ });
+ }
+
+ let mut returns = vec![];
+ collect_returns(self, body, source_map, body.root_expr(), &mut returns);
+ returns
+ }
+
pub fn resolve_lifetime_param(&self, lifetime: &ast::Lifetime) -> Option<LifetimeParam> {
let text = lifetime.text();
let lifetime_param = lifetime.syntax().ancestors().find_map(|syn| {