typeprof 0.15.3 → 0.20.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 13f530c84fe1b38000dc93982adac87c01d6d3a3516f8502e3de252d56428a12
4
- data.tar.gz: b799ff212fd16b59bb96f8b560252e687d206e9a3ba541eaa6033532108957e3
3
+ metadata.gz: 109bbaf7daec0e4dce2f23c17a73d9528c51441cf61f1e23f5dc5d3c2c47dbff
4
+ data.tar.gz: bbd47838c15aa0e2a12645a8c9d5f56b0587323e96d919240681d747e2b73696
5
5
  SHA512:
6
- metadata.gz: 6e11866f36a7570ba564bf2abe6912f2531f728e76c4afc32f9bfddc436ea03a86a996eb4d3ddd2bf8c24e9eeae0986b45f17f06575d80df21b812585976f1ba
7
- data.tar.gz: 8e990ceee15c1dba1cf529990fbb6e26a4f48946088549f51471c48ff1aeccfdc7cb8b6547c1105e00767263acee681db4340240f94c786b39bbeff842d501dc
6
+ metadata.gz: 6e1ff8245d59eb81f253544b9a1a0e6a54f154fb17634e739210d4320e96619d59b70f9efd6811f600ab67e52ea341d3d9a886ab2b00d397ede5594f23ce8340
7
+ data.tar.gz: 2723c535e5f42e13e419e2646607ba9a5ec0a90c266fd2a927e658b133703f658af0cdfc2f392c6acd7f6f96fbbb54019251163f2109b1624158a48e019a56f2
@@ -7,7 +7,7 @@ jobs:
7
7
  strategy:
8
8
  fail-fast: false
9
9
  matrix:
10
- ruby-version: [2.7, 3.0, head]
10
+ ruby-version: [2.7, 3.0,head]
11
11
  runs-on: ubuntu-latest
12
12
  steps:
13
13
  - uses: actions/checkout@v2
data/Gemfile.lock CHANGED
@@ -1,8 +1,8 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- typeprof (0.15.3)
5
- rbs (>= 1.3.1)
4
+ typeprof (0.20.0)
5
+ rbs (>= 1.6.2)
6
6
 
7
7
  GEM
8
8
  remote: https://rubygems.org/
@@ -11,7 +11,7 @@ GEM
11
11
  docile (1.4.0)
12
12
  power_assert (2.0.0)
13
13
  rake (13.0.1)
14
- rbs (1.6.1)
14
+ rbs (1.6.2)
15
15
  simplecov (0.21.2)
16
16
  docile (~> 1.1)
17
17
  simplecov-html (~> 0.11)
@@ -19,7 +19,7 @@ GEM
19
19
  simplecov-html (0.12.3)
20
20
  simplecov_json_formatter (0.1.3)
21
21
  stackprof (0.2.17)
22
- test-unit (3.4.2)
22
+ test-unit (3.4.4)
23
23
  power_assert
24
24
 
25
25
  PLATFORMS
data/exe/typeprof CHANGED
@@ -3,4 +3,8 @@
3
3
  require_relative "../lib/typeprof"
4
4
 
5
5
  config = TypeProf::CLI.parse(ARGV)
6
- TypeProf.analyze(config)
6
+ if config.options[:lsp]
7
+ TypeProf.start_lsp_server(config)
8
+ else
9
+ TypeProf.analyze(config)
10
+ end
@@ -43,6 +43,14 @@ module TypeProf
43
43
  end
44
44
  end
45
45
 
46
+ def detailed_source_location(pc)
47
+ if @iseq
48
+ @iseq.detailed_source_location(pc)
49
+ else
50
+ nil
51
+ end
52
+ end
53
+
46
54
  def replace_cref(cref)
47
55
  Context.new(@iseq, cref, @mid)
48
56
  end
@@ -66,6 +74,14 @@ module TypeProf
66
74
  end
67
75
  end
68
76
 
77
+ def detailed_source_location(_pc)
78
+ if @caller_ep
79
+ @caller_ep.source_location
80
+ else
81
+ nil
82
+ end
83
+ end
84
+
69
85
  def replace_cref(cref)
70
86
  # What to do?
71
87
  end
@@ -101,6 +117,14 @@ module TypeProf
101
117
  def source_location
102
118
  @ctx.source_location(@pc)
103
119
  end
120
+
121
+ def detailed_source_location
122
+ @ctx.detailed_source_location(@pc)
123
+ end
124
+
125
+ def absolute_path
126
+ @ctx.iseq.absolute_path
127
+ end
104
128
  end
105
129
 
106
130
  class StaticEnv
@@ -287,6 +311,9 @@ module TypeProf
287
311
 
288
312
  @types_being_shown = []
289
313
  @namespace = nil
314
+
315
+ @lsp_completion = nil
316
+ @lsp_signature_help = CodeRangeTable.new
290
317
  end
291
318
 
292
319
  def add_entrypoint(iseq)
@@ -335,7 +362,7 @@ module TypeProf
335
362
  @subclasses = []
336
363
  end
337
364
 
338
- attr_reader :kind, :modules, :consts, :methods, :ivars, :cvars, :absolute_path, :subclasses
365
+ attr_reader :kind, :modules, :methods, :ivars, :cvars, :absolute_path, :subclasses
339
366
  attr_accessor :name, :klass_obj
340
367
 
341
368
  def mix_module(kind, mod, type_args, singleton, absolute_path)
@@ -350,24 +377,43 @@ module TypeProf
350
377
  end
351
378
 
352
379
  def get_constant(name)
353
- ty, = @consts[name]
354
- ty || Type.any # XXX: warn?
380
+ ty, locs = @consts[name]
381
+ ty = ty || Type.any # XXX: warn?
382
+ return ty, locs
355
383
  end
356
384
 
357
- def add_constant(name, ty, absolute_path)
385
+ def add_constant(name, ty, def_ep)
358
386
  if @consts[name]
359
387
  # XXX: warn!
388
+ _, eps = @consts[name]
389
+ @consts[name] = [ty, eps + [def_ep&.detailed_source_location]]
390
+ return
391
+ end
392
+ @consts[name] = [ty, [def_ep&.detailed_source_location]]
393
+ end
394
+
395
+ def consts
396
+ @consts.lazy.flat_map do |name, (ty, eps)|
397
+ eps.map do |ep|
398
+ [name, [ty, ep]]
399
+ end
360
400
  end
361
- @consts[name] = [ty, absolute_path]
362
401
  end
363
402
 
403
+ def add_class_open(name, open_ep)
404
+ ty, eps = @consts[name]
405
+ raise "call this only if the class is opened more than once" if ty.nil?
406
+ @consts[name] = [ty, eps + [open_ep&.detailed_source_location]]
407
+ end
408
+
409
+
364
410
  def adjust_substitution_for_module(mods, mid, mthd, subst, &blk)
365
411
  mods.each do |mod_def, type_args,|
366
412
  if mod_def.klass_obj.type_params && type_args
367
413
  subst2 = {}
368
414
  mod_def.klass_obj.type_params.zip(type_args) do |(tyvar, *), tyarg|
369
415
  tyvar = Type::Var.new(tyvar)
370
- subst2[tyvar] = tyarg.substitute(subst, Config.options[:type_depth_limit])
416
+ subst2[tyvar] = tyarg.substitute(subst, Config.current.options[:type_depth_limit])
371
417
  end
372
418
  mod_def.adjust_substitution(false, mid, mthd, subst2, false, &blk)
373
419
  end
@@ -444,23 +490,23 @@ module TypeProf
444
490
  cbase && cbase.idx != 1 ? @class_defs[cbase.idx].name : []
445
491
  end
446
492
 
447
- def new_class(cbase, name, type_params, superclass, absolute_path)
493
+ def new_class(cbase, name, type_params, superclass, def_ep)
448
494
  show_name = cbase_path(cbase) + [name]
449
495
  idx = @class_defs.size
450
496
  if superclass
451
- @class_defs[idx] = ClassDef.new(:class, show_name, absolute_path)
497
+ @class_defs[idx] = ClassDef.new(:class, show_name, def_ep&.absolute_path)
452
498
  @class_defs[superclass.idx].subclasses << idx unless superclass == :__root__
453
499
  klass = Type::Class.new(:class, idx, type_params, superclass, show_name)
454
500
  @class_defs[idx].klass_obj = klass
455
501
  cbase ||= klass # for bootstrap
456
- add_constant(cbase, name, klass, absolute_path)
502
+ add_constant(cbase, name, klass, def_ep)
457
503
  return klass
458
504
  else
459
505
  # module
460
- @class_defs[idx] = ClassDef.new(:module, show_name, absolute_path)
506
+ @class_defs[idx] = ClassDef.new(:module, show_name, def_ep&.absolute_path)
461
507
  mod = Type::Class.new(:module, idx, type_params, nil, show_name)
462
508
  @class_defs[idx].klass_obj = mod
463
- add_constant(cbase, name, mod, absolute_path)
509
+ add_constant(cbase, name, mod, def_ep)
464
510
  return mod
465
511
  end
466
512
  end
@@ -519,7 +565,7 @@ module TypeProf
519
565
  subst2 = {}
520
566
  klass.superclass.type_params.zip(klass.superclass_type_args) do |(tyvar, *), tyarg|
521
567
  tyvar = Type::Var.new(tyvar)
522
- subst2[tyvar] = tyarg.substitute(subst, Config.options[:type_depth_limit])
568
+ subst2[tyvar] = tyarg.substitute(subst, Config.current.options[:type_depth_limit])
523
569
  end
524
570
  subst = subst2
525
571
  end
@@ -601,29 +647,53 @@ module TypeProf
601
647
  nil
602
648
  end
603
649
 
650
+ def get_all_methods(klass, singleton, _include_subclasses)
651
+ names = {}
652
+
653
+ if klass.kind == :class
654
+ while klass != :__root__
655
+ # TODO: module
656
+ @class_defs[klass.idx].methods.each_key do |singleton0, name|
657
+ if singleton == singleton0
658
+ names[name] = true
659
+ end
660
+ end
661
+ klass = klass.superclass
662
+ end
663
+ else
664
+ @class_defs[klass.idx].methods.each_key do |singleton0, name|
665
+ if singleton == singleton0
666
+ names[name] = true
667
+ end
668
+ end
669
+ end
670
+
671
+ names
672
+ end
673
+
604
674
  def get_constant(klass, name)
605
675
  if klass == Type.any
606
- Type.any
676
+ [Type.any, nil]
607
677
  elsif klass.is_a?(Type::Class)
608
678
  @class_defs[klass.idx].get_constant(name)
609
679
  else
610
- Type.any
680
+ [Type.any, nil]
611
681
  end
612
682
  end
613
683
 
614
684
  def search_constant(cref, name)
615
685
  while cref != :bottom
616
- val = get_constant(cref.klass, name)
617
- return val if val != Type.any
686
+ ty, locs = get_constant(cref.klass, name)
687
+ return ty, locs if ty != Type.any
618
688
  cref = cref.outer
619
689
  end
620
690
 
621
- Type.any
691
+ return Type.any, nil
622
692
  end
623
693
 
624
- def add_constant(klass, name, value, user_defined)
694
+ def add_constant(klass, name, value, def_ep)
625
695
  if klass.is_a?(Type::Class)
626
- @class_defs[klass.idx].add_constant(name, value, user_defined)
696
+ @class_defs[klass.idx].add_constant(name, value, def_ep)
627
697
  end
628
698
  end
629
699
 
@@ -694,7 +764,13 @@ module TypeProf
694
764
  end
695
765
 
696
766
  def add_callsite!(callee_ctx, caller_ep, caller_env, &ctn)
697
- @executed_iseqs << callee_ctx.iseq if callee_ctx.is_a?(Context)
767
+ if callee_ctx.is_a?(Context)
768
+ @executed_iseqs << callee_ctx.iseq
769
+ callee_type = callee_ctx.iseq.type
770
+ if caller_ep.ctx.is_a?(Context) && (callee_type == :method || callee_type == :block)
771
+ caller_ep.ctx.iseq&.add_called_iseq(caller_ep.pc, callee_ctx.iseq)
772
+ end
773
+ end
698
774
 
699
775
  @callsites[callee_ctx] ||= {}
700
776
  @callsites[callee_ctx][caller_ep] = ctn
@@ -743,23 +819,23 @@ module TypeProf
743
819
  end
744
820
 
745
821
  class VarTable
746
- Entry = Struct.new(:rbs_declared, :read_continuations, :type, :absolute_paths)
822
+ Entry = Struct.new(:rbs_declared, :read_continuations, :type, :absolute_paths, :write_eps)
747
823
 
748
824
  def initialize
749
825
  @tbl = {}
750
826
  end
751
827
 
752
828
  def add_read!(site, ep, &ctn)
753
- entry = @tbl[site] ||= Entry.new(false, {}, Type.bot, Utils::MutableSet.new)
829
+ entry = @tbl[site] ||= Entry.new(false, {}, Type.bot, Utils::MutableSet.new, Utils::MutableSet.new)
754
830
  entry.read_continuations[ep] = ctn
755
831
  entry.absolute_paths << ep.ctx.iseq.absolute_path if ep.ctx.is_a?(Context)
756
832
  ty = entry.type
757
833
  ty = Type.nil if ty == Type.bot
758
- ctn[ty, ep]
834
+ ctn[ty, ep, entry.write_eps]
759
835
  end
760
836
 
761
837
  def add_write!(site, ty, ep, scratch)
762
- entry = @tbl[site] ||= Entry.new(!ep, {}, Type.bot, Utils::MutableSet.new)
838
+ entry = @tbl[site] ||= Entry.new(!ep, {}, Type.bot, Utils::MutableSet.new, Utils::MutableSet.new)
763
839
  if ep
764
840
  if entry.rbs_declared
765
841
  unless Type.match?(ty, entry.type)
@@ -768,10 +844,11 @@ module TypeProf
768
844
  end
769
845
  end
770
846
  entry.absolute_paths << ep.ctx.iseq.absolute_path
847
+ entry.write_eps << ep
771
848
  end
772
849
  entry.type = entry.type.union(ty)
773
- entry.read_continuations.each do |ep, ctn|
774
- ctn[ty, ep]
850
+ entry.read_continuations.each do |read_ep, ctn|
851
+ ctn[ty, read_ep, [ep]]
775
852
  end
776
853
  end
777
854
 
@@ -815,7 +892,8 @@ module TypeProf
815
892
  recv.each_child do |recv|
816
893
  class_def, singleton = get_ivar(recv, var)
817
894
  next unless class_def
818
- class_def.ivars.add_write!([singleton, var], ty, ep, self)
895
+ site = [singleton, var]
896
+ class_def.ivars.add_write!(site, ty, ep, self)
819
897
  end
820
898
  end
821
899
 
@@ -846,18 +924,18 @@ module TypeProf
846
924
  end
847
925
 
848
926
  def error(ep, msg)
849
- p [ep.source_location, "[error] " + msg] if Config.verbose >= 2
927
+ p [ep.source_location, "[error] " + msg] if Config.current.verbose >= 2
850
928
  @errors << [ep, "[error] " + msg]
851
929
  end
852
930
 
853
931
  def warn(ep, msg)
854
- p [ep.source_location, "[warning] " + msg] if Config.verbose >= 2
932
+ p [ep.source_location, "[warning] " + msg] if Config.current.verbose >= 2
855
933
  @errors << [ep, "[warning] " + msg]
856
934
  end
857
935
 
858
936
  def reveal_type(ep, ty)
859
937
  key = ep.source_location
860
- puts "reveal:#{ ep.source_location }:#{ ty.screen_name(self) }" if Config.verbose >= 2
938
+ puts "reveal:#{ ep.source_location }:#{ ty.screen_name(self) }" if Config.current.verbose >= 2
861
939
  if @reveal_types[key]
862
940
  @reveal_types[key] = @reveal_types[key].union(ty)
863
941
  else
@@ -924,8 +1002,9 @@ module TypeProf
924
1002
  end
925
1003
  end
926
1004
 
927
- def type_profile
928
- start_time = tick = Time.now
1005
+ def type_profile(cancel_token = nil)
1006
+ cancel_token ||= Utils::TimerCancelToken.new(Config.current.max_sec)
1007
+ tick = Time.now
929
1008
  iter_counter = 0
930
1009
  stat_eps = Utils::MutableSet.new
931
1010
 
@@ -938,7 +1017,7 @@ module TypeProf
938
1017
  if entrypoint.is_a?(String)
939
1018
  file = entrypoint
940
1019
  next if @loaded_files[File.expand_path(file)]
941
- iseq = ISeq.compile(file)
1020
+ iseq, = ISeq.compile(file)
942
1021
  else
943
1022
  iseq = entrypoint
944
1023
  end
@@ -953,7 +1032,7 @@ module TypeProf
953
1032
  ep = @worklist.deletemin
954
1033
 
955
1034
  iter_counter += 1
956
- if Config.options[:show_indicator]
1035
+ if Config.current.options[:show_indicator]
957
1036
  tick2 = Time.now
958
1037
  if tick2 - tick >= 1
959
1038
  tick = tick2
@@ -962,7 +1041,7 @@ module TypeProf
962
1041
  end
963
1042
  end
964
1043
 
965
- if (Config.max_sec && Time.now - start_time >= Config.max_sec) || (Config.max_iter && Config.max_iter <= iter_counter)
1044
+ if (Config.current.max_iter && Config.current.max_iter <= iter_counter) || cancel_token.cancelled?
966
1045
  @terminated = true
967
1046
  break
968
1047
  end
@@ -973,7 +1052,7 @@ module TypeProf
973
1052
 
974
1053
  break if @terminated
975
1054
 
976
- break unless Config.options[:stub_execution]
1055
+ break unless Config.current.options[:stub_execution]
977
1056
 
978
1057
  begin
979
1058
  iseq, (kind, dummy_continuation) = @pending_execution.first
@@ -981,7 +1060,7 @@ module TypeProf
981
1060
  @pending_execution.delete(iseq)
982
1061
  end while @executed_iseqs.include?(iseq)
983
1062
 
984
- puts "DEBUG: trigger stub execution (#{ iseq&.name || "(nil)" }): rest #{ @pending_execution.size }" if Config.verbose >= 2
1063
+ puts "DEBUG: trigger stub execution (#{ iseq&.name || "(nil)" }): rest #{ @pending_execution.size }" if Config.current.verbose >= 2
985
1064
 
986
1065
  break if !iseq
987
1066
  case kind
@@ -1000,7 +1079,7 @@ module TypeProf
1000
1079
  end
1001
1080
  end
1002
1081
 
1003
- $stderr.print "\r\e[K" if Config.options[:show_indicator]
1082
+ $stderr.print "\r\e[K" if Config.current.options[:show_indicator]
1004
1083
 
1005
1084
  stat_eps
1006
1085
  end
@@ -1017,13 +1096,70 @@ module TypeProf
1017
1096
  RubySignatureExporter.new(self, @class_defs, @iseq_method_to_ctxs).show(stat_eps, output)
1018
1097
  end
1019
1098
 
1099
+ def report_lsp
1100
+ errs = @errors.map do |ep, msg|
1101
+ [ep&.detailed_source_location, msg]
1102
+ end
1103
+
1104
+ res = RubySignatureExporter.new(self, @class_defs, @iseq_method_to_ctxs).show_lsp
1105
+
1106
+ path, loc = Config.current.options[:signature_help_loc]
1107
+ if path
1108
+ sig_help_res = []
1109
+ sig_help = @lsp_signature_help[loc]
1110
+ if sig_help
1111
+ recv = sig_help[:recv]
1112
+ mid = sig_help[:mid]
1113
+ singleton = sig_help[:singleton]
1114
+ mdefs = sig_help[:mdefs]
1115
+ node_id = sig_help[:node_id]
1116
+ mdefs.each do |mdef|
1117
+ case mdef
1118
+ when ISeqMethodDef
1119
+ ctxs = @iseq_method_to_ctxs[mdef]
1120
+ next unless ctxs
1121
+
1122
+ ctx = ctxs.find {|ctx| ctx.mid == mid } || ctxs.first
1123
+
1124
+ method_name = mid
1125
+ method_name = "self.#{ method_name }" if singleton
1126
+
1127
+ str = recv.screen_name(self)
1128
+ str += singleton ? "." : "#"
1129
+ str += method_name.to_s
1130
+ str += ": "
1131
+ sig, _, sig_help = show_method_signature(ctx)
1132
+ offset = str.size
1133
+ sig_help = sig_help.transform_values {|r| (r.begin + offset ... r.end + offset) }
1134
+ str += sig
1135
+ sig_help_res << [str, sig_help, node_id]
1136
+ when AliasMethodDef
1137
+ # TODO
1138
+ when TypedMethodDef
1139
+ mdef.rbs_source&.[](1)&.each do |rbs|
1140
+ # TODO: sig_help
1141
+ sig_help_res << [rbs, {}, node_id]
1142
+ end
1143
+ end
1144
+ end
1145
+ end
1146
+ end
1147
+
1148
+ {
1149
+ sigs: res,
1150
+ errors: errs,
1151
+ completion: @lsp_completion,
1152
+ signature_help: sig_help_res,
1153
+ }
1154
+ end
1155
+
1020
1156
  def globalize_type(ty, env, ep)
1021
1157
  if ep.outer
1022
1158
  tmp_ep = ep
1023
1159
  tmp_ep = tmp_ep.outer while tmp_ep.outer
1024
1160
  env = @return_envs[tmp_ep]
1025
1161
  end
1026
- ty.globalize(env, {}, Config.options[:type_depth_limit])
1162
+ ty.globalize(env, {}, Config.current.options[:type_depth_limit])
1027
1163
  end
1028
1164
 
1029
1165
  def localize_type(ty, env, ep, alloc_site = AllocationSite.new(ep))
@@ -1031,13 +1167,13 @@ module TypeProf
1031
1167
  tmp_ep = ep
1032
1168
  tmp_ep = tmp_ep.outer while tmp_ep.outer
1033
1169
  target_env = @return_envs[tmp_ep]
1034
- target_env, ty = ty.localize(target_env, alloc_site, Config.options[:type_depth_limit])
1170
+ target_env, ty = ty.localize(target_env, alloc_site, Config.current.options[:type_depth_limit])
1035
1171
  merge_return_env(tmp_ep) do |env|
1036
1172
  env ? env.merge(target_env) : target_env
1037
1173
  end
1038
1174
  return env, ty
1039
1175
  else
1040
- return ty.localize(env, alloc_site, Config.options[:type_depth_limit])
1176
+ return ty.localize(env, alloc_site, Config.current.options[:type_depth_limit])
1041
1177
  end
1042
1178
  end
1043
1179
 
@@ -1099,13 +1235,16 @@ module TypeProf
1099
1235
  end
1100
1236
 
1101
1237
  def get_instance_variable(recv, var, ep, env)
1102
- add_ivar_read!(recv, var, ep) do |ty, ep|
1238
+ add_ivar_read!(recv, var, ep) do |ty, ep, write_eps|
1103
1239
  alloc_site = AllocationSite.new(ep)
1104
1240
  nenv, ty = localize_type(ty, env, ep, alloc_site)
1105
1241
  case ty
1106
1242
  when Type::Local
1107
1243
  @alloc_site_to_global_id[ty.id] = [recv, var] # need overwrite check??
1108
1244
  end
1245
+ write_eps.each do |write_ep|
1246
+ ep.ctx.iseq.add_def_loc(ep.pc, write_ep.detailed_source_location)
1247
+ end
1109
1248
  yield ty, nenv
1110
1249
  end
1111
1250
  end
@@ -1122,7 +1261,7 @@ module TypeProf
1122
1261
  insn = ep.ctx.iseq.insns[ep.pc]
1123
1262
  operands = insn.operands
1124
1263
 
1125
- if Config.verbose >= 2
1264
+ if Config.current.verbose >= 2
1126
1265
  # XXX: more dedicated output
1127
1266
  puts "DEBUG: stack=%p" % [env.stack]
1128
1267
  puts "DEBUG: %s (%s) PC=%d insn=%s sp=%d" % [ep.source_location, ep.ctx.iseq.name, ep.pc, insn.insn, env.stack.size]
@@ -1291,8 +1430,10 @@ module TypeProf
1291
1430
  case flags & 7
1292
1431
  when 0, 2 # CLASS / MODULE
1293
1432
  type = (flags & 7) == 2 ? :module : :class
1294
- existing_klass = get_constant(cbase, id) # TODO: multiple return values
1433
+ existing_klass, = get_constant(cbase, id) # TODO: multiple return values
1295
1434
  if existing_klass.is_a?(Type::Class)
1435
+ # record re-opening location
1436
+ @class_defs[cbase.idx].add_class_open(id, ep)
1296
1437
  klass = existing_klass
1297
1438
  else
1298
1439
  if existing_klass != Type.any
@@ -1317,7 +1458,7 @@ module TypeProf
1317
1458
  superclass = nil
1318
1459
  end
1319
1460
  if cbase.is_a?(Type::Class)
1320
- klass = new_class(cbase, id, [], superclass, ep.ctx.iseq.absolute_path)
1461
+ klass = new_class(cbase, id, [], superclass, ep)
1321
1462
  if superclass
1322
1463
  add_superclass_type_args!(klass, superclass.type_params.map { Type.any })
1323
1464
 
@@ -1631,7 +1772,7 @@ module TypeProf
1631
1772
  var, = operands
1632
1773
  ty = Type.builtin_global_variable_type(var)
1633
1774
  if ty
1634
- ty = get_constant(Type::Builtin[:obj], ty) if ty.is_a?(Symbol)
1775
+ ty, locs = get_constant(Type::Builtin[:obj], ty) if ty.is_a?(Symbol)
1635
1776
  env, ty = localize_type(ty, env, ep)
1636
1777
  env = env.push(ty)
1637
1778
  else
@@ -1776,20 +1917,23 @@ module TypeProf
1776
1917
  name, = operands
1777
1918
  env, (cbase, _allow_nil,) = env.pop(2)
1778
1919
  if cbase == Type.nil
1779
- ty = search_constant(ep.ctx.cref, name)
1920
+ ty, locs = search_constant(ep.ctx.cref, name)
1780
1921
  env, ty = localize_type(ty, env, ep)
1781
1922
  env = env.push(ty)
1782
1923
  elsif cbase == Type.any
1783
1924
  env = env.push(Type.any) # XXX: warning needed?
1784
1925
  else
1785
- ty = get_constant(cbase, name)
1926
+ ty, locs = get_constant(cbase, name)
1786
1927
  env, ty = localize_type(ty, env, ep)
1787
1928
  env = env.push(ty)
1788
1929
  end
1930
+ locs&.each do |loc|
1931
+ ep.ctx.iseq.add_def_loc(ep.pc, loc)
1932
+ end
1789
1933
  when :setconstant
1790
1934
  name, = operands
1791
1935
  env, (ty, cbase) = env.pop(2)
1792
- old_ty = get_constant(cbase, name)
1936
+ old_ty, = get_constant(cbase, name)
1793
1937
  if old_ty != Type.any # XXX???
1794
1938
  warn(ep, "already initialized constant #{ Type::Instance.new(cbase).screen_name(self) }::#{ name }")
1795
1939
  end
@@ -1798,7 +1942,7 @@ module TypeProf
1798
1942
  @class_defs[ty.idx].name = cbase_path(cbase) + [name]
1799
1943
  end
1800
1944
  end
1801
- add_constant(cbase, name, globalize_type(ty, env, ep), ep.ctx.iseq.absolute_path)
1945
+ add_constant(cbase, name, globalize_type(ty, env, ep), ep)
1802
1946
 
1803
1947
  when :getspecial
1804
1948
  key, type = operands
@@ -2186,10 +2330,26 @@ module TypeProf
2186
2330
  merge_return_env(ep) {|tenv| tenv ? tenv.merge(env) : env }
2187
2331
  end
2188
2332
 
2333
+ aargs.node_id = opt[:node_id]
2334
+
2189
2335
  return env, recv, mid, aargs
2190
2336
  end
2191
2337
 
2192
2338
  def do_send(recvs, mid, aargs, ep, env, &ctn)
2339
+ if mid == :__typeprof_lsp_completion
2340
+ names = {}
2341
+ recvs.each_child do |recv|
2342
+ case recv
2343
+ when Type::Void, Type::Any
2344
+ else
2345
+ klass, singleton, include_subclasses = recv.method_dispatch_info
2346
+ names.merge!(get_all_methods(klass, singleton, include_subclasses)) if klass
2347
+ end
2348
+ end
2349
+ @lsp_completion = names
2350
+ return ctn[Type.any, ep, env]
2351
+ end
2352
+
2193
2353
  recvs.each_child do |recv|
2194
2354
  case recv
2195
2355
  when Type::Void
@@ -2201,6 +2361,19 @@ module TypeProf
2201
2361
  klass, singleton, include_subclasses = recv.method_dispatch_info
2202
2362
  meths = get_method(klass, singleton, include_subclasses, mid) if klass
2203
2363
  if meths
2364
+ path, loc = Config.current.options[:signature_help_loc]
2365
+ if path && path == ep.ctx.iseq.path && mid != :inherited # XXX: too ad-hoc!!!
2366
+ path, code_range = ep&.detailed_source_location
2367
+ if path && code_range&.contain_loc?(loc)
2368
+ @lsp_signature_help[code_range] = {
2369
+ recv: recv,
2370
+ mid: mid,
2371
+ singleton: singleton,
2372
+ mdefs: meths,
2373
+ node_id: aargs.node_id,
2374
+ }
2375
+ end
2376
+ end
2204
2377
  meths.each do |meth|
2205
2378
  meth.do_send(recv, mid, aargs, ep, env, self, &ctn)
2206
2379
  end
@@ -2282,7 +2455,7 @@ module TypeProf
2282
2455
 
2283
2456
  bsig ||= BlockSignature.new([], [], nil, Type.nil)
2284
2457
 
2285
- bsig = bsig.screen_name(nil, self)
2458
+ bsig, = bsig.screen_name(nil, self)
2286
2459
  ret_ty = ret_ty.screen_name(self)
2287
2460
  ret_ty = (ret_ty.include?("|") ? "(#{ ret_ty })" : ret_ty) # XXX?
2288
2461
 
@@ -2317,7 +2490,7 @@ module TypeProf
2317
2490
 
2318
2491
  begin
2319
2492
  @types_being_shown << farg_tys << ret_ty
2320
- farg_tys = farg_tys ? farg_tys.screen_name(nil, self) : "(unknown)"
2493
+ farg_tys, = farg_tys ? farg_tys.screen_name(nil, self) : ["(unknown)"]
2321
2494
  ret_ty = ret_ty.screen_name(self)
2322
2495
  ret_ty = (ret_ty.include?("|") ? "(#{ ret_ty })" : ret_ty) # XXX?
2323
2496
 
@@ -2330,15 +2503,16 @@ module TypeProf
2330
2503
 
2331
2504
  def show_method_signature(ctx)
2332
2505
  farg_tys = @method_signatures[ctx]
2506
+ return nil unless farg_tys
2333
2507
  ret_ty = ctx.mid == :initialize ? Type::Void.new : @return_values[ctx] || Type.bot
2334
2508
 
2335
2509
  untyped = farg_tys.include_untyped?(self) || ret_ty.include_untyped?(self)
2336
2510
 
2337
- farg_tys = farg_tys.screen_name(ctx.iseq, self)
2511
+ farg_tys, ranges = farg_tys.screen_name(ctx.iseq, self)
2338
2512
  ret_ty = ret_ty.screen_name(self)
2339
2513
  ret_ty = (ret_ty.include?("|") ? "(#{ ret_ty })" : ret_ty) # XXX?
2340
2514
 
2341
- ["#{ (farg_tys.empty? ? "" : "#{ farg_tys } ") }-> #{ ret_ty }", untyped]
2515
+ return "#{ (farg_tys.empty? ? "" : "#{ farg_tys } ") }-> #{ ret_ty }", untyped, ranges
2342
2516
  end
2343
2517
  end
2344
2518
  end
@@ -16,6 +16,7 @@ module TypeProf
16
16
  end
17
17
 
18
18
  attr_reader :lead_tys, :rest_ty, :kw_tys, :blk_ty
19
+ attr_accessor :node_id
19
20
 
20
21
  def globalize(caller_env, visited, depth)
21
22
  lead_tys = @lead_tys.map {|ty| ty.globalize(caller_env, visited, depth) }