mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-09-28 21:05:02 +00:00
Mark (method-)calls with never type as exit points
This commit is contained in:
parent
cc791538d6
commit
f283fce594
2 changed files with 58 additions and 9 deletions
|
@ -2075,10 +2075,15 @@ impl Type {
|
||||||
pub fn is_unit(&self) -> bool {
|
pub fn is_unit(&self) -> bool {
|
||||||
matches!(self.ty.kind(&Interner), TyKind::Tuple(0, ..))
|
matches!(self.ty.kind(&Interner), TyKind::Tuple(0, ..))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_bool(&self) -> bool {
|
pub fn is_bool(&self) -> bool {
|
||||||
matches!(self.ty.kind(&Interner), TyKind::Scalar(Scalar::Bool))
|
matches!(self.ty.kind(&Interner), TyKind::Scalar(Scalar::Bool))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn is_never(&self) -> bool {
|
||||||
|
matches!(self.ty.kind(&Interner), TyKind::Never)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn is_mutable_reference(&self) -> bool {
|
pub fn is_mutable_reference(&self) -> bool {
|
||||||
matches!(self.ty.kind(&Interner), TyKind::Ref(hir_ty::Mutability::Mut, ..))
|
matches!(self.ty.kind(&Interner), TyKind::Ref(hir_ty::Mutability::Mut, ..))
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,7 +36,7 @@ pub(crate) fn highlight_related(
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
match token.kind() {
|
match token.kind() {
|
||||||
QUESTION | RETURN_KW | THIN_ARROW => highlight_exit_points(token),
|
QUESTION | RETURN_KW | THIN_ARROW => highlight_exit_points(sema, token),
|
||||||
AWAIT_KW | ASYNC_KW => highlight_yield_points(token),
|
AWAIT_KW | ASYNC_KW => highlight_yield_points(token),
|
||||||
_ => highlight_references(sema, &syntax, position),
|
_ => highlight_references(sema, &syntax, position),
|
||||||
}
|
}
|
||||||
|
@ -74,8 +74,14 @@ fn highlight_references(
|
||||||
Some(res)
|
Some(res)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn highlight_exit_points(token: SyntaxToken) -> Option<Vec<DocumentHighlight>> {
|
fn highlight_exit_points(
|
||||||
fn hl(body: Option<ast::Expr>) -> Option<Vec<DocumentHighlight>> {
|
sema: &Semantics<RootDatabase>,
|
||||||
|
token: SyntaxToken,
|
||||||
|
) -> Option<Vec<DocumentHighlight>> {
|
||||||
|
fn hl(
|
||||||
|
sema: &Semantics<RootDatabase>,
|
||||||
|
body: Option<ast::Expr>,
|
||||||
|
) -> Option<Vec<DocumentHighlight>> {
|
||||||
let mut highlights = Vec::new();
|
let mut highlights = Vec::new();
|
||||||
let body = body?;
|
let body = body?;
|
||||||
walk(&body, |node| {
|
walk(&body, |node| {
|
||||||
|
@ -93,9 +99,19 @@ fn highlight_exit_points(token: SyntaxToken) -> Option<Vec<DocumentHighlight>> {
|
||||||
range: token.text_range(),
|
range: token.text_range(),
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
// All the following are different contexts so skip them
|
ast::Expr(expr) => match expr {
|
||||||
ast::EffectExpr(effect) => return effect.async_token().is_some() || effect.try_token().is_some(),
|
ast::Expr::MethodCallExpr(_) | ast::Expr::CallExpr(_) | ast::Expr::MacroCall(_) => {
|
||||||
ast::ClosureExpr(__) => return true,
|
if sema.type_of_expr(&expr).map_or(false, |ty| ty.is_never()) {
|
||||||
|
highlights.push(DocumentHighlight {
|
||||||
|
access: None,
|
||||||
|
range: expr.syntax().text_range(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
ast::Expr::EffectExpr(effect) => return effect.async_token().is_some() || effect.try_token().is_some(),
|
||||||
|
ast::Expr::ClosureExpr(_) => return true,
|
||||||
|
_ => (),
|
||||||
|
},
|
||||||
ast::Item(__) => return true,
|
ast::Item(__) => return true,
|
||||||
// Don't look into const args
|
// Don't look into const args
|
||||||
ast::Path(__) => return true,
|
ast::Path(__) => return true,
|
||||||
|
@ -116,10 +132,10 @@ fn highlight_exit_points(token: SyntaxToken) -> Option<Vec<DocumentHighlight>> {
|
||||||
for anc in token.ancestors() {
|
for anc in token.ancestors() {
|
||||||
return match_ast! {
|
return match_ast! {
|
||||||
match anc {
|
match anc {
|
||||||
ast::Fn(fn_) => hl(fn_.body().map(ast::Expr::BlockExpr)),
|
ast::Fn(fn_) => hl(sema, fn_.body().map(ast::Expr::BlockExpr)),
|
||||||
ast::ClosureExpr(closure) => hl(closure.body()),
|
ast::ClosureExpr(closure) => hl(sema, closure.body()),
|
||||||
ast::EffectExpr(effect) => if effect.async_token().is_some() || effect.try_token().is_some() {
|
ast::EffectExpr(effect) => if effect.async_token().is_some() || effect.try_token().is_some() {
|
||||||
hl(effect.block_expr().map(ast::Expr::BlockExpr))
|
hl(sema, effect.block_expr().map(ast::Expr::BlockExpr))
|
||||||
} else {
|
} else {
|
||||||
continue;
|
continue;
|
||||||
},
|
},
|
||||||
|
@ -399,6 +415,34 @@ fn foo() -> u32 {
|
||||||
foo$0()
|
foo$0()
|
||||||
// ^^^
|
// ^^^
|
||||||
}
|
}
|
||||||
|
"#,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_hl_never_call_is_exit_point() {
|
||||||
|
check(
|
||||||
|
r#"
|
||||||
|
struct Never;
|
||||||
|
impl Never {
|
||||||
|
fn never(self) -> ! { loop {} }
|
||||||
|
}
|
||||||
|
macro_rules! never {
|
||||||
|
() => { never() }
|
||||||
|
}
|
||||||
|
fn never() -> ! { loop {} }
|
||||||
|
fn foo() ->$0 u32 {
|
||||||
|
never();
|
||||||
|
// ^^^^^^^
|
||||||
|
never!();
|
||||||
|
// FIXME sema doesnt give us types for macrocalls
|
||||||
|
|
||||||
|
Never.never();
|
||||||
|
// ^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
0
|
||||||
|
// ^
|
||||||
|
}
|
||||||
"#,
|
"#,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue