Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/ide-assists/src/utils.rs')
| -rw-r--r-- | crates/ide-assists/src/utils.rs | 95 |
1 files changed, 84 insertions, 11 deletions
diff --git a/crates/ide-assists/src/utils.rs b/crates/ide-assists/src/utils.rs index 20e0302b57..de8c4b6bca 100644 --- a/crates/ide-assists/src/utils.rs +++ b/crates/ide-assists/src/utils.rs @@ -57,6 +57,14 @@ pub fn extract_trivial_expression(block_expr: &ast::BlockExpr) -> Option<ast::Ex }); non_trivial_children.next().is_some() }; + if stmt_list + .syntax() + .children_with_tokens() + .filter_map(NodeOrToken::into_token) + .any(|token| token.kind() == syntax::SyntaxKind::COMMENT) + { + return None; + } if let Some(expr) = stmt_list.tail_expr() { if has_anything_else(expr.syntax()) { @@ -93,16 +101,7 @@ pub fn test_related_attribute_syn(fn_def: &ast::Fn) -> Option<ast::Attr> { } pub fn has_test_related_attribute(attrs: &hir::AttrsWithOwner) -> bool { - attrs.iter().any(|attr| { - let path = attr.path(); - (|| { - Some( - path.segments().first()?.as_str().starts_with("test") - || path.segments().last()?.as_str().ends_with("test"), - ) - })() - .unwrap_or_default() - }) + attrs.is_test() } #[derive(Clone, Copy, PartialEq)] @@ -128,7 +127,7 @@ pub fn filter_assoc_items( .copied() .filter(|assoc_item| { if ignore_items == IgnoreAssocItems::DocHiddenAttrPresent - && assoc_item.attrs(sema.db).has_doc_hidden() + && assoc_item.attrs(sema.db).is_doc_hidden() { if let hir::AssocItem::Function(f) = assoc_item && !f.has_body(sema.db) @@ -1057,6 +1056,33 @@ fn test_string_suffix() { assert_eq!(Some("i32"), string_suffix(r##"r#""#i32"##)); } +/// Calculate the string literal prefix length +pub(crate) fn string_prefix(s: &str) -> Option<&str> { + s.split_once(['"', '\'', '#']).map(|(prefix, _)| prefix) +} +#[test] +fn test_string_prefix() { + assert_eq!(Some(""), string_prefix(r#""abc""#)); + assert_eq!(Some(""), string_prefix(r#""""#)); + assert_eq!(Some(""), string_prefix(r#"""suffix"#)); + assert_eq!(Some("c"), string_prefix(r#"c"""#)); + assert_eq!(Some("r"), string_prefix(r#"r"""#)); + assert_eq!(Some("cr"), string_prefix(r#"cr"""#)); + assert_eq!(Some("r"), string_prefix(r##"r#""#"##)); +} + +pub(crate) fn add_group_separators(s: &str, group_size: usize) -> String { + let mut chars = Vec::new(); + for (i, ch) in s.chars().filter(|&ch| ch != '_').rev().enumerate() { + if i > 0 && i % group_size == 0 && ch != '-' { + chars.push('_'); + } + chars.push(ch); + } + + chars.into_iter().rev().collect() +} + /// Replaces the record expression, handling field shorthands including inside macros. pub(crate) fn replace_record_field_expr( ctx: &AssistContext<'_>, @@ -1118,6 +1144,37 @@ pub(crate) fn tt_from_syntax(node: SyntaxNode) -> Vec<NodeOrToken<ast::TokenTree tt_stack.pop().expect("parent token tree was closed before it was completed").1 } +pub(crate) fn cover_let_chain(mut expr: ast::Expr, range: TextRange) -> Option<ast::Expr> { + if !expr.syntax().text_range().contains_range(range) { + return None; + } + loop { + let (chain_expr, rest) = if let ast::Expr::BinExpr(bin_expr) = &expr + && bin_expr.op_kind() == Some(ast::BinaryOp::LogicOp(ast::LogicOp::And)) + { + (bin_expr.rhs(), bin_expr.lhs()) + } else { + (Some(expr), None) + }; + + if let Some(chain_expr) = chain_expr + && chain_expr.syntax().text_range().contains_range(range) + { + break Some(chain_expr); + } + expr = rest?; + } +} + +pub(crate) fn is_selected( + it: &impl AstNode, + selection: syntax::TextRange, + allow_empty: bool, +) -> bool { + selection.intersect(it.syntax().text_range()).is_some_and(|it| !it.is_empty()) + || allow_empty && it.syntax().text_range().contains_range(selection) +} + pub fn is_body_const(sema: &Semantics<'_, RootDatabase>, expr: &ast::Expr) -> bool { let mut is_const = true; preorder_expr(expr, &mut |ev| { @@ -1150,3 +1207,19 @@ pub fn is_body_const(sema: &Semantics<'_, RootDatabase>, expr: &ast::Expr) -> bo }); is_const } + +// FIXME: #20460 When hir-ty can analyze the `never` statement at the end of block, remove it +pub(crate) fn is_never_block( + sema: &Semantics<'_, RootDatabase>, + block_expr: &ast::BlockExpr, +) -> bool { + if let Some(tail_expr) = block_expr.tail_expr() { + sema.type_of_expr(&tail_expr).is_some_and(|ty| ty.original.is_never()) + } else if let Some(ast::Stmt::ExprStmt(expr_stmt)) = block_expr.statements().last() + && let Some(expr) = expr_stmt.expr() + { + sema.type_of_expr(&expr).is_some_and(|ty| ty.original.is_never()) + } else { + false + } +} |