solargraph 0.58.0 → 0.59.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 (219) hide show
  1. checksums.yaml +4 -4
  2. data/.envrc +3 -0
  3. data/.gitattributes +2 -0
  4. data/.github/workflows/linting.yml +6 -5
  5. data/.github/workflows/plugins.yml +48 -35
  6. data/.github/workflows/rspec.yml +15 -28
  7. data/.github/workflows/typecheck.yml +3 -2
  8. data/.gitignore +1 -0
  9. data/.rubocop.yml +38 -6
  10. data/.rubocop_todo.yml +53 -966
  11. data/CHANGELOG.md +24 -0
  12. data/Gemfile +3 -1
  13. data/README.md +3 -3
  14. data/Rakefile +26 -23
  15. data/bin/solargraph +9 -8
  16. data/lib/solargraph/api_map/cache.rb +110 -110
  17. data/lib/solargraph/api_map/constants.rb +288 -279
  18. data/lib/solargraph/api_map/index.rb +204 -193
  19. data/lib/solargraph/api_map/source_to_yard.rb +110 -97
  20. data/lib/solargraph/api_map/store.rb +395 -384
  21. data/lib/solargraph/api_map.rb +1029 -945
  22. data/lib/solargraph/bench.rb +44 -45
  23. data/lib/solargraph/complex_type/conformance.rb +176 -0
  24. data/lib/solargraph/complex_type/type_methods.rb +240 -228
  25. data/lib/solargraph/complex_type/unique_type.rb +641 -482
  26. data/lib/solargraph/complex_type.rb +557 -444
  27. data/lib/solargraph/convention/data_definition/data_assignment_node.rb +61 -61
  28. data/lib/solargraph/convention/data_definition/data_definition_node.rb +93 -91
  29. data/lib/solargraph/convention/data_definition.rb +108 -105
  30. data/lib/solargraph/convention/gemfile.rb +15 -15
  31. data/lib/solargraph/convention/gemspec.rb +23 -23
  32. data/lib/solargraph/convention/rakefile.rb +17 -17
  33. data/lib/solargraph/convention/struct_definition/struct_assignment_node.rb +62 -61
  34. data/lib/solargraph/convention/struct_definition/struct_definition_node.rb +103 -102
  35. data/lib/solargraph/convention/struct_definition.rb +168 -164
  36. data/lib/solargraph/convention.rb +78 -78
  37. data/lib/solargraph/converters/dd.rb +19 -17
  38. data/lib/solargraph/converters/dl.rb +17 -15
  39. data/lib/solargraph/converters/dt.rb +17 -15
  40. data/lib/solargraph/converters/misc.rb +3 -1
  41. data/lib/solargraph/diagnostics/require_not_found.rb +54 -53
  42. data/lib/solargraph/diagnostics/rubocop.rb +119 -118
  43. data/lib/solargraph/diagnostics/rubocop_helpers.rb +70 -68
  44. data/lib/solargraph/diagnostics/type_check.rb +56 -55
  45. data/lib/solargraph/diagnostics/update_errors.rb +37 -41
  46. data/lib/solargraph/doc_map.rb +438 -439
  47. data/lib/solargraph/equality.rb +34 -34
  48. data/lib/solargraph/gem_pins.rb +98 -98
  49. data/lib/solargraph/language_server/error_codes.rb +20 -20
  50. data/lib/solargraph/language_server/host/diagnoser.rb +89 -89
  51. data/lib/solargraph/language_server/host/dispatch.rb +130 -130
  52. data/lib/solargraph/language_server/host/message_worker.rb +113 -112
  53. data/lib/solargraph/language_server/host/sources.rb +100 -99
  54. data/lib/solargraph/language_server/host.rb +886 -878
  55. data/lib/solargraph/language_server/message/base.rb +97 -97
  56. data/lib/solargraph/language_server/message/client/register_capability.rb +13 -15
  57. data/lib/solargraph/language_server/message/completion_item/resolve.rb +58 -60
  58. data/lib/solargraph/language_server/message/extended/check_gem_version.rb +108 -114
  59. data/lib/solargraph/language_server/message/extended/document.rb +24 -23
  60. data/lib/solargraph/language_server/message/extended/document_gems.rb +32 -32
  61. data/lib/solargraph/language_server/message/extended/download_core.rb +20 -19
  62. data/lib/solargraph/language_server/message/extended/search.rb +20 -20
  63. data/lib/solargraph/language_server/message/initialize.rb +197 -191
  64. data/lib/solargraph/language_server/message/text_document/completion.rb +58 -56
  65. data/lib/solargraph/language_server/message/text_document/definition.rb +49 -40
  66. data/lib/solargraph/language_server/message/text_document/document_highlight.rb +23 -16
  67. data/lib/solargraph/language_server/message/text_document/document_symbol.rb +36 -26
  68. data/lib/solargraph/language_server/message/text_document/formatting.rb +150 -148
  69. data/lib/solargraph/language_server/message/text_document/hover.rb +58 -58
  70. data/lib/solargraph/language_server/message/text_document/prepare_rename.rb +18 -11
  71. data/lib/solargraph/language_server/message/text_document/references.rb +23 -16
  72. data/lib/solargraph/language_server/message/text_document/rename.rb +26 -19
  73. data/lib/solargraph/language_server/message/text_document/signature_help.rb +25 -24
  74. data/lib/solargraph/language_server/message/text_document/type_definition.rb +33 -25
  75. data/lib/solargraph/language_server/message/workspace/did_change_configuration.rb +41 -35
  76. data/lib/solargraph/language_server/message/workspace/did_change_watched_files.rb +48 -40
  77. data/lib/solargraph/language_server/message/workspace/did_change_workspace_folders.rb +32 -26
  78. data/lib/solargraph/language_server/message/workspace/workspace_symbol.rb +33 -23
  79. data/lib/solargraph/language_server/message.rb +94 -94
  80. data/lib/solargraph/language_server/request.rb +29 -27
  81. data/lib/solargraph/language_server/transport/data_reader.rb +72 -74
  82. data/lib/solargraph/language_server/uri_helpers.rb +49 -49
  83. data/lib/solargraph/library.rb +702 -683
  84. data/lib/solargraph/location.rb +85 -82
  85. data/lib/solargraph/logging.rb +55 -37
  86. data/lib/solargraph/page.rb +92 -92
  87. data/lib/solargraph/parser/comment_ripper.rb +84 -69
  88. data/lib/solargraph/parser/flow_sensitive_typing.rb +471 -255
  89. data/lib/solargraph/parser/node_processor/base.rb +122 -92
  90. data/lib/solargraph/parser/node_processor.rb +63 -62
  91. data/lib/solargraph/parser/parser_gem/class_methods.rb +165 -149
  92. data/lib/solargraph/parser/parser_gem/flawed_builder.rb +19 -19
  93. data/lib/solargraph/parser/parser_gem/node_chainer.rb +191 -166
  94. data/lib/solargraph/parser/parser_gem/node_methods.rb +507 -486
  95. data/lib/solargraph/parser/parser_gem/node_processors/and_node.rb +22 -22
  96. data/lib/solargraph/parser/parser_gem/node_processors/args_node.rb +61 -59
  97. data/lib/solargraph/parser/parser_gem/node_processors/begin_node.rb +24 -15
  98. data/lib/solargraph/parser/parser_gem/node_processors/block_node.rb +45 -46
  99. data/lib/solargraph/parser/parser_gem/node_processors/def_node.rb +60 -53
  100. data/lib/solargraph/parser/parser_gem/node_processors/defs_node.rb +38 -37
  101. data/lib/solargraph/parser/parser_gem/node_processors/if_node.rb +53 -23
  102. data/lib/solargraph/parser/parser_gem/node_processors/ivasgn_node.rb +42 -40
  103. data/lib/solargraph/parser/parser_gem/node_processors/lvasgn_node.rb +30 -29
  104. data/lib/solargraph/parser/parser_gem/node_processors/masgn_node.rb +61 -59
  105. data/lib/solargraph/parser/parser_gem/node_processors/opasgn_node.rb +98 -98
  106. data/lib/solargraph/parser/parser_gem/node_processors/or_node.rb +22 -0
  107. data/lib/solargraph/parser/parser_gem/node_processors/orasgn_node.rb +17 -17
  108. data/lib/solargraph/parser/parser_gem/node_processors/resbody_node.rb +39 -38
  109. data/lib/solargraph/parser/parser_gem/node_processors/sclass_node.rb +51 -52
  110. data/lib/solargraph/parser/parser_gem/node_processors/send_node.rb +302 -291
  111. data/lib/solargraph/parser/parser_gem/node_processors/until_node.rb +29 -29
  112. data/lib/solargraph/parser/parser_gem/node_processors/when_node.rb +23 -0
  113. data/lib/solargraph/parser/parser_gem/node_processors/while_node.rb +33 -29
  114. data/lib/solargraph/parser/parser_gem/node_processors.rb +74 -70
  115. data/lib/solargraph/parser/parser_gem.rb +14 -12
  116. data/lib/solargraph/parser/region.rb +75 -69
  117. data/lib/solargraph/parser/snippet.rb +19 -17
  118. data/lib/solargraph/parser.rb +25 -23
  119. data/lib/solargraph/pin/base.rb +773 -729
  120. data/lib/solargraph/pin/base_variable.rb +375 -126
  121. data/lib/solargraph/pin/block.rb +127 -104
  122. data/lib/solargraph/pin/breakable.rb +15 -9
  123. data/lib/solargraph/pin/callable.rb +275 -231
  124. data/lib/solargraph/pin/closure.rb +69 -72
  125. data/lib/solargraph/pin/common.rb +97 -79
  126. data/lib/solargraph/pin/compound_statement.rb +55 -0
  127. data/lib/solargraph/pin/constant.rb +43 -45
  128. data/lib/solargraph/pin/conversions.rb +129 -123
  129. data/lib/solargraph/pin/delegated_method.rb +131 -120
  130. data/lib/solargraph/pin/documenting.rb +116 -114
  131. data/lib/solargraph/pin/instance_variable.rb +38 -34
  132. data/lib/solargraph/pin/keyword.rb +16 -20
  133. data/lib/solargraph/pin/local_variable.rb +31 -75
  134. data/lib/solargraph/pin/method.rb +724 -672
  135. data/lib/solargraph/pin/method_alias.rb +42 -34
  136. data/lib/solargraph/pin/namespace.rb +122 -115
  137. data/lib/solargraph/pin/parameter.rb +339 -275
  138. data/lib/solargraph/pin/proxy_type.rb +42 -39
  139. data/lib/solargraph/pin/reference/override.rb +47 -47
  140. data/lib/solargraph/pin/reference/superclass.rb +17 -15
  141. data/lib/solargraph/pin/reference/type_alias.rb +16 -0
  142. data/lib/solargraph/pin/reference.rb +59 -39
  143. data/lib/solargraph/pin/search.rb +62 -61
  144. data/lib/solargraph/pin/signature.rb +64 -61
  145. data/lib/solargraph/pin/symbol.rb +54 -53
  146. data/lib/solargraph/pin/until.rb +16 -18
  147. data/lib/solargraph/pin/while.rb +16 -18
  148. data/lib/solargraph/pin.rb +46 -44
  149. data/lib/solargraph/pin_cache.rb +248 -245
  150. data/lib/solargraph/position.rb +139 -119
  151. data/lib/solargraph/range.rb +113 -112
  152. data/lib/solargraph/rbs_map/conversions.rb +952 -823
  153. data/lib/solargraph/rbs_map/core_fills.rb +91 -84
  154. data/lib/solargraph/rbs_map/core_map.rb +65 -58
  155. data/lib/solargraph/rbs_map/stdlib_map.rb +71 -43
  156. data/lib/solargraph/rbs_map.rb +207 -163
  157. data/lib/solargraph/server_methods.rb +16 -16
  158. data/lib/solargraph/shell.rb +555 -352
  159. data/lib/solargraph/source/chain/array.rb +39 -37
  160. data/lib/solargraph/source/chain/call.rb +377 -337
  161. data/lib/solargraph/source/chain/class_variable.rb +13 -13
  162. data/lib/solargraph/source/chain/constant.rb +30 -26
  163. data/lib/solargraph/source/chain/global_variable.rb +13 -13
  164. data/lib/solargraph/source/chain/hash.rb +37 -34
  165. data/lib/solargraph/source/chain/if.rb +30 -28
  166. data/lib/solargraph/source/chain/instance_variable.rb +36 -13
  167. data/lib/solargraph/source/chain/link.rb +99 -109
  168. data/lib/solargraph/source/chain/literal.rb +51 -48
  169. data/lib/solargraph/source/chain/or.rb +29 -23
  170. data/lib/solargraph/source/chain/q_call.rb +13 -11
  171. data/lib/solargraph/source/chain/variable.rb +15 -13
  172. data/lib/solargraph/source/chain/z_super.rb +28 -30
  173. data/lib/solargraph/source/chain.rb +304 -291
  174. data/lib/solargraph/source/change.rb +89 -82
  175. data/lib/solargraph/source/cursor.rb +172 -166
  176. data/lib/solargraph/source/encoding_fixes.rb +22 -23
  177. data/lib/solargraph/source/source_chainer.rb +218 -194
  178. data/lib/solargraph/source/updater.rb +59 -55
  179. data/lib/solargraph/source.rb +522 -498
  180. data/lib/solargraph/source_map/clip.rb +245 -226
  181. data/lib/solargraph/source_map/data.rb +37 -34
  182. data/lib/solargraph/source_map/mapper.rb +286 -259
  183. data/lib/solargraph/source_map.rb +224 -212
  184. data/lib/solargraph/type_checker/problem.rb +34 -32
  185. data/lib/solargraph/type_checker/rules.rb +157 -84
  186. data/lib/solargraph/type_checker.rb +888 -814
  187. data/lib/solargraph/version.rb +5 -5
  188. data/lib/solargraph/workspace/config.rb +258 -255
  189. data/lib/solargraph/workspace/gemspecs.rb +367 -0
  190. data/lib/solargraph/workspace/require_paths.rb +98 -97
  191. data/lib/solargraph/workspace.rb +242 -220
  192. data/lib/solargraph/yard_map/helpers.rb +49 -44
  193. data/lib/solargraph/yard_map/mapper/to_method.rb +136 -130
  194. data/lib/solargraph/yard_map/mapper/to_namespace.rb +32 -31
  195. data/lib/solargraph/yard_map/mapper.rb +84 -79
  196. data/lib/solargraph/yard_map.rb +17 -18
  197. data/lib/solargraph/yard_tags.rb +20 -20
  198. data/lib/solargraph/yardoc.rb +90 -87
  199. data/lib/solargraph.rb +128 -105
  200. data/rbs/fills/rubygems/0/dependency.rbs +193 -0
  201. data/rbs/fills/tuple/tuple.rbs +28 -0
  202. data/rbs/shims/ast/0/node.rbs +5 -0
  203. data/rbs/shims/diff-lcs/1.5/diff-lcs.rbs +11 -0
  204. data/rbs_collection.yaml +1 -1
  205. data/solargraph.gemspec +37 -35
  206. metadata +52 -51
  207. data/lib/solargraph/type_checker/checks.rb +0 -124
  208. data/lib/solargraph/type_checker/param_def.rb +0 -37
  209. data/lib/solargraph/yard_map/to_method.rb +0 -89
  210. data/sig/shims/ast/0/node.rbs +0 -5
  211. /data/{sig → rbs}/shims/ast/2.4/.rbs_meta.yaml +0 -0
  212. /data/{sig → rbs}/shims/ast/2.4/ast.rbs +0 -0
  213. /data/{sig → rbs}/shims/parser/3.2.0.1/builders/default.rbs +0 -0
  214. /data/{sig → rbs}/shims/parser/3.2.0.1/manifest.yaml +0 -0
  215. /data/{sig → rbs}/shims/parser/3.2.0.1/parser.rbs +0 -0
  216. /data/{sig → rbs}/shims/parser/3.2.0.1/polyfill.rbs +0 -0
  217. /data/{sig → rbs}/shims/thor/1.2.0.1/.rbs_meta.yaml +0 -0
  218. /data/{sig → rbs}/shims/thor/1.2.0.1/manifest.yaml +0 -0
  219. /data/{sig → rbs}/shims/thor/1.2.0.1/thor.rbs +0 -0
@@ -1,53 +1,54 @@
1
- # frozen_string_literal: true
2
-
3
- module Solargraph
4
- module Diagnostics
5
- # RequireNotFound reports required paths that could not be resolved to
6
- # either a file in the workspace or a gem.
7
- #
8
- class RequireNotFound < Base
9
- def diagnose source, api_map
10
- return [] unless source.parsed? && source.synchronized?
11
- result = []
12
- refs = {}
13
- map = api_map.source_map(source.filename)
14
- map.requires.each { |ref| refs[ref.name] = ref }
15
- api_map.missing_docs.each do |r|
16
- next unless refs.key?(r)
17
- result.push docs_error(r, refs[r].location)
18
- end
19
- api_map.unresolved_requires.each do |r|
20
- next unless refs.key?(r)
21
- result.push require_error(r, refs[r].location)
22
- end
23
- result
24
- end
25
-
26
- private
27
-
28
- # @param path [String]
29
- # @param location [Location]
30
- # @return [Hash]
31
- def docs_error path, location
32
- {
33
- range: location.range.to_hash,
34
- severity: Diagnostics::Severities::WARNING,
35
- source: 'RequireNotFound',
36
- message: "YARD docs not found for #{path}"
37
- }
38
- end
39
-
40
- # @param path [String]
41
- # @param location [Location]
42
- # @return [Hash]
43
- def require_error path, location
44
- {
45
- range: location.range.to_hash,
46
- severity: Diagnostics::Severities::WARNING,
47
- source: 'RequireNotFound',
48
- message: "Required path #{path} could not be resolved."
49
- }
50
- end
51
- end
52
- end
53
- end
1
+ # frozen_string_literal: true
2
+
3
+ module Solargraph
4
+ module Diagnostics
5
+ # RequireNotFound reports required paths that could not be resolved to
6
+ # either a file in the workspace or a gem.
7
+ #
8
+ class RequireNotFound < Base
9
+ def diagnose source, api_map
10
+ return [] unless source.parsed? && source.synchronized?
11
+ result = []
12
+ refs = {}
13
+ # @sg-ignore Need to add nil check here
14
+ map = api_map.source_map(source.filename)
15
+ map.requires.each { |ref| refs[ref.name] = ref }
16
+ api_map.missing_docs.each do |r|
17
+ next unless refs.key?(r)
18
+ result.push docs_error(r, refs[r].location)
19
+ end
20
+ api_map.unresolved_requires.each do |r|
21
+ next unless refs.key?(r)
22
+ result.push require_error(r, refs[r].location)
23
+ end
24
+ result
25
+ end
26
+
27
+ private
28
+
29
+ # @param path [String]
30
+ # @param location [Location]
31
+ # @return [Hash]
32
+ def docs_error path, location
33
+ {
34
+ range: location.range.to_hash,
35
+ severity: Diagnostics::Severities::WARNING,
36
+ source: 'RequireNotFound',
37
+ message: "YARD docs not found for #{path}"
38
+ }
39
+ end
40
+
41
+ # @param path [String]
42
+ # @param location [Location]
43
+ # @return [Hash]
44
+ def require_error path, location
45
+ {
46
+ range: location.range.to_hash,
47
+ severity: Diagnostics::Severities::WARNING,
48
+ source: 'RequireNotFound',
49
+ message: "Required path #{path} could not be resolved."
50
+ }
51
+ end
52
+ end
53
+ end
54
+ end
@@ -1,118 +1,119 @@
1
- # frozen_string_literal: true
2
-
3
- require 'stringio'
4
-
5
- module Solargraph
6
- module Diagnostics
7
- # This reporter provides linting through RuboCop.
8
- #
9
- class Rubocop < Base
10
- include RubocopHelpers
11
-
12
- # Conversion of RuboCop severity names to LSP constants
13
- SEVERITIES = {
14
- 'info' => Severities::HINT,
15
- 'refactor' => Severities::HINT,
16
- 'convention' => Severities::INFORMATION,
17
- 'warning' => Severities::WARNING,
18
- 'error' => Severities::ERROR,
19
- 'fatal' => Severities::ERROR
20
- }
21
-
22
- # @param source [Solargraph::Source]
23
- # @param _api_map [Solargraph::ApiMap]
24
- # @return [Array<Hash>]
25
- def diagnose source, _api_map
26
- @source = source
27
- require_rubocop(rubocop_version)
28
- options, paths = generate_options(source.filename, source.code)
29
- store = RuboCop::ConfigStore.new
30
- runner = RuboCop::Runner.new(options, store)
31
- # Ensure only one instance of RuboCop::Runner is running at
32
- # a time - it uses 'chdir' to read config files with ERB,
33
- # which can conflict with other chdirs.
34
- result = Solargraph::CHDIR_MUTEX.synchronize do
35
- redirect_stdout{ runner.run(paths) }
36
- end
37
-
38
- return [] if result.empty?
39
-
40
- make_array JSON.parse(result)
41
- rescue RuboCop::ValidationError, RuboCop::ConfigNotFoundError => e
42
- raise DiagnosticsError, "Error in RuboCop configuration: #{e.message}"
43
- rescue JSON::ParserError => e
44
- raise DiagnosticsError, "RuboCop returned invalid data: #{e.message}"
45
- end
46
-
47
- private
48
-
49
- # Extracts the rubocop version from _args_
50
- #
51
- # @return [String]
52
- def rubocop_version
53
- args.find { |a| a =~ /version=/ }.to_s.split('=').last
54
- end
55
-
56
- # @param resp [Hash{String => Array<Hash{String => Array<Hash{String => undefined}>}>}]
57
- # @return [Array<Hash>]
58
- def make_array resp
59
- diagnostics = []
60
- resp['files'].each do |file|
61
- file['offenses'].each do |off|
62
- diagnostics.push offense_to_diagnostic(off)
63
- end
64
- end
65
- diagnostics
66
- end
67
-
68
- # Convert a RuboCop offense to an LSP diagnostic
69
- #
70
- # @param off [Hash{String => unknown}] Offense received from Rubocop
71
- # @return [Hash{Symbol => Hash, String, Integer}] LSP diagnostic
72
- def offense_to_diagnostic off
73
- {
74
- range: offense_range(off).to_hash,
75
- # 1 = Error, 2 = Warning, 3 = Information, 4 = Hint
76
- severity: SEVERITIES[off['severity']],
77
- source: 'rubocop',
78
- code: off['cop_name'],
79
- message: off['message'].gsub(/^#{off['cop_name']}\:/, '')
80
- }
81
- end
82
-
83
- # @param off [Hash]
84
- # @return [Range]
85
- def offense_range off
86
- Range.new(offense_start_position(off), offense_ending_position(off))
87
- end
88
-
89
- # @param off [Hash{String => Hash{String => Integer}}]
90
- # @return [Position]
91
- def offense_start_position off
92
- Position.new(off['location']['start_line'] - 1, off['location']['start_column'] - 1)
93
- end
94
-
95
- # @param off [Hash{String => Hash{String => Integer}}]
96
- # @return [Position]
97
- def offense_ending_position off
98
- if off['location']['start_line'] != off['location']['last_line']
99
- Position.new(off['location']['start_line'], 0)
100
- else
101
- start_line = off['location']['start_line'] - 1
102
- # @type [Integer]
103
- last_column = off['location']['last_column']
104
- line = @source.code.lines[start_line]
105
- col_off = if line.nil? || line.empty?
106
- 1
107
- else
108
- 0
109
- end
110
-
111
- Position.new(
112
- start_line, last_column - col_off
113
- )
114
- end
115
- end
116
- end
117
- end
118
- end
1
+ # frozen_string_literal: true
2
+
3
+ require 'stringio'
4
+
5
+ module Solargraph
6
+ module Diagnostics
7
+ # This reporter provides linting through RuboCop.
8
+ #
9
+ class Rubocop < Base
10
+ include RubocopHelpers
11
+
12
+ # Conversion of RuboCop severity names to LSP constants
13
+ SEVERITIES = {
14
+ 'info' => Severities::HINT,
15
+ 'refactor' => Severities::HINT,
16
+ 'convention' => Severities::INFORMATION,
17
+ 'warning' => Severities::WARNING,
18
+ 'error' => Severities::ERROR,
19
+ 'fatal' => Severities::ERROR
20
+ }.freeze
21
+
22
+ # @param source [Solargraph::Source]
23
+ # @param _api_map [Solargraph::ApiMap]
24
+ # @return [Array<Hash>]
25
+ def diagnose source, _api_map
26
+ @source = source
27
+ require_rubocop(rubocop_version)
28
+ # @sg-ignore Need to add nil check here
29
+ options, paths = generate_options(source.filename, source.code)
30
+ store = RuboCop::ConfigStore.new
31
+ runner = RuboCop::Runner.new(options, store)
32
+ # Ensure only one instance of RuboCop::Runner is running at
33
+ # a time - it uses 'chdir' to read config files with ERB,
34
+ # which can conflict with other chdirs.
35
+ result = Solargraph::CHDIR_MUTEX.synchronize do
36
+ redirect_stdout { runner.run(paths) }
37
+ end
38
+
39
+ return [] if result.empty?
40
+
41
+ make_array JSON.parse(result)
42
+ rescue RuboCop::ValidationError, RuboCop::ConfigNotFoundError => e
43
+ raise DiagnosticsError, "Error in RuboCop configuration: #{e.message}"
44
+ rescue JSON::ParserError => e
45
+ raise DiagnosticsError, "RuboCop returned invalid data: #{e.message}"
46
+ end
47
+
48
+ private
49
+
50
+ # Extracts the rubocop version from _args_
51
+ #
52
+ # @return [String]
53
+ def rubocop_version
54
+ args.find { |a| a =~ /version=/ }.to_s.split('=').last
55
+ end
56
+
57
+ # @param resp [Hash{String => Array<Hash{String => Array<Hash{String => undefined}>}>}]
58
+ # @return [Array<Hash>]
59
+ def make_array resp
60
+ diagnostics = []
61
+ resp['files'].each do |file|
62
+ file['offenses'].each do |off|
63
+ diagnostics.push offense_to_diagnostic(off)
64
+ end
65
+ end
66
+ diagnostics
67
+ end
68
+
69
+ # Convert a RuboCop offense to an LSP diagnostic
70
+ #
71
+ # @param off [Hash{String => unknown}] Offense received from Rubocop
72
+ # @return [Hash{Symbol => Hash, String, Integer}] LSP diagnostic
73
+ def offense_to_diagnostic off
74
+ {
75
+ range: offense_range(off).to_hash,
76
+ # 1 = Error, 2 = Warning, 3 = Information, 4 = Hint
77
+ severity: SEVERITIES[off['severity']],
78
+ source: 'rubocop',
79
+ code: off['cop_name'],
80
+ message: off['message'].gsub(/^#{off['cop_name']}:/, '')
81
+ }
82
+ end
83
+
84
+ # @param off [Hash]
85
+ # @return [Range]
86
+ def offense_range off
87
+ Range.new(offense_start_position(off), offense_ending_position(off))
88
+ end
89
+
90
+ # @param off [Hash{String => Hash{String => Integer}}]
91
+ # @return [Position]
92
+ def offense_start_position off
93
+ Position.new(off['location']['start_line'] - 1, off['location']['start_column'] - 1)
94
+ end
95
+
96
+ # @param off [Hash{String => Hash{String => Integer}}]
97
+ # @return [Position]
98
+ def offense_ending_position off
99
+ if off['location']['start_line'] == off['location']['last_line']
100
+ start_line = off['location']['start_line'] - 1
101
+ # @type [Integer]
102
+ last_column = off['location']['last_column']
103
+ line = @source.code.lines[start_line]
104
+ col_off = if line.nil? || line.empty?
105
+ 1
106
+ else
107
+ 0
108
+ end
109
+
110
+ Position.new(
111
+ start_line, last_column - col_off
112
+ )
113
+ else
114
+ Position.new(off['location']['start_line'], 0)
115
+ end
116
+ end
117
+ end
118
+ end
119
+ end
@@ -1,68 +1,70 @@
1
- # frozen_string_literal: true
2
-
3
- module Solargraph
4
- module Diagnostics
5
- # Utility methods for the RuboCop diagnostics reporter.
6
- #
7
- module RubocopHelpers
8
- module_function
9
-
10
- # Requires a specific version of rubocop, or the latest installed version
11
- # if _version_ is `nil`.
12
- #
13
- # @param version [String, nil]
14
- # @raise [InvalidRubocopVersionError] if _version_ is not installed
15
- # @return [void]
16
- def require_rubocop(version = nil)
17
- begin
18
- # @type [String]
19
- gem_path = Gem::Specification.find_by_name('rubocop', version).full_gem_path
20
- gem_lib_path = File.join(gem_path, 'lib')
21
- $LOAD_PATH.unshift(gem_lib_path) unless $LOAD_PATH.include?(gem_lib_path)
22
- rescue Gem::MissingSpecVersionError => e
23
- # @type [Array<Gem::Specification>]
24
- specs = e.specs
25
- raise InvalidRubocopVersionError,
26
- "could not find '#{e.name}' (#{e.requirement}) - "\
27
- "did find: [#{specs.map { |s| s.version.version }.join(', ')}]"
28
- end
29
- require 'rubocop'
30
- end
31
-
32
- # Generate command-line options for the specified filename and code.
33
- #
34
- # @param filename [String]
35
- # @param code [String]
36
- # @return [Array(Array<String>, Array<String>)]
37
- def generate_options filename, code
38
- args = ['-f', 'j', '--force-exclusion', filename]
39
- base_options = RuboCop::Options.new
40
- options, paths = base_options.parse(args)
41
- # @sg-ignore
42
- options[:stdin] = code
43
- [options, paths]
44
- end
45
-
46
- # RuboCop internally uses capitalized drive letters for Windows paths,
47
- # so we need to convert the paths provided to the command.
48
- #
49
- # @param path [String]
50
- # @return [String]
51
- def fix_drive_letter path
52
- return path unless path.match(/^[a-z]:/)
53
- path[0].upcase + path[1..-1]
54
- end
55
-
56
- # @todo This is a smelly way to redirect output, but the RuboCop specs do
57
- # the same thing.
58
- # @return [String]
59
- def redirect_stdout
60
- redir = StringIO.new
61
- $stdout = redir
62
- yield if block_given?
63
- $stdout = STDOUT
64
- redir.string
65
- end
66
- end
67
- end
68
- end
1
+ # frozen_string_literal: true
2
+
3
+ module Solargraph
4
+ module Diagnostics
5
+ # Utility methods for the RuboCop diagnostics reporter.
6
+ #
7
+ module RubocopHelpers
8
+ module_function
9
+
10
+ # Requires a specific version of rubocop, or the latest installed version
11
+ # if _version_ is `nil`.
12
+ #
13
+ # @param version [String, nil]
14
+ # @raise [InvalidRubocopVersionError] if _version_ is not installed
15
+ # @return [void]
16
+ def require_rubocop version = nil
17
+ begin
18
+ # @type [String]
19
+ gem_path = Gem::Specification.find_by_name('rubocop', version).full_gem_path
20
+ gem_lib_path = File.join(gem_path, 'lib')
21
+ # @sg-ignore Should better support meaning of '&' in RBS
22
+ $LOAD_PATH.unshift(gem_lib_path) unless $LOAD_PATH.include?(gem_lib_path)
23
+ rescue Gem::MissingSpecVersionError => e
24
+ # @type [Array<Gem::Specification>]
25
+ specs = e.specs
26
+ raise InvalidRubocopVersionError,
27
+ "could not find '#{e.name}' (#{e.requirement}) - " \
28
+ "did find: [#{specs.map { |s| s.version.version }.join(', ')}]"
29
+ end
30
+ require 'rubocop'
31
+ end
32
+
33
+ # Generate command-line options for the specified filename and code.
34
+ #
35
+ # @param filename [String]
36
+ # @param code [String]
37
+ # @return [Array(Array<String>, Array<String>)]
38
+ def generate_options filename, code
39
+ args = ['-f', 'j', '--force-exclusion', filename]
40
+ base_options = RuboCop::Options.new
41
+ options, paths = base_options.parse(args)
42
+ # @sg-ignore
43
+ options[:stdin] = code
44
+ [options, paths]
45
+ end
46
+
47
+ # RuboCop internally uses capitalized drive letters for Windows paths,
48
+ # so we need to convert the paths provided to the command.
49
+ #
50
+ # @param path [String]
51
+ # @return [String]
52
+ def fix_drive_letter path
53
+ return path unless path.match(/^[a-z]:/)
54
+ # @sg-ignore Need to add nil check here
55
+ path[0].upcase + path[1..]
56
+ end
57
+
58
+ # @todo This is a smelly way to redirect output, but the RuboCop specs do
59
+ # the same thing.
60
+ # @return [String]
61
+ def redirect_stdout
62
+ redir = StringIO.new
63
+ $stdout = redir
64
+ yield if block_given?
65
+ $stdout = STDOUT
66
+ redir.string
67
+ end
68
+ end
69
+ end
70
+ end
@@ -1,55 +1,56 @@
1
- # frozen_string_literal: true
2
-
3
- module Solargraph
4
- module Diagnostics
5
- # TypeCheck reports methods with undefined return types, untagged
6
- # parameters, and invalid param tags.
7
- #
8
- class TypeCheck < Base
9
- # @return [Array<Hash>]
10
- def diagnose source, api_map
11
- # return [] unless args.include?('always') || api_map.workspaced?(source.filename)
12
- severity = Diagnostics::Severities::ERROR
13
- level = (args.reverse.find { |a| ['normal', 'typed', 'strict', 'strong'].include?(a) }) || :normal
14
- checker = Solargraph::TypeChecker.new(source.filename, api_map: api_map, level: level.to_sym)
15
- checker.problems
16
- .sort { |a, b| a.location.range.start.line <=> b.location.range.start.line }
17
- .map do |problem|
18
- {
19
- range: extract_first_line(problem.location, source),
20
- severity: severity,
21
- source: 'Typecheck',
22
- message: problem.message
23
- }
24
- end
25
- end
26
-
27
- private
28
-
29
- # @param location [Location]
30
- # @param source [Source]
31
- # @return [Hash]
32
- def extract_first_line location, source
33
- return location.range.to_hash if location.range.start.line == location.range.ending.line
34
- {
35
- start: {
36
- line: location.range.start.line,
37
- character: location.range.start.character
38
- },
39
- end: {
40
- line: location.range.start.line,
41
- character: last_character(location.range.start, source)
42
- }
43
- }
44
- end
45
-
46
- # @param position [Solargraph::Position]
47
- # @param source [Solargraph::Source]
48
- # @return [Integer]
49
- def last_character position, source
50
- cursor = Position.to_offset(source.code, position)
51
- source.code.index(/[\r\n]/, cursor) || source.code.length
52
- end
53
- end
54
- end
55
- end
1
+ # frozen_string_literal: true
2
+
3
+ module Solargraph
4
+ module Diagnostics
5
+ # TypeCheck reports methods with undefined return types, untagged
6
+ # parameters, and invalid param tags.
7
+ #
8
+ class TypeCheck < Base
9
+ # @return [Array<Hash>]
10
+ def diagnose source, api_map
11
+ # return [] unless args.include?('always') || api_map.workspaced?(source.filename)
12
+ severity = Diagnostics::Severities::ERROR
13
+ level = args.reverse.find { |a| %w[normal typed strict strong].include?(a) } || :normal
14
+ # @sg-ignore sensitive typing needs to handle || on nil types
15
+ checker = Solargraph::TypeChecker.new(source.filename, api_map: api_map, level: level.to_sym)
16
+ checker.problems
17
+ .sort { |a, b| a.location.range.start.line <=> b.location.range.start.line }
18
+ .map do |problem|
19
+ {
20
+ range: extract_first_line(problem.location, source),
21
+ severity: severity,
22
+ source: 'Typecheck',
23
+ message: problem.message
24
+ }
25
+ end
26
+ end
27
+
28
+ private
29
+
30
+ # @param location [Location]
31
+ # @param source [Source]
32
+ # @return [Hash]
33
+ def extract_first_line location, source
34
+ return location.range.to_hash if location.range.start.line == location.range.ending.line
35
+ {
36
+ start: {
37
+ line: location.range.start.line,
38
+ character: location.range.start.character
39
+ },
40
+ end: {
41
+ line: location.range.start.line,
42
+ character: last_character(location.range.start, source)
43
+ }
44
+ }
45
+ end
46
+
47
+ # @param position [Solargraph::Position]
48
+ # @param source [Solargraph::Source]
49
+ # @return [Integer]
50
+ def last_character position, source
51
+ cursor = Position.to_offset(source.code, position)
52
+ source.code.index(/[\r\n]/, cursor) || source.code.length
53
+ end
54
+ end
55
+ end
56
+ end