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 ParseCallbacks::process_comment #2347

Merged
merged 2 commits into from Nov 22, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 2 additions & 0 deletions CHANGELOG.md
Expand Up @@ -152,6 +152,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

Expand Down
5 changes: 5 additions & 0 deletions bindgen/callbacks.rs
Expand Up @@ -108,4 +108,9 @@ pub trait ParseCallbacks: fmt::Debug {
fn add_derives(&self, _name: &str) -> Vec<String> {
vec![]
}

/// Process a source code comment.
fn process_comment(&self, _comment: &str) -> Option<String> {
None
}
}
8 changes: 5 additions & 3 deletions bindgen/codegen/helpers.rs
Expand Up @@ -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 {
Expand Down
52 changes: 4 additions & 48 deletions bindgen/codegen/mod.rs
Expand Up @@ -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,
Expand Down Expand Up @@ -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,
Expand All @@ -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,
Expand All @@ -1282,7 +1279,6 @@ impl<'a> FieldCodegen<'a> for Field {
data.codegen(
ctx,
fields_should_be_private,
codegen_depth,
accessor_kind,
parent,
result,
Expand All @@ -1296,7 +1292,6 @@ impl<'a> FieldCodegen<'a> for Field {
unit.codegen(
ctx,
fields_should_be_private,
codegen_depth,
accessor_kind,
parent,
result,
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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);
}
}
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -1630,7 +1622,6 @@ impl<'a> FieldCodegen<'a> for BitfieldUnit {
bf.codegen(
ctx,
fields_should_be_private,
codegen_depth,
accessor_kind,
parent,
result,
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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
Expand All @@ -1894,7 +1883,6 @@ impl CodeGenerator for CompInfo {
field.codegen(
ctx,
fields_should_be_private,
codegen_depth,
struct_accessor_kind,
self,
result,
Expand Down Expand Up @@ -2701,41 +2689,27 @@ 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,
is_global: bool,
},
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 { .. })
Expand All @@ -2748,7 +2722,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());

Expand All @@ -2757,7 +2730,6 @@ impl<'a> EnumBuilder<'a> {
is_bitfield,
is_global,
} => EnumBuilder::NewType {
codegen_depth: enum_codegen_depth,
canonical_name: name,
tokens: quote! {
#( #attrs )*
Expand All @@ -2772,7 +2744,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,
Expand All @@ -2788,10 +2759,7 @@ impl<'a> EnumBuilder<'a> {
pub type #ident = #repr;
});

EnumBuilder::Consts {
variants,
codegen_depth: enum_codegen_depth,
}
EnumBuilder::Consts { variants }
}

EnumVariation::ModuleConsts => {
Expand All @@ -2805,7 +2773,6 @@ impl<'a> EnumBuilder<'a> {
};

EnumBuilder::ModuleConsts {
codegen_depth: enum_codegen_depth + 1,
module_name: name,
module_items: vec![type_definition],
}
Expand Down Expand Up @@ -2837,8 +2804,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);
}
}
Expand All @@ -2849,13 +2815,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
Expand Down Expand Up @@ -2916,7 +2880,6 @@ impl<'a> EnumBuilder<'a> {
self
}
EnumBuilder::ModuleConsts {
codegen_depth,
module_name,
mut module_items,
} => {
Expand All @@ -2930,7 +2893,6 @@ impl<'a> EnumBuilder<'a> {
EnumBuilder::ModuleConsts {
module_name,
module_items,
codegen_depth,
}
}
}
Expand Down Expand Up @@ -3208,13 +3170,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();
Expand Down
51 changes: 16 additions & 35 deletions bindgen/ir/comment.rs
Expand Up @@ -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(),
}
}
Expand All @@ -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();
}

Expand All @@ -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"
);
}
}
7 changes: 3 additions & 4 deletions bindgen/ir/item.rs
Expand Up @@ -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::{
Expand Down Expand Up @@ -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?
Expand Down