summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristian Poveda Ruiz <31802960+pvdrz@users.noreply.github.com>2022-11-22 11:25:13 -0500
committerGitHub <noreply@github.com>2022-11-22 11:25:13 -0500
commitf160d11d56007fe1b1125d04f0cb31af0b18fc6e (patch)
tree7b8906d8bf4919c0eab989262f1bad194027ca99
parent34f0bacb7eb72413c9c27684cb01a205ee43037e (diff)
Add `ParseCallbacks::process_comment` (#2347)
This method can be used to process comments and replace them with whatever the user wants.
-rw-r--r--CHANGELOG.md2
-rw-r--r--bindgen/callbacks.rs5
-rw-r--r--bindgen/codegen/helpers.rs8
-rw-r--r--bindgen/codegen/mod.rs52
-rw-r--r--bindgen/ir/comment.rs51
-rw-r--r--bindgen/ir/item.rs7
-rw-r--r--bindgen/lib.rs10
7 files changed, 45 insertions, 90 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 9224c018..2c9889f2 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -178,6 +178,8 @@
matching a regular expression.
* new feature: allow using the `C-unwind` ABI in `--override-abi` on nightly
rust.
+ * new feature: `process_comments` method to the `ParseCallbacks` trait to
+ handle source code comments.
## Changed
diff --git a/bindgen/callbacks.rs b/bindgen/callbacks.rs
index bebd6978..5e8ac788 100644
--- a/bindgen/callbacks.rs
+++ b/bindgen/callbacks.rs
@@ -108,6 +108,11 @@ pub trait ParseCallbacks: fmt::Debug {
fn add_derives(&self, _info: &DeriveInfo<'_>) -> Vec<String> {
vec![]
}
+
+ /// Process a source code comment.
+ fn process_comment(&self, _comment: &str) -> Option<String> {
+ None
+ }
}
/// Relevant information about a type to which new derive attributes will be added using
diff --git a/bindgen/codegen/helpers.rs b/bindgen/codegen/helpers.rs
index 5bf36acb..088c7f93 100644
--- a/bindgen/codegen/helpers.rs
+++ b/bindgen/codegen/helpers.rs
@@ -55,9 +55,11 @@ pub mod attributes {
}
pub fn doc(comment: String) -> TokenStream {
- // NOTE(emilio): By this point comments are already preprocessed and in
- // `///` form. Quote turns them into `#[doc]` comments, but oh well.
- TokenStream::from_str(&comment).unwrap()
+ if comment.is_empty() {
+ quote!()
+ } else {
+ quote!(#[doc = #comment])
+ }
}
pub fn link_name(name: &str) -> TokenStream {
diff --git a/bindgen/codegen/mod.rs b/bindgen/codegen/mod.rs
index e758963a..c1e92b77 100644
--- a/bindgen/codegen/mod.rs
+++ b/bindgen/codegen/mod.rs
@@ -20,7 +20,6 @@ use super::BindgenOptions;
use crate::ir::analysis::{HasVtable, Sizedness};
use crate::ir::annotations::FieldAccessorKind;
-use crate::ir::comment;
use crate::ir::comp::{
Bitfield, BitfieldUnit, CompInfo, CompKind, Field, FieldData, FieldMethods,
Method, MethodKind,
@@ -1245,7 +1244,6 @@ trait FieldCodegen<'a> {
&self,
ctx: &BindgenContext,
fields_should_be_private: bool,
- codegen_depth: usize,
accessor_kind: FieldAccessorKind,
parent: &CompInfo,
result: &mut CodegenResult,
@@ -1265,7 +1263,6 @@ impl<'a> FieldCodegen<'a> for Field {
&self,
ctx: &BindgenContext,
fields_should_be_private: bool,
- codegen_depth: usize,
accessor_kind: FieldAccessorKind,
parent: &CompInfo,
result: &mut CodegenResult,
@@ -1282,7 +1279,6 @@ impl<'a> FieldCodegen<'a> for Field {
data.codegen(
ctx,
fields_should_be_private,
- codegen_depth,
accessor_kind,
parent,
result,
@@ -1296,7 +1292,6 @@ impl<'a> FieldCodegen<'a> for Field {
unit.codegen(
ctx,
fields_should_be_private,
- codegen_depth,
accessor_kind,
parent,
result,
@@ -1346,7 +1341,6 @@ impl<'a> FieldCodegen<'a> for FieldData {
&self,
ctx: &BindgenContext,
fields_should_be_private: bool,
- codegen_depth: usize,
accessor_kind: FieldAccessorKind,
parent: &CompInfo,
result: &mut CodegenResult,
@@ -1392,8 +1386,7 @@ impl<'a> FieldCodegen<'a> for FieldData {
let mut field = quote! {};
if ctx.options().generate_comments {
if let Some(raw_comment) = self.comment() {
- let comment =
- comment::preprocess(raw_comment, codegen_depth + 1);
+ let comment = ctx.options().process_comment(raw_comment);
field = attributes::doc(comment);
}
}
@@ -1553,7 +1546,6 @@ impl<'a> FieldCodegen<'a> for BitfieldUnit {
&self,
ctx: &BindgenContext,
fields_should_be_private: bool,
- codegen_depth: usize,
accessor_kind: FieldAccessorKind,
parent: &CompInfo,
result: &mut CodegenResult,
@@ -1630,7 +1622,6 @@ impl<'a> FieldCodegen<'a> for BitfieldUnit {
bf.codegen(
ctx,
fields_should_be_private,
- codegen_depth,
accessor_kind,
parent,
result,
@@ -1705,7 +1696,6 @@ impl<'a> FieldCodegen<'a> for Bitfield {
&self,
ctx: &BindgenContext,
fields_should_be_private: bool,
- _codegen_depth: usize,
_accessor_kind: FieldAccessorKind,
parent: &CompInfo,
_result: &mut CodegenResult,
@@ -1883,7 +1873,6 @@ impl CodeGenerator for CompInfo {
let mut methods = vec![];
if !is_opaque {
- let codegen_depth = item.codegen_depth(ctx);
let fields_should_be_private =
item.annotations().private_fields().unwrap_or(false);
let struct_accessor_kind = item
@@ -1894,7 +1883,6 @@ impl CodeGenerator for CompInfo {
field.codegen(
ctx,
fields_should_be_private,
- codegen_depth,
struct_accessor_kind,
self,
result,
@@ -2703,14 +2691,12 @@ impl std::str::FromStr for EnumVariation {
/// A helper type to construct different enum variations.
enum EnumBuilder<'a> {
Rust {
- codegen_depth: usize,
attrs: Vec<proc_macro2::TokenStream>,
ident: Ident,
tokens: proc_macro2::TokenStream,
emitted_any_variants: bool,
},
NewType {
- codegen_depth: usize,
canonical_name: &'a str,
tokens: proc_macro2::TokenStream,
is_bitfield: bool,
@@ -2718,26 +2704,14 @@ enum EnumBuilder<'a> {
},
Consts {
variants: Vec<proc_macro2::TokenStream>,
- codegen_depth: usize,
},
ModuleConsts {
- codegen_depth: usize,
module_name: &'a str,
module_items: Vec<proc_macro2::TokenStream>,
},
}
impl<'a> EnumBuilder<'a> {
- /// Returns the depth of the code generation for a variant of this enum.
- fn codegen_depth(&self) -> usize {
- match *self {
- EnumBuilder::Rust { codegen_depth, .. } |
- EnumBuilder::NewType { codegen_depth, .. } |
- EnumBuilder::ModuleConsts { codegen_depth, .. } |
- EnumBuilder::Consts { codegen_depth, .. } => codegen_depth,
- }
- }
-
/// Returns true if the builder is for a rustified enum.
fn is_rust_enum(&self) -> bool {
matches!(*self, EnumBuilder::Rust { .. })
@@ -2750,7 +2724,6 @@ impl<'a> EnumBuilder<'a> {
mut attrs: Vec<proc_macro2::TokenStream>,
repr: proc_macro2::TokenStream,
enum_variation: EnumVariation,
- enum_codegen_depth: usize,
) -> Self {
let ident = Ident::new(name, Span::call_site());
@@ -2759,7 +2732,6 @@ impl<'a> EnumBuilder<'a> {
is_bitfield,
is_global,
} => EnumBuilder::NewType {
- codegen_depth: enum_codegen_depth,
canonical_name: name,
tokens: quote! {
#( #attrs )*
@@ -2774,7 +2746,6 @@ impl<'a> EnumBuilder<'a> {
attrs.insert(0, quote! { #[repr( #repr )] });
let tokens = quote!();
EnumBuilder::Rust {
- codegen_depth: enum_codegen_depth + 1,
attrs,
ident,
tokens,
@@ -2790,10 +2761,7 @@ impl<'a> EnumBuilder<'a> {
pub type #ident = #repr;
});
- EnumBuilder::Consts {
- variants,
- codegen_depth: enum_codegen_depth,
- }
+ EnumBuilder::Consts { variants }
}
EnumVariation::ModuleConsts => {
@@ -2807,7 +2775,6 @@ impl<'a> EnumBuilder<'a> {
};
EnumBuilder::ModuleConsts {
- codegen_depth: enum_codegen_depth + 1,
module_name: name,
module_items: vec![type_definition],
}
@@ -2839,8 +2806,7 @@ impl<'a> EnumBuilder<'a> {
let mut doc = quote! {};
if ctx.options().generate_comments {
if let Some(raw_comment) = variant.comment() {
- let comment =
- comment::preprocess(raw_comment, self.codegen_depth());
+ let comment = ctx.options().process_comment(raw_comment);
doc = attributes::doc(comment);
}
}
@@ -2851,13 +2817,11 @@ impl<'a> EnumBuilder<'a> {
ident,
tokens,
emitted_any_variants: _,
- codegen_depth,
} => {
let name = ctx.rust_ident(variant_name);
EnumBuilder::Rust {
attrs,
ident,
- codegen_depth,
tokens: quote! {
#tokens
#doc
@@ -2918,7 +2882,6 @@ impl<'a> EnumBuilder<'a> {
self
}
EnumBuilder::ModuleConsts {
- codegen_depth,
module_name,
mut module_items,
} => {
@@ -2932,7 +2895,6 @@ impl<'a> EnumBuilder<'a> {
EnumBuilder::ModuleConsts {
module_name,
module_items,
- codegen_depth,
}
}
}
@@ -3211,13 +3173,7 @@ impl CodeGenerator for Enum {
let repr = repr.to_rust_ty_or_opaque(ctx, item);
- let mut builder = EnumBuilder::new(
- &name,
- attrs,
- repr,
- variation,
- item.codegen_depth(ctx),
- );
+ let mut builder = EnumBuilder::new(&name, attrs, repr, variation);
// A map where we keep a value -> variant relation.
let mut seen_values = HashMap::<_, Ident>::default();
diff --git a/bindgen/ir/comment.rs b/bindgen/ir/comment.rs
index c96e3ebb..3eb17aac 100644
--- a/bindgen/ir/comment.rs
+++ b/bindgen/ir/comment.rs
@@ -12,10 +12,10 @@ enum Kind {
}
/// Preprocesses a C/C++ comment so that it is a valid Rust comment.
-pub fn preprocess(comment: &str, indent: usize) -> String {
+pub fn preprocess(comment: &str) -> String {
match self::kind(comment) {
- Some(Kind::SingleLines) => preprocess_single_lines(comment, indent),
- Some(Kind::MultiLine) => preprocess_multi_line(comment, indent),
+ Some(Kind::SingleLines) => preprocess_single_lines(comment),
+ Some(Kind::MultiLine) => preprocess_multi_line(comment),
None => comment.to_owned(),
}
}
@@ -31,56 +31,34 @@ fn kind(comment: &str) -> Option<Kind> {
}
}
-fn make_indent(indent: usize) -> String {
- const RUST_INDENTATION: usize = 4;
- " ".repeat(indent * RUST_INDENTATION)
-}
-
/// Preprocesses multiple single line comments.
///
/// Handles lines starting with both `//` and `///`.
-fn preprocess_single_lines(comment: &str, indent: usize) -> String {
+fn preprocess_single_lines(comment: &str) -> String {
debug_assert!(comment.starts_with("//"), "comment is not single line");
- let indent = make_indent(indent);
- let mut is_first = true;
let lines: Vec<_> = comment
.lines()
.map(|l| l.trim().trim_start_matches('/'))
- .map(|l| {
- let indent = if is_first { "" } else { &*indent };
- is_first = false;
- format!("{}///{}", indent, l)
- })
.collect();
lines.join("\n")
}
-fn preprocess_multi_line(comment: &str, indent: usize) -> String {
+fn preprocess_multi_line(comment: &str) -> String {
let comment = comment
.trim_start_matches('/')
.trim_end_matches('/')
.trim_end_matches('*');
- let indent = make_indent(indent);
// Strip any potential `*` characters preceding each line.
- let mut is_first = true;
let mut lines: Vec<_> = comment
.lines()
.map(|line| line.trim().trim_start_matches('*').trim_start_matches('!'))
.skip_while(|line| line.trim().is_empty()) // Skip the first empty lines.
- .map(|line| {
- let indent = if is_first { "" } else { &*indent };
- is_first = false;
- format!("{}///{}", indent, line)
- })
.collect();
// Remove the trailing line corresponding to the `*/`.
- if lines
- .last()
- .map_or(false, |l| l.trim().is_empty() || l.trim() == "///")
- {
+ if lines.last().map_or(false, |l| l.trim().is_empty()) {
lines.pop();
}
@@ -99,21 +77,24 @@ mod test {
#[test]
fn processes_single_lines_correctly() {
- assert_eq!(preprocess("/// hello", 0), "/// hello");
- assert_eq!(preprocess("// hello", 0), "/// hello");
- assert_eq!(preprocess("// hello", 0), "/// hello");
+ assert_eq!(preprocess("///"), "");
+ assert_eq!(preprocess("/// hello"), " hello");
+ assert_eq!(preprocess("// hello"), " hello");
+ assert_eq!(preprocess("// hello"), " hello");
}
#[test]
fn processes_multi_lines_correctly() {
+ assert_eq!(preprocess("/**/"), "");
+
assert_eq!(
- preprocess("/** hello \n * world \n * foo \n */", 0),
- "/// hello\n/// world\n/// foo"
+ preprocess("/** hello \n * world \n * foo \n */"),
+ " hello\n world\n foo"
);
assert_eq!(
- preprocess("/**\nhello\n*world\n*foo\n*/", 0),
- "///hello\n///world\n///foo"
+ preprocess("/**\nhello\n*world\n*foo\n*/"),
+ "hello\nworld\nfoo"
);
}
}
diff --git a/bindgen/ir/item.rs b/bindgen/ir/item.rs
index 446d78bd..5e9aff91 100644
--- a/bindgen/ir/item.rs
+++ b/bindgen/ir/item.rs
@@ -3,7 +3,6 @@
use super::super::codegen::{EnumVariation, CONSTIFIED_ENUM_MODULE_REPR_NAME};
use super::analysis::{HasVtable, HasVtableResult, Sizedness, SizednessResult};
use super::annotations::Annotations;
-use super::comment;
use super::comp::{CompKind, MethodKind};
use super::context::{BindgenContext, ItemId, PartialType, TypeId};
use super::derive::{
@@ -515,9 +514,9 @@ impl Item {
return None;
}
- self.comment.as_ref().map(|comment| {
- comment::preprocess(comment, self.codegen_depth(ctx))
- })
+ self.comment
+ .as_ref()
+ .map(|comment| ctx.options().process_comment(comment))
}
/// What kind of item is this?
diff --git a/bindgen/lib.rs b/bindgen/lib.rs
index bfc22bb6..d281e949 100644
--- a/bindgen/lib.rs
+++ b/bindgen/lib.rs
@@ -78,6 +78,8 @@ doc_mod!(ir, ir_docs);
doc_mod!(parse, parse_docs);
doc_mod!(regex_set, regex_set_docs);
+use ir::comment;
+
pub use crate::codegen::{
AliasVariation, EnumVariation, MacroTypeVariation, NonCopyUnionStyle,
};
@@ -2176,6 +2178,14 @@ impl BindgenOptions {
.flat_map(|cb| f(cb.as_ref()))
.collect()
}
+
+ fn process_comment(&self, comment: &str) -> String {
+ let comment = comment::preprocess(comment);
+ self.parse_callbacks
+ .last()
+ .and_then(|cb| cb.process_comment(&comment))
+ .unwrap_or(comment)
+ }
}
impl Default for BindgenOptions {