Skip to content

Commit f160d11

Browse files
authored
Add ParseCallbacks::process_comment (#2347)
This method can be used to process comments and replace them with whatever the user wants.
1 parent 34f0bac commit f160d11

File tree

7 files changed

+45
-90
lines changed

7 files changed

+45
-90
lines changed

CHANGELOG.md

+2
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,8 @@
178178
matching a regular expression.
179179
* new feature: allow using the `C-unwind` ABI in `--override-abi` on nightly
180180
rust.
181+
* new feature: `process_comments` method to the `ParseCallbacks` trait to
182+
handle source code comments.
181183

182184
## Changed
183185

bindgen/callbacks.rs

+5
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,11 @@ pub trait ParseCallbacks: fmt::Debug {
108108
fn add_derives(&self, _info: &DeriveInfo<'_>) -> Vec<String> {
109109
vec![]
110110
}
111+
112+
/// Process a source code comment.
113+
fn process_comment(&self, _comment: &str) -> Option<String> {
114+
None
115+
}
111116
}
112117

113118
/// Relevant information about a type to which new derive attributes will be added using

bindgen/codegen/helpers.rs

+5-3
Original file line numberDiff line numberDiff line change
@@ -55,9 +55,11 @@ pub mod attributes {
5555
}
5656

5757
pub fn doc(comment: String) -> TokenStream {
58-
// NOTE(emilio): By this point comments are already preprocessed and in
59-
// `///` form. Quote turns them into `#[doc]` comments, but oh well.
60-
TokenStream::from_str(&comment).unwrap()
58+
if comment.is_empty() {
59+
quote!()
60+
} else {
61+
quote!(#[doc = #comment])
62+
}
6163
}
6264

6365
pub fn link_name(name: &str) -> TokenStream {

bindgen/codegen/mod.rs

+4-48
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@ use super::BindgenOptions;
2020

2121
use crate::ir::analysis::{HasVtable, Sizedness};
2222
use crate::ir::annotations::FieldAccessorKind;
23-
use crate::ir::comment;
2423
use crate::ir::comp::{
2524
Bitfield, BitfieldUnit, CompInfo, CompKind, Field, FieldData, FieldMethods,
2625
Method, MethodKind,
@@ -1245,7 +1244,6 @@ trait FieldCodegen<'a> {
12451244
&self,
12461245
ctx: &BindgenContext,
12471246
fields_should_be_private: bool,
1248-
codegen_depth: usize,
12491247
accessor_kind: FieldAccessorKind,
12501248
parent: &CompInfo,
12511249
result: &mut CodegenResult,
@@ -1265,7 +1263,6 @@ impl<'a> FieldCodegen<'a> for Field {
12651263
&self,
12661264
ctx: &BindgenContext,
12671265
fields_should_be_private: bool,
1268-
codegen_depth: usize,
12691266
accessor_kind: FieldAccessorKind,
12701267
parent: &CompInfo,
12711268
result: &mut CodegenResult,
@@ -1282,7 +1279,6 @@ impl<'a> FieldCodegen<'a> for Field {
12821279
data.codegen(
12831280
ctx,
12841281
fields_should_be_private,
1285-
codegen_depth,
12861282
accessor_kind,
12871283
parent,
12881284
result,
@@ -1296,7 +1292,6 @@ impl<'a> FieldCodegen<'a> for Field {
12961292
unit.codegen(
12971293
ctx,
12981294
fields_should_be_private,
1299-
codegen_depth,
13001295
accessor_kind,
13011296
parent,
13021297
result,
@@ -1346,7 +1341,6 @@ impl<'a> FieldCodegen<'a> for FieldData {
13461341
&self,
13471342
ctx: &BindgenContext,
13481343
fields_should_be_private: bool,
1349-
codegen_depth: usize,
13501344
accessor_kind: FieldAccessorKind,
13511345
parent: &CompInfo,
13521346
result: &mut CodegenResult,
@@ -1392,8 +1386,7 @@ impl<'a> FieldCodegen<'a> for FieldData {
13921386
let mut field = quote! {};
13931387
if ctx.options().generate_comments {
13941388
if let Some(raw_comment) = self.comment() {
1395-
let comment =
1396-
comment::preprocess(raw_comment, codegen_depth + 1);
1389+
let comment = ctx.options().process_comment(raw_comment);
13971390
field = attributes::doc(comment);
13981391
}
13991392
}
@@ -1553,7 +1546,6 @@ impl<'a> FieldCodegen<'a> for BitfieldUnit {
15531546
&self,
15541547
ctx: &BindgenContext,
15551548
fields_should_be_private: bool,
1556-
codegen_depth: usize,
15571549
accessor_kind: FieldAccessorKind,
15581550
parent: &CompInfo,
15591551
result: &mut CodegenResult,
@@ -1630,7 +1622,6 @@ impl<'a> FieldCodegen<'a> for BitfieldUnit {
16301622
bf.codegen(
16311623
ctx,
16321624
fields_should_be_private,
1633-
codegen_depth,
16341625
accessor_kind,
16351626
parent,
16361627
result,
@@ -1705,7 +1696,6 @@ impl<'a> FieldCodegen<'a> for Bitfield {
17051696
&self,
17061697
ctx: &BindgenContext,
17071698
fields_should_be_private: bool,
1708-
_codegen_depth: usize,
17091699
_accessor_kind: FieldAccessorKind,
17101700
parent: &CompInfo,
17111701
_result: &mut CodegenResult,
@@ -1883,7 +1873,6 @@ impl CodeGenerator for CompInfo {
18831873

18841874
let mut methods = vec![];
18851875
if !is_opaque {
1886-
let codegen_depth = item.codegen_depth(ctx);
18871876
let fields_should_be_private =
18881877
item.annotations().private_fields().unwrap_or(false);
18891878
let struct_accessor_kind = item
@@ -1894,7 +1883,6 @@ impl CodeGenerator for CompInfo {
18941883
field.codegen(
18951884
ctx,
18961885
fields_should_be_private,
1897-
codegen_depth,
18981886
struct_accessor_kind,
18991887
self,
19001888
result,
@@ -2703,41 +2691,27 @@ impl std::str::FromStr for EnumVariation {
27032691
/// A helper type to construct different enum variations.
27042692
enum EnumBuilder<'a> {
27052693
Rust {
2706-
codegen_depth: usize,
27072694
attrs: Vec<proc_macro2::TokenStream>,
27082695
ident: Ident,
27092696
tokens: proc_macro2::TokenStream,
27102697
emitted_any_variants: bool,
27112698
},
27122699
NewType {
2713-
codegen_depth: usize,
27142700
canonical_name: &'a str,
27152701
tokens: proc_macro2::TokenStream,
27162702
is_bitfield: bool,
27172703
is_global: bool,
27182704
},
27192705
Consts {
27202706
variants: Vec<proc_macro2::TokenStream>,
2721-
codegen_depth: usize,
27222707
},
27232708
ModuleConsts {
2724-
codegen_depth: usize,
27252709
module_name: &'a str,
27262710
module_items: Vec<proc_macro2::TokenStream>,
27272711
},
27282712
}
27292713

27302714
impl<'a> EnumBuilder<'a> {
2731-
/// Returns the depth of the code generation for a variant of this enum.
2732-
fn codegen_depth(&self) -> usize {
2733-
match *self {
2734-
EnumBuilder::Rust { codegen_depth, .. } |
2735-
EnumBuilder::NewType { codegen_depth, .. } |
2736-
EnumBuilder::ModuleConsts { codegen_depth, .. } |
2737-
EnumBuilder::Consts { codegen_depth, .. } => codegen_depth,
2738-
}
2739-
}
2740-
27412715
/// Returns true if the builder is for a rustified enum.
27422716
fn is_rust_enum(&self) -> bool {
27432717
matches!(*self, EnumBuilder::Rust { .. })
@@ -2750,7 +2724,6 @@ impl<'a> EnumBuilder<'a> {
27502724
mut attrs: Vec<proc_macro2::TokenStream>,
27512725
repr: proc_macro2::TokenStream,
27522726
enum_variation: EnumVariation,
2753-
enum_codegen_depth: usize,
27542727
) -> Self {
27552728
let ident = Ident::new(name, Span::call_site());
27562729

@@ -2759,7 +2732,6 @@ impl<'a> EnumBuilder<'a> {
27592732
is_bitfield,
27602733
is_global,
27612734
} => EnumBuilder::NewType {
2762-
codegen_depth: enum_codegen_depth,
27632735
canonical_name: name,
27642736
tokens: quote! {
27652737
#( #attrs )*
@@ -2774,7 +2746,6 @@ impl<'a> EnumBuilder<'a> {
27742746
attrs.insert(0, quote! { #[repr( #repr )] });
27752747
let tokens = quote!();
27762748
EnumBuilder::Rust {
2777-
codegen_depth: enum_codegen_depth + 1,
27782749
attrs,
27792750
ident,
27802751
tokens,
@@ -2790,10 +2761,7 @@ impl<'a> EnumBuilder<'a> {
27902761
pub type #ident = #repr;
27912762
});
27922763

2793-
EnumBuilder::Consts {
2794-
variants,
2795-
codegen_depth: enum_codegen_depth,
2796-
}
2764+
EnumBuilder::Consts { variants }
27972765
}
27982766

27992767
EnumVariation::ModuleConsts => {
@@ -2807,7 +2775,6 @@ impl<'a> EnumBuilder<'a> {
28072775
};
28082776

28092777
EnumBuilder::ModuleConsts {
2810-
codegen_depth: enum_codegen_depth + 1,
28112778
module_name: name,
28122779
module_items: vec![type_definition],
28132780
}
@@ -2839,8 +2806,7 @@ impl<'a> EnumBuilder<'a> {
28392806
let mut doc = quote! {};
28402807
if ctx.options().generate_comments {
28412808
if let Some(raw_comment) = variant.comment() {
2842-
let comment =
2843-
comment::preprocess(raw_comment, self.codegen_depth());
2809+
let comment = ctx.options().process_comment(raw_comment);
28442810
doc = attributes::doc(comment);
28452811
}
28462812
}
@@ -2851,13 +2817,11 @@ impl<'a> EnumBuilder<'a> {
28512817
ident,
28522818
tokens,
28532819
emitted_any_variants: _,
2854-
codegen_depth,
28552820
} => {
28562821
let name = ctx.rust_ident(variant_name);
28572822
EnumBuilder::Rust {
28582823
attrs,
28592824
ident,
2860-
codegen_depth,
28612825
tokens: quote! {
28622826
#tokens
28632827
#doc
@@ -2918,7 +2882,6 @@ impl<'a> EnumBuilder<'a> {
29182882
self
29192883
}
29202884
EnumBuilder::ModuleConsts {
2921-
codegen_depth,
29222885
module_name,
29232886
mut module_items,
29242887
} => {
@@ -2932,7 +2895,6 @@ impl<'a> EnumBuilder<'a> {
29322895
EnumBuilder::ModuleConsts {
29332896
module_name,
29342897
module_items,
2935-
codegen_depth,
29362898
}
29372899
}
29382900
}
@@ -3211,13 +3173,7 @@ impl CodeGenerator for Enum {
32113173

32123174
let repr = repr.to_rust_ty_or_opaque(ctx, item);
32133175

3214-
let mut builder = EnumBuilder::new(
3215-
&name,
3216-
attrs,
3217-
repr,
3218-
variation,
3219-
item.codegen_depth(ctx),
3220-
);
3176+
let mut builder = EnumBuilder::new(&name, attrs, repr, variation);
32213177

32223178
// A map where we keep a value -> variant relation.
32233179
let mut seen_values = HashMap::<_, Ident>::default();

bindgen/ir/comment.rs

+16-35
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,10 @@ enum Kind {
1212
}
1313

1414
/// Preprocesses a C/C++ comment so that it is a valid Rust comment.
15-
pub fn preprocess(comment: &str, indent: usize) -> String {
15+
pub fn preprocess(comment: &str) -> String {
1616
match self::kind(comment) {
17-
Some(Kind::SingleLines) => preprocess_single_lines(comment, indent),
18-
Some(Kind::MultiLine) => preprocess_multi_line(comment, indent),
17+
Some(Kind::SingleLines) => preprocess_single_lines(comment),
18+
Some(Kind::MultiLine) => preprocess_multi_line(comment),
1919
None => comment.to_owned(),
2020
}
2121
}
@@ -31,56 +31,34 @@ fn kind(comment: &str) -> Option<Kind> {
3131
}
3232
}
3333

34-
fn make_indent(indent: usize) -> String {
35-
const RUST_INDENTATION: usize = 4;
36-
" ".repeat(indent * RUST_INDENTATION)
37-
}
38-
3934
/// Preprocesses multiple single line comments.
4035
///
4136
/// Handles lines starting with both `//` and `///`.
42-
fn preprocess_single_lines(comment: &str, indent: usize) -> String {
37+
fn preprocess_single_lines(comment: &str) -> String {
4338
debug_assert!(comment.starts_with("//"), "comment is not single line");
4439

45-
let indent = make_indent(indent);
46-
let mut is_first = true;
4740
let lines: Vec<_> = comment
4841
.lines()
4942
.map(|l| l.trim().trim_start_matches('/'))
50-
.map(|l| {
51-
let indent = if is_first { "" } else { &*indent };
52-
is_first = false;
53-
format!("{}///{}", indent, l)
54-
})
5543
.collect();
5644
lines.join("\n")
5745
}
5846

59-
fn preprocess_multi_line(comment: &str, indent: usize) -> String {
47+
fn preprocess_multi_line(comment: &str) -> String {
6048
let comment = comment
6149
.trim_start_matches('/')
6250
.trim_end_matches('/')
6351
.trim_end_matches('*');
6452

65-
let indent = make_indent(indent);
6653
// Strip any potential `*` characters preceding each line.
67-
let mut is_first = true;
6854
let mut lines: Vec<_> = comment
6955
.lines()
7056
.map(|line| line.trim().trim_start_matches('*').trim_start_matches('!'))
7157
.skip_while(|line| line.trim().is_empty()) // Skip the first empty lines.
72-
.map(|line| {
73-
let indent = if is_first { "" } else { &*indent };
74-
is_first = false;
75-
format!("{}///{}", indent, line)
76-
})
7758
.collect();
7859

7960
// Remove the trailing line corresponding to the `*/`.
80-
if lines
81-
.last()
82-
.map_or(false, |l| l.trim().is_empty() || l.trim() == "///")
83-
{
61+
if lines.last().map_or(false, |l| l.trim().is_empty()) {
8462
lines.pop();
8563
}
8664

@@ -99,21 +77,24 @@ mod test {
9977

10078
#[test]
10179
fn processes_single_lines_correctly() {
102-
assert_eq!(preprocess("/// hello", 0), "/// hello");
103-
assert_eq!(preprocess("// hello", 0), "/// hello");
104-
assert_eq!(preprocess("// hello", 0), "/// hello");
80+
assert_eq!(preprocess("///"), "");
81+
assert_eq!(preprocess("/// hello"), " hello");
82+
assert_eq!(preprocess("// hello"), " hello");
83+
assert_eq!(preprocess("// hello"), " hello");
10584
}
10685

10786
#[test]
10887
fn processes_multi_lines_correctly() {
88+
assert_eq!(preprocess("/**/"), "");
89+
10990
assert_eq!(
110-
preprocess("/** hello \n * world \n * foo \n */", 0),
111-
"/// hello\n/// world\n/// foo"
91+
preprocess("/** hello \n * world \n * foo \n */"),
92+
" hello\n world\n foo"
11293
);
11394

11495
assert_eq!(
115-
preprocess("/**\nhello\n*world\n*foo\n*/", 0),
116-
"///hello\n///world\n///foo"
96+
preprocess("/**\nhello\n*world\n*foo\n*/"),
97+
"hello\nworld\nfoo"
11798
);
11899
}
119100
}

0 commit comments

Comments
 (0)