Skip to content

Commit 5ca0569

Browse files
author
bors-servo
authored
Auto merge of rust-lang#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: rust-lang#900
2 parents f9087f3 + 27dd628 commit 5ca0569

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
@@ -51,6 +51,7 @@ syntex_syntax = "0.58"
5151
regex = "0.2"
5252
# This kinda sucks: https://github.com/rust-lang/cargo/issues/1982
5353
clap = "2"
54+
which = "1.0.2"
5455

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

src/codegen/mod.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -175,7 +175,7 @@ impl<'a> CodegenResult<'a> {
175175
/// counter internally so the next time we ask for the overload for this
176176
/// name, we get the incremented value, and so on.
177177
fn overload_number(&mut self, name: &str) -> u32 {
178-
let mut counter =
178+
let counter =
179179
self.overload_counters.entry(name.into()).or_insert(0);
180180
let number = *counter;
181181
*counter += 1;
@@ -2030,7 +2030,7 @@ impl MethodCodegen for Method {
20302030
}
20312031

20322032
let count = {
2033-
let mut count = method_names.entry(name.clone()).or_insert(0);
2033+
let count = method_names.entry(name.clone()).or_insert(0);
20342034
*count += 1;
20352035
*count - 1
20362036
};

src/ir/comp.rs

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

481-
fn flush_allocation_unit<E>(mut fields: &mut E,
481+
fn flush_allocation_unit<E>(fields: &mut E,
482482
bitfield_unit_count: &mut usize,
483483
unit_size_in_bits: usize,
484484
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]
@@ -455,6 +456,19 @@ impl Builder {
455456
);
456457
}
457458

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

@@ -840,6 +854,20 @@ impl Builder {
840854
self
841855
}
842856

857+
/// Set whether rustfmt should format the generated bindings.
858+
pub fn rustfmt_bindings(mut self, doit: bool) -> Self {
859+
self.options.rustfmt_bindings = doit;
860+
self
861+
}
862+
863+
/// Set the absolute path to the rustfmt configuration file, if None, the standard rustfmt
864+
/// options are used.
865+
pub fn rustfmt_configuration_file(mut self, path: Option<PathBuf>) -> Self {
866+
self = self.rustfmt_bindings(true);
867+
self.options.rustfmt_configuration_file = path;
868+
self
869+
}
870+
843871
/// Generate the Rust bindings using the options built up thus far.
844872
pub fn generate<'ctx>(mut self) -> Result<Bindings<'ctx>, ()> {
845873
self.options.input_header = self.input_headers.pop();
@@ -1099,6 +1127,13 @@ pub struct BindgenOptions {
10991127

11001128
/// Features to enable, derived from `rust_target`
11011129
rust_features: RustFeatures,
1130+
1131+
/// Whether rustfmt should format the generated bindings.
1132+
pub rustfmt_bindings: bool,
1133+
1134+
/// The absolute path to the rustfmt configuration file, if None, the standard rustfmt
1135+
/// options are used.
1136+
pub rustfmt_configuration_file: Option<PathBuf>,
11021137
}
11031138

11041139
/// TODO(emilio): This is sort of a lie (see the error message that results from
@@ -1183,6 +1218,8 @@ impl Default for BindgenOptions {
11831218
objc_extern_crate: false,
11841219
enable_mangling: true,
11851220
prepend_enum_name: true,
1221+
rustfmt_bindings: false,
1222+
rustfmt_configuration_file: None,
11861223
}
11871224
}
11881225
}
@@ -1334,14 +1371,18 @@ impl<'ctx> Bindings<'ctx> {
13341371

13351372
/// Write these bindings as source text to a file.
13361373
pub fn write_to_file<P: AsRef<Path>>(&self, path: P) -> io::Result<()> {
1337-
let file = try!(
1338-
OpenOptions::new()
1339-
.write(true)
1340-
.truncate(true)
1341-
.create(true)
1342-
.open(path)
1343-
);
1344-
self.write(Box::new(file))
1374+
{
1375+
let file = try!(
1376+
OpenOptions::new()
1377+
.write(true)
1378+
.truncate(true)
1379+
.create(true)
1380+
.open(path.as_ref())
1381+
);
1382+
self.write(Box::new(file))?;
1383+
}
1384+
1385+
self.rustfmt_generated_file(path.as_ref())
13451386
}
13461387

13471388
/// Write these bindings as source text to the given `Write`able.
@@ -1364,6 +1405,63 @@ impl<'ctx> Bindings<'ctx> {
13641405
try!(eof(&mut ps.s));
13651406
ps.s.out.flush()
13661407
}
1408+
1409+
/// Checks if rustfmt_bindings is set and runs rustfmt on the file
1410+
fn rustfmt_generated_file(&self, file: &Path) -> io::Result<()> {
1411+
if !self.context.options().rustfmt_bindings {
1412+
return Ok(());
1413+
}
1414+
1415+
let rustfmt = if let Ok(rustfmt) = which::which("rustfmt") {
1416+
rustfmt
1417+
} else {
1418+
return Err(io::Error::new(
1419+
io::ErrorKind::Other,
1420+
"Rustfmt activated, but it could not be found in global path.",
1421+
));
1422+
};
1423+
1424+
let mut cmd = Command::new(rustfmt);
1425+
1426+
if let Some(path) = self.context
1427+
.options()
1428+
.rustfmt_configuration_file
1429+
.as_ref()
1430+
.and_then(|f| f.to_str())
1431+
{
1432+
cmd.args(&["--config-path", path]);
1433+
}
1434+
1435+
if let Ok(output) = cmd.arg(file).output() {
1436+
if !output.status.success() {
1437+
let stderr = String::from_utf8_lossy(&output.stderr);
1438+
match output.status.code() {
1439+
Some(2) => Err(io::Error::new(
1440+
io::ErrorKind::Other,
1441+
format!("Rustfmt parsing errors:\n{}", stderr),
1442+
)),
1443+
Some(3) => {
1444+
warn!(
1445+
"Rustfmt could not format some lines:\n{}",
1446+
stderr
1447+
);
1448+
Ok(())
1449+
}
1450+
_ => Err(io::Error::new(
1451+
io::ErrorKind::Other,
1452+
format!("Internal rustfmt error:\n{}", stderr),
1453+
)),
1454+
}
1455+
} else {
1456+
Ok(())
1457+
}
1458+
} else {
1459+
Err(io::Error::new(
1460+
io::ErrorKind::Other,
1461+
"Error executing rustfmt!",
1462+
))
1463+
}
1464+
}
13671465
}
13681466

13691467
/// 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
@@ -4,6 +4,7 @@ use clap::{App, Arg};
44
use std::fs::File;
55
use std::io::{self, Error, ErrorKind, Write, stderr};
66
use std::str::FromStr;
7+
use std::path::PathBuf;
78

89
/// Construct a new [`Builder`](./struct.Builder.html) from command line flags.
910
pub fn builder_from_flags<I>(
@@ -231,7 +232,20 @@ where
231232
.help("Preprocess and dump the input header files to disk. \
232233
Useful when debugging bindgen, using C-Reduce, or when \
233234
filing issues. The resulting file will be named \
234-
something like `__bindgen.i` or `__bindgen.ii`.")
235+
something like `__bindgen.i` or `__bindgen.ii`."),
236+
Arg::with_name("rustfmt-bindings")
237+
.long("rustfmt-bindings")
238+
.help("Format the generated bindings with rustfmt. \
239+
Rustfmt needs to be in the global PATH."),
240+
Arg::with_name("rustfmt-configuration-file")
241+
.long("rustfmt-configuration-file")
242+
.help("The absolute path to the rustfmt configuration file. \
243+
The configuration file will be used for formatting the bindings. \
244+
Setting this parameter, will automatically set --rustfmt-bindings.")
245+
.value_name("path")
246+
.takes_value(true)
247+
.multiple(false)
248+
.number_of_values(1),
235249
]) // .args()
236250
.get_matches_from(args);
237251

@@ -458,6 +472,27 @@ where
458472
builder.dump_preprocessed_input()?;
459473
}
460474

475+
if matches.is_present("rustfmt-bindings") {
476+
builder = builder.rustfmt_bindings(true);
477+
}
478+
479+
if let Some(path_str) = matches.value_of("rustfmt-configuration-file") {
480+
let path = PathBuf::from(path_str);
481+
482+
if !path.is_absolute() {
483+
return Err(Error::new(ErrorKind::Other,
484+
"--rustfmt-configuration--file needs to be an absolute path!"));
485+
}
486+
487+
if path.to_str().is_none() {
488+
return Err(
489+
Error::new(ErrorKind::Other,
490+
"--rustfmt-configuration-file contains non-valid UTF8 characters."));
491+
}
492+
493+
builder = builder.rustfmt_configuration_file(Some(path));
494+
}
495+
461496
let verbose = matches.is_present("verbose");
462497

463498
Ok((builder, output, verbose))

0 commit comments

Comments
 (0)