summaryrefslogtreecommitdiff
path: root/libbindgen/src/clang.rs
diff options
context:
space:
mode:
Diffstat (limited to 'libbindgen/src/clang.rs')
-rw-r--r--libbindgen/src/clang.rs1371
1 files changed, 0 insertions, 1371 deletions
diff --git a/libbindgen/src/clang.rs b/libbindgen/src/clang.rs
deleted file mode 100644
index 491aaa07..00000000
--- a/libbindgen/src/clang.rs
+++ /dev/null
@@ -1,1371 +0,0 @@
-//! A higher level Clang API built on top of the generated bindings in the
-//! `clang_sys` module.
-
-#![allow(non_upper_case_globals, dead_code)]
-
-
-use cexpr;
-use clang_sys::*;
-use std::{mem, ptr, slice};
-use std::ffi::{CStr, CString};
-use std::fmt;
-use std::hash::Hash;
-use std::hash::Hasher;
-use std::os::raw::{c_char, c_int, c_uint, c_ulong};
-
-/// A cursor into the Clang AST, pointing to an AST node.
-///
-/// We call the AST node pointed to by the cursor the cursor's "referent".
-#[derive(Copy, Clone)]
-pub struct Cursor {
- x: CXCursor,
-}
-
-impl fmt::Debug for Cursor {
- fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
- write!(fmt,
- "Cursor({} kind: {}, loc: {}, usr: {:?})",
- self.spelling(),
- kind_to_str(self.kind()),
- self.location(),
- self.usr())
- }
-}
-
-impl Cursor {
- /// Get the Unified Symbol Resolution for this cursor's referent, if
- /// available.
- ///
- /// The USR can be used to compare entities across translation units.
- pub fn usr(&self) -> Option<String> {
- let s = unsafe { cxstring_into_string(clang_getCursorUSR(self.x)) };
- if s.is_empty() { None } else { Some(s) }
- }
-
- /// Is this cursor's referent a declaration?
- pub fn is_declaration(&self) -> bool {
- unsafe { clang_isDeclaration(self.kind()) != 0 }
- }
-
- /// Get the null cursor, which has no referent.
- pub fn null() -> Self {
- Cursor {
- x: unsafe { clang_getNullCursor() },
- }
- }
-
- /// Get this cursor's referent's spelling.
- pub fn spelling(&self) -> String {
- unsafe { cxstring_into_string(clang_getCursorSpelling(self.x)) }
- }
-
- /// Get this cursor's referent's display name.
- ///
- /// This is not necessarily a valid identifier. It includes extra
- /// information, such as parameters for a function, etc.
- pub fn display_name(&self) -> String {
- unsafe { cxstring_into_string(clang_getCursorDisplayName(self.x)) }
- }
-
- /// Get the mangled name of this cursor's referent.
- pub fn mangling(&self) -> String {
- unsafe { cxstring_into_string(clang_Cursor_getMangling(self.x)) }
- }
-
- /// Get the `Cursor` for this cursor's referent's lexical parent.
- ///
- /// The lexical parent is the parent of the definition. The semantic parent
- /// is the parent of the declaration. Generally, the lexical parent doesn't
- /// have any effect on semantics, while the semantic parent does.
- ///
- /// In the following snippet, the `Foo` class would be the semantic parent
- /// of the out-of-line `method` definition, while the lexical parent is the
- /// translation unit.
- ///
- /// ```c++
- /// class Foo {
- /// void method();
- /// };
- ///
- /// void Foo::method() { /* ... */ }
- /// ```
- pub fn lexical_parent(&self) -> Cursor {
- unsafe {
- Cursor {
- x: clang_getCursorLexicalParent(self.x),
- }
- }
- }
-
- /// Get the referent's semantic parent, if one is available.
- ///
- /// See documentation for `lexical_parent` for details on semantic vs
- /// lexical parents.
- pub fn fallible_semantic_parent(&self) -> Option<Cursor> {
- let sp = unsafe {
- Cursor {
- x: clang_getCursorSemanticParent(self.x),
- }
- };
- if sp == *self || !sp.is_valid() {
- return None;
- }
- Some(sp)
- }
-
- /// Get the referent's semantic parent.
- ///
- /// See documentation for `lexical_parent` for details on semantic vs
- /// lexical parents.
- pub fn semantic_parent(&self) -> Cursor {
- self.fallible_semantic_parent().unwrap()
- }
-
- /// Return the number of template arguments used by this cursor's referent,
- /// if the referent is either a template specialization or
- /// declaration. Returns -1 otherwise.
- ///
- /// NOTE: This may not return `Some` for some non-fully specialized
- /// templates, see #193 and #194.
- pub fn num_template_args(&self) -> Option<u32> {
- let n: c_int = unsafe { clang_Cursor_getNumTemplateArguments(self.x) };
-
- if n >= 0 {
- Some(n as u32)
- } else {
- debug_assert_eq!(n, -1);
- None
- }
- }
-
- /// Get a cursor pointing to this referent's containing translation unit.
- ///
- /// Note that we shouldn't create a `TranslationUnit` struct here, because
- /// bindgen assumes there will only be one of them alive at a time, and
- /// disposes it on drop. That can change if this would be required, but I
- /// think we can survive fine without it.
- pub fn translation_unit(&self) -> Cursor {
- assert!(self.is_valid());
- unsafe {
- let tu = clang_Cursor_getTranslationUnit(self.x);
- let cursor = Cursor {
- x: clang_getTranslationUnitCursor(tu),
- };
- assert!(cursor.is_valid());
- cursor
- }
- }
-
- /// Is the referent a top level construct?
- pub fn is_toplevel(&self) -> bool {
- let mut semantic_parent = self.fallible_semantic_parent();
-
- while semantic_parent.is_some() &&
- (semantic_parent.unwrap().kind() == CXCursor_Namespace ||
- semantic_parent.unwrap().kind() == CXCursor_NamespaceAlias ||
- semantic_parent.unwrap().kind() == CXCursor_NamespaceRef) {
- semantic_parent = semantic_parent.unwrap()
- .fallible_semantic_parent();
- }
-
- let tu = self.translation_unit();
- // Yes, this can happen with, e.g., macro definitions.
- semantic_parent == tu.fallible_semantic_parent()
- }
-
- /// There are a few kinds of types that we need to treat specially, mainly
- /// not tracking the type declaration but the location of the cursor, given
- /// clang doesn't expose a proper declaration for these types.
- pub fn is_template_like(&self) -> bool {
- match self.kind() {
- CXCursor_ClassTemplate |
- CXCursor_ClassTemplatePartialSpecialization |
- CXCursor_TypeAliasTemplateDecl => true,
- _ => false,
- }
- }
-
- /// Get the kind of referent this cursor is pointing to.
- pub fn kind(&self) -> CXCursorKind {
- unsafe { clang_getCursorKind(self.x) }
- }
-
- /// Is the referent an anonymous record definition?
- pub fn is_anonymous(&self) -> bool {
- unsafe { clang_Cursor_isAnonymous(self.x) != 0 }
- }
-
- /// Is the referent a template specialization?
- pub fn is_template(&self) -> bool {
- self.specialized().is_some()
- }
-
- /// Is the referent a fully specialized template specialization without any
- /// remaining free template arguments?
- pub fn is_fully_specialized_template(&self) -> bool {
- self.is_template() && self.num_template_args().unwrap_or(0) > 0
- }
-
- /// Is the referent a template specialization that still has remaining free
- /// template arguments?
- pub fn is_in_non_fully_specialized_template(&self) -> bool {
- if self.is_toplevel() {
- return false;
- }
- let parent = self.semantic_parent();
- (parent.is_template() && !parent.is_fully_specialized_template()) ||
- parent.is_in_non_fully_specialized_template()
- }
-
- /// Is this cursor pointing a valid referent?
- pub fn is_valid(&self) -> bool {
- unsafe { clang_isInvalid(self.kind()) == 0 }
- }
-
- /// Get the source location for the referent.
- pub fn location(&self) -> SourceLocation {
- unsafe {
- SourceLocation {
- x: clang_getCursorLocation(self.x),
- }
- }
- }
-
- /// Get the source location range for the referent.
- pub fn extent(&self) -> CXSourceRange {
- unsafe { clang_getCursorExtent(self.x) }
- }
-
- /// Get the raw declaration comment for this referent, if one exists.
- pub fn raw_comment(&self) -> Option<String> {
- let s = unsafe {
- cxstring_into_string(clang_Cursor_getRawCommentText(self.x))
- };
- if s.is_empty() { None } else { Some(s) }
- }
-
- /// Get the referent's parsed comment.
- pub fn comment(&self) -> Comment {
- unsafe {
- Comment {
- x: clang_Cursor_getParsedComment(self.x),
- }
- }
- }
-
- /// Get the referent's type.
- pub fn cur_type(&self) -> Type {
- unsafe {
- Type {
- x: clang_getCursorType(self.x),
- }
- }
- }
-
- /// Given that this cursor's referent is a reference to another type, or is
- /// a declaration, get the cursor pointing to the referenced type or type of
- /// the declared thing.
- pub fn definition(&self) -> Option<Cursor> {
- unsafe {
- let ret = Cursor {
- x: clang_getCursorDefinition(self.x),
- };
-
- if ret.is_valid() { Some(ret) } else { None }
- }
- }
-
- /// Given that this cursor's referent is reference type, get the cursor
- /// pointing to the referenced type.
- pub fn referenced(&self) -> Option<Cursor> {
- unsafe {
- let ret = Cursor {
- x: clang_getCursorReferenced(self.x),
- };
-
- if ret.is_valid() { Some(ret) } else { None }
- }
- }
-
- /// Get the canonical cursor for this referent.
- ///
- /// Many types can be declared multiple times before finally being properly
- /// defined. This method allows us to get the canonical cursor for the
- /// referent type.
- pub fn canonical(&self) -> Cursor {
- unsafe {
- Cursor {
- x: clang_getCanonicalCursor(self.x),
- }
- }
- }
-
- /// Given that this cursor points to a template specialization, get a cursor
- /// pointing to the template definition that is being specialized.
- pub fn specialized(&self) -> Option<Cursor> {
- unsafe {
- let ret = Cursor {
- x: clang_getSpecializedCursorTemplate(self.x),
- };
- if ret.is_valid() { Some(ret) } else { None }
- }
- }
-
- /// Assuming that this cursor's referent is a template declaration, get the
- /// kind of cursor that would be generated for its specializations.
- pub fn template_kind(&self) -> CXCursorKind {
- unsafe { clang_getTemplateCursorKind(self.x) }
- }
-
- /// Traverse this cursor's referent and its children.
- ///
- /// Call the given function on each AST node traversed.
- pub fn visit<Visitor>(&self, mut visitor: Visitor)
- where Visitor: FnMut(Cursor) -> CXChildVisitResult,
- {
- unsafe {
- clang_visitChildren(self.x,
- visit_children::<Visitor>,
- mem::transmute(&mut visitor));
- }
- }
-
- /// Returns whether the given location contains a cursor with the given
- /// kind in the first level of nesting underneath (doesn't look
- /// recursively).
- pub fn contains_cursor(&self, kind: CXCursorKind) -> bool {
- let mut found = false;
-
- self.visit(|c| {
- if c.kind() == kind {
- found = true;
- CXChildVisit_Break
- } else {
- CXChildVisit_Continue
- }
- });
-
- found
- }
-
- /// Is the referent an inlined function?
- pub fn is_inlined_function(&self) -> bool {
- clang_Cursor_isFunctionInlined::is_loaded() &&
- unsafe { clang_Cursor_isFunctionInlined(self.x) != 0 }
- }
-
- /// Get the width of this cursor's referent bit field, or `None` if the
- /// referent is not a bit field.
- pub fn bit_width(&self) -> Option<u32> {
- unsafe {
- let w = clang_getFieldDeclBitWidth(self.x);
- if w == -1 { None } else { Some(w as u32) }
- }
- }
-
- /// Get the integer representation type used to hold this cursor's referent
- /// enum type.
- pub fn enum_type(&self) -> Option<Type> {
- unsafe {
- let t = Type {
- x: clang_getEnumDeclIntegerType(self.x),
- };
- if t.is_valid() { Some(t) } else { None }
- }
- }
-
- /// Get the signed constant value for this cursor's enum variant referent.
- ///
- /// Returns None if the cursor's referent is not an enum variant.
- pub fn enum_val_signed(&self) -> Option<i64> {
- unsafe {
- if self.kind() == CXCursor_EnumConstantDecl {
- Some(clang_getEnumConstantDeclValue(self.x) as i64)
- } else {
- None
- }
- }
- }
-
- /// Get the unsigned constant value for this cursor's enum variant referent.
- ///
- /// Returns None if the cursor's referent is not an enum variant.
- pub fn enum_val_unsigned(&self) -> Option<u64> {
- unsafe {
- if self.kind() == CXCursor_EnumConstantDecl {
- Some(clang_getEnumConstantDeclUnsignedValue(self.x) as u64)
- } else {
- None
- }
- }
- }
-
- /// Given that this cursor's referent is a `typedef`, get the `Type` that is
- /// being aliased.
- pub fn typedef_type(&self) -> Option<Type> {
- let inner = Type {
- x: unsafe { clang_getTypedefDeclUnderlyingType(self.x) },
- };
-
- if inner.is_valid() { Some(inner) } else { None }
- }
-
- /// Get the linkage kind for this cursor's referent.
- ///
- /// This only applies to functions and variables.
- pub fn linkage(&self) -> CXLinkageKind {
- unsafe { clang_getCursorLinkage(self.x) }
- }
-
- /// Get the visibility of this cursor's referent.
- pub fn visibility(&self) -> CXVisibilityKind {
- unsafe { clang_getCursorVisibility(self.x) }
- }
-
- /// Given that this cursor's referent is a function, return cursors to its
- /// parameters.
- pub fn args(&self) -> Option<Vec<Cursor>> {
- // XXX: We might want to use and keep num_args
- // match self.kind() {
- // CXCursor_FunctionDecl |
- // CXCursor_CXXMethod => {
- unsafe {
- let w = clang_Cursor_getNumArguments(self.x);
- if w == -1 {
- None
- } else {
- let num = w as u32;
-
- let mut args = vec![];
- for i in 0..num {
- args.push(Cursor {
- x: clang_Cursor_getArgument(self.x, i as c_uint),
- });
- }
- Some(args)
- }
- }
- }
-
- /// Given that this cursor's referent is a function/method call or
- /// declaration, return the number of arguments it takes.
- ///
- /// Returns -1 if the cursor's referent is not a function/method call or
- /// declaration.
- pub fn num_args(&self) -> Result<u32, ()> {
- unsafe {
- let w = clang_Cursor_getNumArguments(self.x);
- if w == -1 { Err(()) } else { Ok(w as u32) }
- }
- }
-
- /// Get the access specifier for this cursor's referent.
- pub fn access_specifier(&self) -> CX_CXXAccessSpecifier {
- unsafe { clang_getCXXAccessSpecifier(self.x) }
- }
-
- /// Is this cursor's referent a field declaration that is marked as
- /// `mutable`?
- pub fn is_mutable_field(&self) -> bool {
- unsafe { clang_CXXField_isMutable(self.x) != 0 }
- }
-
- /// Is this cursor's referent a member function that is declared `static`?
- pub fn method_is_static(&self) -> bool {
- unsafe { clang_CXXMethod_isStatic(self.x) != 0 }
- }
-
- /// Is this cursor's referent a member function that is declared `const`?
- pub fn method_is_const(&self) -> bool {
- unsafe { clang_CXXMethod_isConst(self.x) != 0 }
- }
-
- /// Is this cursor's referent a member function that is declared `const`?
- pub fn method_is_virtual(&self) -> bool {
- unsafe { clang_CXXMethod_isVirtual(self.x) != 0 }
- }
-
- /// Is this cursor's referent a struct or class with virtual members?
- pub fn is_virtual_base(&self) -> bool {
- unsafe { clang_isVirtualBase(self.x) != 0 }
- }
-
- /// Try to evaluate this cursor.
- pub fn evaluate(&self) -> Option<EvalResult> {
- EvalResult::new(*self)
- }
-}
-
-extern "C" fn visit_children<Visitor>(cur: CXCursor,
- _parent: CXCursor,
- data: CXClientData)
- -> CXChildVisitResult
- where Visitor: FnMut(Cursor) -> CXChildVisitResult,
-{
- let func: &mut Visitor = unsafe { mem::transmute(data) };
- let child = Cursor {
- x: cur,
- };
-
- (*func)(child)
-}
-
-impl PartialEq for Cursor {
- fn eq(&self, other: &Cursor) -> bool {
- unsafe { clang_equalCursors(self.x, other.x) == 1 }
- }
-}
-
-impl Eq for Cursor {}
-
-impl Hash for Cursor {
- fn hash<H: Hasher>(&self, state: &mut H) {
- unsafe { clang_hashCursor(self.x) }.hash(state)
- }
-}
-
-/// The type of a node in clang's AST.
-#[derive(Clone)]
-pub struct Type {
- x: CXType,
-}
-
-impl PartialEq for Type {
- fn eq(&self, other: &Self) -> bool {
- unsafe { clang_equalTypes(self.x, other.x) != 0 }
- }
-}
-
-impl Eq for Type {}
-
-impl fmt::Debug for Type {
- fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
- write!(fmt,
- "Type({}, kind: {}, decl: {:?}, canon: {:?})",
- self.spelling(),
- type_to_str(self.kind()),
- self.declaration(),
- self.declaration().canonical())
- }
-}
-
-/// An error about the layout of a struct, class, or type.
-#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
-pub enum LayoutError {
- /// Asked for the layout of an invalid type.
- Invalid,
- /// Asked for the layout of an incomplete type.
- Incomplete,
- /// Asked for the layout of a dependent type.
- Dependent,
- /// Asked for the layout of a type that does not have constant size.
- NotConstantSize,
- /// Asked for the layout of a field in a type that does not have such a
- /// field.
- InvalidFieldName,
- /// An unknown layout error.
- Unknown,
-}
-
-impl ::std::convert::From<i32> for LayoutError {
- fn from(val: i32) -> Self {
- use self::LayoutError::*;
- let val = match CXTypeLayoutError::from_raw(val) {
- Some(val) => val,
- None => return Unknown,
- };
-
- match val {
- CXTypeLayoutError_Invalid => Invalid,
- CXTypeLayoutError_Incomplete => Incomplete,
- CXTypeLayoutError_Dependent => Dependent,
- CXTypeLayoutError_NotConstantSize => NotConstantSize,
- CXTypeLayoutError_InvalidFieldName => InvalidFieldName,
- _ => Unknown,
- }
- }
-}
-
-impl Type {
- /// Get this type's kind.
- pub fn kind(&self) -> CXTypeKind {
- self.x.kind
- }
-
- /// Get a cursor pointing to this type's declaration.
- pub fn declaration(&self) -> Cursor {
- unsafe {
- Cursor {
- x: clang_getTypeDeclaration(self.x),
- }
- }
- }
-
- /// Get a raw display name for this type.
- pub fn spelling(&self) -> String {
- unsafe { cxstring_into_string(clang_getTypeSpelling(self.x)) }
- }
-
- /// Is this type const qualified?
- pub fn is_const(&self) -> bool {
- unsafe { clang_isConstQualifiedType(self.x) != 0 }
- }
-
- /// What is the size of this type? Paper over invalid types by returning `0`
- /// for them.
- pub fn size(&self) -> usize {
- unsafe {
- let val = clang_Type_getSizeOf(self.x);
- if val < 0 { 0 } else { val as usize }
- }
- }
-
- /// What is the size of this type?
- pub fn fallible_size(&self) -> Result<usize, LayoutError> {
- let val = unsafe { clang_Type_getSizeOf(self.x) };
- if val < 0 {
- Err(LayoutError::from(val as i32))
- } else {
- Ok(val as usize)
- }
- }
-
- /// What is the alignment of this type? Paper over invalid types by
- /// returning `0`.
- pub fn align(&self) -> usize {
- unsafe {
- let val = clang_Type_getAlignOf(self.x);
- if val < 0 { 0 } else { val as usize }
- }
- }
-
- /// What is the alignment of this type?
- pub fn fallible_align(&self) -> Result<usize, LayoutError> {
- unsafe {
- let val = clang_Type_getAlignOf(self.x);
- if val < 0 {
- Err(LayoutError::from(val as i32))
- } else {
- Ok(val as usize)
- }
- }
- }
-
- /// Get the layout for this type, or an error describing why it does not
- /// have a valid layout.
- pub fn fallible_layout(&self) -> Result<::ir::layout::Layout, LayoutError> {
- use ir::layout::Layout;
- let size = try!(self.fallible_size());
- let align = try!(self.fallible_align());
- Ok(Layout::new(size, align))
- }
-
- /// If this type is a class template specialization, return its
- /// template arguments. Otherwise, return None.
- pub fn template_args(&self) -> Option<TypeTemplateArgIterator> {
- let n = unsafe { clang_Type_getNumTemplateArguments(self.x) };
- if n >= 0 {
- Some(TypeTemplateArgIterator {
- x: self.x,
- length: n as u32,
- index: 0,
- })
- } else {
- debug_assert_eq!(n, -1);
- None
- }
- }
-
- /// Given that this type is a pointer type, return the type that it points
- /// to.
- pub fn pointee_type(&self) -> Option<Type> {
- match self.kind() {
- CXType_Pointer |
- CXType_RValueReference |
- CXType_LValueReference |
- CXType_MemberPointer => {
- let ret = Type {
- x: unsafe { clang_getPointeeType(self.x) },
- };
- debug_assert!(ret.is_valid());
- Some(ret)
- }
- _ => None,
- }
- }
-
- /// Given that this type is an array, vector, or complex type, return the
- /// type of its elements.
- pub fn elem_type(&self) -> Option<Type> {
- let current_type = Type {
- x: unsafe { clang_getElementType(self.x) },
- };
- if current_type.is_valid() {
- Some(current_type)
- } else {
- None
- }
- }
-
- /// Given that this type is an array or vector type, return its number of
- /// elements.
- pub fn num_elements(&self) -> Option<usize> {
- let num_elements_returned = unsafe { clang_getNumElements(self.x) };
- if num_elements_returned != -1 {
- Some(num_elements_returned as usize)
- } else {
- None
- }
- }
-
- /// Get the canonical version of this type. This sees through `typdef`s and
- /// aliases to get the underlying, canonical type.
- pub fn canonical_type(&self) -> Type {
- unsafe {
- Type {
- x: clang_getCanonicalType(self.x),
- }
- }
- }
-
- /// Is this type a variadic function type?
- pub fn is_variadic(&self) -> bool {
- unsafe { clang_isFunctionTypeVariadic(self.x) != 0 }
- }
-
- /// Given that this type is a function type, get the type of its return
- /// value.
- pub fn ret_type(&self) -> Option<Type> {
- let rt = Type {
- x: unsafe { clang_getResultType(self.x) },
- };
- if rt.is_valid() { Some(rt) } else { None }
- }
-
- /// Given that this type is a function type, get its calling convention. If
- /// this is not a function type, `CXCallingConv_Invalid` is returned.
- pub fn call_conv(&self) -> CXCallingConv {
- unsafe { clang_getFunctionTypeCallingConv(self.x) }
- }
-
- /// For elaborated types (types which use `class`, `struct`, or `union` to
- /// disambiguate types from local bindings), get the underlying type.
- pub fn named(&self) -> Type {
- unsafe {
- Type {
- x: clang_Type_getNamedType(self.x),
- }
- }
- }
-
- /// Is this a valid type?
- pub fn is_valid(&self) -> bool {
- self.kind() != CXType_Invalid
- }
-
- /// Is this a valid and exposed type?
- pub fn is_valid_and_exposed(&self) -> bool {
- self.is_valid() && self.kind() != CXType_Unexposed
- }
-
- /// Is this type a fully specialized template?
- pub fn is_fully_specialized_template(&self) -> bool {
- // Yep, the spelling of this containing type-parameter is extremely
- // nasty... But can happen in <type_traits>. Unfortunately I couldn't
- // reduce it enough :(
- !self.spelling().contains("type-parameter") &&
- self.template_args()
- .map_or(false, |mut args| {
- args.len() > 0 &&
- !args.any(|t| t.spelling().contains("type-parameter"))
- })
- }
-}
-
-/// An iterator for a type's template arguments.
-pub struct TypeTemplateArgIterator {
- x: CXType,
- length: u32,
- index: u32,
-}
-
-impl Iterator for TypeTemplateArgIterator {
- type Item = Type;
- fn next(&mut self) -> Option<Type> {
- if self.index < self.length {
- let idx = self.index as c_uint;
- self.index += 1;
- Some(Type {
- x: unsafe { clang_Type_getTemplateArgumentAsType(self.x, idx) },
- })
- } else {
- None
- }
- }
-}
-
-impl ExactSizeIterator for TypeTemplateArgIterator {
- fn len(&self) -> usize {
- assert!(self.index <= self.length);
- (self.length - self.index) as usize
- }
-}
-
-/// A `SourceLocation` is a file, line, column, and byte offset location for
-/// some source text.
-pub struct SourceLocation {
- x: CXSourceLocation,
-}
-
-impl SourceLocation {
- /// Get the (file, line, column, byte offset) tuple for this source
- /// location.
- pub fn location(&self) -> (File, usize, usize, usize) {
- unsafe {
- let mut file = mem::zeroed();
- let mut line = 0;
- let mut col = 0;
- let mut off = 0;
- clang_getSpellingLocation(self.x,
- &mut file,
- &mut line,
- &mut col,
- &mut off);
- (File {
- x: file,
- },
- line as usize,
- col as usize,
- off as usize)
- }
- }
-}
-
-impl fmt::Display for SourceLocation {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- let (file, line, col, _) = self.location();
- if let Some(name) = file.name() {
- write!(f, "{}:{}:{}", name, line, col)
- } else {
- "builtin definitions".fmt(f)
- }
- }
-}
-
-/// A comment in the source text.
-///
-/// Comments are sort of parsed by Clang, and have a tree structure.
-pub struct Comment {
- x: CXComment,
-}
-
-impl Comment {
- /// What kind of comment is this?
- pub fn kind(&self) -> CXCommentKind {
- unsafe { clang_Comment_getKind(self.x) }
- }
-
- /// Get this comment's children comment
- pub fn get_children(&self) -> CommentChildrenIterator {
- CommentChildrenIterator {
- parent: self.x,
- length: unsafe { clang_Comment_getNumChildren(self.x) },
- index: 0,
- }
- }
-
- /// Given that this comment is the start or end of an HTML tag, get its tag
- /// name.
- pub fn get_tag_name(&self) -> String {
- unsafe { cxstring_into_string(clang_HTMLTagComment_getTagName(self.x)) }
- }
-
- /// Given that this comment is an HTML start tag, get its attributes.
- pub fn get_tag_attrs(&self) -> CommentAttributesIterator {
- CommentAttributesIterator {
- x: self.x,
- length: unsafe { clang_HTMLStartTag_getNumAttrs(self.x) },
- index: 0,
- }
- }
-}
-
-/// An iterator for a comment's children
-pub struct CommentChildrenIterator {
- parent: CXComment,
- length: c_uint,
- index: c_uint,
-}
-
-impl Iterator for CommentChildrenIterator {
- type Item = Comment;
- fn next(&mut self) -> Option<Comment> {
- if self.index < self.length {
- let idx = self.index;
- self.index += 1;
- Some(Comment {
- x: unsafe { clang_Comment_getChild(self.parent, idx) },
- })
- } else {
- None
- }
- }
-}
-
-/// An HTML start tag comment attribute
-pub struct CommentAttribute {
- /// HTML start tag attribute name
- pub name: String,
- /// HTML start tag attribute value
- pub value: String,
-}
-
-/// An iterator for a comment's attributes
-pub struct CommentAttributesIterator {
- x: CXComment,
- length: c_uint,
- index: c_uint,
-}
-
-impl Iterator for CommentAttributesIterator {
- type Item = CommentAttribute;
- fn next(&mut self) -> Option<CommentAttribute> {
- if self.index < self.length {
- let idx = self.index;
- self.index += 1;
- Some(CommentAttribute {
- name: unsafe {
- cxstring_into_string(
- clang_HTMLStartTag_getAttrName(self.x, idx))
- },
- value: unsafe {
- cxstring_into_string(
- clang_HTMLStartTag_getAttrValue(self.x, idx))
- },
- })
- } else {
- None
- }
- }
-}
-
-/// A source file.
-pub struct File {
- x: CXFile,
-}
-
-impl File {
- /// Get the name of this source file.
- pub fn name(&self) -> Option<String> {
- if self.x.is_null() {
- return None;
- }
- Some(unsafe { cxstring_into_string(clang_getFileName(self.x)) })
- }
-}
-
-fn cxstring_into_string(s: CXString) -> String {
- if s.data.is_null() {
- return "".to_owned();
- }
- unsafe {
- let c_str = CStr::from_ptr(clang_getCString(s) as *const _);
- let ret = c_str.to_string_lossy().into_owned();
- clang_disposeString(s);
- ret
- }
-}
-
-/// An `Index` is an environment for a set of translation units that will
-/// typically end up linked together in one final binary.
-pub struct Index {
- x: CXIndex,
-}
-
-impl Index {
- /// Construct a new `Index`.
- ///
- /// The `pch` parameter controls whether declarations in pre-compiled
- /// headers are included when enumerating a translation unit's "locals".
- ///
- /// The `diag` parameter controls whether debugging diagnostics are enabled.
- pub fn new(pch: bool, diag: bool) -> Index {
- unsafe {
- Index {
- x: clang_createIndex(pch as c_int, diag as c_int),
- }
- }
- }
-}
-
-impl fmt::Debug for Index {
- fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
- write!(fmt, "Index {{ }}")
- }
-}
-
-impl Drop for Index {
- fn drop(&mut self) {
- unsafe {
- clang_disposeIndex(self.x);
- }
- }
-}
-
-/// A token emitted by clang's lexer.
-#[derive(Debug)]
-pub struct Token {
- /// The kind of token this is.
- pub kind: CXTokenKind,
- /// A display name for this token.
- pub spelling: String,
-}
-
-/// A translation unit (or "compilation unit").
-pub struct TranslationUnit {
- x: CXTranslationUnit,
-}
-
-impl fmt::Debug for TranslationUnit {
- fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
- write!(fmt, "TranslationUnit {{ }}")
- }
-}
-
-impl TranslationUnit {
- /// Parse a source file into a translation unit.
- pub fn parse(ix: &Index,
- file: &str,
- cmd_args: &[String],
- unsaved: &[UnsavedFile],
- opts: CXTranslationUnit_Flags)
- -> Option<TranslationUnit> {
- let fname = CString::new(file).unwrap();
- let _c_args: Vec<CString> =
- cmd_args.iter().map(|s| CString::new(s.clone()).unwrap()).collect();
- let c_args: Vec<*const c_char> =
- _c_args.iter().map(|s| s.as_ptr()).collect();
- let mut c_unsaved: Vec<CXUnsavedFile> =
- unsaved.iter().map(|f| f.x).collect();
- let tu = unsafe {
- clang_parseTranslationUnit(ix.x,
- fname.as_ptr(),
- c_args.as_ptr(),
- c_args.len() as c_int,
- c_unsaved.as_mut_ptr(),
- c_unsaved.len() as c_uint,
- opts)
- };
- if tu.is_null() {
- None
- } else {
- Some(TranslationUnit {
- x: tu,
- })
- }
- }
-
- /// Get the Clang diagnostic information associated with this translation
- /// unit.
- pub fn diags(&self) -> Vec<Diagnostic> {
- unsafe {
- let num = clang_getNumDiagnostics(self.x) as usize;
- let mut diags = vec![];
- for i in 0..num {
- diags.push(Diagnostic {
- x: clang_getDiagnostic(self.x, i as c_uint),
- });
- }
- diags
- }
- }
-
- /// Get a cursor pointing to the root of this translation unit's AST.
- pub fn cursor(&self) -> Cursor {
- unsafe {
- Cursor {
- x: clang_getTranslationUnitCursor(self.x),
- }
- }
- }
-
- /// Is this the null translation unit?
- pub fn is_null(&self) -> bool {
- self.x.is_null()
- }
-
- /// Invoke Clang's lexer on this translation unit and get the stream of
- /// tokens that come out.
- pub fn tokens(&self, cursor: &Cursor) -> Option<Vec<Token>> {
- let range = cursor.extent();
- let mut tokens = vec![];
- unsafe {
- let mut token_ptr = ptr::null_mut();
- let mut num_tokens: c_uint = 0;
- clang_tokenize(self.x, range, &mut token_ptr, &mut num_tokens);
- if token_ptr.is_null() {
- return None;
- }
-
- let token_array = slice::from_raw_parts(token_ptr,
- num_tokens as usize);
- for &token in token_array.iter() {
- let kind = clang_getTokenKind(token);
- let spelling =
- cxstring_into_string(clang_getTokenSpelling(self.x, token));
-
- tokens.push(Token {
- kind: kind,
- spelling: spelling,
- });
- }
- clang_disposeTokens(self.x, token_ptr, num_tokens);
- }
- Some(tokens)
- }
-
- /// Convert a set of tokens from clang into `cexpr` tokens, for further
- /// processing.
- pub fn cexpr_tokens(&self,
- cursor: &Cursor)
- -> Option<Vec<cexpr::token::Token>> {
- use cexpr::token;
-
- let mut tokens = match self.tokens(cursor) {
- Some(tokens) => tokens,
- None => return None,
- };
-
- // FIXME(emilio): LLVM 3.9 at least always include an extra token for no
- // good reason (except if we're at EOF). So we do this kind of hack,
- // where we skip known-to-cause problems trailing punctuation and
- // trailing keywords.
- //
- // This is sort of unfortunate, though :(.
- //
- // I'll try to get it fixed in LLVM if I have the time to submit a
- // patch.
- let mut trim_last_token = false;
- if let Some(token) = tokens.last() {
- // The starting of the next macro.
- trim_last_token |= token.spelling == "#" &&
- token.kind == CXToken_Punctuation;
-
- // A following keyword of any kind, like a following declaration.
- trim_last_token |= token.kind == CXToken_Keyword;
- }
-
- if trim_last_token {
- tokens.pop().unwrap();
- }
-
- Some(tokens.into_iter()
- .filter_map(|token| {
- let kind = match token.kind {
- CXToken_Punctuation => token::Kind::Punctuation,
- CXToken_Literal => token::Kind::Literal,
- CXToken_Identifier => token::Kind::Identifier,
- CXToken_Keyword => token::Kind::Keyword,
- // NB: cexpr is not too happy about comments inside
- // expressions, so we strip them down here.
- CXToken_Comment => return None,
- _ => {
- panic!("Found unexpected token kind: {:?}", token.kind)
- }
- };
-
- Some(token::Token {
- kind: kind,
- raw: token.spelling.into_bytes().into_boxed_slice(),
- })
- })
- .collect::<Vec<_>>())
- }
-}
-
-impl Drop for TranslationUnit {
- fn drop(&mut self) {
- unsafe {
- clang_disposeTranslationUnit(self.x);
- }
- }
-}
-
-
-/// A diagnostic message generated while parsing a translation unit.
-pub struct Diagnostic {
- x: CXDiagnostic,
-}
-
-impl Diagnostic {
- /// Format this diagnostic message as a string, using the given option bit
- /// flags.
- pub fn format(&self) -> String {
- unsafe {
- let opts = clang_defaultDiagnosticDisplayOptions();
- cxstring_into_string(clang_formatDiagnostic(self.x, opts))
- }
- }
-
- /// What is the severity of this diagnostic message?
- pub fn severity(&self) -> CXDiagnosticSeverity {
- unsafe { clang_getDiagnosticSeverity(self.x) }
- }
-}
-
-impl Drop for Diagnostic {
- /// Destroy this diagnostic message.
- fn drop(&mut self) {
- unsafe {
- clang_disposeDiagnostic(self.x);
- }
- }
-}
-
-/// A file which has not been saved to disk.
-pub struct UnsavedFile {
- x: CXUnsavedFile,
- name: CString,
- contents: CString,
-}
-
-impl UnsavedFile {
- /// Construct a new unsaved file with the given `name` and `contents`.
- pub fn new(name: &str, contents: &str) -> UnsavedFile {
- let name = CString::new(name).unwrap();
- let contents = CString::new(contents).unwrap();
- let x = CXUnsavedFile {
- Filename: name.as_ptr(),
- Contents: contents.as_ptr(),
- Length: contents.as_bytes().len() as c_ulong,
- };
- UnsavedFile {
- x: x,
- name: name,
- contents: contents,
- }
- }
-}
-
-/// Convert a cursor kind into a static string.
-pub fn kind_to_str(x: CXCursorKind) -> String {
- unsafe { cxstring_into_string(clang_getCursorKindSpelling(x)) }
-}
-
-/// Convert a type kind to a static string.
-pub fn type_to_str(x: CXTypeKind) -> String {
- unsafe { cxstring_into_string(clang_getTypeKindSpelling(x)) }
-}
-
-/// Dump the Clang AST to stdout for debugging purposes.
-pub fn ast_dump(c: &Cursor, depth: isize) -> CXChildVisitResult {
- fn print_indent(depth: isize, s: &str) {
- for _ in 0..depth {
- print!("\t");
- }
- println!("{}", s);
- }
-
- print_indent(depth,
- &format!("(kind: {}, spelling: {}, type: {}",
- kind_to_str(c.kind()),
- c.spelling(),
- type_to_str(c.cur_type().kind())));
-
- // Recurse.
- c.visit(|s| ast_dump(&s, depth + 1));
-
- print_indent(depth, ")");
-
- CXChildVisit_Continue
-}
-
-/// Try to extract the clang version to a string
-pub fn extract_clang_version() -> String {
- unsafe { cxstring_into_string(clang_getClangVersion()) }
-}
-
-/// A wrapper for the result of evaluating an expression.
-#[derive(Debug)]
-pub struct EvalResult {
- x: CXEvalResult,
-}
-
-impl EvalResult {
- /// Evaluate `cursor` and return the result.
- pub fn new(cursor: Cursor) -> Option<Self> {
- if !clang_Cursor_Evaluate::is_loaded() {
- return None;
- }
-
- // Clang has an internal assertion we can trigger if we try to evaluate
- // a cursor containing a variadic template type reference. Triggering
- // the assertion aborts the process, and we don't want that. Clang
- // *also* doesn't expose any API for finding variadic vs non-variadic
- // template type references, let alone whether a type referenced is a
- // template type, instead they seem to show up as type references to an
- // unexposed type. Our solution is to just flat out ban all
- // `CXType_Unexposed` from evaluation.
- let mut found_cant_eval = false;
- cursor.visit(|c| {
- if c.kind() == CXCursor_TypeRef &&
- c.cur_type().kind() == CXType_Unexposed {
- found_cant_eval = true;
- CXChildVisit_Break
- } else {
- CXChildVisit_Recurse
- }
- });
- if found_cant_eval {
- return None;
- }
-
- Some(EvalResult {
- x: unsafe { clang_Cursor_Evaluate(cursor.x) },
- })
- }
-
- fn kind(&self) -> CXEvalResultKind {
- unsafe { clang_EvalResult_getKind(self.x) }
- }
-
- /// Try to get back the result as a double.
- pub fn as_double(&self) -> Option<f64> {
- match self.kind() {
- CXEval_Float => {
- Some(unsafe { clang_EvalResult_getAsDouble(self.x) } as f64)
- }
- _ => None,
- }
- }
-
- /// Try to get back the result as an integer.
- pub fn as_int(&self) -> Option<i32> {
- match self.kind() {
- CXEval_Int => {
- Some(unsafe { clang_EvalResult_getAsInt(self.x) } as i32)
- }
- _ => None,
- }
- }
-
- /// Evaluates the expression as a literal string, that may or may not be
- /// valid utf-8.
- pub fn as_literal_string(&self) -> Option<Vec<u8>> {
- match self.kind() {
- CXEval_StrLiteral => {
- let ret = unsafe {
- CStr::from_ptr(clang_EvalResult_getAsStr(self.x))
- };
- Some(ret.to_bytes().to_vec())
- }
- _ => None,
- }
- }
-}
-
-impl Drop for EvalResult {
- fn drop(&mut self) {
- unsafe { clang_EvalResult_dispose(self.x) };
- }
-}