Skip to content

docgen/website: show deprecated function warnings on docs website #584

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 10 commits into
base: main
Choose a base branch
from
71 changes: 60 additions & 11 deletions tools/src/bin/docgen/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,8 @@ struct ItemMetadata {
comment: Option<Comment>,
/// A feature requirement that must be enabled for the item
feature: Option<Feature>,
/// A deprecation message for the item
deprecation: Option<Deprecation>,
}

impl ItemMetadata {
Expand All @@ -158,15 +160,17 @@ impl ItemMetadata {
/// * `prev` is not a comment, and not a feature requirement.
/// * `prev` is a Comment, and has no feature requirement before it.
/// * `prev` is a Comment, and has a feature requirement before it.
/// * `prev` is a Deprecation, and has a comment and feature requirement before it.
/// * `prev` is a Deprecation, and has a comment and no feature requirement before it.
/// * `prev` is a bare feature requirement
///
/// cbindgen won't create a comment before a feature requirement so we don't have to
/// consider that case.
/// cbindgen won't create other permutations (e.g. comment before a feature requirement, or
/// a deprecation before a feature requirement) so we don't have to consider those cases.
fn new(prev: Node, src: &[u8]) -> Result<Self, Box<dyn Error>> {
let prev_prev = prev.prev_named_sibling();

// In the simple case, `prev` is a comment and `prev_prev` may
// be a feature requirement.
// be a feature requirement. Deprecations aren't in play.
if let Ok(comment) = Comment::new(prev, src) {
let feature = match prev_prev {
Some(prev_prev) => Feature::new(prev_prev, src).ok(),
Expand All @@ -175,24 +179,36 @@ impl ItemMetadata {
return Ok(ItemMetadata {
comment: Some(comment),
feature,
deprecation: None,
});
}

// If `prev` wasn't a comment, see if it was an expression_statement
// that itself was preceded by a comment. This skips over
// expression-like preprocessor attributes on function decls.
if prev.kind() == "expression_statement" {
return match prev_prev {
Some(prev_prev) => Self::new(prev_prev, src),
None => Ok(ItemMetadata::default()),
// `prev` is a deprecation, `prev_prev` may be a comment, and `prev_prev_prev`
// may be a feature requirement.
if let Ok(deprecation) = Deprecation::new(prev, src) {
let comment = match prev_prev {
Some(prev_prev) => Comment::new(prev_prev, src).ok(),
None => None,
};
Comment on lines +189 to +192
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: use .map() more to avoid the None => None branches?

let prev_prev_prev = prev_prev.and_then(|prev_prev| prev_prev.prev_named_sibling());
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider making this part of the previous match?

let feature = match prev_prev_prev {
Some(prev_prev_prev) => Feature::new(prev_prev_prev, src).ok(),
None => None,
};
return Ok(ItemMetadata {
comment,
feature,
deprecation: Some(deprecation),
});
}

// If `prev` wasn't a comment, or an expression_statement preceded by a comment,
// then it's either a bare feature requirement or we have no metadata to return.
// then it's either a bare feature requirement without a deprecation or we have no
// metadata to return.
Ok(ItemMetadata {
comment: None,
feature: Feature::new(prev, src).ok(),
deprecation: None,
})
}

Expand Down Expand Up @@ -322,6 +338,39 @@ impl Display for Comment {
}
}

#[derive(Debug, Default, Serialize)]
struct Deprecation(String);

impl Deprecation {
fn new(node: Node, src: &[u8]) -> Result<Self, Box<dyn Error>> {
require_kind("expression_statement", node, src)?;

let query_str = r#"
(call_expression
function: (identifier) @func (#eq? @func "DEPRECATED_FUNC")
arguments: (argument_list
(string_literal (string_content) @content)
)
)
"#;

let mut query_cursor = QueryCursor::new();
let language = tree_sitter_c::LANGUAGE;
let query = Query::new(&language.into(), query_str)?;

let captures = query_cursor.captures(&query, node, src);
for (mat, _) in captures {
for capture in mat.captures {
if query.capture_names()[capture.index as usize] == "content" {
return Ok(Self(node_text(capture.node, src)));
}
}
}

Err(node_error("DEPRECATED_FUNC call not found or malformed", node, src).into())
}
}

fn process_typedef_item(
mut metadata: ItemMetadata,
item: Node,
Expand Down
Loading