Added test mod_attr project

Added impl of `fmt::Display` for `Cfg`

Added  `fn matched_defines(…)` for filtering for matches in `[defines]`

Changes semantic of `has_defines` from `∀` to `∃` (i.e. all -> one or more)

Changed `write_before` to use `matched_defines`

Added logging of warning for omitted `#[cfg(…)]`s

Added expectations for `mod_attr` test project

Renamed function arguments in `mod_attr` test project

Rustfmt

Introduced `Condition` type to ensure correct API usage of `Cfg`

Merged `Condition::Boolean` and `Condition::Named` into `Condition::Define`

Removed `DefineConfig` and `MissingDefineBehavior`.

(Was getting a bit ahead of myself with these.)

Rustfmt
This commit is contained in:
Vincent Esche
2018-08-12 21:06:24 +02:00
committed by Ryan Hunt
parent b627b8f6da
commit 68a22aac3c
16 changed files with 354 additions and 112 deletions
+142 -88
View File
@@ -2,6 +2,7 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use std::fmt;
use std::io::Write;
use syn;
@@ -9,6 +10,7 @@ use syn;
use bindgen::config::Config;
use bindgen::writer::SourceWriter;
#[derive(PartialEq, Eq)]
enum DefineKey<'a> {
Boolean(&'a str),
Named(&'a str, &'a str),
@@ -52,6 +54,36 @@ pub enum Cfg {
Not(Box<Cfg>),
}
impl fmt::Display for Cfg {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Cfg::Boolean(key) => write!(f, "{}", key),
Cfg::Named(key, value) => write!(f, "{} = {:?}", key, value),
Cfg::Any(cfgs) => {
write!(f, "any(")?;
for (index, cfg) in cfgs.iter().enumerate() {
if index > 0 {
write!(f, ", ")?;
}
write!(f, "{}", cfg)?;
}
write!(f, ")")
}
Cfg::All(cfgs) => {
write!(f, "all(")?;
for (index, cfg) in cfgs.iter().enumerate() {
if index > 0 {
write!(f, ", ")?;
}
write!(f, "{}", cfg)?;
}
write!(f, ")")
}
Cfg::Not(cfg) => write!(f, "not({})", cfg),
}
}
}
impl Cfg {
pub fn join(cfgs: &[Cfg]) -> Option<Cfg> {
if cfgs.len() == 0 {
@@ -166,139 +198,161 @@ impl Cfg {
Some(configs)
}
}
}
fn has_defines(&self, config: &Config) -> bool {
pub trait ToCondition: Sized {
type Output;
fn to_condition(self, config: &Config) -> Option<Self::Output>;
}
impl<'a> ToCondition for &'a Option<Cfg> {
type Output = Condition;
fn to_condition(self, config: &Config) -> Option<Self::Output> {
self.clone().and_then(|cfg| cfg.to_condition(config))
}
}
impl ToCondition for Option<Cfg> {
type Output = Condition;
fn to_condition(self, config: &Config) -> Option<Self::Output> {
self.and_then(|cfg| cfg.to_condition(config))
}
}
impl<'a> ToCondition for &'a Cfg {
type Output = Condition;
fn to_condition(self, config: &Config) -> Option<Self::Output> {
self.clone().to_condition(config)
}
}
impl ToCondition for Cfg {
type Output = Condition;
fn to_condition(self, config: &Config) -> Option<Self::Output> {
match self {
&Cfg::Boolean(ref cfg_name) => {
for (key, ..) in &config.defines {
let key = DefineKey::load(key);
match key {
DefineKey::Boolean(key_name) => if cfg_name == key_name {
return true;
},
DefineKey::Named(..) => {}
}
Cfg::Boolean(cfg_name) => {
let define = config
.defines
.iter()
.find(|(key, ..)| DefineKey::Boolean(&cfg_name) == DefineKey::load(key));
if let Some((_, define)) = define {
Some(Condition::Define(define.to_owned()))
} else {
warn!(
"Missing `[defines]` entry for `{}` in cbindgen config.",
Cfg::Boolean(cfg_name)
);
None
}
false
}
&Cfg::Named(ref cfg_name, ref cfg_value) => {
for (key, ..) in &config.defines {
let key = DefineKey::load(key);
match key {
DefineKey::Boolean(..) => {}
DefineKey::Named(key_name, key_value) => {
if cfg_name == key_name && cfg_value == key_value {
return true;
}
}
}
Cfg::Named(cfg_name, cfg_value) => {
let define = config.defines.iter().find(|(key, ..)| {
DefineKey::Named(&cfg_name, &cfg_value) == DefineKey::load(key)
});
if let Some((_, define)) = define {
Some(Condition::Define(define.to_owned()))
} else {
warn!(
"Missing `[defines]` entry for `{}` in cbindgen config.",
Cfg::Named(cfg_name, cfg_value)
);
None
}
false
}
&Cfg::Any(ref cfgs) => cfgs.iter().all(|x| x.has_defines(config)),
&Cfg::All(ref cfgs) => cfgs.iter().all(|x| x.has_defines(config)),
&Cfg::Not(ref cfg) => cfg.has_defines(config),
Cfg::Any(children) => {
let conditions: Vec<_> = children
.into_iter()
.filter_map(|x| x.to_condition(config))
.collect();
match conditions.len() {
0 => None,
1 => conditions.into_iter().next(),
_ => Some(Condition::Any(conditions)),
}
}
Cfg::All(children) => {
let cfgs: Vec<_> = children
.into_iter()
.filter_map(|x| x.to_condition(config))
.collect();
match cfgs.len() {
0 => None,
1 => cfgs.into_iter().next(),
_ => Some(Condition::All(cfgs)),
}
}
Cfg::Not(child) => child
.to_condition(config)
.map(|cfg| Condition::Not(Box::new(cfg))),
}
}
}
fn write_condition<F: Write>(&self, config: &Config, out: &mut SourceWriter<F>) {
#[derive(Debug, Clone)]
pub enum Condition {
Define(String),
Any(Vec<Condition>),
All(Vec<Condition>),
Not(Box<Condition>),
}
impl Condition {
fn write<F: Write>(&self, config: &Config, out: &mut SourceWriter<F>) {
match self {
&Cfg::Boolean(ref cfg_name) => {
let mut define: &str = cfg_name;
for (key, define_value) in &config.defines {
let key = DefineKey::load(key);
match key {
DefineKey::Boolean(key_name) => if cfg_name == key_name {
define = define_value;
},
DefineKey::Named(..) => {}
}
}
&Condition::Define(ref define) => {
out.write("defined(");
write!(out, "{}", define);
out.write(")");
}
&Cfg::Named(ref cfg_name, ref cfg_value) => {
let mut define: &str = cfg_name;
for (key, define_value) in &config.defines {
let key = DefineKey::load(key);
match key {
DefineKey::Boolean(..) => {}
DefineKey::Named(key_name, key_value) => {
if cfg_name == key_name && cfg_value == key_value {
define = define_value;
}
}
}
}
out.write("defined(");
write!(out, "{}", define);
out.write(")");
}
&Cfg::Any(ref cfgs) => {
&Condition::Any(ref conditions) => {
out.write("(");
for (i, cfg) in cfgs.iter().enumerate() {
for (i, condition) in conditions.iter().enumerate() {
if i != 0 {
out.write(" || ");
}
cfg.write_condition(config, out);
condition.write(config, out);
}
out.write(")");
}
&Cfg::All(ref cfgs) => {
&Condition::All(ref conditions) => {
out.write("(");
for (i, cfg) in cfgs.iter().enumerate() {
for (i, condition) in conditions.iter().enumerate() {
if i != 0 {
out.write(" && ");
}
cfg.write_condition(config, out);
condition.write(config, out);
}
out.write(")");
}
&Cfg::Not(ref cfg) => {
&Condition::Not(ref condition) => {
out.write("!");
cfg.write_condition(config, out);
condition.write(config, out);
}
}
}
}
pub trait CfgWrite {
pub trait ConditionWrite {
fn write_before<F: Write>(&self, config: &Config, out: &mut SourceWriter<F>);
fn write_after<F: Write>(&self, config: &Config, out: &mut SourceWriter<F>);
}
impl CfgWrite for Option<Cfg> {
impl ConditionWrite for Option<Condition> {
fn write_before<F: Write>(&self, config: &Config, out: &mut SourceWriter<F>) {
if let &Some(ref cfg) = self {
if !cfg.has_defines(config) {
return;
}
out.write("#if ");
cfg.write_condition(config, out);
cfg.write(config, out);
out.new_line();
}
}
fn write_after<F: Write>(&self, config: &Config, out: &mut SourceWriter<F>) {
if let &Some(ref cfg) = self {
// TODO
if !cfg.has_defines(config) {
return;
}
fn write_after<F: Write>(&self, _config: &Config, out: &mut SourceWriter<F>) {
if self.is_some() {
out.new_line();
out.write("#endif");
}
+6 -3
View File
@@ -9,7 +9,9 @@ use syn;
use bindgen::config::{Config, Language};
use bindgen::declarationtyperesolver::DeclarationTypeResolver;
use bindgen::ir::{AnnotationSet, Cfg, CfgWrite, Documentation, Item, ItemContainer, Type};
use bindgen::ir::{
AnnotationSet, Cfg, ConditionWrite, Documentation, Item, ItemContainer, ToCondition, Type,
};
use bindgen::writer::{Source, SourceWriter};
#[derive(Debug, Clone)]
@@ -137,7 +139,8 @@ impl Item for Constant {
impl Source for Constant {
fn write<F: Write>(&self, config: &Config, out: &mut SourceWriter<F>) {
self.cfg.write_before(config, out);
let condition = (&self.cfg).to_condition(config);
condition.write_before(config, out);
if config.constant.allow_static_const && config.language == Language::Cxx {
if let Type::ConstPtr(..) = self.ty {
out.write("static ");
@@ -149,6 +152,6 @@ impl Source for Constant {
} else {
write!(out, "#define {} {}", self.name, self.value.0)
}
self.cfg.write_after(config, out);
condition.write_after(config, out);
}
}
+6 -4
View File
@@ -10,8 +10,8 @@ use bindgen::config::{Config, Language};
use bindgen::declarationtyperesolver::DeclarationTypeResolver;
use bindgen::dependencies::Dependencies;
use bindgen::ir::{
AnnotationSet, Cfg, CfgWrite, Documentation, GenericParams, GenericPath, Item, ItemContainer,
Repr, ReprStyle, ReprType, Struct, Type,
AnnotationSet, Cfg, ConditionWrite, Documentation, GenericParams, GenericPath, Item,
ItemContainer, Repr, ReprStyle, ReprType, Struct, ToCondition, Type,
};
use bindgen::library::Library;
use bindgen::rename::{IdentifierType, RenameRule};
@@ -317,7 +317,9 @@ impl Source for Enum {
ReprType::I8 => "int8_t",
});
self.cfg.write_before(config, out);
let condition = (&self.cfg).to_condition(config);
condition.write_before(config, out);
self.documentation.write(config, out);
@@ -543,6 +545,6 @@ impl Source for Enum {
}
}
self.cfg.write_after(config, out);
condition.write_after(config, out);
}
}
+10 -5
View File
@@ -10,7 +10,9 @@ use bindgen::cdecl;
use bindgen::config::{Config, Language, Layout};
use bindgen::declarationtyperesolver::DeclarationTypeResolver;
use bindgen::dependencies::Dependencies;
use bindgen::ir::{AnnotationSet, Cfg, CfgWrite, Documentation, PrimitiveType, Type};
use bindgen::ir::{
AnnotationSet, Cfg, ConditionWrite, Documentation, PrimitiveType, ToCondition, Type,
};
use bindgen::library::Library;
use bindgen::monomorph::Monomorphs;
use bindgen::rename::{IdentifierType, RenameRule};
@@ -126,7 +128,8 @@ impl Source for Function {
let prefix = config.function.prefix(&func.annotations);
let postfix = config.function.postfix(&func.annotations);
func.cfg.write_before(config, out);
let condition = (&func.cfg).to_condition(config);
condition.write_before(config, out);
func.documentation.write(config, out);
@@ -147,7 +150,7 @@ impl Source for Function {
}
out.write(";");
func.cfg.write_after(config, out);
condition.write_after(config, out);
}
fn write_2<W: Write>(func: &Function, config: &Config, out: &mut SourceWriter<W>) {
@@ -155,7 +158,9 @@ impl Source for Function {
let prefix = config.function.prefix(&func.annotations);
let postfix = config.function.postfix(&func.annotations);
func.cfg.write_before(config, out);
let condition = (&func.cfg).to_condition(config);
condition.write_before(config, out);
func.documentation.write(config, out);
@@ -176,7 +181,7 @@ impl Source for Function {
}
out.write(";");
func.cfg.write_after(config, out);
condition.write_after(config, out);
};
let option_1 = out.measure(|out| write_1(self, config, out));
+5 -3
View File
@@ -10,7 +10,8 @@ use bindgen::config::{Config, Language};
use bindgen::declarationtyperesolver::DeclarationTypeResolver;
use bindgen::dependencies::Dependencies;
use bindgen::ir::{
AnnotationSet, Cfg, CfgWrite, Documentation, GenericParams, Item, ItemContainer, Path, Type,
AnnotationSet, Cfg, ConditionWrite, Documentation, GenericParams, Item, ItemContainer, Path,
ToCondition, Type,
};
use bindgen::library::Library;
use bindgen::mangle;
@@ -107,7 +108,8 @@ impl Item for OpaqueItem {
impl Source for OpaqueItem {
fn write<F: Write>(&self, config: &Config, out: &mut SourceWriter<F>) {
self.cfg.write_before(config, out);
let condition = (&self.cfg).to_condition(config);
condition.write_before(config, out);
self.documentation.write(config, out);
@@ -119,6 +121,6 @@ impl Source for OpaqueItem {
write!(out, "struct {};", self.name);
}
self.cfg.write_after(config, out);
condition.write_after(config, out);
}
}
+5 -3
View File
@@ -10,7 +10,8 @@ use bindgen::config::{Config, Language};
use bindgen::declarationtyperesolver::DeclarationTypeResolver;
use bindgen::dependencies::Dependencies;
use bindgen::ir::{
AnnotationSet, Cfg, CfgWrite, Documentation, GenericParams, Item, ItemContainer, Repr, Type,
AnnotationSet, Cfg, ConditionWrite, Documentation, GenericParams, Item, ItemContainer, Repr,
ToCondition, Type,
};
use bindgen::library::Library;
use bindgen::mangle;
@@ -234,7 +235,8 @@ impl Item for Struct {
impl Source for Struct {
fn write<F: Write>(&self, config: &Config, out: &mut SourceWriter<F>) {
self.cfg.write_before(config, out);
let condition = (&self.cfg).to_condition(config);
condition.write_before(config, out);
self.documentation.write(config, out);
@@ -396,7 +398,7 @@ impl Source for Struct {
out.close_brace(true);
}
self.cfg.write_after(config, out);
condition.write_after(config, out);
}
}
+5 -3
View File
@@ -11,7 +11,8 @@ use bindgen::config::{Config, Language};
use bindgen::declarationtyperesolver::DeclarationTypeResolver;
use bindgen::dependencies::Dependencies;
use bindgen::ir::{
AnnotationSet, Cfg, CfgWrite, Documentation, GenericParams, Item, ItemContainer, Path, Type,
AnnotationSet, Cfg, ConditionWrite, Documentation, GenericParams, Item, ItemContainer, Path,
ToCondition, Type,
};
use bindgen::library::Library;
use bindgen::mangle;
@@ -168,7 +169,8 @@ impl Item for Typedef {
impl Source for Typedef {
fn write<F: Write>(&self, config: &Config, out: &mut SourceWriter<F>) {
self.cfg.write_before(config, out);
let condition = (&self.cfg).to_condition(config);
condition.write_before(config, out);
self.documentation.write(config, out);
@@ -183,6 +185,6 @@ impl Source for Typedef {
}
out.write(";");
self.cfg.write_after(config, out);
condition.write_after(config, out);
}
}
+5 -3
View File
@@ -11,7 +11,8 @@ use bindgen::declarationtyperesolver::DeclarationTypeResolver;
use bindgen::dependencies::Dependencies;
use bindgen::ir::SynFieldHelpers;
use bindgen::ir::{
AnnotationSet, Cfg, CfgWrite, Documentation, GenericParams, Item, ItemContainer, Repr, Type,
AnnotationSet, Cfg, ConditionWrite, Documentation, GenericParams, Item, ItemContainer, Repr,
ToCondition, Type,
};
use bindgen::library::Library;
use bindgen::mangle;
@@ -220,7 +221,8 @@ impl Item for Union {
impl Source for Union {
fn write<F: Write>(&self, config: &Config, out: &mut SourceWriter<F>) {
self.cfg.write_before(config, out);
let condition = (&self.cfg).to_condition(config);
condition.write_before(config, out);
self.documentation.write(config, out);
@@ -265,6 +267,6 @@ impl Source for Union {
out.close_brace(true);
}
self.cfg.write_after(config, out);
condition.write_after(config, out);
}
}
+31
View File
@@ -0,0 +1,31 @@
#include <stdint.h>
#include <stdlib.h>
#include <stdbool.h>
#if defined(BAR)
#define BAR 2
#endif
#if defined(FOO)
#define FOO 1
#endif
#if defined(BAR)
typedef struct Bar {
} Bar;
#endif
#if defined(FOO)
typedef struct Foo {
} Foo;
#endif
#if defined(BAR)
void bar(const Bar *bar);
#endif
#if defined(FOO)
void foo(const Foo *foo);
#endif
+31
View File
@@ -0,0 +1,31 @@
#include <stdint.h>
#include <stdlib.h>
#include <stdbool.h>
#if defined(BAR)
#define BAR 2
#endif
#if defined(FOO)
#define FOO 1
#endif
#if defined(BAR)
typedef struct {
} Bar;
#endif
#if defined(FOO)
typedef struct {
} Foo;
#endif
#if defined(BAR)
void bar(const Bar *bar);
#endif
#if defined(FOO)
void foo(const Foo *foo);
#endif
+34
View File
@@ -0,0 +1,34 @@
#include <cstdint>
#include <cstdlib>
#if defined(BAR)
static const int32_t BAR = 2;
#endif
#if defined(FOO)
static const int32_t FOO = 1;
#endif
#if defined(BAR)
struct Bar {
};
#endif
#if defined(FOO)
struct Foo {
};
#endif
extern "C" {
#if defined(BAR)
void bar(const Bar *bar);
#endif
#if defined(FOO)
void foo(const Foo *foo);
#endif
} // extern "C"
+31
View File
@@ -0,0 +1,31 @@
#include <stdint.h>
#include <stdlib.h>
#include <stdbool.h>
#if defined(BAR)
#define BAR 2
#endif
#if defined(FOO)
#define FOO 1
#endif
#if defined(BAR)
struct Bar {
};
#endif
#if defined(FOO)
struct Foo {
};
#endif
#if defined(BAR)
void bar(const struct Bar *bar);
#endif
#if defined(FOO)
void foo(const struct Foo *foo);
#endif
+4
View File
@@ -0,0 +1,4 @@
[[package]]
name = "mod_attr"
version = "0.1.0"
+11
View File
@@ -0,0 +1,11 @@
[package]
name = "mod_attr"
version = "0.1.0"
authors = ["cbindgen"]
[lib]
name = "mod_attr"
crate-type = ["lib", "dylib"]
[features]
foobar = []
+4
View File
@@ -0,0 +1,4 @@
[defines]
"foo" = "FOO"
"bar" = "BAR"
# "feature = foobar" = "FOOBAR"
+24
View File
@@ -0,0 +1,24 @@
#[cfg(foo)]
pub const FOO: i32 = 1;
#[cfg(foo)]
#[no_mangle]
pub unsafe extern "C" fn foo(foo: &Foo) {}
#[cfg(foo)]
#[repr(C)]
pub struct Foo {}
#[cfg(feature = "foobar")]
pub mod foo {
#[cfg(bar)]
pub const BAR: i32 = 2;
#[cfg(bar)]
#[no_mangle]
pub unsafe extern "C" fn bar(bar: &Bar) {}
#[cfg(bar)]
#[repr(C)]
pub struct Bar {}
}