1 //! Intermediate representation of variables.
2
3 use super::super::codegen::MacroTypeVariation;
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 crate::callbacks::{ItemInfo, ItemKind, MacroParsingBehavior};
11 use crate::clang;
12 use crate::clang::ClangToken;
13 use crate::parse::{ClangSubItemParser, ParseError, ParseResult};
14 use cexpr;
15 use std::io;
16 use std::num::Wrapping;
17
18 /// The type for a constant variable.
19 #[derive(Debug)]
20 pub enum VarType {
21 /// A boolean.
22 Bool(bool),
23 /// An integer.
24 Int(i64),
25 /// A floating point number.
26 Float(f64),
27 /// A character.
28 Char(u8),
29 /// A string, not necessarily well-formed utf-8.
30 String(Vec<u8>),
31 }
32
33 /// A `Var` is our intermediate representation of a variable.
34 #[derive(Debug)]
35 pub struct Var {
36 /// The name of the variable.
37 name: String,
38 /// The mangled name of the variable.
39 mangled_name: Option<String>,
40 /// The type of the variable.
41 ty: TypeId,
42 /// The value of the variable, that needs to be suitable for `ty`.
43 val: Option<VarType>,
44 /// Whether this variable is const.
45 is_const: bool,
46 }
47
48 impl Var {
49 /// Construct a new `Var`.
new( name: String, mangled_name: Option<String>, ty: TypeId, val: Option<VarType>, is_const: bool, ) -> Var50 pub fn new(
51 name: String,
52 mangled_name: Option<String>,
53 ty: TypeId,
54 val: Option<VarType>,
55 is_const: bool,
56 ) -> Var {
57 assert!(!name.is_empty());
58 Var {
59 name,
60 mangled_name,
61 ty,
62 val,
63 is_const,
64 }
65 }
66
67 /// Is this variable `const` qualified?
is_const(&self) -> bool68 pub fn is_const(&self) -> bool {
69 self.is_const
70 }
71
72 /// The value of this constant variable, if any.
val(&self) -> Option<&VarType>73 pub fn val(&self) -> Option<&VarType> {
74 self.val.as_ref()
75 }
76
77 /// Get this variable's type.
ty(&self) -> TypeId78 pub fn ty(&self) -> TypeId {
79 self.ty
80 }
81
82 /// Get this variable's name.
name(&self) -> &str83 pub fn name(&self) -> &str {
84 &self.name
85 }
86
87 /// Get this variable's mangled name.
mangled_name(&self) -> Option<&str>88 pub fn mangled_name(&self) -> Option<&str> {
89 self.mangled_name.as_deref()
90 }
91 }
92
93 impl DotAttributes for Var {
dot_attributes<W>( &self, _ctx: &BindgenContext, out: &mut W, ) -> io::Result<()> where W: io::Write,94 fn dot_attributes<W>(
95 &self,
96 _ctx: &BindgenContext,
97 out: &mut W,
98 ) -> io::Result<()>
99 where
100 W: io::Write,
101 {
102 if self.is_const {
103 writeln!(out, "<tr><td>const</td><td>true</td></tr>")?;
104 }
105
106 if let Some(ref mangled) = self.mangled_name {
107 writeln!(
108 out,
109 "<tr><td>mangled name</td><td>{}</td></tr>",
110 mangled
111 )?;
112 }
113
114 Ok(())
115 }
116 }
117
default_macro_constant_type(ctx: &BindgenContext, value: i64) -> IntKind118 fn default_macro_constant_type(ctx: &BindgenContext, value: i64) -> IntKind {
119 if value < 0 ||
120 ctx.options().default_macro_constant_type ==
121 MacroTypeVariation::Signed
122 {
123 if value < i32::min_value() as i64 || value > i32::max_value() as i64 {
124 IntKind::I64
125 } else if !ctx.options().fit_macro_constants ||
126 value < i16::min_value() as i64 ||
127 value > i16::max_value() as i64
128 {
129 IntKind::I32
130 } else if value < i8::min_value() as i64 ||
131 value > i8::max_value() as i64
132 {
133 IntKind::I16
134 } else {
135 IntKind::I8
136 }
137 } else if value > u32::max_value() as i64 {
138 IntKind::U64
139 } else if !ctx.options().fit_macro_constants ||
140 value > u16::max_value() as i64
141 {
142 IntKind::U32
143 } else if value > u8::max_value() as i64 {
144 IntKind::U16
145 } else {
146 IntKind::U8
147 }
148 }
149
150 /// Parses tokens from a CXCursor_MacroDefinition pointing into a function-like
151 /// macro, and calls the func_macro callback.
handle_function_macro( cursor: &clang::Cursor, callbacks: &dyn crate::callbacks::ParseCallbacks, )152 fn handle_function_macro(
153 cursor: &clang::Cursor,
154 callbacks: &dyn crate::callbacks::ParseCallbacks,
155 ) {
156 let is_closing_paren = |t: &ClangToken| {
157 // Test cheap token kind before comparing exact spellings.
158 t.kind == clang_sys::CXToken_Punctuation && t.spelling() == b")"
159 };
160 let tokens: Vec<_> = cursor.tokens().iter().collect();
161 if let Some(boundary) = tokens.iter().position(is_closing_paren) {
162 let mut spelled = tokens.iter().map(ClangToken::spelling);
163 // Add 1, to convert index to length.
164 let left = spelled.by_ref().take(boundary + 1);
165 let left = left.collect::<Vec<_>>().concat();
166 if let Ok(left) = String::from_utf8(left) {
167 let right: Vec<_> = spelled.collect();
168 callbacks.func_macro(&left, &right);
169 }
170 }
171 }
172
173 impl ClangSubItemParser for Var {
parse( cursor: clang::Cursor, ctx: &mut BindgenContext, ) -> Result<ParseResult<Self>, ParseError>174 fn parse(
175 cursor: clang::Cursor,
176 ctx: &mut BindgenContext,
177 ) -> Result<ParseResult<Self>, ParseError> {
178 use cexpr::expr::EvalResult;
179 use cexpr::literal::CChar;
180 use clang_sys::*;
181 match cursor.kind() {
182 CXCursor_MacroDefinition => {
183 for callbacks in &ctx.options().parse_callbacks {
184 match callbacks.will_parse_macro(&cursor.spelling()) {
185 MacroParsingBehavior::Ignore => {
186 return Err(ParseError::Continue);
187 }
188 MacroParsingBehavior::Default => {}
189 }
190
191 if cursor.is_macro_function_like() {
192 handle_function_macro(&cursor, callbacks.as_ref());
193 // We handled the macro, skip macro processing below.
194 return Err(ParseError::Continue);
195 }
196 }
197
198 let value = parse_macro(ctx, &cursor);
199
200 let (id, value) = match value {
201 Some(v) => v,
202 None => return Err(ParseError::Continue),
203 };
204
205 assert!(!id.is_empty(), "Empty macro name?");
206
207 let previously_defined = ctx.parsed_macro(&id);
208
209 // NB: It's important to "note" the macro even if the result is
210 // not an integer, otherwise we might loose other kind of
211 // derived macros.
212 ctx.note_parsed_macro(id.clone(), value.clone());
213
214 if previously_defined {
215 let name = String::from_utf8(id).unwrap();
216 warn!("Duplicated macro definition: {}", name);
217 return Err(ParseError::Continue);
218 }
219
220 // NOTE: Unwrapping, here and above, is safe, because the
221 // identifier of a token comes straight from clang, and we
222 // enforce utf8 there, so we should have already panicked at
223 // this point.
224 let name = String::from_utf8(id).unwrap();
225 let (type_kind, val) = match value {
226 EvalResult::Invalid => return Err(ParseError::Continue),
227 EvalResult::Float(f) => {
228 (TypeKind::Float(FloatKind::Double), VarType::Float(f))
229 }
230 EvalResult::Char(c) => {
231 let c = match c {
232 CChar::Char(c) => {
233 assert_eq!(c.len_utf8(), 1);
234 c as u8
235 }
236 CChar::Raw(c) => {
237 assert!(c <= ::std::u8::MAX as u64);
238 c as u8
239 }
240 };
241
242 (TypeKind::Int(IntKind::U8), VarType::Char(c))
243 }
244 EvalResult::Str(val) => {
245 let char_ty = Item::builtin_type(
246 TypeKind::Int(IntKind::U8),
247 true,
248 ctx,
249 );
250 for callbacks in &ctx.options().parse_callbacks {
251 callbacks.str_macro(&name, &val);
252 }
253 (TypeKind::Pointer(char_ty), VarType::String(val))
254 }
255 EvalResult::Int(Wrapping(value)) => {
256 let kind = ctx
257 .options()
258 .last_callback(|c| c.int_macro(&name, value))
259 .unwrap_or_else(|| {
260 default_macro_constant_type(ctx, value)
261 });
262
263 (TypeKind::Int(kind), VarType::Int(value))
264 }
265 };
266
267 let ty = Item::builtin_type(type_kind, true, ctx);
268
269 Ok(ParseResult::New(
270 Var::new(name, None, ty, Some(val), true),
271 Some(cursor),
272 ))
273 }
274 CXCursor_VarDecl => {
275 let mut name = cursor.spelling();
276 if cursor.linkage() == CXLinkage_External {
277 if let Some(nm) = ctx.options().last_callback(|callbacks| {
278 callbacks.generated_name_override(ItemInfo {
279 name: name.as_str(),
280 kind: ItemKind::Var,
281 })
282 }) {
283 name = nm;
284 }
285 }
286 // No more changes to name
287 let name = name;
288
289 if name.is_empty() {
290 warn!("Empty constant name?");
291 return Err(ParseError::Continue);
292 }
293
294 let ty = cursor.cur_type();
295
296 // TODO(emilio): do we have to special-case constant arrays in
297 // some other places?
298 let is_const = ty.is_const() ||
299 ([CXType_ConstantArray, CXType_IncompleteArray]
300 .contains(&ty.kind()) &&
301 ty.elem_type()
302 .map_or(false, |element| element.is_const()));
303
304 let ty = match Item::from_ty(&ty, cursor, None, ctx) {
305 Ok(ty) => ty,
306 Err(e) => {
307 assert!(
308 matches!(ty.kind(), CXType_Auto | CXType_Unexposed),
309 "Couldn't resolve constant type, and it \
310 wasn't an nondeductible auto type or unexposed \
311 type!"
312 );
313 return Err(e);
314 }
315 };
316
317 // Note: Ty might not be totally resolved yet, see
318 // tests/headers/inner_const.hpp
319 //
320 // That's fine because in that case we know it's not a literal.
321 let canonical_ty = ctx
322 .safe_resolve_type(ty)
323 .and_then(|t| t.safe_canonical_type(ctx));
324
325 let is_integer = canonical_ty.map_or(false, |t| t.is_integer());
326 let is_float = canonical_ty.map_or(false, |t| t.is_float());
327
328 // TODO: We could handle `char` more gracefully.
329 // TODO: Strings, though the lookup is a bit more hard (we need
330 // to look at the canonical type of the pointee too, and check
331 // is char, u8, or i8 I guess).
332 let value = if is_integer {
333 let kind = match *canonical_ty.unwrap().kind() {
334 TypeKind::Int(kind) => kind,
335 _ => unreachable!(),
336 };
337
338 let mut val = cursor.evaluate().and_then(|v| v.as_int());
339 if val.is_none() || !kind.signedness_matches(val.unwrap()) {
340 val = get_integer_literal_from_cursor(&cursor);
341 }
342
343 val.map(|val| {
344 if kind == IntKind::Bool {
345 VarType::Bool(val != 0)
346 } else {
347 VarType::Int(val)
348 }
349 })
350 } else if is_float {
351 cursor
352 .evaluate()
353 .and_then(|v| v.as_double())
354 .map(VarType::Float)
355 } else {
356 cursor
357 .evaluate()
358 .and_then(|v| v.as_literal_string())
359 .map(VarType::String)
360 };
361
362 let mangling = cursor_mangling(ctx, &cursor);
363 let var = Var::new(name, mangling, ty, value, is_const);
364
365 Ok(ParseResult::New(var, Some(cursor)))
366 }
367 _ => {
368 /* TODO */
369 Err(ParseError::Continue)
370 }
371 }
372 }
373 }
374
375 /// 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)>376 fn parse_macro(
377 ctx: &BindgenContext,
378 cursor: &clang::Cursor,
379 ) -> Option<(Vec<u8>, cexpr::expr::EvalResult)> {
380 use cexpr::expr;
381
382 let cexpr_tokens = cursor.cexpr_tokens();
383
384 let parser = expr::IdentifierParser::new(ctx.parsed_macros());
385
386 match parser.macro_definition(&cexpr_tokens) {
387 Ok((_, (id, val))) => Some((id.into(), val)),
388 _ => None,
389 }
390 }
391
parse_int_literal_tokens(cursor: &clang::Cursor) -> Option<i64>392 fn parse_int_literal_tokens(cursor: &clang::Cursor) -> Option<i64> {
393 use cexpr::expr;
394 use cexpr::expr::EvalResult;
395
396 let cexpr_tokens = cursor.cexpr_tokens();
397
398 // TODO(emilio): We can try to parse other kinds of literals.
399 match expr::expr(&cexpr_tokens) {
400 Ok((_, EvalResult::Int(Wrapping(val)))) => Some(val),
401 _ => None,
402 }
403 }
404
get_integer_literal_from_cursor(cursor: &clang::Cursor) -> Option<i64>405 fn get_integer_literal_from_cursor(cursor: &clang::Cursor) -> Option<i64> {
406 use clang_sys::*;
407 let mut value = None;
408 cursor.visit(|c| {
409 match c.kind() {
410 CXCursor_IntegerLiteral | CXCursor_UnaryOperator => {
411 value = parse_int_literal_tokens(&c);
412 }
413 CXCursor_UnexposedExpr => {
414 value = get_integer_literal_from_cursor(&c);
415 }
416 _ => (),
417 }
418 if value.is_some() {
419 CXChildVisit_Break
420 } else {
421 CXChildVisit_Continue
422 }
423 });
424 value
425 }
426