Skip to content

Commit f36d076

Browse files
committed
Filter where clause predicates
1 parent 530591f commit f36d076

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! {
@@ -1346,93 +1348,144 @@ fn format_function(
13461348
let const_kw = if fun.mods.is_const { "const " } else { "" };
13471349
let async_kw = if fun.control_flow.is_async { "async " } else { "" };
13481350
let unsafe_kw = if fun.control_flow.is_unsafe { "unsafe " } else { "" };
1349-
let (generic_params, where_clause) = format_generic_params_and_where_clause(ctx, fun);
1351+
let (generic_params, where_clause) = make_generic_params_and_where_clause(ctx, fun);
13501352
match ctx.config.snippet_cap {
13511353
Some(_) => format_to!(
13521354
fn_def,
1353-
"\n\n{}{}{}{}fn $0{}{}{}{}",
1355+
"\n\n{}{}{}{}fn $0{}",
13541356
new_indent,
13551357
const_kw,
13561358
async_kw,
13571359
unsafe_kw,
13581360
fun.name,
1359-
generic_params,
1360-
params,
1361-
where_clause
13621361
),
13631362
None => format_to!(
13641363
fn_def,
1365-
"\n\n{}{}{}{}fn {}{}{}{}",
1364+
"\n\n{}{}{}{}fn {}",
13661365
new_indent,
13671366
const_kw,
13681367
async_kw,
13691368
unsafe_kw,
13701369
fun.name,
1371-
generic_params,
1372-
params,
1373-
where_clause,
13741370
),
13751371
}
1372+
1373+
if let Some(generic_params) = generic_params {
1374+
format_to!(fn_def, "{}", generic_params);
1375+
}
1376+
1377+
format_to!(fn_def, "{}", params);
1378+
1379+
if let Some(where_clause) = where_clause {
1380+
format_to!(fn_def, " {}", where_clause);
1381+
}
1382+
13761383
if let Some(ret_ty) = ret_ty {
13771384
format_to!(fn_def, " {}", ret_ty);
13781385
}
1386+
13791387
format_to!(fn_def, " {}", body);
13801388

13811389
fn_def
13821390
}
13831391

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

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

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

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

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

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

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

0 commit comments

Comments
 (0)