cpp_info.rb (5656B)
1 # frozen_string_literal: true 2 3 require 'digest/sha2' 4 5 require_relative 'aliaser' 6 require_relative 'util' 7 8 class Parser 9 def init_cpp_info 10 return if @cpp_info_inited 11 12 tu.cursor.visit_children do |c, parent| 13 next :continue unless filter[c, parent] 14 case c.kind 15 when :namespace; next :recurse 16 when :type_alias_decl 17 if Util.has_annotation?(c) {|ann| ann == 'libshit_binding_alias' } 18 aliaser.add_alias c.typedef_type.canonical, c.spelling 19 end 20 end 21 :continue 22 end 23 24 @cpp_info_inited = true 25 end 26 end 27 28 class CppClass 29 attr_reader :parser, :type 30 31 def initialize parser, t 32 @parser = parser 33 @type = t 34 end 35 36 def name 37 @name ||= @parser.aliaser.type_name @type, @type.declaration 38 end 39 40 def short_name 41 @type.declaration.spelling 42 end 43 44 def id 45 # not the most human readable, but at least handles every character without 46 # collisions 47 Digest::SHA256.hexdigest name 48 end 49 50 def bases 51 @bases ||= 52 begin 53 tmp = [] 54 @type.declaration.visit_children do |c, par| 55 tmp << c.type if c.kind == :cxx_base_specifier 56 :continue 57 end 58 tmp 59 end 60 end 61 62 def enum? = @type.kind == :enum 63 end 64 65 module CppMember 66 attr_reader :cursor, :klass 67 68 def initialize cursor:, klass: 69 @cursor = cursor 70 @klass = klass 71 end 72 73 def member? = !!@klass 74 75 attr_writer :klass_name 76 def klass_name 77 @klass_name ||= @klass.name 78 end 79 80 def name = @cursor.spelling 81 def qualified_name 82 @qualified_name ||= Util.fun_qualified_name(@cursor).freeze 83 end 84 end 85 86 class CppFunction 87 include CppMember 88 ANNOTATIONS = %i(result_type).freeze 89 Annotation = Struct.new *ANNOTATIONS, keyword_init: true 90 91 KNOWN_TYPES = %i( 92 function_decl cxx_method constructor destructor conversion_function 93 ).freeze 94 95 attr_reader :aliaser, :annotation 96 97 def initialize aliaser:, annotation:, **kw 98 super **kw 99 @aliaser = aliaser 100 @annotation = annotation 101 @is_template = cursor.kind == :function_template 102 @real_kind = @is_template ? cursor.template_kind : cursor.kind 103 104 unless KNOWN_TYPES.include? @real_kind 105 raise ArgumentError, "Invalid cursor kind #{@real_kind}" 106 end 107 end 108 109 def method? = @real_kind != :function_decl 110 def noexcept? = @cursor.type.noexcept? 111 def noexcept_suffix_str 112 noexcept? ? ' noexcept' : '' 113 end 114 115 def const? = @cursor.const? 116 def const_suffix_str 117 @cursor.const? ? ' const' : '' 118 end 119 120 def ptr_type_prefix_str 121 @ptr_type_prefix_str ||= 122 ((!method? || @cursor.static?) ? '' : "#{klass_name}::").freeze 123 end 124 def ptr_type_suffix_str 125 @ptr_type_suffix_str ||= 126 ((@cursor.const? ? ' const' : '') + (noexcept? ? ' noexcept' : '')).freeze 127 end 128 129 def ptr_type_str 130 @ptr_type_str ||= 131 "#{result_type_str} (#{ptr_type_prefix_str}*)(#{arguments_str})" \ 132 "#{ptr_type_suffix_str}".freeze 133 end 134 135 def ptr_value_prefix_str 136 # retarded compiler error with gcc in some cases if a non overloaded 137 # static member function is casted, if we manually take the address. 138 # not writing & for non static member functions is a compile error... 139 @ptr_value_prefix_str ||= 140 ((@cursor.static? ? '' : '&') + (method? ? "#{klass_name}::" : '')).freeze 141 end 142 143 def ptr_value_uncasted_str 144 @ptr_value_uncasted_str ||= 145 "#{ptr_value_prefix_str}#{qualified_name}#{template_suffix_str}".freeze 146 end 147 148 def ptr_value_str 149 @ptr_value_str ||= 150 "static_cast<#{ptr_type_str}>(#{ptr_value_uncasted_str})".freeze 151 end 152 153 def arguments 154 @args ||= Util.collect_args(@cursor).freeze 155 end 156 157 def arguments_str wrap = nil, &; 158 @aliaser.type_list arguments, wrap, & 159 end 160 161 def result_type = @cursor.result_type 162 def result_type_str 163 @result_type_str ||= calc_result_type_str.freeze 164 end 165 166 private def calc_result_type_str 167 return @annotation.result_type if @annotation.result_type 168 rt = result_type 169 if rt.spelling == 'auto' 170 # fake return type with decltype if it's auto, because you can't cast to 171 # function pointer returning auto... 172 this = method? ? "std::declval<#{klass_name}>()." : '' 173 args = arguments_str {|x| "std::declval<#{x}>()" } 174 "decltype(#{this}#{qualified_name}#{template_suffix_str}(#{args}))" 175 else 176 @aliaser.type_name result_type, @cursor 177 end 178 end 179 180 def template_arguments 181 @template_args ||= Util.collect_template_args(@cursor).freeze 182 end 183 184 attr_reader :template_arguments_map 185 def template_arguments_map= map 186 targs = template_arguments 187 if map.size != targs.size 188 raise ArgumentError, "Invalid map size #{map.size} != #{targs.size}" 189 end 190 191 @aliaser = @aliaser.dup # TODO 192 targs.zip(map).each do |targ, s| 193 @aliaser.add_alias targ, s.freeze 194 end 195 @template_arguments_map = map.freeze 196 end 197 198 def template_arguments_map_str 199 @template_arguments_map_str ||= @template_arguments_map.join(', ').freeze 200 end 201 202 def template_suffix_str 203 @template_suffix_str ||= 204 (@is_template ? "<#{template_arguments_map_str}>" : '').freeze 205 end 206 end 207 208 class CppVariable 209 include CppMember 210 attr_reader :parser 211 212 def initialize parser:, **kw 213 super **kw 214 @parser = parser 215 end 216 217 def type = @cursor.type 218 def type_str 219 @type_str ||= @parser.aliaser.type_name @cursor 220 end 221 222 def ptr_type_str 223 @ptr_type_str ||= (member? ? "#{type_str} #{klass_name}::*" : type_str).freeze 224 end 225 226 def ptr_value_str 227 @ptr_value_str ||= "&#{klass_name}::#{qualified_name}".freeze 228 end 229 end 230 231 class CppEnumConstant 232 include CppMember 233 234 def value_str 235 @value_str ||= "#{klass_name}::#{qualified_name}".freeze 236 end 237 end