Skip to content

Commit ef8e6a4

Browse files
committed
Filter where clause predicates
1 parent 9454be5 commit ef8e6a4

File tree

1 file changed

+124
-48
lines changed

1 file changed

+124
-48
lines changed

crates/ide-assists/src/handlers/extract_function.rs

+124-48
Original file line numberDiff line numberDiff line change
@@ -697,7 +697,9 @@ impl FunctionBody {
697697
}
698698
};
699699

700-
let (mut generic_param_list, mut where_clause) = (None, None);
700+
let mut generic_param_list = None;
701+
let mut where_clause = None;
702+
701703
let (is_const, expr, ty) = loop {
702704
let anc = ancestors.next()?;
703705
break match_ast! {
@@ -1345,93 +1347,144 @@ fn format_function(
13451347
let const_kw = if fun.mods.is_const { "const " } else { "" };
13461348
let async_kw = if fun.control_flow.is_async { "async " } else { "" };
13471349
let unsafe_kw = if fun.control_flow.is_unsafe { "unsafe " } else { "" };
1348-
let (generic_params, where_clause) = format_generic_params_and_where_clause(ctx, fun);
1350+
let (generic_params, where_clause) = make_generic_params_and_where_clause(ctx, fun);
13491351
match ctx.config.snippet_cap {
13501352
Some(_) => format_to!(
13511353
fn_def,
1352-
"\n\n{}{}{}{}fn $0{}{}{}{}",
1354+
"\n\n{}{}{}{}fn $0{}",
13531355
new_indent,
13541356
const_kw,
13551357
async_kw,
13561358
unsafe_kw,
13571359
fun.name,
1358-
generic_params,
1359-
params,
1360-
where_clause
13611360
),
13621361
None => format_to!(
13631362
fn_def,
1364-
"\n\n{}{}{}{}fn {}{}{}{}",
1363+
"\n\n{}{}{}{}fn {}",
13651364
new_indent,
13661365
const_kw,
13671366
async_kw,
13681367
unsafe_kw,
13691368
fun.name,
1370-
generic_params,
1371-
params,
1372-
where_clause,
13731369
),
13741370
}
1371+
1372+
if let Some(generic_params) = generic_params {
1373+
format_to!(fn_def, "{}", generic_params);
1374+
}
1375+
1376+
format_to!(fn_def, "{}", params);
1377+
1378+
if let Some(where_clause) = where_clause {
1379+
format_to!(fn_def, " {}", where_clause);
1380+
}
1381+
13751382
if let Some(ret_ty) = ret_ty {
13761383
format_to!(fn_def, " {}", ret_ty);
13771384
}
1385+
13781386
format_to!(fn_def, " {}", body);
13791387

13801388
fn_def
13811389
}
13821390

1383-
fn format_generic_params_and_where_clause(ctx: &AssistContext, fun: &Function) -> (String, String) {
1384-
(format_generic_param_list(fun, ctx), format_where_clause(fun))
1385-
}
1386-
1387-
fn format_generic_param_list(fun: &Function, ctx: &AssistContext) -> String {
1388-
let type_params_in_descendant_paths =
1389-
fun.body.descendant_paths().filter_map(|it| match ctx.sema.resolve_path(&it) {
1390-
Some(PathResolution::TypeParam(type_param)) => Some(type_param),
1391-
_ => None,
1391+
fn make_generic_params_and_where_clause(
1392+
ctx: &AssistContext,
1393+
fun: &Function,
1394+
) -> (Option<ast::GenericParamList>, Option<ast::WhereClause>) {
1395+
let used_type_params = fun.type_params(ctx);
1396+
1397+
let generic_param_list = fun
1398+
.mods
1399+
.generic_param_list
1400+
.as_ref()
1401+
.map(|parent_params| make_generic_param_list(ctx, parent_params, &used_type_params))
1402+
.flatten();
1403+
1404+
let where_clause =
1405+
fun.mods.where_clause.as_ref().map(|parent_where_clause| {
1406+
make_where_clause(ctx, parent_where_clause, &used_type_params)
13921407
});
13931408

1394-
let type_params_in_params = fun.params.iter().filter_map(|p| p.ty.as_type_param(ctx.db()));
1409+
(generic_param_list, where_clause)
1410+
}
13951411

1396-
let used_type_params: Vec<TypeParam> =
1397-
type_params_in_descendant_paths.chain(type_params_in_params).collect();
1412+
fn make_generic_param_list(
1413+
ctx: &AssistContext,
1414+
parent_params: &ast::GenericParamList,
1415+
used_type_params: &[TypeParam],
1416+
) -> Option<ast::GenericParamList> {
1417+
let required_generic_params: Vec<ast::GenericParam> = parent_params
1418+
.generic_params()
1419+
.filter(|param| param_is_required(ctx, param, used_type_params))
1420+
.collect();
1421+
if required_generic_params.is_empty() {
1422+
None
1423+
} else {
1424+
Some(make::generic_param_list(required_generic_params))
1425+
}
1426+
}
13981427

1399-
match &fun.mods.generic_param_list {
1400-
Some(list) => {
1401-
let filtered_generic_params = filter_generic_param_list(ctx, list, used_type_params);
1402-
if filtered_generic_params.is_empty() {
1403-
return "".to_string();
1404-
}
1405-
format!("{}", make::generic_param_list(filtered_generic_params))
1406-
}
1407-
None => "".to_string(),
1428+
fn param_is_required(
1429+
ctx: &AssistContext,
1430+
param: &ast::GenericParam,
1431+
used_type_params: &[TypeParam],
1432+
) -> bool {
1433+
match param {
1434+
ast::GenericParam::ConstParam(_) | ast::GenericParam::LifetimeParam(_) => true,
1435+
ast::GenericParam::TypeParam(type_param) => match &ctx.sema.to_def(type_param) {
1436+
Some(def) => used_type_params.iter().contains(def),
1437+
_ => false,
1438+
},
14081439
}
14091440
}
14101441

1411-
fn filter_generic_param_list(
1442+
fn make_where_clause(
14121443
ctx: &AssistContext,
1413-
list: &ast::GenericParamList,
1414-
used_type_params: Vec<TypeParam>,
1415-
) -> Vec<ast::GenericParam> {
1416-
list.generic_params()
1417-
.filter(|p| match p {
1418-
ast::GenericParam::ConstParam(_) | ast::GenericParam::LifetimeParam(_) => true,
1419-
ast::GenericParam::TypeParam(type_param) => match &ctx.sema.to_def(type_param) {
1420-
Some(def) => used_type_params.iter().contains(def),
1421-
_ => false,
1422-
},
1423-
})
1424-
.collect()
1444+
parent_where_clause: &ast::WhereClause,
1445+
used_type_params: &[TypeParam],
1446+
) -> ast::WhereClause {
1447+
let preds = parent_where_clause
1448+
.predicates()
1449+
.filter(|pred| pred_is_required(ctx, pred, used_type_params));
1450+
make::where_clause(preds)
14251451
}
14261452

1427-
fn format_where_clause(fun: &Function) -> String {
1428-
match &fun.mods.where_clause {
1429-
Some(it) => format!(" {}", it),
1430-
None => "".to_string(),
1453+
fn pred_is_required(
1454+
ctx: &AssistContext,
1455+
pred: &ast::WherePred,
1456+
used_type_params: &[TypeParam],
1457+
) -> bool {
1458+
match resolved_type_param(ctx, pred) {
1459+
Some(it) => used_type_params.contains(&it),
1460+
None => false,
1461+
}
1462+
}
1463+
1464+
fn resolved_type_param(ctx: &AssistContext, pred: &ast::WherePred) -> Option<TypeParam> {
1465+
let path = match pred.ty()? {
1466+
ast::Type::PathType(path_type) => path_type.path(),
1467+
_ => None,
1468+
}?;
1469+
1470+
match ctx.sema.resolve_path(&path)? {
1471+
PathResolution::TypeParam(type_param) => Some(type_param),
1472+
_ => None,
14311473
}
14321474
}
14331475

14341476
impl Function {
1477+
/// Collect all the `TypeParam`s used in the `body` and `params`.
1478+
fn type_params(&self, ctx: &AssistContext) -> Vec<TypeParam> {
1479+
let type_params_in_descendant_paths =
1480+
self.body.descendant_paths().filter_map(|it| match ctx.sema.resolve_path(&it) {
1481+
Some(PathResolution::TypeParam(type_param)) => Some(type_param),
1482+
_ => None,
1483+
});
1484+
let type_params_in_params = self.params.iter().filter_map(|p| p.ty.as_type_param(ctx.db()));
1485+
type_params_in_descendant_paths.chain(type_params_in_params).collect()
1486+
}
1487+
14351488
fn make_param_list(&self, ctx: &AssistContext, module: hir::Module) -> ast::ParamList {
14361489
let self_param = self.self_param.clone();
14371490
let params = self.params.iter().map(|param| param.to_param(ctx, module));
@@ -4905,6 +4958,29 @@ fn func<T>(i: T) where T: Debug {
49054958
fun_name(i);
49064959
}
49074960
4961+
fn $0fun_name<T>(i: T) where T: Debug {
4962+
foo(i);
4963+
}
4964+
"#,
4965+
);
4966+
}
4967+
4968+
#[test]
4969+
fn filter_unused_where_clause() {
4970+
check_assist(
4971+
extract_function,
4972+
r#"
4973+
fn func<T, U>(i: T, u: U) where T: Debug, U: Copy {
4974+
bar(u);
4975+
$0foo(i);$0
4976+
}
4977+
"#,
4978+
r#"
4979+
fn func<T, U>(i: T, u: U) where T: Debug, U: Copy {
4980+
bar(u);
4981+
fun_name(i);
4982+
}
4983+
49084984
fn $0fun_name<T>(i: T) where T: Debug {
49094985
foo(i);
49104986
}

0 commit comments

Comments
 (0)