Skip to content

Commit da503b6

Browse files
committed
Auto merge of rust-lang#12274 - jonas-schievink:move-getter-docs-generation, r=jonas-schievink
feat: Handle getters and setters in documentation template assist The assist can now turn this: ```rust pub struct S; impl S { pub fn data_mut$0(&mut self) -> &mut [u8] { &mut [] } } ``` into ```rust pub struct S; impl S { /// Returns a mutable reference to the data. /// /// # Examples /// /// ``` /// use test::S; /// /// let mut s = ; /// assert_eq!(s.data_mut(), ); /// assert_eq!(s, ); /// ``` pub fn data_mut(&mut self) -> &mut [u8] { &mut [] } } ``` And similarly for by-value or immutable getters, and for setters. Previously the intro line would be empty. This PR also removes the documentation generation function from the "Generate getter/setter" assist, since that is better handled by applying the 2 assists in sequence. cc rust-lang/rust-analyzer#12273
2 parents 825ce48 + f1b6e45 commit da503b6

File tree

5 files changed

+252
-55
lines changed

5 files changed

+252
-55
lines changed

crates/hir/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1466,6 +1466,7 @@ impl Function {
14661466
}
14671467

14681468
// Note: logically, this belongs to `hir_ty`, but we are not using it there yet.
1469+
#[derive(Clone, Copy, PartialEq, Eq)]
14691470
pub enum Access {
14701471
Shared,
14711472
Exclusive,

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

Lines changed: 247 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ pub(crate) fn generate_documentation_template(
6060
text_range,
6161
|builder| {
6262
// Introduction / short function description before the sections
63-
let mut doc_lines = vec![introduction_builder(&ast_func, ctx)];
63+
let mut doc_lines = vec![introduction_builder(&ast_func, ctx).unwrap_or(".".into())];
6464
// Then come the sections
6565
if let Some(mut lines) = examples_builder(&ast_func, ctx) {
6666
doc_lines.push("".into());
@@ -78,26 +78,64 @@ pub(crate) fn generate_documentation_template(
7878
}
7979

8080
/// Builds an introduction, trying to be smart if the function is `::new()`
81-
fn introduction_builder(ast_func: &ast::Fn, ctx: &AssistContext) -> String {
82-
|| -> Option<String> {
83-
let hir_func = ctx.sema.to_def(ast_func)?;
84-
let container = hir_func.as_assoc_item(ctx.db())?.container(ctx.db());
85-
if let hir::AssocItemContainer::Impl(implementation) = container {
86-
let ret_ty = hir_func.ret_type(ctx.db());
87-
let self_ty = implementation.self_ty(ctx.db());
88-
89-
let is_new = ast_func.name()?.to_string() == "new";
90-
match is_new && ret_ty == self_ty {
91-
true => {
92-
Some(format!("Creates a new [`{}`].", self_type_without_lifetimes(ast_func)?))
81+
fn introduction_builder(ast_func: &ast::Fn, ctx: &AssistContext) -> Option<String> {
82+
let hir_func = ctx.sema.to_def(ast_func)?;
83+
let container = hir_func.as_assoc_item(ctx.db())?.container(ctx.db());
84+
if let hir::AssocItemContainer::Impl(imp) = container {
85+
let ret_ty = hir_func.ret_type(ctx.db());
86+
let self_ty = imp.self_ty(ctx.db());
87+
let name = ast_func.name()?.to_string();
88+
89+
let intro_for_new = || {
90+
let is_new = name == "new";
91+
if is_new && ret_ty == self_ty {
92+
Some(format!("Creates a new [`{}`].", self_type_without_lifetimes(ast_func)?))
93+
} else {
94+
None
95+
}
96+
};
97+
98+
let intro_for_getter = || match (
99+
hir_func.self_param(ctx.sema.db),
100+
&*hir_func.params_without_self(ctx.sema.db),
101+
) {
102+
(Some(self_param), []) if self_param.access(ctx.sema.db) != hir::Access::Owned => {
103+
if name.starts_with("as_") || name.starts_with("to_") || name == "get" {
104+
return None;
93105
}
94-
false => None,
106+
let what = name.trim_end_matches("_mut").replace('_', " ");
107+
let reference = if ret_ty.is_mutable_reference() {
108+
" a mutable reference to"
109+
} else if ret_ty.is_reference() {
110+
" a reference to"
111+
} else {
112+
""
113+
};
114+
Some(format!("Returns{reference} the {what}."))
95115
}
96-
} else {
97-
None
116+
_ => None,
117+
};
118+
119+
let intro_for_setter = || {
120+
if !name.starts_with("set_") {
121+
return None;
122+
}
123+
124+
let what = name.trim_start_matches("set_").replace('_', " ");
125+
Some(format!("Sets the {what}."))
126+
};
127+
128+
if let Some(intro) = intro_for_new() {
129+
return Some(intro);
130+
}
131+
if let Some(intro) = intro_for_getter() {
132+
return Some(intro);
98133
}
99-
}()
100-
.unwrap_or_else(|| ".".into())
134+
if let Some(intro) = intro_for_setter() {
135+
return Some(intro);
136+
}
137+
}
138+
None
101139
}
102140

103141
/// Builds an `# Examples` section. An option is returned to be able to manage an error in the AST.
@@ -1220,6 +1258,197 @@ impl<T> MyGenericStruct<T> {
12201258
self.x = new_value;
12211259
}
12221260
}
1261+
"#,
1262+
);
1263+
}
1264+
1265+
#[test]
1266+
fn generates_intro_for_getters() {
1267+
check_assist(
1268+
generate_documentation_template,
1269+
r#"
1270+
pub struct S;
1271+
impl S {
1272+
pub fn speed$0(&self) -> f32 { 0.0 }
1273+
}
1274+
"#,
1275+
r#"
1276+
pub struct S;
1277+
impl S {
1278+
/// Returns the speed.
1279+
///
1280+
/// # Examples
1281+
///
1282+
/// ```
1283+
/// use test::S;
1284+
///
1285+
/// let s = ;
1286+
/// assert_eq!(s.speed(), );
1287+
/// ```
1288+
pub fn speed(&self) -> f32 { 0.0 }
1289+
}
1290+
"#,
1291+
);
1292+
check_assist(
1293+
generate_documentation_template,
1294+
r#"
1295+
pub struct S;
1296+
impl S {
1297+
pub fn data$0(&self) -> &[u8] { &[] }
1298+
}
1299+
"#,
1300+
r#"
1301+
pub struct S;
1302+
impl S {
1303+
/// Returns a reference to the data.
1304+
///
1305+
/// # Examples
1306+
///
1307+
/// ```
1308+
/// use test::S;
1309+
///
1310+
/// let s = ;
1311+
/// assert_eq!(s.data(), );
1312+
/// ```
1313+
pub fn data(&self) -> &[u8] { &[] }
1314+
}
1315+
"#,
1316+
);
1317+
check_assist(
1318+
generate_documentation_template,
1319+
r#"
1320+
pub struct S;
1321+
impl S {
1322+
pub fn data$0(&mut self) -> &mut [u8] { &mut [] }
1323+
}
1324+
"#,
1325+
r#"
1326+
pub struct S;
1327+
impl S {
1328+
/// Returns a mutable reference to the data.
1329+
///
1330+
/// # Examples
1331+
///
1332+
/// ```
1333+
/// use test::S;
1334+
///
1335+
/// let mut s = ;
1336+
/// assert_eq!(s.data(), );
1337+
/// assert_eq!(s, );
1338+
/// ```
1339+
pub fn data(&mut self) -> &mut [u8] { &mut [] }
1340+
}
1341+
"#,
1342+
);
1343+
check_assist(
1344+
generate_documentation_template,
1345+
r#"
1346+
pub struct S;
1347+
impl S {
1348+
pub fn data_mut$0(&mut self) -> &mut [u8] { &mut [] }
1349+
}
1350+
"#,
1351+
r#"
1352+
pub struct S;
1353+
impl S {
1354+
/// Returns a mutable reference to the data.
1355+
///
1356+
/// # Examples
1357+
///
1358+
/// ```
1359+
/// use test::S;
1360+
///
1361+
/// let mut s = ;
1362+
/// assert_eq!(s.data_mut(), );
1363+
/// assert_eq!(s, );
1364+
/// ```
1365+
pub fn data_mut(&mut self) -> &mut [u8] { &mut [] }
1366+
}
1367+
"#,
1368+
);
1369+
}
1370+
1371+
#[test]
1372+
fn no_getter_intro_for_prefixed_methods() {
1373+
check_assist(
1374+
generate_documentation_template,
1375+
r#"
1376+
pub struct S;
1377+
impl S {
1378+
pub fn as_bytes$0(&self) -> &[u8] { &[] }
1379+
}
1380+
"#,
1381+
r#"
1382+
pub struct S;
1383+
impl S {
1384+
/// .
1385+
///
1386+
/// # Examples
1387+
///
1388+
/// ```
1389+
/// use test::S;
1390+
///
1391+
/// let s = ;
1392+
/// assert_eq!(s.as_bytes(), );
1393+
/// ```
1394+
pub fn as_bytes(&self) -> &[u8] { &[] }
1395+
}
1396+
"#,
1397+
);
1398+
}
1399+
1400+
#[test]
1401+
fn generates_intro_for_setters() {
1402+
check_assist(
1403+
generate_documentation_template,
1404+
r#"
1405+
pub struct S;
1406+
impl S {
1407+
pub fn set_data$0(&mut self, data: Vec<u8>) {}
1408+
}
1409+
"#,
1410+
r#"
1411+
pub struct S;
1412+
impl S {
1413+
/// Sets the data.
1414+
///
1415+
/// # Examples
1416+
///
1417+
/// ```
1418+
/// use test::S;
1419+
///
1420+
/// let mut s = ;
1421+
/// s.set_data(data);
1422+
/// assert_eq!(s, );
1423+
/// ```
1424+
pub fn set_data(&mut self, data: Vec<u8>) {}
1425+
}
1426+
"#,
1427+
);
1428+
check_assist(
1429+
generate_documentation_template,
1430+
r#"
1431+
pub struct S;
1432+
impl S {
1433+
pub fn set_domain_name$0(&mut self, name: String) {}
1434+
}
1435+
"#,
1436+
r#"
1437+
pub struct S;
1438+
impl S {
1439+
/// Sets the domain name.
1440+
///
1441+
/// # Examples
1442+
///
1443+
/// ```
1444+
/// use test::S;
1445+
///
1446+
/// let mut s = ;
1447+
/// s.set_domain_name(name);
1448+
/// assert_eq!(s, );
1449+
/// ```
1450+
pub fn set_domain_name(&mut self, name: String) {}
1451+
}
12231452
"#,
12241453
);
12251454
}

0 commit comments

Comments
 (0)