Skip to content

Commit 304d63a

Browse files
committed
docgen: parse function deprecation messages
The `api.json` data is updated to add the newly parsed deprecation messages.
1 parent c731b24 commit 304d63a

2 files changed

Lines changed: 257 additions & 10 deletions

File tree

tools/src/bin/docgen/main.rs

Lines changed: 63 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,8 @@ struct ItemMetadata {
149149
comment: Option<Comment>,
150150
/// A feature requirement that must be enabled for the item
151151
feature: Option<Feature>,
152+
/// A deprecation message for the item
153+
deprecation: Option<Deprecation>,
152154
}
153155

154156
impl ItemMetadata {
@@ -162,35 +164,49 @@ impl ItemMetadata {
162164
/// * `prev` is not a comment, and not a feature requirement.
163165
/// * `prev` is a Comment, and has no feature requirement before it.
164166
/// * `prev` is a Comment, and has a feature requirement before it.
167+
/// * `prev` is a Deprecation, and has a comment and feature requirement before it.
168+
/// * `prev` is a Deprecation, and has a comment and no feature requirement before it.
165169
/// * `prev` is a bare feature requirement
166170
///
167-
/// cbindgen won't create a comment before a feature requirement so we don't have to
168-
/// consider that case.
171+
/// cbindgen won't create other permutations (e.g. comment before a feature requirement, or
172+
/// a deprecation before a feature requirement) so we don't have to consider those cases.
169173
fn new(prev: Node, src: &[u8]) -> Result<Self, Box<dyn Error>> {
170174
let prev_prev = prev.prev_named_sibling();
171175
// In the simple case, `prev` is a comment and `prev_prev` may be a feature requirement.
176+
// Deprecations aren't in play in this case based on how cbindgen works.
172177
if let Ok(comment) = Comment::new(prev, src) {
173178
return Ok(Self {
174179
comment: Some(comment),
175180
feature: prev_prev.and_then(|prev_prev| Feature::new(prev_prev, src).ok()),
181+
deprecation: None,
176182
});
177183
}
178184

179-
// If node wasn't a comment, see if it was an expression_statement
180-
// that itself was preceded by a comment. This skips over
181-
// expression-like preprocessor attributes on function decls.
182-
if prev.kind() == "expression_statement" {
183-
return match prev_prev {
184-
Some(prev_prev) => Self::new(prev_prev, src),
185-
None => Ok(ItemMetadata::default()),
185+
// `prev` is a deprecation, `prev_prev` may be a comment, and `prev_prev_prev`
186+
// may be a feature requirement.
187+
if let Ok(deprecation) = Deprecation::new(prev, src) {
188+
let (comment, feature) = match prev_prev {
189+
Some(prev_prev) => (
190+
Comment::new(prev_prev, src).ok(),
191+
prev_prev
192+
.prev_named_sibling()
193+
.and_then(|prev_prev_prev| Feature::new(prev_prev_prev, src).ok()),
194+
),
195+
None => (None, None),
186196
};
197+
return Ok(ItemMetadata {
198+
comment,
199+
feature,
200+
deprecation: Some(deprecation),
201+
});
187202
}
188203

189-
// If `prev` wasn't a comment, or an expression_statement preceded by a comment,
204+
// If `prev` wasn't a comment, or a deprecation,
190205
// then it's either a bare feature requirement or we have no metadata to return.
191206
Ok(Self {
192207
comment: None,
193208
feature: Feature::new(prev, src).ok(),
209+
deprecation: None,
194210
})
195211
}
196212

@@ -320,6 +336,43 @@ impl Display for Comment {
320336
}
321337
}
322338

339+
#[derive(Debug, Default, Serialize)]
340+
struct Deprecation(String);
341+
342+
impl Deprecation {
343+
fn new(node: Node, src: &[u8]) -> Result<Self, Box<dyn Error>> {
344+
require_kind("expression_statement", node, src)?;
345+
346+
let query_str = r#"
347+
(call_expression
348+
function: (identifier) @func (#eq? @func "DEPRECATED_FUNC")
349+
arguments: (argument_list
350+
(string_literal (string_content) @content)
351+
)
352+
)
353+
"#;
354+
355+
let mut query_cursor = QueryCursor::new();
356+
let language = tree_sitter_c::LANGUAGE;
357+
let query = Query::new(&language.into(), query_str)?;
358+
359+
let mut captures = query_cursor.captures(&query, node, src);
360+
loop {
361+
captures.advance();
362+
let Some((mat, _)) = captures.get() else {
363+
break;
364+
};
365+
for capture in mat.captures {
366+
if query.capture_names()[capture.index as usize] == "content" {
367+
return Ok(Self(node_text(capture.node, src)));
368+
}
369+
}
370+
}
371+
372+
Err(node_error("DEPRECATED_FUNC call not found or malformed", node, src).into())
373+
}
374+
}
375+
323376
fn process_typedef_item(
324377
mut metadata: ItemMetadata,
325378
item: Node,

0 commit comments

Comments
 (0)