FFI::ClangSourceFFIClangCursor

class Cursor

Represents a cursor in the abstract syntax tree (AST).

Nested

Definitions

attr_reader :cursor

Signature

attribute FFI::Lib::CXCursor

The underlying libclang cursor structure.

attr_reader :translation_unit

Signature

attribute TranslationUnit

The translation unit this cursor belongs to.

def self.null_cursor

Get a null cursor.

Signature

returns Cursor

A null cursor instance.

Implementation

def self.null_cursor
	Cursor.new Lib.get_null_cursor, nil
end

def self.kind_spelling(kind)

Get the spelling of a cursor kind.

Signature

parameter kind Symbol

The cursor kind.

returns String

The string representation of the cursor kind.

Implementation

def self.kind_spelling(kind)
	Lib.extract_string Lib.get_cursor_kind_spelling(kind)
end

def kind_spelling

Get the spelling of the cursor kind.

Signature

returns String

The cursor kind spelling.

Implementation

def kind_spelling
	Cursor.kind_spelling @cursor[:kind]
end

def initialize(cxcursor, translation_unit)

Initialize a cursor with a libclang cursor structure.

Signature

parameter cxcursor Lib::CXCursor

The libclang cursor.

parameter translation_unit TranslationUnit

The parent translation unit.

Implementation

def initialize(cxcursor, translation_unit)
	@cursor = cxcursor
	@translation_unit = translation_unit
end

def null?

Check if this cursor is null.

Signature

returns Boolean

True if the cursor is null.

Implementation

def null?
	Lib.cursor_is_null(@cursor) != 0
end

def raw_comment_text

Get the raw comment text associated with this cursor.

Signature

returns String

The raw comment text.

Implementation

def raw_comment_text
	Lib.extract_string Lib.cursor_get_raw_comment_text(@cursor)
end

def comment

Get the parsed comment associated with this cursor.

Signature

returns Comment

The parsed comment structure.

Implementation

def comment
	Comment.build_from Lib.cursor_get_parsed_comment(@cursor)
end

def comment_range

Get the source range of the comment.

Signature

returns SourceRange

The comment source range.

Implementation

def comment_range
	SourceRange.new(Lib.cursor_get_comment_range(@cursor))
end

def completion

Get the code completion string for this cursor.

Signature

returns CodeCompletion::String

The completion string.

Implementation

def completion
	CodeCompletion::String.new Lib.get_cursor_completion_string(@cursor)
end

def anonymous?

Check if this cursor is anonymous.

Signature

returns Boolean

True if the cursor is anonymous.

Implementation

def anonymous?
	Lib.cursor_is_anonymous(@cursor) != 0
end

def anonymous_record_declaration?

Check if this cursor is an anonymous record declaration.

Signature

returns Boolean

True if it's an anonymous record declaration.

Implementation

def anonymous_record_declaration?
	Lib.cursor_is_anonymous_record_decl(@cursor) != 0
end

def declaration?

Check if this cursor is a declaration.

Signature

returns Boolean

True if it's a declaration.

Implementation

def declaration?
	Lib.is_declaration(kind) != 0
end

def reference?

Check if this cursor is a reference.

Signature

returns Boolean

True if it's a reference.

Implementation

def reference?
	Lib.is_reference(kind) != 0
end

def expression?

Check if this cursor is an expression.

Signature

returns Boolean

True if it's an expression.

Implementation

def expression?
	Lib.is_expression(kind) != 0
end

def statement?

Check if this cursor is a statement.

Signature

returns Boolean

True if it's a statement.

Implementation

def statement?
	Lib.is_statement(kind) != 0
end

def attribute?

Check if this cursor is an attribute.

Signature

returns Boolean

True if it's an attribute.

Implementation

def attribute?
	Lib.is_attribute(kind) != 0
end

def public?

Check if this cursor has public access.

Signature

returns Boolean

True if the cursor is public.

Implementation

def public?
	Lib.cxx_get_access_specifier(@cursor) == :public
end

def private?

Check if this cursor has private access.

Signature

returns Boolean

True if the cursor is private.

Implementation

def private?
	Lib.cxx_get_access_specifier(@cursor) == :private
end

def protected?

Check if this cursor has protected access.

Signature

returns Boolean

True if the cursor is protected.

Implementation

def protected?
	Lib.cxx_get_access_specifier(@cursor) == :protected
end

def invalid?

Check if this cursor is invalid.

Signature

returns Boolean

True if the cursor is invalid.

Implementation

def invalid?
	Lib.is_invalid(kind) != 0
end

def translation_unit?

Check if this cursor is a translation unit.

Signature

returns Boolean

True if it's a translation unit.

Implementation

def translation_unit?
	Lib.is_translation_unit(kind) != 0
end

def preprocessing?

Check if this cursor is a preprocessing directive.

Signature

returns Boolean

True if it's a preprocessing directive.

Implementation

def preprocessing?
	Lib.is_preprocessing(kind) != 0
end

def unexposed?

Check if this cursor is unexposed.

Signature

returns Boolean

True if the cursor is unexposed.

Implementation

def unexposed?
	Lib.is_unexposed(kind) != 0
end

def expansion_location

Get the expansion location of this cursor.

Signature

returns ExpansionLocation

The expansion location.

Implementation

def expansion_location
	ExpansionLocation.new(Lib.get_cursor_location(@cursor))
end

def presumed_location

Get the presumed location of this cursor.

Signature

returns PresumedLocation

The presumed location.

Implementation

def presumed_location
	PresumedLocation.new(Lib.get_cursor_location(@cursor))
end

def spelling_location

Get the spelling location of this cursor.

Signature

returns SpellingLocation

The spelling location.

Implementation

def spelling_location
	SpellingLocation.new(Lib.get_cursor_location(@cursor))
end

def file_location

Get the file location of this cursor.

Signature

returns FileLocation

The file location.

Implementation

def file_location
	FileLocation.new(Lib.get_cursor_location(@cursor))
end

def extent

Get the source extent of this cursor.

Signature

returns SourceRange

The source extent.

Implementation

def extent
	SourceRange.new(Lib.get_cursor_extent(@cursor))
end

def display_name

Get the display name of this cursor.

Signature

returns String

The display name.

Implementation

def display_name
	Lib.extract_string Lib.get_cursor_display_name(@cursor)
end

def qualified_display_name

Get the qualified display name including parent scope.

Signature

returns String | Nil

The qualified display name, or nil for translation units.

raises ArgumentError

If the semantic parent is invalid.

Implementation

def qualified_display_name
	if self.kind != :cursor_translation_unit
		if self.semantic_parent.kind == :cursor_invalid_file
			raise(ArgumentError, "Invalid semantic parent: #{self}")
		end
		result = self.semantic_parent.qualified_display_name
		result ? "#{result}::#{self.display_name}" : self.display_name
	end
end

def qualified_name

Get the fully qualified name of this cursor.

Signature

returns String | Nil

The qualified name, or nil for translation units.

raises ArgumentError

If the semantic parent is invalid.

Implementation

def qualified_name
	if self.kind != :cursor_translation_unit
		if self.semantic_parent.kind == :cursor_invalid_file
			raise(ArgumentError, "Invalid semantic parent: #{self}")
		end
		result = self.semantic_parent.qualified_name
		result ? "#{result}::#{self.spelling}" : self.spelling
	end
end

def spelling

Get the spelling (name) of this cursor.

Signature

returns String

The cursor spelling.

Implementation

def spelling
	Lib.extract_string Lib.get_cursor_spelling(@cursor)
end

def printing_policy

Get the printing policy for this cursor.

Signature

returns PrintingPolicy

The printing policy.

Implementation

def printing_policy
	PrintingPolicy.new(cursor)
end

def usr

Get the Unified Symbol Resolution (USR) for this cursor.

Signature

returns String

The USR string.

Implementation

def usr
	Lib.extract_string Lib.get_cursor_usr(@cursor)
end

def kind

Get the kind of this cursor.

Signature

returns Symbol | Nil

The cursor kind.

Implementation

def kind
	@cursor ? @cursor[:kind] : nil
end

def type

Get the type of this cursor.

Signature

returns Types::Type

The cursor type.

Implementation

def type
	Types::Type.create Lib.get_cursor_type(@cursor), @translation_unit
end

def result_type

Get the result type for a function cursor.

Signature

returns Types::Type

The result type.

Implementation

def result_type
	Types::Type.create Lib.get_cursor_result_type(@cursor), @translation_unit
end

def underlying_type

Get the underlying type for a typedef cursor.

Signature

returns Types::Type

The underlying type.

Implementation

def underlying_type
	Types::Type.create Lib.get_typedef_decl_underlying_type(@cursor), @translation_unit
end

def virtual_base?

Check if this cursor is a virtual base class.

Signature

returns Boolean

True if it's a virtual base.

Implementation

def virtual_base?
	Lib.is_virtual_base(@cursor) != 0
end

def dynamic_call?

Check if this cursor is a dynamic call.

Signature

returns Boolean

True if it's a dynamic call.

Implementation

def dynamic_call?
	Lib.is_dynamic_call(@cursor) != 0
end

def variadic?

Check if this cursor is variadic.

Signature

returns Boolean

True if the cursor is variadic.

Implementation

def variadic?
	Lib.is_variadic(@cursor) != 0
end

def definition?

Check if this cursor is a definition.

Signature

returns Boolean

True if the cursor is a definition.

Implementation

def definition?
	Lib.is_definition(@cursor) != 0
end

def static?

Check if this is a static method.

Signature

returns Boolean

True if the method is static.

Implementation

def static?
	Lib.cxx_method_is_static(@cursor) != 0
end

def virtual?

Check if this is a virtual method.

Signature

returns Boolean

True if the method is virtual.

Implementation

def virtual?
	Lib.cxx_method_is_virtual(@cursor) != 0
end

def pure_virtual?

Check if this is a pure virtual method.

Signature

returns Boolean

True if the method is pure virtual.

Implementation

def pure_virtual?
	Lib.cxx_method_is_pure_virtual(@cursor) != 0
end

def enum_value

Get the value of an enum constant.

Signature

returns Integer

The enum value.

Implementation

def enum_value
	Lib.get_enum_value @cursor
end

def enum_unsigned_value

Get the unsigned value of an enum constant.

Signature

returns Integer

The unsigned enum value.

Implementation

def enum_unsigned_value
	Lib.get_enum_unsigned_value @cursor
end

def enum_type

Get the integer type of an enum declaration.

Signature

returns Types::Type

The enum's underlying integer type.

Implementation

def enum_type
	Types::Type.create Lib.get_enum_decl_integer_type(@cursor), @translation_unit
end

def specialized_template

Get the template that this cursor specializes.

Signature

returns Cursor

The specialized template cursor.

Implementation

def specialized_template
	Cursor.new Lib.get_specialized_cursor_template(@cursor), @translation_unit
end

def canonical

Get the canonical cursor for this cursor.

Signature

returns Cursor

The canonical cursor.

Implementation

def canonical
	Cursor.new Lib.get_canonical_cursor(@cursor), @translation_unit
end

def definition

Get the definition cursor for this cursor.

Signature

returns Cursor

The definition cursor.

Implementation

def definition
	Cursor.new Lib.get_cursor_definition(@cursor), @translation_unit
end

def opaque_declaration?

Check if this is an opaque declaration without a definition.

Signature

returns Boolean

True if it's an opaque declaration.

Implementation

def opaque_declaration?
	# Is this a declaration that does not have a definition in the translation unit
	self.declaration? && !self.definition? && self.definition.invalid?
end

def forward_declaration?

Check if this is a forward declaration.

Signature

returns Boolean

True if it's a forward declaration.

Implementation

def forward_declaration?
	# Is this a forward declaration for a definition contained in the same translation_unit?
	# https://joshpeterson.github.io/identifying-a-forward-declaration-with-libclang
	#
	# Possible alternate implementations?
	# self.declaration? && !self.definition? && self.definition
	# !self.definition? && self.definition
	self.declaration? && !self.eql?(self.definition) && !self.definition.invalid?
end

def referenced

Get the cursor referenced by this cursor.

Signature

returns Cursor

The referenced cursor.

Implementation

def referenced
	Cursor.new Lib.get_cursor_referenced(@cursor), @translation_unit
end

def semantic_parent

Get the semantic parent of this cursor.

Signature

returns Cursor

The semantic parent cursor.

Implementation

def semantic_parent
	Cursor.new Lib.get_cursor_semantic_parent(@cursor), @translation_unit
end

def lexical_parent

Get the lexical parent of this cursor.

Signature

returns Cursor

The lexical parent cursor.

Implementation

def lexical_parent
	Cursor.new Lib.get_cursor_lexical_parent(@cursor), @translation_unit
end

def template_kind

Get the template cursor kind.

Signature

returns Symbol

The template cursor kind.

Implementation

def template_kind
	Lib.get_template_cursor_kind @cursor
end

def access_specifier

Get the C++ access specifier.

Signature

returns Symbol

The access specifier (:public, :private, or :protected).

Implementation

def access_specifier
	Lib.get_cxx_access_specifier @cursor
end

def language

Get the programming language of this cursor.

Signature

returns Symbol

The language symbol.

Implementation

def language
	Lib.get_language @cursor
end

def num_args

Get the number of arguments for this cursor.

Signature

returns Integer

The number of arguments.

Implementation

def num_args
	Lib.get_num_args @cursor
end

def each(recurse = true, &block)

Iterate over child cursors.

Signature

parameter recurse Boolean

Whether to recurse into children by default.

yields {|cursor, parent| ...}

Each child cursor with its parent.

parameter cursor Cursor

The child cursor.

parameter parent Cursor

The parent cursor.

returns Enumerator

If no block is given.

Implementation

def each(recurse = true, &block)
	return to_enum(:each, recurse) unless block_given?
	
	adapter = Proc.new do |cxcursor, parent_cursor, unused|
		# Call the block and capture the result. This lets advanced users
		# modify the recursion on a case by case basis if needed
		result = block.call Cursor.new(cxcursor, @translation_unit), Cursor.new(parent_cursor, @translation_unit)
		case result
		when :continue
			:continue
		when :recurse
			:recurse
		else
			recurse ? :recurse : :continue
		end
	end
	
	Lib.visit_children(@cursor, adapter, nil)
end

def visit_children(&block)

Visit only direct children without recursing.

Signature

yields {|cursor, parent| ...}

Each direct child cursor.

parameter cursor Cursor

The child cursor.

parameter parent Cursor

The parent cursor.

Implementation

def visit_children(&block)
	each(false, &block)
end

def ancestors_by_kind(*kinds)

Find ancestors of this cursor by kind.

Signature

parameter kinds Array(Symbol)

The cursor kinds to search for.

returns Array(Cursor)

Array of ancestor cursors matching the kinds.

Implementation

def ancestors_by_kind(*kinds)
	result = Array.new
	
	parent = self
	while parent != self.semantic_parent
		parent = self.semantic_parent
		if kinds.include?(parent.kind)
			result << parent
		end
	end
	result
end

def find_by_kind(recurse, *kinds)

Find child cursors by kind.

Signature

parameter recurse Boolean | Nil

Whether to recurse into children.

parameter kinds Array(Symbol)

The cursor kinds to search for.

returns Array(Cursor)

Array of matching cursors.

raises RuntimeError

If recurse parameter is not nil or boolean.

Implementation

def find_by_kind(recurse, *kinds)
	unless (recurse == nil || recurse == true || recurse == false)
		raise("Recurse parameter must be nil or a boolean value. Value was: #{recurse}")
	end
	
	result = Array.new
	self.each(recurse) do |child, parent|
		if kinds.include?(child.kind)
			result << child
		end
	end
	result
end

def find_references_in_file(file = nil, &block)

Find all references to this cursor in a file.

Signature

parameter file String | Nil

The file path, or nil to use the translation unit file.

yields {|cursor, range| ...}

Each reference with its cursor and source range.

parameter cursor Cursor

The reference cursor.

parameter range SourceRange

The source range of the reference.

Implementation

def find_references_in_file(file = nil, &block)
	file ||= Lib.extract_string Lib.get_translation_unit_spelling(@translation_unit)
	
	visit_adapter = Proc.new do |unused, cxcursor, cxsource_range|
		block.call Cursor.new(cxcursor, @translation_unit), SourceRange.new(cxsource_range)
	end
	visitor = FFI::Clang::Lib::CXCursorAndRangeVisitor.new
	visitor[:visit] = visit_adapter
	
	Lib.find_references_in_file(@cursor, Lib.get_file(@translation_unit, file), visitor)
end

def linkage

Get the linkage of this cursor.

Signature

returns Symbol

The linkage kind.

Implementation

def linkage
	Lib.get_cursor_linkage(@cursor)
end

def exception_specification

Get the exception specification type for this cursor.

Signature

returns Symbol

The exception specification type.

Implementation

def exception_specification
	Lib.get_cursor_exception_specification_type(@cursor)
end

def availability

Get the availability of this cursor.

Signature

returns Symbol

The availability status.

Implementation

def availability
	Lib.get_cursor_availability(@cursor)
end

def included_file

Get the file included by this cursor.

Signature

returns File

The included file.

Implementation

def included_file
	File.new Lib.get_included_file(@cursor), @translation_unit
end

def platform_availability(max_availability_size = 4)

Get platform availability information for this cursor.

Signature

parameter max_availability_size Integer

Maximum number of platforms to query.

returns Hash

Platform availability information.

Implementation

def platform_availability(max_availability_size = 4)
	availability_ptr = FFI::MemoryPointer.new(Lib::CXPlatformAvailability, max_availability_size)
	always_deprecated_ptr = FFI::MemoryPointer.new :int
	always_unavailable_ptr = FFI::MemoryPointer.new :int
	deprecated_message_ptr = FFI::MemoryPointer.new Lib::CXString
	unavailable_message_ptr = FFI::MemoryPointer.new Lib::CXString
	
	actual_availability_size = Lib.get_cursor_platform_availability(
		@cursor,
		always_deprecated_ptr, deprecated_message_ptr,
		always_unavailable_ptr, unavailable_message_ptr,
		availability_ptr, max_availability_size)
	
	availability = []
	cur_ptr = availability_ptr
	[actual_availability_size, max_availability_size].min.times {availability << PlatformAvailability.new(cur_ptr)
																																																														cur_ptr += Lib::CXPlatformAvailability.size
	}
	
	# return as Hash
	{
		always_deprecated: always_deprecated_ptr.get_int(0),
		always_unavailable: always_unavailable_ptr.get_int(0),
		deprecated_message: Lib.extract_string(Lib::CXString.new(deprecated_message_ptr)),
		unavailable_message: Lib.extract_string(Lib::CXString.new(unavailable_message_ptr)),
		availability: availability
	}
end

def overriddens

Get all cursors that this cursor overrides.

Signature

returns Array(Cursor)

Array of overridden cursors.

Implementation

def overriddens
	cursor_ptr = FFI::MemoryPointer.new :pointer
	num_ptr = FFI::MemoryPointer.new :uint
	Lib.get_overridden_cursors(@cursor, cursor_ptr, num_ptr)
	num = num_ptr.get_uint(0)
	cur_ptr = cursor_ptr.get_pointer(0)
	
	overriddens = []
	num.times {overriddens << Cursor.new(cur_ptr, @translation_unit)
												cur_ptr += Lib::CXCursor.size
	}
	Lib.dispose_overridden_cursors(cursor_ptr.get_pointer(0)) if num != 0
	overriddens
end

def bitfield?

Check if this cursor represents a bitfield.

Signature

returns Boolean

True if it's a bitfield.

Implementation

def bitfield?
	Lib.is_bit_field(@cursor) != 0
end

def bitwidth

Get the bit width of a bitfield.

Signature

returns Integer

The bitfield width.

Implementation

def bitwidth
	Lib.get_field_decl_bit_width(@cursor)
end

def overloaded_decl(i)

Get an overloaded declaration by index.

Signature

parameter i Integer

The index of the overloaded declaration.

returns Cursor

The overloaded declaration cursor.

Implementation

def overloaded_decl(i)
	Cursor.new Lib.get_overloaded_decl(@cursor, i), @translation_unit
end

def num_overloaded_decls

Get the number of overloaded declarations.

Signature

returns Integer

The number of overloaded declarations.

Implementation

def num_overloaded_decls
	Lib.get_num_overloaded_decls(@cursor)
end

def objc_type_encoding

Get the Objective-C type encoding.

Signature

returns String

The Objective-C type encoding.

Implementation

def objc_type_encoding
	Lib.extract_string Lib.get_decl_objc_type_encoding(@cursor)
end

def argument(i)

Get a function or method argument by index.

Signature

parameter i Integer

The argument index.

returns Cursor

The argument cursor.

Implementation

def argument(i)
	Cursor.new Lib.cursor_get_argument(@cursor, i), @translation_unit
end

def num_arguments

Get the number of arguments.

Signature

returns Integer

The number of arguments.

Implementation

def num_arguments
	Lib.cursor_get_num_arguments(@cursor)
end

def eql?(other)

Check if this cursor equals another cursor.

Signature

parameter other Cursor

The cursor to compare with.

returns Boolean

True if the cursors are equal.

Implementation

def eql?(other)
	Lib.are_equal(@cursor, other.cursor) != 0
end

def hash

Get the hash code for this cursor.

Signature

returns Integer

The hash code.

Implementation

def hash
	Lib.get_cursor_hash(@cursor)
end

def to_s

Get a string representation of this cursor.

Signature

returns String

The cursor string representation.

Implementation

def to_s
	"Cursor <#{self.kind.to_s.gsub(/^cursor_/, '')}: #{self.spelling}>"
end

def references(file = nil)

Find all references to this cursor.

Signature

parameter file String | Nil

The file to search in, or nil for the translation unit file.

returns Array(Cursor)

Array of reference cursors.

Implementation

def references(file = nil)
	refs = []
	self.find_references_in_file(file) do |cursor, unused|
		refs << cursor
		:continue
	end
	refs
end

def converting_constructor?

Check if this is a converting constructor.

Signature

returns Boolean

True if it's a converting constructor.

Implementation

def converting_constructor?
	Lib.is_converting_constructor(@cursor) != 0
end

def copy_constructor?

Check if this is a copy constructor.

Signature

returns Boolean

True if it's a copy constructor.

Implementation

def copy_constructor?
	Lib.is_copy_constructor(@cursor) != 0
end

def default_constructor?

Check if this is a default constructor.

Signature

returns Boolean

True if it's a default constructor.

Implementation

def default_constructor?
	Lib.is_default_constructor(@cursor) != 0
end

def move_constructor?

Check if this is a move constructor.

Signature

returns Boolean

True if it's a move constructor.

Implementation

def move_constructor?
	Lib.is_move_constructor(@cursor) != 0
end

def mutable?

Check if this cursor is mutable.

Signature

returns Boolean

True if it's mutable.

Implementation

def mutable?
	Lib.is_mutable(@cursor) != 0
end

def defaulted?

Check if this cursor is defaulted.

Signature

returns Boolean

True if it's defaulted.

Implementation

def defaulted?
	Lib.is_defaulted(@cursor) != 0
end

def deleted?

Check if this cursor is deleted.

Signature

returns Boolean

True if it's deleted.

Implementation

def deleted?
	Lib.is_deleted(@cursor) != 0
end

def copy_assignment_operator?

Check if this is a copy assignment operator.

Signature

returns Boolean

True if it's a copy assignment operator.

Implementation

def copy_assignment_operator?
	Lib.is_copy_assignment_operator(@cursor) != 0
end

def move_assignment_operator?

Check if this is a move assignment operator.

Signature

returns Boolean

True if it's a move assignment operator.

Implementation

def move_assignment_operator?
	Lib.is_move_assignment_operator(@cursor) != 0
end

def explicit?

Check if this cursor is explicit.

Signature

returns Boolean

True if it's explicit.

Implementation

def explicit?
	Lib.is_explicit(@cursor) != 0
end

def abstract?

Check if this cursor is abstract.

Signature

returns Boolean

True if it's abstract.

Implementation

def abstract?
	Lib.is_abstract(@cursor) != 0
end

def enum_scoped?

Check if this is a scoped enum.

Signature

returns Boolean

True if it's a scoped enum.

Implementation

def enum_scoped?
	Lib.is_enum_scoped(@cursor) != 0
end

def const?

Check if this cursor is const-qualified.

Signature

returns Boolean

True if it's const.

Implementation

def const?
	Lib.is_const(@cursor) != 0
end