Skip to content

Commit 90a68cd

Browse files
committed
Parse annotations.
1 parent e00a8a1 commit 90a68cd

File tree

6 files changed

+135
-13
lines changed

6 files changed

+135
-13
lines changed

src/ir/annotations.rs

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
use clang;
2+
3+
#[derive(Copy, PartialEq, Clone, Debug)]
4+
pub enum FieldAccessorKind {
5+
None,
6+
Regular,
7+
Unsafe,
8+
Immutable,
9+
}
10+
11+
/// Annotations for a given item, or a field.
12+
#[derive(Clone, PartialEq, Debug)]
13+
pub struct Annotations {
14+
/// Whether this item is marked as opaque. Only applies to types.
15+
opaque: bool,
16+
/// Whether this item should be hidden from the output. Only applies to
17+
/// types.
18+
hide: bool,
19+
/// Whether this type should be replaced by another. The name must be the
20+
/// canonical name that that type would get.
21+
use_as: Option<String>,
22+
/// Manually disable deriving copy/clone on this type. Only applies to
23+
/// struct or union types.
24+
no_copy: bool,
25+
/// Whether fields should be marked as private or not. You can set this on
26+
/// structs (it will apply to all the fields), or individual fields.
27+
private_fields: Option<bool>,
28+
/// The kind of accessor this field will have. Also can be applied to
29+
/// structs so all the fields inside share it by default.
30+
accessor_kind: Option<FieldAccessorKind>,
31+
}
32+
33+
fn parse_accessor(s: &str) -> FieldAccessorKind {
34+
match s {
35+
"false" => FieldAccessorKind::None,
36+
"unsafe" => FieldAccessorKind::Unsafe,
37+
"immutable" => FieldAccessorKind::Immutable,
38+
_ => FieldAccessorKind::Regular,
39+
}
40+
}
41+
42+
impl Default for Annotations {
43+
fn default() -> Self {
44+
Annotations {
45+
opaque: false,
46+
hide: false,
47+
use_as: None,
48+
no_copy: false,
49+
private_fields: None,
50+
accessor_kind: None
51+
}
52+
}
53+
}
54+
55+
impl Annotations {
56+
pub fn new(cursor: &clang::Cursor) -> Option<Annotations> {
57+
let mut anno = Annotations::default();
58+
let mut matched_one = false;
59+
anno.parse(&cursor.comment(), &mut matched_one);
60+
61+
if matched_one {
62+
Some(anno)
63+
} else {
64+
None
65+
}
66+
}
67+
68+
fn parse(&mut self, comment: &clang::Comment, matched: &mut bool) {
69+
use clangll::CXComment_HTMLStartTag;
70+
if comment.kind() == CXComment_HTMLStartTag &&
71+
comment.get_tag_name() == "div" &&
72+
comment.get_num_tag_attrs() > 1 &&
73+
comment.get_tag_attr_name(0) == "rustbindgen" {
74+
*matched = true;
75+
for i in 0..comment.get_num_tag_attrs() {
76+
let value = comment.get_tag_attr_value(i);
77+
let name = comment.get_tag_attr_name(i);
78+
match name.as_str() {
79+
"opaque" => self.opaque = true,
80+
"hide" => self.hide = true,
81+
"nocopy" => self.no_copy = true,
82+
"replaces" => self.use_as = Some(value),
83+
"private" => self.private_fields = Some(value != "false"),
84+
"accessor"
85+
=> self.accessor_kind = Some(parse_accessor(&value)),
86+
_ => {},
87+
}
88+
}
89+
}
90+
91+
for i in 0..comment.num_children() {
92+
self.parse(&comment.get_child(i), matched);
93+
}
94+
}
95+
}
96+

src/ir/comp.rs

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use super::annotations::Annotations;
12
use super::context::BindgenContext;
23
use super::context::TypeResolver;
34
use super::layout::Layout;
@@ -70,6 +71,7 @@ impl Field {
7071
pub fn new(name: String,
7172
ty: ItemId,
7273
comment: Option<String>,
74+
annotations: Option<Annotations>,
7375
bitfield: Option<u32>,
7476
mutable: bool) -> Field {
7577
Field {
@@ -391,12 +393,17 @@ impl CompInfo {
391393
let field_type = Item::from_ty(&cur.cur_type(), Some(*cur), Some(potential_id), ctx)
392394
.expect("FieldDecl?");
393395
let comment = cur.raw_comment();
396+
let annotations = Annotations::new(cur);
394397
let name = cur.spelling();
395398
let is_mutable = cursor.is_mutable_field();
399+
396400
// Name can be empty if there are bitfields, for example,
397401
// see tests/headers/struct_with_bitfields.h
398-
assert!(!name.is_empty() || bit_width.is_some(), "Empty field name?");
399-
let field = Field::new(name, field_type, comment, bit_width, is_mutable);
402+
assert!(!name.is_empty() || bit_width.is_some(),
403+
"Empty field name?");
404+
405+
let field = Field::new(name, field_type, comment,
406+
annotations, bit_width, is_mutable);
400407
ci.fields.push(field)
401408
}
402409
CXCursor_EnumDecl |

src/ir/context.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -238,7 +238,7 @@ impl<'ctx> BindgenContext<'ctx> {
238238
fn build_root_module() -> Item {
239239
let module = Module::new(None, None);
240240
let id = ItemId::next();
241-
Item::new(id, None, id, ItemKind::Module(module))
241+
Item::new(id, None, None, id, ItemKind::Module(module))
242242
}
243243

244244
pub fn root_module(&self) -> ItemId {
@@ -343,7 +343,7 @@ impl<'ctx> BindgenContext<'ctx> {
343343
let name = ty.spelling();
344344
let name = if name.is_empty() { None } else { Some(name) };
345345
let ty = Type::new(name, ty.fallible_layout().ok(), type_kind, ty.is_const());
346-
Item::new(self_id, None, parent_id, ItemKind::Type(ty))
346+
Item::new(self_id, None, None, parent_id, ItemKind::Type(ty))
347347
};
348348

349349
// Bypass all the validations in add_item explicitly.
@@ -433,7 +433,7 @@ impl<'ctx> BindgenContext<'ctx> {
433433
let layout = ty.fallible_layout().ok();
434434
let ty = Type::new(Some(spelling), layout, type_kind, is_const);
435435
let id = ItemId::next();
436-
let item = Item::new(id, None, self.root_module, ItemKind::Type(ty));
436+
let item = Item::new(id, None, None, self.root_module, ItemKind::Type(ty));
437437
self.add_builtin_item(item);
438438
Some(id)
439439
}

src/ir/function.rs

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,20 @@ pub struct Function {
1616
mangled_name: Option<String>,
1717
/// The id pointing to the current function signature.
1818
signature: ItemId,
19+
/// The doc comment on the function, if any.
20+
comment: Option<String>,
1921
}
2022

2123
impl Function {
22-
pub fn new(name: String, mangled_name: Option<String>, sig: ItemId) -> Self {
24+
pub fn new(name: String,
25+
mangled_name: Option<String>,
26+
sig: ItemId,
27+
comment: Option<String>) -> Self {
2328
Function {
2429
name: name,
2530
mangled_name: mangled_name,
2631
signature: sig,
32+
comment: comment,
2733
}
2834
}
2935

@@ -180,7 +186,9 @@ impl ClangSubItemParser for Function {
180186
mangled_name = None;
181187
}
182188

183-
let function = Self::new(name, mangled_name, sig);
189+
let comment = cursor.raw_comment();
190+
191+
let function = Self::new(name, mangled_name, sig, comment);
184192
Ok(ParseResult::New(function, Some(cursor)))
185193
}
186194
}

src/ir/item.rs

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use super::context::BindgenContext;
22
use super::item_kind::ItemKind;
33
use super::ty::{Type, TypeKind};
4+
use super::annotations::Annotations;
45
use std::fmt;
56
use std::sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT, Ordering};
67
use parse::{ClangItemParser, ClangSubItemParser, ParseError, ParseResult};
@@ -31,28 +32,33 @@ impl ItemId {
3132
pub struct Item {
3233
/// This item's id.
3334
id: ItemId,
35+
/// A doc comment over the item, if any.
36+
comment: Option<String>,
37+
/// Annotations extracted from the doc comment, or the default ones
38+
/// otherwise.
39+
annotations: Annotations,
3440
/// An item's parent id. This will most likely be a class where this item
3541
/// was declared, or a module, etc.
3642
///
3743
/// All the items have a parent, except the root module, in which case the
3844
/// parent id is its own id.
3945
parent_id: ItemId,
40-
/// A doc comment over the item, if any.
41-
comment: Option<String>,
4246
/// The item kind.
4347
kind: ItemKind,
4448
}
4549

4650
impl Item {
4751
pub fn new(id: ItemId,
4852
comment: Option<String>,
53+
annotations: Option<Annotations>,
4954
parent_id: ItemId,
5055
kind: ItemKind) -> Self {
5156
debug_assert!(id != parent_id || kind.is_module());
5257
Item {
5358
id: id,
5459
parent_id: parent_id,
5560
comment: comment,
61+
annotations: annotations.unwrap_or_default(),
5662
kind: kind,
5763
}
5864
}
@@ -93,7 +99,7 @@ impl ClangItemParser for Item {
9399
let ty = Type::new(None, None, kind, is_const);
94100
let id = ItemId::next();
95101
let module = ctx.root_module();
96-
ctx.add_item(Item::new(id, None, module, ItemKind::Type(ty)),
102+
ctx.add_item(Item::new(id, None, None, module, ItemKind::Type(ty)),
97103
None, None);
98104
id
99105
}
@@ -113,6 +119,7 @@ impl ClangItemParser for Item {
113119
}
114120

115121
let comment = cursor.raw_comment();
122+
let annotations = Annotations::new(&cursor);
116123

117124
// FIXME: The current_module logic is not really accurate. We should be
118125
// able to index modules by their Cursor, and locate the proper module
@@ -126,7 +133,7 @@ impl ClangItemParser for Item {
126133
match $what::parse(cursor, context) {
127134
Ok(ParseResult::New(item, declaration)) => {
128135
let id = ItemId::next();
129-
context.add_item(Item::new(id, comment,
136+
context.add_item(Item::new(id, comment, annotations,
130137
parent_id.unwrap_or(current_module),
131138
ItemKind::$what(item)),
132139
declaration,
@@ -193,6 +200,9 @@ impl ClangItemParser for Item {
193200
let comment =
194201
definition.raw_comment()
195202
.or_else(|| location.as_ref().and_then(|l| l.raw_comment()));
203+
let annotations =
204+
Annotations::new(&definition)
205+
.or_else(|| location.as_ref().and_then(|l| Annotations::new(l)));
196206

197207
if let Some(ty) = context.builtin_or_resolved_ty(parent_id, ty, location) {
198208
return Ok(ty);
@@ -228,7 +238,7 @@ impl ClangItemParser for Item {
228238
let ret = match result {
229239
Ok(ParseResult::AlreadyResolved(ty)) => Ok(ty),
230240
Ok(ParseResult::New(item, declaration)) => {
231-
context.add_item(Item::new(id, comment,
241+
context.add_item(Item::new(id, comment, annotations,
232242
parent_id.unwrap_or(current_module),
233243
ItemKind::Type(item)),
234244
declaration,
@@ -306,7 +316,7 @@ impl ClangItemParser for Item {
306316
{
307317
let name = name.into();
308318

309-
context.add_item(Item::new(id, None, parent_id,
319+
context.add_item(Item::new(id, None, None, parent_id,
310320
ItemKind::Type(Type::named(name))),
311321
None,
312322
None);

src/ir/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
pub mod annotations;
12
pub mod comp;
23
pub mod context;
34
pub mod enum_ty;

0 commit comments

Comments
 (0)