Skip to content
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

Add: Support #[deprecated] attribute #860

Closed
wants to merge 25 commits into from
Closed
Show file tree
Hide file tree
Changes from 15 commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
f86d749
WIP:
sevenc-nanashi Jul 22, 2023
87561a4
Add: Add deprecated
sevenc-nanashi Jul 23, 2023
e001222
Fix: Fix it generates invalid python code
sevenc-nanashi Jul 23, 2023
d75abe9
Fix: Support quotes
sevenc-nanashi Jul 23, 2023
19845d8
Change: Move creation of [[deprecated]]
sevenc-nanashi Jul 23, 2023
608a31e
Add: Support enum
sevenc-nanashi Jul 23, 2023
ff164fb
Change: Add deprecate if c23
sevenc-nanashi Jul 23, 2023
6c29ff7
Update: Update test
sevenc-nanashi Jul 23, 2023
5733bf8
Add: Add test exceptation
sevenc-nanashi Jul 23, 2023
b5ae00e
Code: Use out.write
sevenc-nanashi Jul 23, 2023
a9587bb
Fix: Fix condition
sevenc-nanashi Jul 23, 2023
fbe51c6
(WIP) Change: make it like must_use
sevenc-nanashi Jul 28, 2023
6bfb3ff
Change: make it like must_use
sevenc-nanashi Jul 28, 2023
31fff88
Fix: Fix formatting
sevenc-nanashi Jul 28, 2023
a439a3a
Update: Update template.toml
sevenc-nanashi Jul 28, 2023
bb39e3a
Change: deprecated -> deprecated_node
sevenc-nanashi Aug 25, 2023
1a3f566
Change: move finding deperecation node to outer side of a function
sevenc-nanashi Aug 25, 2023
81bf4ca
Refactor: Move to a new function to avoid copy-pasting
sevenc-nanashi Aug 25, 2023
50b6171
Change: Option<String> -> Option<&str>
sevenc-nanashi Aug 27, 2023
05d7035
Change: Result<Option<String>, String> -> Option<String> and warn!
sevenc-nanashi Aug 27, 2023
19db2a4
Change: Use helper
sevenc-nanashi Aug 27, 2023
d13bb58
Merge: master -> add/deprecated
sevenc-nanashi Aug 27, 2023
5b119db
Change: Use helper
sevenc-nanashi Aug 27, 2023
507eaa5
Change: Remove let-else
sevenc-nanashi Aug 27, 2023
5809afc
Fix: Use Some(
sevenc-nanashi Aug 27, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 2 additions & 2 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ serde = { version = "1.0.103", default-features = false, features = ["derive"] }
serde_json = "1.0"
tempfile = "3"
toml = "0.5"
proc-macro2 = "1"
proc-macro2 = "1.0.60"
Copy link
Contributor Author

Choose a reason for hiding this comment

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

ref: #859

quote = "1"
heck = "0.4"

Expand Down
51 changes: 51 additions & 0 deletions docs.md
Original file line number Diff line number Diff line change
Expand Up @@ -680,6 +680,23 @@ args = "horizontal"
# default: nothing is emitted for must_use functions
must_use = "MUST_USE_FUNC"

# An optional string that should prefix function declarations which have been
# marked as `#[deprecated]` without note. For instance, "__attribute__((deprecated))"
# would be a reasonable value if targeting gcc/clang. A more portable solution
# would involve emitting the name of a macro which you define in a
# platform-specific way. e.g. "DEPRECATED_FUNC"
# default: nothing is emitted for deprecated functions
deprecated = "DEPRECATED_FUNC"

# An optional string that should prefix function declarations which have been
# marked as `#[deprecated(note = "reason")]`. `{}` will be replaced with the
# double-quoted string. For instance, "__attribute__((deprecated({})))"
# would be a reasonable value if targeting gcc/clang. A more portable solution
# would involve emitting the name of a macro which you define in a
# platform-specific way. e.g. "DEPRECATED_FUNC_WITH_NOTE(note)"
# default: nothing is emitted for deprecated functions
deprecated_with_notes = "DEPRECATED_FUNC_WITH_NOTE"

# An optional string that will be used in the attribute position for functions
# that don't return (that return `!` in Rust).
#
Expand Down Expand Up @@ -752,6 +769,23 @@ rename_fields = "PascalCase"
# default: nothing is emitted for must_use structs
must_use = "MUST_USE_STRUCT"

# An optional string that should come before the name of any struct which has been
# marked as `#[deprecated]` without note. For instance, "__attribute__((deprecated))"
# would be a reasonable value if targeting gcc/clang. A more portable solution
# would involve emitting the name of a macro which you define in a
# platform-specific way. e.g. "DEPRECATED_STRUCT"
# default: nothing is emitted for deprecated structs
deprecated = "DEPRECATED_STRUCT"

# An optional string that should come before the name of any struct which has been
# marked as `#[deprecated(note = "reason")]`. `{}` will be replaced with the
# double-quoted string. For instance, "__attribute__((deprecated({})))"
# would be a reasonable value if targeting gcc/clang. A more portable solution
# would involve emitting the name of a macro which you define in a
# platform-specific way. e.g. "DEPRECATED_STRUCT_WITH_NOTE(note)"
# default: nothing is emitted for deprecated structs
deprecated_with_notes = "DEPRECATED_STRUCT_WITH_NOTE"

# Whether a Rust type with associated consts should emit those consts inside the
# type's body. Otherwise they will be emitted trailing and with the type's name
# prefixed. This does nothing if the target is C, or if
Expand Down Expand Up @@ -865,6 +899,23 @@ cast_assert_name = "MOZ_RELEASE_ASSERT"
# default: nothing is emitted for must_use enums
must_use = "MUST_USE_ENUM"

# An optional string that should come before the name of any enum which has been
# marked as `#[deprecated]` without note. For instance, "__attribute__((deprecated))"
# would be a reasonable value if targeting gcc/clang. A more portable solution
# would involve emitting the name of a macro which you define in a
# platform-specific way. e.g. "DEPRECATED_ENUM"
# default: nothing is emitted for deprecated enums
deprecated = "DEPRECATED_ENUM"

# An optional string that should come before the name of any enum which has been
# marked as `#[deprecated(note = "reason")]`. `{}` will be replaced with the
# double-quoted string. For instance, "__attribute__((deprecated({})))"
# would be a reasonable value if targeting gcc/clang. A more portable solution
# would involve emitting the name of a macro which you define in a
# platform-specific way. e.g. "DEPRECATED_ENUM_WITH_NOTE(note)"
# default: nothing is emitted for deprecated enums
deprecated_with_notes = "DEPRECATED_ENUM_WITH_NOTE"

# Whether enums with fields should generate destructors. This exists so that generic
# enums can be properly instantiated with payloads that are C++ types with
# destructors. This isn't necessary for structs because C++ has rules to
Expand Down
3 changes: 3 additions & 0 deletions src/bindgen/cdecl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ struct CDecl {
type_generic_args: Vec<GenericArgument>,
declarators: Vec<CDeclarator>,
type_ctype: Option<DeclarationType>,
deprecated: Option<String>,
}

impl CDecl {
Expand All @@ -50,6 +51,7 @@ impl CDecl {
type_generic_args: Vec::new(),
declarators: Vec::new(),
type_ctype: None,
deprecated: None,
}
}

Expand Down Expand Up @@ -99,6 +101,7 @@ impl CDecl {
layout,
never_return: f.never_return,
});
self.deprecated = f.annotations.deprecated.clone();
self.build_type(&f.ret, false, config);
}

Expand Down
16 changes: 16 additions & 0 deletions src/bindgen/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -425,6 +425,10 @@ pub struct FunctionConfig {
pub postfix: Option<String>,
/// The way to annotation this function as #[must_use]
pub must_use: Option<String>,
/// The way to annotation this function as #[deprecated] without notes
pub deprecated: Option<String>,
/// The way to annotation this function as #[deprecated] with notes
pub deprecated_with_note: Option<String>,
/// The style to layout the args
pub args: Layout,
/// The rename rule to apply to function args
Expand All @@ -443,6 +447,8 @@ impl Default for FunctionConfig {
prefix: None,
postfix: None,
must_use: None,
deprecated: None,
deprecated_with_note: None,
args: Layout::Auto,
rename_args: RenameRule::None,
swift_name_macro: None,
Expand Down Expand Up @@ -498,6 +504,10 @@ pub struct StructConfig {
pub associated_constants_in_body: bool,
/// The way to annotate this struct as #[must_use].
pub must_use: Option<String>,
/// The way to annotation this function as #[deprecated] without notes
pub deprecated: Option<String>,
/// The way to annotation this function as #[deprecated] with notes
pub deprecated_with_note: Option<String>,
}

impl StructConfig {
Expand Down Expand Up @@ -581,6 +591,10 @@ pub struct EnumConfig {
pub cast_assert_name: Option<String>,
/// The way to annotation this enum as #[must_use].
pub must_use: Option<String>,
/// The way to annotation this function as #[deprecated] without notes
pub deprecated: Option<String>,
/// The way to annotation this function as #[deprecated] with notes
pub deprecated_with_note: Option<String>,
/// Whether to generate destructors of tagged enums.
pub derive_tagged_enum_destructor: bool,
/// Whether to generate copy-constructors of tagged enums.
Expand Down Expand Up @@ -612,6 +626,8 @@ impl Default for EnumConfig {
derive_mut_casts: false,
cast_assert_name: None,
must_use: None,
deprecated: None,
deprecated_with_note: None,
derive_tagged_enum_destructor: false,
derive_tagged_enum_copy_constructor: false,
derive_tagged_enum_copy_assignment: false,
Expand Down
37 changes: 37 additions & 0 deletions src/bindgen/ir/annotation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,13 +35,15 @@ pub enum AnnotationValue {
pub struct AnnotationSet {
annotations: HashMap<String, AnnotationValue>,
pub must_use: bool,
pub deprecated: Option<String>,
}

impl AnnotationSet {
pub fn new() -> AnnotationSet {
AnnotationSet {
annotations: HashMap::new(),
must_use: false,
deprecated: None,
}
}

Expand All @@ -53,6 +55,10 @@ impl AnnotationSet {
self.must_use && config.language != Language::Cython
}

pub(crate) fn deprecated(&self, config: &Config) -> bool {
sevenc-nanashi marked this conversation as resolved.
Show resolved Hide resolved
self.deprecated.is_some() && config.language != Language::Cython
}

pub fn load(attrs: &[syn::Attribute]) -> Result<AnnotationSet, String> {
let lines = attrs.get_comment_lines();
let lines: Vec<&str> = lines
Expand All @@ -68,6 +74,36 @@ impl AnnotationSet {
.collect();

let must_use = attrs.has_attr_word("must_use");
let deprecated = if let Some(note) = attrs.attr_name_value_lookup("deprecated") {
sevenc-nanashi marked this conversation as resolved.
Show resolved Hide resolved
Some(note)
} else if attrs.has_attr_word("deprecated") {
Some("".to_string())
} else if let Some(attr) = attrs.iter().find(|attr| {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Is this code-path tested?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It should be.

if let Ok(syn::Meta::List(list)) = attr.parse_meta() {
list.path.is_ident("deprecated")
} else {
false
}
}) {
let args: syn::punctuated::Punctuated<syn::MetaNameValue, Token![,]> = attr
.parse_args_with(syn::punctuated::Punctuated::parse_terminated)
.map_err(|e| format!("Couldn't parse deprecated attribute: {}", e.to_string()))?;
let Some(lit) = args
.iter()
.find(|arg| arg.path.is_ident("note"))
.map(|arg| &arg.lit)
else {
return Err("Couldn't parse deprecated attribute: no `note` field".to_string());
};

if let syn::Lit::Str(lit) = lit {
Some(lit.value())
} else {
return Err("deprecated attribute must be a string".to_string());
}
} else {
None
};

let mut annotations = HashMap::new();

Expand Down Expand Up @@ -118,6 +154,7 @@ impl AnnotationSet {
Ok(AnnotationSet {
annotations,
must_use,
deprecated,
})
}

Expand Down
57 changes: 56 additions & 1 deletion src/bindgen/ir/enumeration.rs
Original file line number Diff line number Diff line change
Expand Up @@ -753,7 +753,22 @@ impl Enum {
if let Some(prim) = size {
// If we need to specify size, then we have no choice but to create a typedef,
// so `config.style` is not respected.
write!(out, "enum {}", tag_name);
write!(out, "enum");
if self.annotations.deprecated(config) {
let note = self.annotations.deprecated.as_ref().unwrap();
if note.is_empty() {
if let Some(ref anno) = config.structure.deprecated {
write!(out, " {}", anno);
}
} else if let Some(ref anno) = config.structure.deprecated_with_note {
write!(
out,
" {}",
anno.replace("{}", format!("{:?}", note).as_str())
);
}
}
write!(out, " {}", tag_name);

if config.cpp_compatible_c() {
out.new_line();
Expand All @@ -769,6 +784,20 @@ impl Enum {
out.write("typedef ");
}
out.write("enum");
if self.annotations.deprecated(config) {
let note = self.annotations.deprecated.as_ref().unwrap();
if note.is_empty() {
if let Some(ref anno) = config.structure.deprecated {
write!(out, " {}", anno);
}
} else if let Some(ref anno) = config.structure.deprecated_with_note {
write!(
out,
" {}",
anno.replace("{}", format!("{:?}", note).as_str())
);
}
}
if config.style.generate_tag() {
write!(out, " {}", tag_name);
}
Expand All @@ -787,6 +816,21 @@ impl Enum {
}
}

if self.annotations.deprecated(config) {
sevenc-nanashi marked this conversation as resolved.
Show resolved Hide resolved
let note = self.annotations.deprecated.as_ref().unwrap();
if note.is_empty() {
if let Some(ref anno) = config.structure.deprecated {
write!(out, " {}", anno);
}
} else if let Some(ref anno) = config.structure.deprecated_with_note {
write!(
out,
" {}",
anno.replace("{}", format!("{:?}", note).as_str())
);
}
}

write!(out, " {}", tag_name);
if let Some(prim) = size {
write!(out, " : {}", prim);
Expand Down Expand Up @@ -865,6 +909,17 @@ impl Enum {
}
}

if self.annotations.deprecated(config) {
let note = self.annotations.deprecated.as_ref().unwrap();
if note.is_empty() {
if let Some(ref anno) = config.structure.deprecated {
write!(out, " {}", anno);
}
} else if let Some(ref anno) = config.structure.deprecated_with_note {
write!(out, " {}", anno);
sevenc-nanashi marked this conversation as resolved.
Show resolved Hide resolved
}
}

if config.language != Language::C || config.style.generate_tag() {
write!(out, " {}", self.export_name());
}
Expand Down
30 changes: 30 additions & 0 deletions src/bindgen/ir/function.rs
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,20 @@ impl Source for Function {
write!(out, "{} ", anno);
}
}
if func.annotations.deprecated(config) {
let note = func.annotations.deprecated.as_ref().unwrap();
if note.is_empty() {
if let Some(ref anno) = config.function.deprecated {
write!(out, "{} ", anno);
}
} else if let Some(ref anno) = config.function.deprecated_with_note {
write!(
out,
"{} ",
anno.replace("{}", format!("{:?}", note).as_str())
);
}
}
}
cdecl::write_func(out, func, Layout::Horizontal, config);

Expand Down Expand Up @@ -284,6 +298,22 @@ impl Source for Function {
out.new_line();
}
}
if func.annotations.deprecated(config) {
let note = func.annotations.deprecated.as_ref().unwrap();
if note.is_empty() {
if let Some(ref anno) = config.function.deprecated {
write!(out, "{}", anno);
out.new_line();
}
} else if let Some(ref anno) = config.function.deprecated_with_note {
sevenc-nanashi marked this conversation as resolved.
Show resolved Hide resolved
write!(
out,
"{}",
anno.replace("{}", format!("{:?}", note).as_str())
);
out.new_line();
}
}
}
cdecl::write_func(out, func, Layout::Vertical, config);
if !func.extern_decl {
Expand Down
14 changes: 14 additions & 0 deletions src/bindgen/ir/structure.rs
Original file line number Diff line number Diff line change
Expand Up @@ -455,6 +455,20 @@ impl Source for Struct {
write!(out, " {}", anno);
}
}
if self.annotations.deprecated(config) {
let note = self.annotations.deprecated.as_ref().unwrap();
if note.is_empty() {
if let Some(ref anno) = config.structure.deprecated {
write!(out, " {}", anno);
}
} else if let Some(ref anno) = config.structure.deprecated_with_note {
write!(
out,
" {}",
anno.replace("{}", format!("{:?}", note).as_str())
);
}
}

if config.language != Language::C || config.style.generate_tag() {
write!(out, " {}", self.export_name());
Expand Down