Class: FFI::Clang::Types::Type
- Inherits:
-
Object
- Object
- FFI::Clang::Types::Type
- Defined in:
- lib/ffi/clang/types/type.rb
Overview
Represents a type in the C/C++ type system. This class wraps libclang’s type representation and provides methods to query type properties.
Instance Attribute Summary collapse
-
#translation_unit ⇒ Object
readonly
Returns the value of attribute translation_unit.
- #type ⇒ Object readonly
Class Method Summary collapse
-
.create(cxtype, translation_unit) ⇒ Object
Create a type instance of the appropriate subclass based on the type kind.
Instance Method Summary collapse
-
#==(other) ⇒ Object
Compare this type with another for equality.
-
#address_space ⇒ Object
Get the address space of this type.
-
#alignof ⇒ Object
Get the alignment of this type in bytes.
-
#canonical ⇒ Object
Get the canonical type.
-
#const_qualified? ⇒ Boolean
Check if this type is const-qualified.
-
#copy_assignable? ⇒ Boolean
Check if this type’s declaration (after reference stripping) has an accessible copy assignment operator and copy-assignable bases.
-
#copyable? ⇒ Boolean
Check if this type’s declaration (after reference stripping) has an accessible copy constructor and copyable bases.
-
#declaration ⇒ Object
Get the cursor for the declaration of this type.
-
#fqn_elaborated(policy) ⇒ Object
Spell an elaborated type (typedef / type alias / enum / class) preserving the alias name where appropriate and qualifying template arguments recursively.
-
#fqn_impl(policy) ⇒ Object
Shim implementation of fully_qualified_name.
-
#fqn_pointer(policy) ⇒ Object
Spell a pointer type and its qualifier chain.
-
#fqn_record ⇒ Object
Spell a record type (class/struct) using its declaration’s type spelling, which suppresses inline namespaces and includes template args.
-
#fqn_template_args(policy) ⇒ Object
Build the qualified template argument list by recursing into each type argument.
-
#fully_qualified_name(policy = nil, with_global_ns_prefix: false) ⇒ Object
Get the fully qualified name of this type.
-
#initialize(type, translation_unit) ⇒ Type
constructor
Create a new type instance.
-
#intrinsic_type ⇒ Object
Get the intrinsic type — strip the reference, follow pointer indirection until reaching a non-pointer type, then drop cv-qualifiers.
-
#kind ⇒ Object
Get the kind of this type.
-
#kind_spelling ⇒ Object
Get the spelling of this type’s kind.
-
#modified_type ⇒ Object
Get the type modified by an attributed type.
-
#non_reference_type ⇒ Object
Get the non-reference type.
-
#nullability ⇒ Object
Get the nullability kind of a pointer type.
-
#num_template_arguments ⇒ Object
Get the number of template arguments for this type.
-
#parse_template_args_from_spelling ⇒ Object
Parse template arguments from the type’s unqualified spelling, respecting nested angle brackets.
-
#pod? ⇒ Boolean
Check if this is a Plain Old Data (POD) type.
-
#pretty_printed(policy) ⇒ Object
Pretty-print this type using a printing policy.
-
#ref_qualifier ⇒ Object
Get the ref-qualifier for this type (C++ only).
-
#reference? ⇒ Boolean
True if this type is an lvalue or rvalue reference.
-
#restrict_qualified? ⇒ Boolean
Check if this type is restrict-qualified.
-
#sizeof ⇒ Object
Get the size of this type in bytes.
-
#spelling ⇒ Object
Get the spelling of this type.
-
#template_argument_type(index) ⇒ Object
Get the type of a template argument at the given index.
-
#to_s ⇒ Object
Get a string representation of this type.
-
#transparent_tag_typedef? ⇒ Boolean
Check if this typedef is transparent.
-
#typedef_name ⇒ Object
Get the typedef name of this type.
-
#unqualified_type ⇒ Object
Get the type with all qualifiers (const, volatile, restrict) removed.
-
#value_type ⇒ Object
Get the value type of an atomic type.
-
#visit_base_classes(&block) ⇒ Object
Visit all base classes of a C++ record type.
-
#visit_fields(&block) ⇒ Object
Visit all fields of a record type.
-
#visit_methods(&block) ⇒ Object
Visit all methods of a C++ record type.
-
#volatile_qualified? ⇒ Boolean
Check if this type is volatile-qualified.
Constructor Details
#initialize(type, translation_unit) ⇒ Type
Create a new type instance.
51 52 53 54 |
# File 'lib/ffi/clang/types/type.rb', line 51 def initialize(type, translation_unit) @type = type @translation_unit = translation_unit end |
Instance Attribute Details
#translation_unit ⇒ Object (readonly)
Returns the value of attribute translation_unit.
21 |
# File 'lib/ffi/clang/types/type.rb', line 21 attr_reader :type, :translation_unit |
#type ⇒ Object (readonly)
21 22 23 |
# File 'lib/ffi/clang/types/type.rb', line 21 def type @type end |
Class Method Details
.create(cxtype, translation_unit) ⇒ Object
Create a type instance of the appropriate subclass based on the type kind.
27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 |
# File 'lib/ffi/clang/types/type.rb', line 27 def self.create(cxtype, translation_unit) case cxtype[:kind] when :type_pointer, :type_block_pointer, :type_obj_c_object_pointer, :type_member_pointer Pointer.new(cxtype, translation_unit) when :type_constant_array, :type_incomplete_array, :type_variable_array, :type_dependent_sized_array Array.new(cxtype, translation_unit) when :type_vector Vector.new(cxtype, translation_unit) when :type_function_no_proto, :type_function_proto Function.new(cxtype, translation_unit) when :type_elaborated Elaborated.new(cxtype, translation_unit) when :type_typedef TypeDef.new(cxtype, translation_unit) when :type_record Record.new(cxtype, translation_unit) else Type.new(cxtype, translation_unit) end end |
Instance Method Details
#==(other) ⇒ Object
Compare this type with another for equality.
552 553 554 |
# File 'lib/ffi/clang/types/type.rb', line 552 def ==(other) Lib.equal_types(@type, other.type) != 0 end |
#address_space ⇒ Object
Get the address space of this type.
222 223 224 |
# File 'lib/ffi/clang/types/type.rb', line 222 def address_space Lib.get_address_space(@type) end |
#alignof ⇒ Object
Get the alignment of this type in bytes.
106 107 108 |
# File 'lib/ffi/clang/types/type.rb', line 106 def alignof Lib.type_get_align_of(@type) end |
#canonical ⇒ Object
Get the canonical type.
76 77 78 |
# File 'lib/ffi/clang/types/type.rb', line 76 def canonical Type.create Lib.get_canonical_type(@type), @translation_unit end |
#const_qualified? ⇒ Boolean
Check if this type is const-qualified.
88 89 90 |
# File 'lib/ffi/clang/types/type.rb', line 88 def const_qualified? Lib.is_const_qualified_type(@type) != 0 end |
#copy_assignable? ⇒ Boolean
Check if this type’s declaration (after reference stripping) has an accessible copy assignment operator and copy-assignable bases. Returns true for non-class types (fundamentals, pointers, enums) and for types whose declaration is unavailable (:cursor_no_decl_found).
199 200 201 |
# File 'lib/ffi/clang/types/type.rb', line 199 def copy_assignable? self.non_reference_type.declaration.copy_assignable? end |
#copyable? ⇒ Boolean
Check if this type’s declaration (after reference stripping) has an accessible copy constructor and copyable bases. Returns true for non-class types (fundamentals, pointers, enums) and for types whose declaration is unavailable (:cursor_no_decl_found).
188 189 190 |
# File 'lib/ffi/clang/types/type.rb', line 188 def copyable? self.non_reference_type.declaration.copyable? end |
#declaration ⇒ Object
Get the cursor for the declaration of this type.
124 125 126 |
# File 'lib/ffi/clang/types/type.rb', line 124 def declaration Cursor.new Lib.get_type_declaration(@type), @translation_unit end |
#fqn_elaborated(policy) ⇒ Object
Spell an elaborated type (typedef / type alias / enum / class) preserving the alias name where appropriate and qualifying template arguments recursively.
347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 |
# File 'lib/ffi/clang/types/type.rb', line 347 def fqn_elaborated(policy) decl = self.declaration const_prefix = self.const_qualified? ? "const " : "" case decl.kind when :cursor_typedef_decl, :cursor_type_alias_decl # Preserve the typedef/alias name and qualify with namespace. spelling = self.unqualified_type.spelling qualified = decl.qualified_name if spelling.include?("::") # Already partially qualified. For nested typedefs in # template classes (e.g., std::vector<Pixel>::iterator), # qualify template args using the parent type's fqn. parent = decl.semantic_parent if parent.kind == :cursor_class_decl || parent.kind == :cursor_struct parent_type = parent.type parent_fqn = parent_type.fqn_impl(policy) member_name = decl.spelling "#{const_prefix}#{parent_fqn}::#{member_name}" else "#{const_prefix}#{spelling}" end elsif qualified "#{const_prefix}#{qualified}" else "#{const_prefix}#{spelling}" end when :cursor_enum_decl "#{const_prefix}#{decl.qualified_name}" else # Alias-template detection: e.g. `AliasOptional<int>` -> `Optional<int>`. # The elaborated spelling preserves the alias; fqn_record # would resolve to the underlying type. Use spelling when # it's already qualified. unqual = self.unqualified_type.spelling if unqual.include?("::") && decl.spelling != unqual.sub(/<.*/, "").split("::").last "#{const_prefix}#{unqual}" else base = fqn_record if self.const_qualified? && !base.start_with?("const ") "const #{base}" else base end end end end |
#fqn_impl(policy) ⇒ Object
Shim implementation of fully_qualified_name. Recursively walks the type tree, dispatching by kind. Public so it can be invoked across Type subclass boundaries during recursion.
292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 |
# File 'lib/ffi/clang/types/type.rb', line 292 def fqn_impl(policy) case self.kind when :type_lvalue_ref "#{self.non_reference_type.fqn_impl(policy)} &" when :type_rvalue_ref "#{self.non_reference_type.fqn_impl(policy)} &&" when :type_pointer fqn_pointer(policy) when :type_constant_array "#{self.element_type.fqn_impl(policy)}[#{self.size}]" when :type_incomplete_array "#{self.element_type.fqn_impl(policy)}[]" when :type_elaborated fqn_elaborated(policy) when :type_record fqn_record else self.spelling end end |
#fqn_pointer(policy) ⇒ Object
Spell a pointer type and its qualifier chain. Function pointers get a single rendering with parameter list; data pointers walk the chain collecting ‘*`/`*const` parts and qualify the leaf child once. Output matches native fqn: `int **`, `const char *const`, etc.
319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 |
# File 'lib/ffi/clang/types/type.rb', line 319 def fqn_pointer(policy) pointee = self.pointee if [:type_function_proto, :type_function_no_proto].include?(pointee.kind) ptr_const = self.const_qualified? ? " const" : "" result_type = pointee.result_type.fqn_impl(policy) arg_types = pointee.arg_types.map{|arg_type| arg_type.fqn_impl(policy)}.join(", ") return "#{result_type} (*#{ptr_const})(#{arg_types})" end parts = [] current = self while current.kind == :type_pointer inner = current.pointee break if [:type_function_proto, :type_function_no_proto].include?(inner.kind) parts << (current.const_qualified? ? "*const" : "*") current = inner end "#{current.fqn_impl(policy)} #{parts.reverse.join}" end |
#fqn_record ⇒ Object
Spell a record type (class/struct) using its declaration’s type spelling, which suppresses inline namespaces and includes template args. Falls back to qualified_name + spelling args for dependent types.
403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 |
# File 'lib/ffi/clang/types/type.rb', line 403 def fqn_record decl = self.declaration return self.spelling if decl.kind == :cursor_no_decl_found const_prefix = self.const_qualified? ? "const " : "" # decl.type.spelling gives the right qualification (no inline # ns, with template args). decl_spelling = decl.type.spelling if decl_spelling && !decl_spelling.empty? && decl_spelling.include?("::") # For concrete template types, recursively qualify args. n = self.num_template_arguments if n > 0 base = decl_spelling.sub(/<.*/, "") template_args = fqn_template_args(nil) "#{const_prefix}#{base}#{template_args}" else "#{const_prefix}#{decl_spelling}" end else # Fallback for types where decl.type.spelling is unqualified. qualified = decl.qualified_name = self.unqualified_type.spelling template_args = .include?("<") ? [/<.*/] : "" "#{const_prefix}#{qualified}#{template_args}" end end |
#fqn_template_args(policy) ⇒ Object
Build the qualified template argument list by recursing into each type argument. Non-type template parameters (e.g. integral values) are recovered from the type’s spelling.
436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 |
# File 'lib/ffi/clang/types/type.rb', line 436 def fqn_template_args(policy) n = self.num_template_arguments return "" unless n > 0 # Extract original args from spelling for non-type template params. spelling_args = parse_template_args_from_spelling args = (0...n).map do |i| arg_type = self.template_argument_type(i) if arg_type.kind == :type_invalid # Non-type template arg (e.g., int N=3) — use from spelling. spelling_args ? spelling_args[i] : nil else arg_type.fqn_impl(policy) end end.compact return "" if args.empty? "<#{args.join(", ")}>" end |
#fully_qualified_name(policy = nil, with_global_ns_prefix: false) ⇒ Object
Get the fully qualified name of this type.
On libclang 21+ this dispatches to clang_getFullyQualifiedName. On earlier libclang versions it falls back to a Ruby shim that composes existing libclang APIs (declaration, qualified_name, template arguments, pointer/array/reference unwrapping, etc.).
Known shim limitation: STL container typedefs that depend on default template arguments (e.g., ‘std::vector<T>::iterator`) don’t expand the defaults. Output is valid C++ and matches the native result for non-STL types.
278 279 280 281 282 283 284 285 |
# File 'lib/ffi/clang/types/type.rb', line 278 def fully_qualified_name(policy = nil, with_global_ns_prefix: false) if Lib.respond_to?(:get_fully_qualified_name) Lib.extract_string Lib.get_fully_qualified_name(@type, policy, with_global_ns_prefix ? 1 : 0) else result = fqn_impl(policy) with_global_ns_prefix ? "::#{result}" : result end end |
#intrinsic_type ⇒ Object
Get the intrinsic type — strip the reference, follow pointer indirection until reaching a non-pointer type, then drop cv-qualifiers. Named after Rice’s ‘intrinsic_type` metafunction of the same shape. Useful when asking “what does this type ultimately denote?” for skip-list and bindability checks.
Examples:
-
‘T &` becomes `T`
-
‘T *` becomes `T`
-
‘T **&` becomes `T`
-
‘const T &` becomes `T`
173 174 175 176 177 178 179 |
# File 'lib/ffi/clang/types/type.rb', line 173 def intrinsic_type type = self.non_reference_type while type.kind == :type_pointer type = type.pointee end type.unqualified_type end |
#kind ⇒ Object
Get the kind of this type.
58 59 60 |
# File 'lib/ffi/clang/types/type.rb', line 58 def kind @type[:kind] end |
#kind_spelling ⇒ Object
Get the spelling of this type’s kind.
64 65 66 |
# File 'lib/ffi/clang/types/type.rb', line 64 def kind_spelling Lib.extract_string Lib.get_type_kind_spelling @type[:kind] end |
#modified_type ⇒ Object
Get the type modified by an attributed type.
246 247 248 |
# File 'lib/ffi/clang/types/type.rb', line 246 def modified_type Type.create Lib.type_get_modified_type(@type), @translation_unit end |
#non_reference_type ⇒ Object
Get the non-reference type. For reference types, returns the type that is being referenced. Guards against :type_invalid input: clang_getNonReferenceType dereferences the underlying QualType without a null check and segfaults on invalid types. Returning self preserves the invalid kind without entering libclang.
155 156 157 158 |
# File 'lib/ffi/clang/types/type.rb', line 155 def non_reference_type return self if self.kind == :type_invalid Type.create Lib.get_non_reference_type(@type), @translation_unit end |
#nullability ⇒ Object
Get the nullability kind of a pointer type.
240 241 242 |
# File 'lib/ffi/clang/types/type.rb', line 240 def nullability Lib.type_get_nullability(@type) end |
#num_template_arguments ⇒ Object
Get the number of template arguments for this type. For template specializations (e.g., ‘std::map<int, std::string>`), this returns the number of template arguments. Returns -1 if this is not a template specialization.
216 217 218 |
# File 'lib/ffi/clang/types/type.rb', line 216 def num_template_arguments Lib.get_num_template_arguments(@type) end |
#parse_template_args_from_spelling ⇒ Object
Parse template arguments from the type’s unqualified spelling, respecting nested angle brackets. Used to recover non-type template arguments that libclang surfaces only as text.
461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 |
# File 'lib/ffi/clang/types/type.rb', line 461 def parse_template_args_from_spelling = self.unqualified_type.spelling start = .index("<") return nil unless start depth = 0 args = [] current = +"" [start + 1..].each_char do |c| case c when "<" depth += 1 current << c when ">" if depth == 0 args << current.strip unless current.strip.empty? break else depth -= 1 current << c end when "," if depth == 0 args << current.strip current = +"" else current << c end else current << c end end args end |
#pod? ⇒ Boolean
Check if this is a Plain Old Data (POD) type.
82 83 84 |
# File 'lib/ffi/clang/types/type.rb', line 82 def pod? Lib.is_pod_type(@type) != 0 end |
#pretty_printed(policy) ⇒ Object
Pretty-print this type using a printing policy.
259 260 261 |
# File 'lib/ffi/clang/types/type.rb', line 259 def pretty_printed(policy) Lib.extract_string Lib.get_type_pretty_printed(@type, policy) end |
#ref_qualifier ⇒ Object
Get the ref-qualifier for this type (C++ only).
118 119 120 |
# File 'lib/ffi/clang/types/type.rb', line 118 def ref_qualifier Lib.type_get_cxx_ref_qualifier(@type) end |
#reference? ⇒ Boolean
True if this type is an lvalue or rvalue reference.
143 144 145 |
# File 'lib/ffi/clang/types/type.rb', line 143 def reference? self.kind == :type_lvalue_ref || self.kind == :type_rvalue_ref end |
#restrict_qualified? ⇒ Boolean
Check if this type is restrict-qualified.
100 101 102 |
# File 'lib/ffi/clang/types/type.rb', line 100 def restrict_qualified? Lib.is_restrict_qualified_type(@type) != 0 end |
#sizeof ⇒ Object
Get the size of this type in bytes.
112 113 114 |
# File 'lib/ffi/clang/types/type.rb', line 112 def sizeof Lib.type_get_size_of(@type) end |
#spelling ⇒ Object
Get the spelling of this type.
70 71 72 |
# File 'lib/ffi/clang/types/type.rb', line 70 def spelling Lib.extract_string Lib.get_type_spelling(@type) end |
#template_argument_type(index) ⇒ Object
Get the type of a template argument at the given index. For template specializations (e.g., ‘std::vector<int>`), this returns the type of the template argument at the specified position.
208 209 210 |
# File 'lib/ffi/clang/types/type.rb', line 208 def template_argument_type(index) Type.create Lib.get_template_argument_as_type(@type, index), @translation_unit end |
#to_s ⇒ Object
Get a string representation of this type.
558 559 560 |
# File 'lib/ffi/clang/types/type.rb', line 558 def to_s "#{self.class.name} <#{self.kind}: #{self.spelling}>" end |
#transparent_tag_typedef? ⇒ Boolean
Check if this typedef is transparent.
234 235 236 |
# File 'lib/ffi/clang/types/type.rb', line 234 def transparent_tag_typedef? Lib.type_is_transparent_tag_typedef(@type) != 0 end |
#typedef_name ⇒ Object
Get the typedef name of this type.
228 229 230 |
# File 'lib/ffi/clang/types/type.rb', line 228 def typedef_name Lib.extract_string Lib.get_typedef_name(@type) end |
#unqualified_type ⇒ Object
Get the type with all qualifiers (const, volatile, restrict) removed. Guards against :type_invalid input: clang_getUnqualifiedType has no null check on the underlying QualType (unlike its siblings clang_getNonReferenceType / clang_getCanonicalType / etc.) and segfaults on invalid types. Returning self preserves the invalid kind without entering libclang.
136 137 138 139 |
# File 'lib/ffi/clang/types/type.rb', line 136 def unqualified_type return self if self.kind == :type_invalid Type.create Lib.get_unqualified_type(@type), @translation_unit end |
#value_type ⇒ Object
Get the value type of an atomic type.
252 253 254 |
# File 'lib/ffi/clang/types/type.rb', line 252 def value_type Type.create Lib.type_get_value_type(@type), @translation_unit end |
#visit_base_classes(&block) ⇒ Object
Visit all base classes of a C++ record type.
501 502 503 504 505 |
# File 'lib/ffi/clang/types/type.rb', line 501 def visit_base_classes(&block) return to_enum(__method__) unless block_given? visit_type(:visit_cxx_base_classes, &block) end |
#visit_fields(&block) ⇒ Object
Visit all fields of a record type.
523 524 525 526 527 |
# File 'lib/ffi/clang/types/type.rb', line 523 def visit_fields(&block) return to_enum(__method__) unless block_given? visit_type(:type_visit_fields, &block) end |
#visit_methods(&block) ⇒ Object
Visit all methods of a C++ record type.
512 513 514 515 516 |
# File 'lib/ffi/clang/types/type.rb', line 512 def visit_methods(&block) return to_enum(__method__) unless block_given? visit_type(:visit_cxx_methods, &block) end |
#volatile_qualified? ⇒ Boolean
Check if this type is volatile-qualified.
94 95 96 |
# File 'lib/ffi/clang/types/type.rb', line 94 def volatile_qualified? Lib.is_volatile_qualified_type(@type) != 0 end |