ffi-clang

FORK: Ruby FFI bindings for my custom patched clang 8.0.
git clone https://git.neptards.moe/neptards/ffi-clang.git
Log | Files | Refs | README

cursor.rb (11206B)


      1 # Copyright, 2010-2012 by Jari Bakken.
      2 # Copyright, 2013, by Samuel G. D. Williams. <http://www.codeotaku.com>
      3 # Copyright, 2014, by Masahiro Sano.
      4 #
      5 # Permission is hereby granted, free of charge, to any person obtaining a copy
      6 # of this software and associated documentation files (the "Software"), to deal
      7 # in the Software without restriction, including without limitation the rights
      8 # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
      9 # copies of the Software, and to permit persons to whom the Software is
     10 # furnished to do so, subject to the following conditions:
     11 #
     12 # The above copyright notice and this permission notice shall be included in
     13 # all copies or substantial portions of the Software.
     14 #
     15 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     16 # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     17 # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
     18 # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     19 # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
     20 # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
     21 # THE SOFTWARE.
     22 
     23 require_relative 'lib/cursor'
     24 require_relative 'lib/code_completion'
     25 
     26 require_relative 'source_location'
     27 require_relative 'source_range'
     28 require_relative 'type'
     29 
     30 module FFI
     31 	module Clang
     32 		class Cursor
     33 			attr_reader :cursor
     34 			attr_reader :translation_unit
     35 
     36 			def self.null_cursor
     37 				Cursor.new Lib.get_null_cursor, nil
     38 			end
     39 
     40 			# this function is categorized as "Debugging facilities"
     41 			def self.kind_spelling(kind)
     42 				Lib.extract_string Lib.get_cursor_kind_spelling(kind)
     43 			end
     44 
     45 			def initialize(cxcursor, translation_unit)
     46 				@cursor = cxcursor
     47 				@translation_unit = translation_unit
     48 			end
     49 
     50 			def null?
     51 				Lib.cursor_is_null(@cursor) != 0
     52 			end
     53 
     54 			def raw_comment_text
     55 				Lib.extract_string Lib.cursor_get_raw_comment_text(@cursor)
     56 			end
     57 
     58 			def brief_comment_text
     59 				Lib.extract_string Lib.cursor_get_brief_comment_text(@cursor)
     60 			end
     61 
     62 			def deleted?
     63 				Lib.cursor_is_deleted(@cursor) != 0
     64 			end
     65 
     66 			def comment_range
     67 				SourceRange.new(Lib.cursor_get_comment_range(@cursor))
     68 			end
     69 
     70 			def completion
     71 				CodeCompletion::String.new Lib.get_cursor_completion_string(@cursor)
     72 			end
     73 
     74 			def declaration?
     75 				Lib.is_declaration(kind) != 0
     76 			end
     77 
     78 			def reference?
     79 				Lib.is_reference(kind) != 0
     80 			end
     81 
     82 			def expression?
     83 				Lib.is_expression(kind) != 0
     84 			end
     85 
     86 			def statement?
     87 				Lib.is_statement(kind) != 0
     88 			end
     89 
     90 			def attribute?
     91 				Lib.is_attribute(kind) != 0
     92 			end
     93 
     94 			def public?
     95 				Lib.cxx_get_access_specifier(@cursor) == :public
     96 			end
     97 
     98 			def private?
     99 				Lib.cxx_get_access_specifier(@cursor) == :private
    100 			end
    101 
    102 			def protected?
    103 				Lib.cxx_get_access_specifier(@cursor) == :protected
    104 			end
    105 
    106 			def invalid?
    107 				Lib.is_invalid(kind) != 0
    108 			end
    109 
    110 			def translation_unit?
    111 				Lib.is_translation_unit(kind) != 0
    112 			end
    113 
    114 			def preprocessing?
    115 				Lib.is_preprocessing(kind) != 0
    116 			end
    117 
    118 			def unexposed?
    119 				Lib.is_unexposed(kind) != 0
    120 			end
    121 
    122 			def location
    123 				ExpansionLocation.new(Lib.get_cursor_location(@cursor))
    124 			end
    125 
    126 			def extent
    127 				SourceRange.new(Lib.get_cursor_extent(@cursor))
    128 			end
    129 
    130 			def display_name
    131 				Lib.extract_string Lib.get_cursor_display_name(@cursor)
    132 			end
    133 
    134 			def spelling
    135 				Lib.extract_string Lib.get_cursor_spelling(@cursor)
    136 			end
    137 
    138 			def usr
    139 				Lib.extract_string Lib.get_cursor_usr(@cursor)
    140 			end
    141 
    142 			def kind
    143 				@cursor[:kind]
    144 			end
    145 
    146 			def kind_spelling
    147 				Cursor.kind_spelling @cursor[:kind]
    148 			end
    149 
    150 			def type
    151 				Type.new Lib.get_cursor_type(@cursor), @translation_unit
    152 			end
    153 
    154 			def result_type
    155 				Type.new Lib.get_cursor_result_type(@cursor), @translation_unit
    156 			end
    157 
    158 			def underlying_type
    159 				Type.new Lib.get_typedef_decl_underlying_type(@cursor), @translation_unit
    160 			end
    161 
    162 			def enum_decl_integer_type
    163 				Type.new Lib.get_enum_decl_integer_type(@cursor), @translation_unit
    164 			end
    165 
    166 			def typedef_type
    167 				Type.new Lib.get_typedef_decl_unerlying_type(@cursor), @translation_unit
    168 			end
    169 
    170 			def virtual_base?
    171 				Lib.is_virtual_base(@cursor) != 0
    172 			end
    173 
    174 			def dynamic_call?
    175 				Lib.is_dynamic_call(@cursor) != 0
    176 			end
    177 
    178 			def variadic?
    179 				Lib.is_variadic(@cursor) != 0
    180 			end
    181 
    182 			def definition?
    183 				Lib.is_definition(@cursor) != 0
    184 			end
    185 
    186 			def static?
    187 				Lib.cxx_method_is_static(@cursor) != 0
    188 			end
    189 
    190 			def virtual?
    191 				Lib.cxx_method_is_virtual(@cursor) != 0
    192 			end
    193 
    194 			def override?
    195 				Lib.cxx_method_is_override(@cursor) != 0
    196 			end
    197 
    198 			def defaulted?
    199 				Lib.cxx_method_is_defaulted(@cursor) != 0
    200 			end
    201 
    202 			def pure_virtual?
    203 				Lib.cxx_method_is_pure_virtual(@cursor) != 0
    204 			end
    205 
    206 			def const?
    207 				Lib.cxx_method_is_const(@cursor) != 0
    208 			end
    209 
    210 			def enum_value
    211 				Lib.get_enum_value @cursor
    212 			end
    213 
    214 			def enum_unsigned_value
    215 				Lib.get_enum_unsigned_value @cursor
    216 			end
    217 
    218 			def enum_type
    219 				Type.new Lib.get_enum_type(@cursor), @translation_unit
    220 			end
    221 
    222 			def specialized_template
    223 				Cursor.new Lib.get_specialized_cursor_template(@cursor), @translation_unit
    224 			end
    225 
    226 			def canonical
    227 				Cursor.new Lib.get_canonical_cursor(@cursor), @translation_unit
    228 			end
    229 
    230 			def definition
    231 				Cursor.new Lib.get_cursor_definition(@cursor), @translation_unit
    232 			end
    233 
    234 			def referenced
    235 				Cursor.new Lib.get_cursor_referenced(@cursor), @translation_unit
    236 			end
    237 
    238 			def semantic_parent
    239 				Cursor.new Lib.get_cursor_semantic_parent(@cursor), @translation_unit
    240 			end
    241 
    242 			def lexical_parent
    243 				Cursor.new Lib.get_cursor_lexical_parent(@cursor), @translation_unit
    244 			end
    245 
    246 			def template_kind
    247 				Lib.get_template_cursor_kind @cursor
    248 			end
    249 
    250 			def access_specifier
    251 				Lib.get_cxx_access_specifier @cursor
    252 			end
    253 
    254 			def language
    255 				Lib.get_language @cursor
    256 			end
    257 
    258 			def num_args
    259 				Lib.get_num_args @cursor
    260 			end
    261 
    262 			def visit_children(&block)
    263 				adapter = Proc.new do |cxcursor, parent_cursor, unused|
    264 					block.call Cursor.new(cxcursor, @translation_unit), Cursor.new(parent_cursor, @translation_unit)
    265 				end
    266 
    267 				Lib.visit_children(@cursor, adapter, nil)
    268 			end
    269 
    270 			def find_references_in_file(file = nil, &block)
    271 				file ||= Lib.extract_string Lib.get_translation_unit_spelling(@translation_unit)
    272 
    273 				visit_adapter = Proc.new do |unused, cxcursor, cxsource_range|
    274 					block.call Cursor.new(cxcursor, @translation_unit), SourceRange.new(cxsource_range)
    275 				end
    276 				visitor = FFI::Clang::Lib::CXCursorAndRangeVisitor.new
    277 				visitor[:visit] = visit_adapter
    278 
    279 				Lib.find_references_in_file(@cursor, Lib.get_file(@translation_unit, file), visitor)
    280 			end
    281 
    282 			def linkage
    283 				Lib.get_cursor_linkage(@cursor)
    284 			end
    285 
    286 			def availability
    287 				Lib.get_cursor_availability(@cursor)
    288 			end
    289 
    290 			def included_file
    291 				File.new Lib.get_included_file(@cursor), @translation_unit
    292 			end
    293 
    294 			def platform_availability(max_availability_size = 4)
    295 				availability_ptr = FFI::MemoryPointer.new(Lib::CXPlatformAvailability, max_availability_size)
    296 				always_deprecated_ptr = FFI::MemoryPointer.new :int
    297 				always_unavailable_ptr = FFI::MemoryPointer.new :int
    298 				deprecated_message_ptr = FFI::MemoryPointer.new Lib::CXString
    299 				unavailable_message_ptr = FFI::MemoryPointer.new Lib::CXString
    300 
    301 				actual_availability_size = Lib.get_cursor_platform_availability(
    302 					@cursor,
    303 					always_deprecated_ptr, deprecated_message_ptr,
    304 					always_unavailable_ptr, unavailable_message_ptr,
    305 					availability_ptr, max_availability_size)
    306 
    307 				availability = []
    308 				cur_ptr = availability_ptr
    309 				[actual_availability_size, max_availability_size].min.times {
    310 					availability << PlatformAvailability.new(cur_ptr)
    311 					cur_ptr += Lib::CXPlatformAvailability.size
    312 				}
    313 
    314 				# return as Hash
    315 				{
    316 					always_deprecated: always_deprecated_ptr.get_int(0),
    317 					always_unavailable: always_unavailable_ptr.get_int(0),
    318 					deprecated_message: Lib.extract_string(Lib::CXString.new(deprecated_message_ptr)),
    319 					unavailable_message: Lib.extract_string(Lib::CXString.new(unavailable_message_ptr)),
    320 					availability: availability
    321 				}
    322 			end
    323 
    324 			def overriddens
    325 				cursor_ptr = FFI::MemoryPointer.new :pointer
    326 				num_ptr = FFI::MemoryPointer.new :uint
    327 				Lib.get_overridden_cursors(@cursor, cursor_ptr, num_ptr)
    328 				num = num_ptr.get_uint(0)
    329 				cur_ptr = cursor_ptr.get_pointer(0)
    330 
    331 				overriddens = []
    332 				num.times {
    333 					overriddens << Cursor.new(cur_ptr, @translation_unit)
    334 					cur_ptr += Lib::CXCursor.size
    335 				}
    336 				Lib.dispose_overridden_cursors(cursor_ptr.get_pointer(0)) if num != 0
    337 				overriddens
    338 			end
    339 
    340 			def hash
    341 				Lib.get_cursor_hash(@cursor)
    342 			end
    343 
    344 			def bitfield?
    345 				Lib.is_bit_field(@cursor) != 0
    346 			end
    347 
    348 			def bitwidth
    349 				Lib.get_field_decl_bit_width(@cursor)
    350 			end
    351 
    352 			def overloaded_decl(i)
    353 				Cursor.new Lib.get_overloaded_decl(@cursor, i), @translation_unit
    354 			end
    355 
    356 			def num_overloaded_decls
    357 				Lib.get_num_overloaded_decls(@cursor)
    358 			end
    359 
    360 			def overloaded_decls
    361 				Lib.get_num_overloaded_decls(@cursor).times.map do |i|
    362 					overloaded_decl(i)
    363 				end
    364 			end
    365 
    366 			def objc_type_encoding
    367 				Lib.extract_string Lib.get_decl_objc_type_encoding(@cursor)
    368 			end
    369 
    370 			def argument(i)
    371 				Cursor.new Lib.cursor_get_argument(@cursor, i), @translation_unit
    372 			end
    373 
    374 			def num_arguments
    375 				Lib.cursor_get_num_arguments(@cursor)
    376 			end
    377 
    378 			def num_template_arguments
    379 				Lib.cursor_get_num_template_arguments(@cursor)
    380 			end
    381 
    382 			def ==(other)
    383 				Lib.are_equal(@cursor, other.cursor) != 0
    384 			end
    385 
    386 			def find_all(*kinds)
    387 				filter do |child, parent|
    388 					kinds.include?(child.kind)
    389 				end
    390 			end
    391 
    392 			def find_first(*kinds)
    393 				find_all(*kinds).first
    394 			end
    395 
    396 			def filter
    397 				return to_enum(:select) unless block_given?
    398 
    399 				matching = []
    400 
    401 				self.visit_children do |child, parent|
    402 					if yield(child, parent)
    403 						matching << child
    404 					end
    405 
    406 					:recurse
    407 				end
    408 
    409 				return matching
    410 			end
    411 
    412 			def select
    413 				filter do |child, parent|
    414 					yield(child)
    415 				end
    416 			end
    417 
    418 			def to_a
    419 				filter.collect{|child, parent| child}
    420 			end
    421 
    422 			def references(file = nil)
    423 				refs = []
    424 				self.find_references_in_file(file) do |cursor, unused|
    425 					refs << cursor
    426 					:continue
    427 				end
    428 				refs
    429 			end
    430 
    431 			class PlatformAvailability < AutoPointer
    432 				def initialize(memory_pointer)
    433 					pointer = FFI::Pointer.new(memory_pointer)
    434 					super(pointer)
    435 
    436 					# I'm not sure this is safe.
    437 					# Keep a reference to CXPlatformAvailability itself allocated by MemoryPointer.
    438 					@memory_pointer = memory_pointer
    439 					@platform_availability = Lib::CXPlatformAvailability.new(memory_pointer)
    440 				end
    441 
    442 				def self.release(pointer)
    443 					# Memory allocated by get_cursor_platform_availability is managed by AutoPointer.
    444 					Lib.dispose_platform_availability(Lib::CXPlatformAvailability.new(pointer))
    445 				end
    446 
    447 				def platform
    448 					Lib.get_string @platform_availability[:platform]
    449 				end
    450 
    451 				def introduced
    452 					@platform_availability[:introduced]
    453 				end
    454 
    455 				def deprecated
    456 					@platform_availability[:deprecated]
    457 				end
    458 
    459 				def obsoleted
    460 					@platform_availability[:obsoleted]
    461 				end
    462 
    463 				def unavailable
    464 					@platform_availability[:unavailable] != 0
    465 				end
    466 
    467 				def message
    468 					Lib.get_string @platform_availability[:message]
    469 				end
    470 			end
    471 		end
    472 	end
    473 end