typeprof 0.30.0 → 0.31.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +23 -4
  3. data/doc/doc.ja.md +1 -1
  4. data/lib/typeprof/cli/cli.rb +28 -10
  5. data/lib/typeprof/cli.rb +1 -0
  6. data/lib/typeprof/code_range.rb +9 -7
  7. data/lib/typeprof/core/ast/base.rb +27 -10
  8. data/lib/typeprof/core/ast/call.rb +90 -21
  9. data/lib/typeprof/core/ast/const.rb +7 -12
  10. data/lib/typeprof/core/ast/control.rb +349 -74
  11. data/lib/typeprof/core/ast/meta.rb +5 -5
  12. data/lib/typeprof/core/ast/method.rb +19 -5
  13. data/lib/typeprof/core/ast/misc.rb +21 -2
  14. data/lib/typeprof/core/ast/module.rb +10 -7
  15. data/lib/typeprof/core/ast/pattern.rb +9 -1
  16. data/lib/typeprof/core/ast/sig_decl.rb +163 -42
  17. data/lib/typeprof/core/ast/sig_type.rb +394 -24
  18. data/lib/typeprof/core/ast/value.rb +11 -3
  19. data/lib/typeprof/core/ast/variable.rb +32 -2
  20. data/lib/typeprof/core/ast.rb +15 -4
  21. data/lib/typeprof/core/builtin.rb +15 -9
  22. data/lib/typeprof/core/env/method.rb +21 -16
  23. data/lib/typeprof/core/env/method_entity.rb +11 -2
  24. data/lib/typeprof/core/env/module_entity.rb +57 -0
  25. data/lib/typeprof/core/env/narrowing.rb +131 -0
  26. data/lib/typeprof/core/env/static_read.rb +9 -8
  27. data/lib/typeprof/core/env.rb +43 -12
  28. data/lib/typeprof/core/graph/box.rb +218 -101
  29. data/lib/typeprof/core/graph/change_set.rb +44 -37
  30. data/lib/typeprof/core/graph/vertex.rb +7 -21
  31. data/lib/typeprof/core/service.rb +61 -40
  32. data/lib/typeprof/core/type.rb +52 -123
  33. data/lib/typeprof/core.rb +1 -1
  34. data/lib/typeprof/diagnostic.rb +5 -6
  35. data/lib/typeprof/lsp/messages.rb +27 -36
  36. data/lib/typeprof/lsp/server.rb +144 -25
  37. data/lib/typeprof/lsp/text.rb +1 -0
  38. data/lib/typeprof/lsp/util.rb +0 -10
  39. data/lib/typeprof/version.rb +1 -1
  40. data/typeprof.conf.jsonc +22 -0
  41. data/typeprof.gemspec +1 -0
  42. metadata +19 -5
  43. data/lib/typeprof/core/graph.rb +0 -3
@@ -1,3 +1,6 @@
1
+ require "cgi/escape"
2
+ require "cgi/util" if RUBY_VERSION < "3.5"
3
+
1
4
  module TypeProf::LSP
2
5
  module ErrorCodes
3
6
  ParseError = -32700
@@ -8,17 +11,17 @@ module TypeProf::LSP
8
11
  end
9
12
 
10
13
  class Server
11
- def self.start_stdio(core)
14
+ def self.start_stdio(core_options)
12
15
  $stdin.binmode
13
16
  $stdout.binmode
14
17
  reader = Reader.new($stdin)
15
18
  writer = Writer.new($stdout)
16
19
  # pipe all builtin print output to stderr to avoid conflicting with lsp
17
20
  $stdout = $stderr
18
- new(core, reader, writer).run
21
+ new(core_options, reader, writer).run
19
22
  end
20
23
 
21
- def self.start_socket(core)
24
+ def self.start_socket(core_options)
22
25
  Socket.tcp_server_sockets("localhost", nil) do |servs|
23
26
  serv = servs[0].local_address
24
27
  $stdout << JSON.generate({
@@ -35,7 +38,7 @@ module TypeProf::LSP
35
38
  begin
36
39
  reader = Reader.new(sock)
37
40
  writer = Writer.new(sock)
38
- new(core, reader, writer).run
41
+ new(core_options, reader, writer).run
39
42
  ensure
40
43
  sock.close
41
44
  end
@@ -44,9 +47,9 @@ module TypeProf::LSP
44
47
  end
45
48
  end
46
49
 
47
- def initialize(core, reader, writer)
48
- @core = core
49
- @workspaces = {}
50
+ def initialize(core_options, reader, writer, url_schema: nil)
51
+ @core_options = core_options
52
+ @cores = {}
50
53
  @reader = reader
51
54
  @writer = writer
52
55
  @request_id = 0
@@ -55,43 +58,140 @@ module TypeProf::LSP
55
58
  @open_texts = {}
56
59
  @exit = false
57
60
  @signature_enabled = true
61
+ @url_schema = url_schema || (File::ALT_SEPARATOR != "\\" ? "file://" : "file:///")
62
+ @diagnostic_severity = :error
58
63
  end
59
64
 
60
- attr_reader :core, :open_texts
65
+ attr_reader :open_texts
61
66
  attr_accessor :signature_enabled
62
67
 
68
+ #: (String) -> String
69
+ def path_to_uri(path)
70
+ @url_schema + File.expand_path(path).split("/").map {|s| CGI.escapeURIComponent(s) }.join("/")
71
+ end
72
+
73
+ def uri_to_path(uri)
74
+ uri.delete_prefix(@url_schema).split("/").map {|s| CGI.unescapeURIComponent(s) }.join("/")
75
+ end
76
+
77
+ #: (Array[String]) -> void
63
78
  def add_workspaces(folders)
64
79
  folders.each do |path|
65
- conf_path = File.join(path, "typeprof.conf.json")
66
- if File.readable?(conf_path)
67
- conf = TypeProf::LSP.load_json_with_comments(conf_path, symbolize_names: true)
68
- if conf
69
- if conf[:typeprof_version] == "experimental"
70
- if conf[:analysis_unit_dirs].size >= 2
71
- puts "currently analysis_unit_dirs can have only one directory"
72
- end
73
- conf[:analysis_unit_dirs].each do |dir|
74
- dir = File.expand_path(dir, path)
75
- @workspaces[dir] = true
76
- @core.add_workspace(dir, conf[:rbs_dir])
80
+ conf_path = [".json", ".jsonc"].map do |ext|
81
+ File.join(path, "typeprof.conf" + ext)
82
+ end.find do |path|
83
+ File.readable?(path)
84
+ end
85
+ unless conf_path
86
+ puts "typeprof.conf.json is not found in #{ path }"
87
+ next
88
+ end
89
+ conf = TypeProf::LSP.load_json_with_comments(conf_path, symbolize_names: true)
90
+ if conf
91
+ if conf[:rbs_dir]
92
+ rbs_dir = File.expand_path(conf[:rbs_dir])
93
+ else
94
+ rbs_dir = File.expand_path(File.expand_path("sig", path))
95
+ end
96
+ @rbs_dir = rbs_dir
97
+ if conf[:typeprof_version] == "experimental"
98
+ if conf[:diagnostic_severity]
99
+ severity = conf[:diagnostic_severity].to_sym
100
+ case severity
101
+ when :error, :warning, :info, :hint
102
+ @diagnostic_severity = severity
103
+ else
104
+ puts "unknown severity: #{ severity }"
77
105
  end
78
- else
79
- puts "Unknown typeprof_version: #{ conf[:typeprof_version] }"
80
106
  end
107
+ conf[:analysis_unit_dirs].each do |dir|
108
+ dir = File.expand_path(dir, path)
109
+ core = @cores[dir] = TypeProf::Core::Service.new(@core_options)
110
+ core.add_workspace(dir, @rbs_dir)
111
+ end
112
+ else
113
+ puts "Unknown typeprof_version: #{ conf[:typeprof_version] }"
81
114
  end
82
- else
83
- puts "typeprof.conf.json is not found"
84
115
  end
85
116
  end
86
117
  end
87
118
 
119
+ #: (String) -> bool
88
120
  def target_path?(path)
89
- @workspaces.each do |folder, _|
121
+ return true if @rbs_dir && path.start_with?(@rbs_dir)
122
+ @cores.each do |folder, _|
90
123
  return true if path.start_with?(folder)
91
124
  end
92
125
  return false
93
126
  end
94
127
 
128
+ def each_core(path)
129
+ @cores.each do |folder, core|
130
+ if path.start_with?(folder) || @rbs_dir && path.start_with?(@rbs_dir)
131
+ yield core
132
+ end
133
+ end
134
+ end
135
+
136
+ def aggregate_each_core(path)
137
+ ret = []
138
+ each_core(path) do |core|
139
+ r = yield(core)
140
+ ret.concat(r) if r
141
+ end
142
+ ret
143
+ end
144
+
145
+ def update_file(path, text)
146
+ each_core(path) do |core|
147
+ core.update_file(path, text)
148
+ end
149
+ end
150
+
151
+ def definitions(path, pos)
152
+ aggregate_each_core(path) do |core|
153
+ core.definitions(path, pos)
154
+ end
155
+ end
156
+
157
+ def type_definitions(path, pos)
158
+ aggregate_each_core(path) do |core|
159
+ core.type_definitions(path, pos)
160
+ end
161
+ end
162
+
163
+ def references(path, pos)
164
+ aggregate_each_core(path) do |core|
165
+ core.references(path, pos)
166
+ end
167
+ end
168
+
169
+ def hover(path, pos)
170
+ ret = []
171
+ each_core(path) do |core|
172
+ ret << core.hover(path, pos)
173
+ end
174
+ ret.compact.first # TODO
175
+ end
176
+
177
+ def code_lens(path, &blk)
178
+ each_core(path) do |core|
179
+ core.code_lens(path, &blk)
180
+ end
181
+ end
182
+
183
+ def completion(path, trigger, pos, &blk)
184
+ each_core(path) do |core|
185
+ core.completion(path, trigger, pos, &blk)
186
+ end
187
+ end
188
+
189
+ def rename(path, pos)
190
+ aggregate_each_core(path) do |core|
191
+ core.rename(path, pos)
192
+ end
193
+ end
194
+
95
195
  def run
96
196
  @reader.read do |json|
97
197
  if json[:method]
@@ -136,6 +236,25 @@ module TypeProf::LSP
136
236
  def exit
137
237
  @exit = true
138
238
  end
239
+
240
+ def publish_updated_diagnostics
241
+ @cores.each do |_, core|
242
+ diags = []
243
+ core.process_diagnostic_paths do |path|
244
+ uri = path_to_uri(path)
245
+ next false unless @open_texts[uri]
246
+ core.diagnostics(path) do |diag|
247
+ diags << diag.to_lsp(severity: @diagnostic_severity)
248
+ end
249
+ send_notification(
250
+ "textDocument/publishDiagnostics",
251
+ uri: uri,
252
+ diagnostics: diags
253
+ )
254
+ true
255
+ end
256
+ end
257
+ end
139
258
  end
140
259
 
141
260
  class Reader
@@ -1,5 +1,6 @@
1
1
  module TypeProf::LSP
2
2
  class Text
3
+ #: (String, String, Integer) -> void
3
4
  def initialize(path, text, version)
4
5
  @path = path
5
6
  @lines = Text.split(text)
@@ -48,14 +48,4 @@ module TypeProf::LSP
48
48
 
49
49
  JSON.parse(json, **opts)
50
50
  end
51
-
52
- FILE_URL_PREFIX = File::ALT_SEPARATOR != "\\" ? "file://" : "file:///"
53
-
54
- def self.file_path_to_uri(path)
55
- FILE_URL_PREFIX + File.expand_path(path)
56
- end
57
-
58
- def self.file_uri_to_path(url)
59
- url.delete_prefix(FILE_URL_PREFIX)
60
- end
61
51
  end
@@ -1,3 +1,3 @@
1
1
  module TypeProf
2
- VERSION = "0.30.0"
2
+ VERSION = "0.31.0"
3
3
  end
@@ -0,0 +1,22 @@
1
+ // Experimental TypeProf configuration
2
+
3
+ // The format is completely tentative and subject to change
4
+ // (including whether to use JSON with Comments or TOML or Ruby DSL or something else)
5
+ {
6
+ // The version of TypeProf; you need to specify "experimental"
7
+ "typeprof_version": "experimental",
8
+
9
+ // The directory containing RBS files that defines the interface between the analysis units
10
+ "rbs_dir": "sig/",
11
+
12
+ // The directories containing Ruby files to be analyzed by TypeProf
13
+ // Each directory will be independently analyzed
14
+ "analysis_unit_dirs": [
15
+ "lib/typeprof/core/",
16
+ "lib/typeprof/lsp"
17
+ ],
18
+
19
+ // Severity of diagnosis, selectable from "error", "warning", "info", "hint", and "none".
20
+ // Currently, TypeProf reports many false positives, so it is recommended to use "hint" or "none".
21
+ "diagnostic_severity": "warning"
22
+ }
data/typeprof.gemspec CHANGED
@@ -28,5 +28,6 @@ Gem::Specification.new do |spec|
28
28
  spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
29
29
  spec.require_paths = ["lib"]
30
30
 
31
+ spec.add_runtime_dependency "prism", ">= 1.4.0"
31
32
  spec.add_runtime_dependency "rbs", ">= 3.6.0"
32
33
  end
metadata CHANGED
@@ -1,15 +1,28 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: typeprof
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.30.0
4
+ version: 0.31.0
5
5
  platform: ruby
6
- original_platform: ''
7
6
  authors:
8
7
  - Yusuke Endoh
9
8
  bindir: bin
10
9
  cert_chain: []
11
- date: 2024-12-13 00:00:00.000000000 Z
10
+ date: 1980-01-02 00:00:00.000000000 Z
12
11
  dependencies:
12
+ - !ruby/object:Gem::Dependency
13
+ name: prism
14
+ requirement: !ruby/object:Gem::Requirement
15
+ requirements:
16
+ - - ">="
17
+ - !ruby/object:Gem::Version
18
+ version: 1.4.0
19
+ type: :runtime
20
+ prerelease: false
21
+ version_requirements: !ruby/object:Gem::Requirement
22
+ requirements:
23
+ - - ">="
24
+ - !ruby/object:Gem::Version
25
+ version: 1.4.0
13
26
  - !ruby/object:Gem::Dependency
14
27
  name: rbs
15
28
  requirement: !ruby/object:Gem::Requirement
@@ -64,10 +77,10 @@ files:
64
77
  - lib/typeprof/core/env/method.rb
65
78
  - lib/typeprof/core/env/method_entity.rb
66
79
  - lib/typeprof/core/env/module_entity.rb
80
+ - lib/typeprof/core/env/narrowing.rb
67
81
  - lib/typeprof/core/env/static_read.rb
68
82
  - lib/typeprof/core/env/type_alias_entity.rb
69
83
  - lib/typeprof/core/env/value_entity.rb
70
- - lib/typeprof/core/graph.rb
71
84
  - lib/typeprof/core/graph/box.rb
72
85
  - lib/typeprof/core/graph/change_set.rb
73
86
  - lib/typeprof/core/graph/filter.rb
@@ -82,6 +95,7 @@ files:
82
95
  - lib/typeprof/lsp/text.rb
83
96
  - lib/typeprof/lsp/util.rb
84
97
  - lib/typeprof/version.rb
98
+ - typeprof.conf.jsonc
85
99
  - typeprof.gemspec
86
100
  homepage: https://github.com/ruby/typeprof
87
101
  licenses:
@@ -103,7 +117,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
103
117
  - !ruby/object:Gem::Version
104
118
  version: '0'
105
119
  requirements: []
106
- rubygems_version: 3.6.0.dev
120
+ rubygems_version: 3.6.9
107
121
  specification_version: 4
108
122
  summary: TypeProf is a type analysis tool for Ruby code based on abstract interpretation
109
123
  test_files: []
@@ -1,3 +0,0 @@
1
- module TypeProf::Core
2
- Fiber[:show_rec] = Set[]
3
- end