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