1 //! Intermediate representation of variables.
2 
3 use callbacks::MacroParsingBehavior;
4 use super::context::{BindgenContext, TypeId};
5 use super::dot::DotAttributes;
6 use super::function::cursor_mangling;
7 use super::int::IntKind;
8 use super::item::Item;
9 use super::ty::{FloatKind, TypeKind};
10 use cexpr;
11 use clang;
12 use parse::{ClangItemParser, ClangSubItemParser, ParseError, ParseResult};
13 use std::io;
14 use std::num::Wrapping;
15 
16 /// The type for a constant variable.
17 #[derive(Debug)]
18 pub enum VarType {
19     /// A boolean.
20     Bool(bool),
21     /// An integer.
22     Int(i64),
23     /// A floating point number.
24     Float(f64),
25     /// A character.
26     Char(u8),
27     /// A string, not necessarily well-formed utf-8.
28     String(Vec<u8>),
29 }
30 
31 /// A `Var` is our intermediate representation of a variable.
32 #[derive(Debug)]
33 pub struct Var {
34     /// The name of the variable.
35     name: String,
36     /// The mangled name of the variable.
37     mangled_name: Option<String>,
38     /// The type of the variable.
39     ty: TypeId,
40     /// The value of the variable, that needs to be suitable for `ty`.
41     val: Option<VarType>,
42     /// Whether this variable is const.
43     is_const: bool,
44 }
45 
46 impl Var {
47     /// Construct a new `Var`.
new( name: String, mangled_name: Option<String>, ty: TypeId, val: Option<VarType>, is_const: bool, ) -> Var48     pub fn new(
49         name: String,
50         mangled_name: Option<String>,
51         ty: TypeId,
52         val: Option<VarType>,
53         is_const: bool,
54     ) -> Var {
55         assert!(!name.is_empty());
56         Var {
57             name,
58             mangled_name,
59             ty,
60             val,
61             is_const,
62         }
63     }
64 
65     /// Is this variable `const` qualified?
is_const(&self) -> bool66     pub fn is_const(&self) -> bool {
67         self.is_const
68     }
69 
70     /// The value of this constant variable, if any.
val(&self) -> Option<&VarType>71     pub fn val(&self) -> Option<&VarType> {
72         self.val.as_ref()
73     }
74 
75     /// Get this variable's type.
ty(&self) -> TypeId76     pub fn ty(&self) -> TypeId {
77         self.ty
78     }
79 
80     /// Get this variable's name.
name(&self) -> &str81     pub fn name(&self) -> &str {
82         &self.name
83     }
84 
85     /// Get this variable's mangled name.
mangled_name(&self) -> Option<&str>86     pub fn mangled_name(&self) -> Option<&str> {
87         self.mangled_name.as_ref().map(|n| &**n)
88     }
89 }
90 
91 impl DotAttributes for Var {
dot_attributes<W>( &self, _ctx: &BindgenContext, out: &mut W, ) -> io::Result<()> where W: io::Write,92     fn dot_attributes<W>(
93         &self,
94         _ctx: &BindgenContext,
95         out: &mut W,
96     ) -> io::Result<()>
97     where
98         W: io::Write,
99     {
100         if self.is_const {
101             writeln!(out, "<tr><td>const</td><td>true</td></tr>")?;
102         }
103 
104         if let Some(ref mangled) = self.mangled_name {
105             writeln!(
106                 out,
107                 "<tr><td>mangled name</td><td>{}</td></tr>",
108                 mangled
109             )?;
110         }
111 
112         Ok(())
113     }
114 }
115 
116 // TODO(emilio): we could make this more (or less) granular, I guess.
default_macro_constant_type(value: i64) -> IntKind117 fn default_macro_constant_type(value: i64) -> IntKind {
118     if value < 0 {
119         if value < i32::min_value() as i64 {
120             IntKind::I64
121         } else {
122             IntKind::I32
123         }
124     } else if value > u32::max_value() as i64 {
125         IntKind::U64
126     } else {
127         IntKind::U32
128     }
129 }
130 
131 impl ClangSubItemParser for Var {
parse( cursor: clang::Cursor, ctx: &mut BindgenContext, ) -> Result<ParseResult<Self>, ParseError>132     fn parse(
133         cursor: clang::Cursor,
134         ctx: &mut BindgenContext,
135     ) -> Result<ParseResult<Self>, ParseError> {
136         use clang_sys::*;
137         use cexpr::expr::EvalResult;
138         use cexpr::literal::CChar;
139         match cursor.kind() {
140             CXCursor_MacroDefinition => {
141                 if let Some(callbacks) = ctx.parse_callbacks() {
142                     match callbacks.will_parse_macro(&cursor.spelling()) {
143                         MacroParsingBehavior::Ignore => {
144                             return Err(ParseError::Continue);
145                         }
146                         MacroParsingBehavior::Default => {}
147                     }
148                 }
149 
150                 let value = parse_macro(ctx, &cursor);
151 
152                 let (id, value) = match value {
153                     Some(v) => v,
154                     None => return Err(ParseError::Continue),
155                 };
156 
157                 assert!(!id.is_empty(), "Empty macro name?");
158 
159                 let previously_defined = ctx.parsed_macro(&id);
160 
161                 // NB: It's important to "note" the macro even if the result is
162                 // not an integer, otherwise we might loose other kind of
163                 // derived macros.
164                 ctx.note_parsed_macro(id.clone(), value.clone());
165 
166                 if previously_defined {
167                     let name = String::from_utf8(id).unwrap();
168                     warn!("Duplicated macro definition: {}", name);
169                     return Err(ParseError::Continue);
170                 }
171 
172                 // NOTE: Unwrapping, here and above, is safe, because the
173                 // identifier of a token comes straight from clang, and we
174                 // enforce utf8 there, so we should have already panicked at
175                 // this point.
176                 let name = String::from_utf8(id).unwrap();
177                 let (type_kind, val) = match value {
178                     EvalResult::Invalid => return Err(ParseError::Continue),
179                     EvalResult::Float(f) => {
180                         (TypeKind::Float(FloatKind::Double), VarType::Float(f))
181                     }
182                     EvalResult::Char(c) => {
183                         let c = match c {
184                             CChar::Char(c) => {
185                                 assert_eq!(c.len_utf8(), 1);
186                                 c as u8
187                             }
188                             CChar::Raw(c) => {
189                                 assert!(c <= ::std::u8::MAX as u64);
190                                 c as u8
191                             }
192                         };
193 
194                         (TypeKind::Int(IntKind::U8), VarType::Char(c))
195                     }
196                     EvalResult::Str(val) => {
197                         let char_ty = Item::builtin_type(
198                             TypeKind::Int(IntKind::U8),
199                             true,
200                             ctx,
201                         );
202                         if let Some(callbacks) = ctx.parse_callbacks() {
203                             callbacks.str_macro(&name, &val);
204                         }
205                         (TypeKind::Pointer(char_ty), VarType::String(val))
206                     }
207                     EvalResult::Int(Wrapping(value)) => {
208                         let kind = ctx.parse_callbacks()
209                             .and_then(|c| c.int_macro(&name, value))
210                             .unwrap_or_else(|| default_macro_constant_type(value));
211 
212                         (TypeKind::Int(kind), VarType::Int(value))
213                     }
214                 };
215 
216                 let ty = Item::builtin_type(type_kind, true, ctx);
217 
218                 Ok(ParseResult::New(
219                     Var::new(name, None, ty, Some(val), true),
220                     Some(cursor),
221                 ))
222             }
223             CXCursor_VarDecl => {
224                 let name = cursor.spelling();
225                 if name.is_empty() {
226                     warn!("Empty constant name?");
227                     return Err(ParseError::Continue);
228                 }
229 
230                 let ty = cursor.cur_type();
231 
232                 // XXX this is redundant, remove!
233                 let is_const = ty.is_const();
234 
235                 let ty = match Item::from_ty(&ty, cursor, None, ctx) {
236                     Ok(ty) => ty,
237                     Err(e) => {
238                         assert_eq!(
239                             ty.kind(),
240                             CXType_Auto,
241                             "Couldn't resolve constant type, and it \
242                                    wasn't an nondeductible auto type!"
243                         );
244                         return Err(e);
245                     }
246                 };
247 
248                 // Note: Ty might not be totally resolved yet, see
249                 // tests/headers/inner_const.hpp
250                 //
251                 // That's fine because in that case we know it's not a literal.
252                 let canonical_ty = ctx.safe_resolve_type(ty).and_then(|t| {
253                     t.safe_canonical_type(ctx)
254                 });
255 
256                 let is_integer = canonical_ty.map_or(false, |t| t.is_integer());
257                 let is_float = canonical_ty.map_or(false, |t| t.is_float());
258 
259                 // TODO: We could handle `char` more gracefully.
260                 // TODO: Strings, though the lookup is a bit more hard (we need
261                 // to look at the canonical type of the pointee too, and check
262                 // is char, u8, or i8 I guess).
263                 let value = if is_integer {
264                     let kind = match *canonical_ty.unwrap().kind() {
265                         TypeKind::Int(kind) => kind,
266                         _ => unreachable!(),
267                     };
268 
269                     let mut val = cursor
270                         .evaluate()
271                         .and_then(|v| v.as_int());
272                     if val.is_none() || !kind.signedness_matches(val.unwrap()) {
273                         let tu = ctx.translation_unit();
274                         val = get_integer_literal_from_cursor(&cursor, tu);
275                     }
276 
277                     val.map(|val| if kind == IntKind::Bool {
278                         VarType::Bool(val != 0)
279                     } else {
280                         VarType::Int(val)
281                     })
282                 } else if is_float {
283                     cursor.evaluate().and_then(|v| v.as_double()).map(
284                         VarType::Float,
285                     )
286                 } else {
287                     cursor.evaluate().and_then(|v| v.as_literal_string()).map(
288                         VarType::String,
289                     )
290                 };
291 
292                 let mangling = cursor_mangling(ctx, &cursor);
293                 let var = Var::new(name, mangling, ty, value, is_const);
294 
295                 Ok(ParseResult::New(var, Some(cursor)))
296             }
297             _ => {
298                 /* TODO */
299                 Err(ParseError::Continue)
300             }
301         }
302     }
303 }
304 
305 /// Try and parse a macro using all the macros parsed until now.
parse_macro( ctx: &BindgenContext, cursor: &clang::Cursor, ) -> Option<(Vec<u8>, cexpr::expr::EvalResult)>306 fn parse_macro(
307     ctx: &BindgenContext,
308     cursor: &clang::Cursor,
309 ) -> Option<(Vec<u8>, cexpr::expr::EvalResult)> {
310     use cexpr::expr;
311 
312     let mut cexpr_tokens = cursor.cexpr_tokens();
313 
314     let parser = expr::IdentifierParser::new(ctx.parsed_macros());
315 
316     match parser.macro_definition(&cexpr_tokens) {
317         Ok((_, (id, val))) => {
318             return Some((id.into(), val));
319         }
320         _ => {}
321     }
322 
323     // Try without the last token, to workaround a libclang bug in versions
324     // previous to 4.0.
325     //
326     // See:
327     //   https://bugs.llvm.org//show_bug.cgi?id=9069
328     //   https://reviews.llvm.org/D26446
329     cexpr_tokens.pop()?;
330 
331     match parser.macro_definition(&cexpr_tokens) {
332         Ok((_, (id, val))) => Some((id.into(), val)),
333         _ => None,
334     }
335 }
336 
parse_int_literal_tokens(cursor: &clang::Cursor) -> Option<i64>337 fn parse_int_literal_tokens(cursor: &clang::Cursor) -> Option<i64> {
338     use cexpr::expr;
339     use cexpr::expr::EvalResult;
340 
341     let cexpr_tokens = cursor.cexpr_tokens();
342 
343     // TODO(emilio): We can try to parse other kinds of literals.
344     match expr::expr(&cexpr_tokens) {
345         Ok((_, EvalResult::Int(Wrapping(val)))) => Some(val),
346         _ => None,
347     }
348 }
349 
get_integer_literal_from_cursor( cursor: &clang::Cursor, unit: &clang::TranslationUnit, ) -> Option<i64>350 fn get_integer_literal_from_cursor(
351     cursor: &clang::Cursor,
352     unit: &clang::TranslationUnit,
353 ) -> Option<i64> {
354     use clang_sys::*;
355     let mut value = None;
356     cursor.visit(|c| {
357         match c.kind() {
358             CXCursor_IntegerLiteral |
359             CXCursor_UnaryOperator => {
360                 value = parse_int_literal_tokens(&c);
361             }
362             CXCursor_UnexposedExpr => {
363                 value = get_integer_literal_from_cursor(&c, unit);
364             }
365             _ => (),
366         }
367         if value.is_some() {
368             CXChildVisit_Break
369         } else {
370             CXChildVisit_Continue
371         }
372     });
373     value
374 }
375