use either::Either;
use hir::PathResolution;
use ide_db::{base_db::FileId, defs::Definition, search::FileReference};
use rustc_hash::FxHashMap;
use syntax::{
ast::{self, AstNode, AstToken, NameOwner},
TextRange,
};
use crate::{
assist_context::{AssistContext, Assists},
AssistId, AssistKind,
};
// Assist: inline_local_variable
//
// Inlines local variable.
//
// ```
// fn main() {
// let x$0 = 1 + 2;
// x * 4;
// }
// ```
// ->
// ```
// fn main() {
// (1 + 2) * 4;
// }
// ```
pub(crate) fn inline_local_variable(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
let InlineData { let_stmt, delete_let, replace_usages, target } =
inline_let(ctx).or_else(|| inline_usage(ctx))?;
let initializer_expr = let_stmt.initializer()?;
let delete_range = if delete_let {
if let Some(whitespace) = let_stmt
.syntax()
.next_sibling_or_token()
.and_then(|it| ast::Whitespace::cast(it.as_token()?.clone()))
{
Some(TextRange::new(
let_stmt.syntax().text_range().start(),
whitespace.syntax().text_range().end(),
))
} else {
Some(let_stmt.syntax().text_range())
}
} else {
None
};
let wrap_in_parens = replace_usages
.iter()
.map(|(&file_id, refs)| {
refs.iter()
.map(|&FileReference { range, .. }| {
let usage_node = ctx
.covering_node_for_range(range)
.ancestors()
.find_map(ast::PathExpr::cast)?;
let usage_parent_option =
usage_node.syntax().parent().and_then(ast::Expr::cast);
let usage_parent = match usage_parent_option {
Some(u) => u,
None => return Some(false),
};
let initializer = matches!(
initializer_expr,
ast::Expr::CallExpr(_)
| ast::Expr::IndexExpr(_)
| ast::Expr::MethodCallExpr(_)
| ast::Expr::FieldExpr(_)
| ast::Expr::TryExpr(_)
| ast::Expr::RefExpr(_)
| ast::Expr::Literal(_)
| ast::Expr::TupleExpr(_)
| ast::Expr::ArrayExpr(_)
| ast::Expr::ParenExpr(_)
| ast::Expr::PathExpr(_)
| ast::Expr::BlockExpr(_)
| ast::Expr::EffectExpr(_),
);
let parent = matches!(
usage_parent,
ast::Expr::CallExpr(_)
| ast::Expr::TupleExpr(_)
| ast::Expr::ArrayExpr(_)
| ast::Expr::ParenExpr(_)
| ast::Expr::ForExpr(_)
| ast::Expr::WhileExpr(_)
| ast::Expr::BreakExpr(_)
| ast::Expr::ReturnExpr(_)
| ast::Expr::MatchExpr(_)
);
Some(!(initializer || parent))
})
.collect::