Skip to content

Commit 804598a

Browse files
committed
clang: Evaluate more complex constant expressions in variables.
1 parent ee351cb commit 804598a

File tree

4 files changed

+72
-6
lines changed

4 files changed

+72
-6
lines changed

src/clang.rs

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -475,6 +475,11 @@ impl Cursor {
475475
pub fn is_virtual_base(&self) -> bool {
476476
unsafe { clang_isVirtualBase(self.x) != 0 }
477477
}
478+
479+
/// Try to evaluate this cursor.
480+
pub fn evaluate(&self) -> EvalResult {
481+
EvalResult::new(*self)
482+
}
478483
}
479484

480485
extern "C" fn visit_children<Visitor>(cur: CXCursor,
@@ -1259,3 +1264,35 @@ pub fn ast_dump(c: &Cursor, depth: isize) -> Enum_CXVisitorResult {
12591264
pub fn extract_clang_version() -> String {
12601265
unsafe { clang_getClangVersion().into() }
12611266
}
1267+
1268+
#[derive(Debug)]
1269+
pub struct EvalResult {
1270+
x: CXEvalResult,
1271+
}
1272+
1273+
impl EvalResult {
1274+
pub fn new(cursor: Cursor) -> Self {
1275+
EvalResult {
1276+
x: unsafe { clang_Cursor_Evaluate(cursor.x) },
1277+
}
1278+
}
1279+
1280+
pub fn kind(&self) -> Enum_CXEvalResultKind {
1281+
unsafe { clang_EvalResult_getKind(self.x) }
1282+
}
1283+
1284+
pub fn as_int(&self) -> Option<i32> {
1285+
match self.kind() {
1286+
CXEval_Int => {
1287+
Some(unsafe { clang_EvalResult_getAsInt(self.x) } as i32)
1288+
}
1289+
_ => None,
1290+
}
1291+
}
1292+
}
1293+
1294+
impl Drop for EvalResult {
1295+
fn drop(&mut self) {
1296+
unsafe { clang_EvalResult_dispose(self.x) };
1297+
}
1298+
}

src/ir/var.rs

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -159,13 +159,23 @@ impl ClangSubItemParser for Var {
159159
// tests/headers/inner_const.hpp
160160
//
161161
// That's fine because in that case we know it's not a literal.
162-
let value = ctx.safe_resolve_type(ty)
162+
let is_integer = ctx.safe_resolve_type(ty)
163163
.and_then(|t| t.safe_canonical_type(ctx))
164-
.and_then(|t| if t.is_integer() { Some(t) } else { None })
165-
.and_then(|_| {
166-
get_integer_literal_from_cursor(&cursor,
167-
ctx.translation_unit())
168-
});
164+
.map(|t| t.is_integer())
165+
.unwrap_or(false);
166+
167+
let value = if is_integer {
168+
cursor.evaluate()
169+
.as_int()
170+
.map(|val| val as i64)
171+
.or_else(|| {
172+
let tu = ctx.translation_unit();
173+
get_integer_literal_from_cursor(&cursor, tu)
174+
})
175+
} else {
176+
None
177+
};
178+
169179

170180
let mangling = cursor_mangling(&cursor);
171181

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
/* automatically generated by rust-bindgen */
2+
3+
4+
#![allow(non_snake_case)]
5+
6+
7+
pub const foo: _bindgen_ty_1 = _bindgen_ty_1::foo;
8+
pub const bar: _bindgen_ty_1 = _bindgen_ty_1::bar;
9+
#[repr(u32)]
10+
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
11+
pub enum _bindgen_ty_1 { foo = 4, bar = 8, }
12+
pub const BAZ: ::std::os::raw::c_longlong = 24;

tests/headers/constant-evaluate.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
2+
enum {
3+
foo = 4,
4+
bar = 8,
5+
};
6+
7+
const long long BAZ = (1 << foo) | bar;

0 commit comments

Comments
 (0)