Skip to content

Commit 99d188f

Browse files
author
bors-servo
authored
Auto merge of #905 - bkchr:rustfmt, r=fitzgen
Adds support for running rustfmt on generated bindings This patch enables bindgen to run rustfmt on generated bindings. Rustfmt is used from the global PATH. Two new command-line arguments are added: 1. --format-bindings: Enables running rustfmt 2. --format-configuration-file: The configuration file for rustfmt (not required). Fixes: #900
2 parents fdee9f1 + 7fe3f0c commit 99d188f

File tree

8 files changed

+162
-18
lines changed

8 files changed

+162
-18
lines changed

Cargo.lock

+10
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ syntex_syntax = "0.58"
5252
regex = "0.2"
5353
# This kinda sucks: https://github.com/rust-lang/cargo/issues/1982
5454
clap = "2"
55+
which = "1.0.2"
5556

5657
[dependencies.aster]
5758
features = ["with-syntex"]

src/codegen/mod.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,7 @@ impl<'a> CodegenResult<'a> {
166166
/// counter internally so the next time we ask for the overload for this
167167
/// name, we get the incremented value, and so on.
168168
fn overload_number(&mut self, name: &str) -> u32 {
169-
let mut counter =
169+
let counter =
170170
self.overload_counters.entry(name.into()).or_insert(0);
171171
let number = *counter;
172172
*counter += 1;
@@ -2012,7 +2012,7 @@ impl MethodCodegen for Method {
20122012
}
20132013

20142014
let count = {
2015-
let mut count = method_names.entry(name.clone()).or_insert(0);
2015+
let count = method_names.entry(name.clone()).or_insert(0);
20162016
*count += 1;
20172017
*count - 1
20182018
};

src/ir/comp.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -459,7 +459,7 @@ fn raw_fields_to_fields_and_bitfield_units<I>(ctx: &BindgenContext,
459459
/// (potentially multiple) bitfield units.
460460
fn bitfields_to_allocation_units<E, I>(ctx: &BindgenContext,
461461
bitfield_unit_count: &mut usize,
462-
mut fields: &mut E,
462+
fields: &mut E,
463463
raw_bitfields: I)
464464
where E: Extend<Field>,
465465
I: IntoIterator<Item=RawField>
@@ -477,7 +477,7 @@ fn bitfields_to_allocation_units<E, I>(ctx: &BindgenContext,
477477
// TODO(emilio): Take into account C++'s wide bitfields, and
478478
// packing, sigh.
479479

480-
fn flush_allocation_unit<E>(mut fields: &mut E,
480+
fn flush_allocation_unit<E>(fields: &mut E,
481481
bitfield_unit_count: &mut usize,
482482
unit_size_in_bits: usize,
483483
unit_align_in_bits: usize,

src/ir/context.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -466,8 +466,8 @@ impl<'ctx> BindgenContext<'ctx> {
466466
assert!(item.id() != self.root_module);
467467
assert!(!self.items.contains_key(&item.id()));
468468

469-
if let Some(mut parent) = self.items.get_mut(&item.parent_id()) {
470-
if let Some(mut module) = parent.as_module_mut() {
469+
if let Some(parent) = self.items.get_mut(&item.parent_id()) {
470+
if let Some(module) = parent.as_module_mut() {
471471
debug!("add_item_to_module: adding {:?} as child of parent module {:?}",
472472
item.id(),
473473
item.parent_id());
@@ -607,7 +607,7 @@ impl<'ctx> BindgenContext<'ctx> {
607607
to opaque blob");
608608
Item::new_opaque_type(self.next_item_id(), &ty, self)
609609
});
610-
let mut item = self.items.get_mut(&id).unwrap();
610+
let item = self.items.get_mut(&id).unwrap();
611611

612612
*item.kind_mut().as_type_mut().unwrap().kind_mut() =
613613
TypeKind::ResolvedTypeRef(resolved);
@@ -699,7 +699,7 @@ impl<'ctx> BindgenContext<'ctx> {
699699
debug!("Replacing {:?} with {:?}", id, replacement);
700700

701701
let new_parent = {
702-
let mut item = self.items.get_mut(&id).unwrap();
702+
let item = self.items.get_mut(&id).unwrap();
703703
*item.kind_mut().as_type_mut().unwrap().kind_mut() =
704704
TypeKind::ResolvedTypeRef(replacement);
705705
item.parent_id()

src/ir/template.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -322,7 +322,7 @@ impl IsOpaque for TemplateInstantiation {
322322
arg_path[1..].join("::")
323323
}).collect();
324324
{
325-
let mut last = path.last_mut().unwrap();
325+
let last = path.last_mut().unwrap();
326326
last.push('<');
327327
last.push_str(&args.join(", "));
328328
last.push('>');

src/lib.rs

+106-8
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ extern crate peeking_take_while;
2626
extern crate regex;
2727
#[macro_use]
2828
extern crate lazy_static;
29+
extern crate which;
2930

3031
#[cfg(feature = "logging")]
3132
#[macro_use]
@@ -453,6 +454,19 @@ impl Builder {
453454
);
454455
}
455456

457+
if !self.options.rustfmt_bindings {
458+
output_vector.push("--rustfmt-bindings".into());
459+
}
460+
461+
if let Some(path) = self.options
462+
.rustfmt_configuration_file
463+
.as_ref()
464+
.and_then(|f| f.to_str())
465+
{
466+
output_vector.push("--rustfmt-configuration-file".into());
467+
output_vector.push(path.into());
468+
}
469+
456470
output_vector
457471
}
458472

@@ -829,6 +843,20 @@ impl Builder {
829843
self
830844
}
831845

846+
/// Set whether rustfmt should format the generated bindings.
847+
pub fn rustfmt_bindings(mut self, doit: bool) -> Self {
848+
self.options.rustfmt_bindings = doit;
849+
self
850+
}
851+
852+
/// Set the absolute path to the rustfmt configuration file, if None, the standard rustfmt
853+
/// options are used.
854+
pub fn rustfmt_configuration_file(mut self, path: Option<PathBuf>) -> Self {
855+
self = self.rustfmt_bindings(true);
856+
self.options.rustfmt_configuration_file = path;
857+
self
858+
}
859+
832860
/// Generate the Rust bindings using the options built up thus far.
833861
pub fn generate<'ctx>(mut self) -> Result<Bindings<'ctx>, ()> {
834862
self.options.input_header = self.input_headers.pop();
@@ -1086,6 +1114,13 @@ pub struct BindgenOptions {
10861114

10871115
/// Whether to prepend the enum name to bitfield or constant variants.
10881116
pub prepend_enum_name: bool,
1117+
1118+
/// Whether rustfmt should format the generated bindings.
1119+
pub rustfmt_bindings: bool,
1120+
1121+
/// The absolute path to the rustfmt configuration file, if None, the standard rustfmt
1122+
/// options are used.
1123+
pub rustfmt_configuration_file: Option<PathBuf>,
10891124
}
10901125

10911126
/// TODO(emilio): This is sort of a lie (see the error message that results from
@@ -1148,6 +1183,8 @@ impl Default for BindgenOptions {
11481183
objc_extern_crate: false,
11491184
enable_mangling: true,
11501185
prepend_enum_name: true,
1186+
rustfmt_bindings: true,
1187+
rustfmt_configuration_file: None,
11511188
}
11521189
}
11531190
}
@@ -1299,14 +1336,18 @@ impl<'ctx> Bindings<'ctx> {
12991336

13001337
/// Write these bindings as source text to a file.
13011338
pub fn write_to_file<P: AsRef<Path>>(&self, path: P) -> io::Result<()> {
1302-
let file = try!(
1303-
OpenOptions::new()
1304-
.write(true)
1305-
.truncate(true)
1306-
.create(true)
1307-
.open(path)
1308-
);
1309-
self.write(Box::new(file))
1339+
{
1340+
let file = try!(
1341+
OpenOptions::new()
1342+
.write(true)
1343+
.truncate(true)
1344+
.create(true)
1345+
.open(path.as_ref())
1346+
);
1347+
self.write(Box::new(file))?;
1348+
}
1349+
1350+
self.rustfmt_generated_file(path.as_ref())
13101351
}
13111352

13121353
/// Write these bindings as source text to the given `Write`able.
@@ -1329,6 +1370,63 @@ impl<'ctx> Bindings<'ctx> {
13291370
try!(eof(&mut ps.s));
13301371
ps.s.out.flush()
13311372
}
1373+
1374+
/// Checks if rustfmt_bindings is set and runs rustfmt on the file
1375+
fn rustfmt_generated_file(&self, file: &Path) -> io::Result<()> {
1376+
if !self.context.options().rustfmt_bindings {
1377+
return Ok(());
1378+
}
1379+
1380+
let rustfmt = if let Ok(rustfmt) = which::which("rustfmt") {
1381+
rustfmt
1382+
} else {
1383+
return Err(io::Error::new(
1384+
io::ErrorKind::Other,
1385+
"Rustfmt activated, but it could not be found in global path.",
1386+
));
1387+
};
1388+
1389+
let mut cmd = Command::new(rustfmt);
1390+
1391+
if let Some(path) = self.context
1392+
.options()
1393+
.rustfmt_configuration_file
1394+
.as_ref()
1395+
.and_then(|f| f.to_str())
1396+
{
1397+
cmd.args(&["--config-path", path]);
1398+
}
1399+
1400+
if let Ok(output) = cmd.arg(file).output() {
1401+
if !output.status.success() {
1402+
let stderr = String::from_utf8_lossy(&output.stderr);
1403+
match output.status.code() {
1404+
Some(2) => Err(io::Error::new(
1405+
io::ErrorKind::Other,
1406+
format!("Rustfmt parsing errors:\n{}", stderr),
1407+
)),
1408+
Some(3) => {
1409+
warn!(
1410+
"Rustfmt could not format some lines:\n{}",
1411+
stderr
1412+
);
1413+
Ok(())
1414+
}
1415+
_ => Err(io::Error::new(
1416+
io::ErrorKind::Other,
1417+
format!("Internal rustfmt error:\n{}", stderr),
1418+
)),
1419+
}
1420+
} else {
1421+
Ok(())
1422+
}
1423+
} else {
1424+
Err(io::Error::new(
1425+
io::ErrorKind::Other,
1426+
"Error executing rustfmt!",
1427+
))
1428+
}
1429+
}
13321430
}
13331431

13341432
/// Determines whether the given cursor is in any of the files matched by the

src/options.rs

+36-1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ use bindgen::{builder, Builder, CodegenConfig};
22
use clap::{App, Arg};
33
use std::fs::File;
44
use std::io::{self, Error, ErrorKind};
5+
use std::path::PathBuf;
56

67
/// Construct a new [`Builder`](./struct.Builder.html) from command line flags.
78
pub fn builder_from_flags<I>(
@@ -221,7 +222,20 @@ where
221222
.help("Preprocess and dump the input header files to disk. \
222223
Useful when debugging bindgen, using C-Reduce, or when \
223224
filing issues. The resulting file will be named \
224-
something like `__bindgen.i` or `__bindgen.ii`.")
225+
something like `__bindgen.i` or `__bindgen.ii`."),
226+
Arg::with_name("rustfmt-bindings")
227+
.long("rustfmt-bindings")
228+
.help("Format the generated bindings with rustfmt. \
229+
Rustfmt needs to be in the global PATH."),
230+
Arg::with_name("rustfmt-configuration-file")
231+
.long("rustfmt-configuration-file")
232+
.help("The absolute path to the rustfmt configuration file. \
233+
The configuration file will be used for formatting the bindings. \
234+
Setting this parameter, will automatically set --rustfmt-bindings.")
235+
.value_name("path")
236+
.takes_value(true)
237+
.multiple(false)
238+
.number_of_values(1),
225239
]) // .args()
226240
.get_matches_from(args);
227241

@@ -442,6 +456,27 @@ where
442456
builder.dump_preprocessed_input()?;
443457
}
444458

459+
if matches.is_present("rustfmt-bindings") {
460+
builder = builder.rustfmt_bindings(true);
461+
}
462+
463+
if let Some(path_str) = matches.value_of("rustfmt-configuration-file") {
464+
let path = PathBuf::from(path_str);
465+
466+
if !path.is_absolute() {
467+
return Err(Error::new(ErrorKind::Other,
468+
"--rustfmt-configuration--file needs to be an absolute path!"));
469+
}
470+
471+
if path.to_str().is_none() {
472+
return Err(
473+
Error::new(ErrorKind::Other,
474+
"--rustfmt-configuration-file contains non-valid UTF8 characters."));
475+
}
476+
477+
builder = builder.rustfmt_configuration_file(Some(path));
478+
}
479+
445480
let verbose = matches.is_present("verbose");
446481

447482
Ok((builder, output, verbose))

0 commit comments

Comments
 (0)