solargraph 0.54.4 → 0.58.3

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 (238) hide show
  1. checksums.yaml +4 -4
  2. data/.gitattributes +2 -0
  3. data/.github/workflows/linting.yml +127 -0
  4. data/.github/workflows/plugins.yml +185 -6
  5. data/.github/workflows/rspec.yml +55 -5
  6. data/.github/workflows/typecheck.yml +8 -3
  7. data/.gitignore +8 -0
  8. data/.overcommit.yml +72 -0
  9. data/.rspec +1 -0
  10. data/.rubocop.yml +66 -0
  11. data/.rubocop_todo.yml +1279 -0
  12. data/.yardopts +1 -0
  13. data/CHANGELOG.md +143 -0
  14. data/README.md +20 -6
  15. data/Rakefile +125 -13
  16. data/bin/solargraph +3 -0
  17. data/lib/solargraph/api_map/cache.rb +110 -109
  18. data/lib/solargraph/api_map/constants.rb +279 -0
  19. data/lib/solargraph/api_map/index.rb +193 -167
  20. data/lib/solargraph/api_map/source_to_yard.rb +97 -88
  21. data/lib/solargraph/api_map/store.rb +384 -241
  22. data/lib/solargraph/api_map.rb +945 -875
  23. data/lib/solargraph/bench.rb +45 -28
  24. data/lib/solargraph/complex_type/type_methods.rb +228 -217
  25. data/lib/solargraph/complex_type/unique_type.rb +482 -386
  26. data/lib/solargraph/complex_type.rb +444 -394
  27. data/lib/solargraph/convention/active_support_concern.rb +111 -0
  28. data/lib/solargraph/convention/base.rb +20 -3
  29. data/lib/solargraph/convention/data_definition/data_assignment_node.rb +61 -0
  30. data/lib/solargraph/convention/data_definition/data_definition_node.rb +91 -0
  31. data/lib/solargraph/convention/data_definition.rb +105 -0
  32. data/lib/solargraph/convention/gemfile.rb +15 -15
  33. data/lib/solargraph/convention/gemspec.rb +23 -22
  34. data/lib/solargraph/convention/rakefile.rb +17 -17
  35. data/lib/solargraph/convention/struct_definition/struct_assignment_node.rb +61 -0
  36. data/lib/solargraph/convention/struct_definition/struct_definition_node.rb +102 -0
  37. data/lib/solargraph/convention/struct_definition.rb +164 -0
  38. data/lib/solargraph/convention.rb +78 -47
  39. data/lib/solargraph/converters/dd.rb +17 -17
  40. data/lib/solargraph/converters/dl.rb +15 -15
  41. data/lib/solargraph/converters/dt.rb +15 -15
  42. data/lib/solargraph/converters/misc.rb +1 -1
  43. data/lib/solargraph/diagnostics/require_not_found.rb +53 -53
  44. data/lib/solargraph/diagnostics/rubocop.rb +118 -113
  45. data/lib/solargraph/diagnostics/rubocop_helpers.rb +68 -66
  46. data/lib/solargraph/diagnostics/type_check.rb +55 -55
  47. data/lib/solargraph/diagnostics/update_errors.rb +41 -41
  48. data/lib/solargraph/doc_map.rb +439 -188
  49. data/lib/solargraph/environ.rb +9 -2
  50. data/lib/solargraph/equality.rb +34 -33
  51. data/lib/solargraph/gem_pins.rb +98 -72
  52. data/lib/solargraph/language_server/error_codes.rb +20 -20
  53. data/lib/solargraph/language_server/host/diagnoser.rb +89 -89
  54. data/lib/solargraph/language_server/host/dispatch.rb +130 -128
  55. data/lib/solargraph/language_server/host/message_worker.rb +112 -106
  56. data/lib/solargraph/language_server/host/sources.rb +99 -99
  57. data/lib/solargraph/language_server/host.rb +878 -861
  58. data/lib/solargraph/language_server/message/base.rb +97 -96
  59. data/lib/solargraph/language_server/message/client/register_capability.rb +15 -15
  60. data/lib/solargraph/language_server/message/completion_item/resolve.rb +60 -60
  61. data/lib/solargraph/language_server/message/extended/check_gem_version.rb +114 -112
  62. data/lib/solargraph/language_server/message/extended/document.rb +23 -20
  63. data/lib/solargraph/language_server/message/extended/document_gems.rb +32 -32
  64. data/lib/solargraph/language_server/message/extended/download_core.rb +19 -19
  65. data/lib/solargraph/language_server/message/extended/search.rb +20 -20
  66. data/lib/solargraph/language_server/message/initialize.rb +191 -191
  67. data/lib/solargraph/language_server/message/text_document/completion.rb +56 -56
  68. data/lib/solargraph/language_server/message/text_document/definition.rb +40 -38
  69. data/lib/solargraph/language_server/message/text_document/document_highlight.rb +16 -16
  70. data/lib/solargraph/language_server/message/text_document/document_symbol.rb +26 -26
  71. data/lib/solargraph/language_server/message/text_document/formatting.rb +148 -131
  72. data/lib/solargraph/language_server/message/text_document/hover.rb +58 -58
  73. data/lib/solargraph/language_server/message/text_document/prepare_rename.rb +11 -11
  74. data/lib/solargraph/language_server/message/text_document/references.rb +16 -16
  75. data/lib/solargraph/language_server/message/text_document/rename.rb +19 -19
  76. data/lib/solargraph/language_server/message/text_document/signature_help.rb +24 -24
  77. data/lib/solargraph/language_server/message/text_document/type_definition.rb +25 -24
  78. data/lib/solargraph/language_server/message/workspace/did_change_configuration.rb +35 -35
  79. data/lib/solargraph/language_server/message/workspace/did_change_watched_files.rb +40 -40
  80. data/lib/solargraph/language_server/message/workspace/did_change_workspace_folders.rb +26 -24
  81. data/lib/solargraph/language_server/message/workspace/workspace_symbol.rb +23 -23
  82. data/lib/solargraph/language_server/message.rb +94 -94
  83. data/lib/solargraph/language_server/progress.rb +8 -0
  84. data/lib/solargraph/language_server/request.rb +27 -24
  85. data/lib/solargraph/language_server/transport/data_reader.rb +74 -74
  86. data/lib/solargraph/language_server/uri_helpers.rb +49 -49
  87. data/lib/solargraph/library.rb +683 -662
  88. data/lib/solargraph/location.rb +82 -58
  89. data/lib/solargraph/logging.rb +37 -27
  90. data/lib/solargraph/page.rb +92 -89
  91. data/lib/solargraph/parser/comment_ripper.rb +69 -56
  92. data/lib/solargraph/parser/flow_sensitive_typing.rb +255 -0
  93. data/lib/solargraph/parser/node_processor/base.rb +92 -87
  94. data/lib/solargraph/parser/node_processor.rb +62 -45
  95. data/lib/solargraph/parser/parser_gem/class_methods.rb +149 -157
  96. data/lib/solargraph/parser/parser_gem/flawed_builder.rb +19 -18
  97. data/lib/solargraph/parser/parser_gem/node_chainer.rb +166 -164
  98. data/lib/solargraph/parser/parser_gem/node_methods.rb +486 -495
  99. data/lib/solargraph/parser/parser_gem/node_processors/alias_node.rb +2 -1
  100. data/lib/solargraph/parser/parser_gem/node_processors/and_node.rb +22 -0
  101. data/lib/solargraph/parser/parser_gem/node_processors/args_node.rb +59 -57
  102. data/lib/solargraph/parser/parser_gem/node_processors/begin_node.rb +15 -15
  103. data/lib/solargraph/parser/parser_gem/node_processors/block_node.rb +46 -43
  104. data/lib/solargraph/parser/parser_gem/node_processors/casgn_node.rb +2 -1
  105. data/lib/solargraph/parser/parser_gem/node_processors/cvasgn_node.rb +2 -1
  106. data/lib/solargraph/parser/parser_gem/node_processors/def_node.rb +53 -50
  107. data/lib/solargraph/parser/parser_gem/node_processors/defs_node.rb +37 -36
  108. data/lib/solargraph/parser/parser_gem/node_processors/gvasgn_node.rb +2 -1
  109. data/lib/solargraph/parser/parser_gem/node_processors/if_node.rb +23 -0
  110. data/lib/solargraph/parser/parser_gem/node_processors/ivasgn_node.rb +40 -38
  111. data/lib/solargraph/parser/parser_gem/node_processors/lvasgn_node.rb +29 -28
  112. data/lib/solargraph/parser/parser_gem/node_processors/masgn_node.rb +59 -53
  113. data/lib/solargraph/parser/parser_gem/node_processors/namespace_node.rb +8 -7
  114. data/lib/solargraph/parser/parser_gem/node_processors/opasgn_node.rb +98 -0
  115. data/lib/solargraph/parser/parser_gem/node_processors/orasgn_node.rb +17 -16
  116. data/lib/solargraph/parser/parser_gem/node_processors/resbody_node.rb +38 -36
  117. data/lib/solargraph/parser/parser_gem/node_processors/sclass_node.rb +52 -42
  118. data/lib/solargraph/parser/parser_gem/node_processors/send_node.rb +291 -259
  119. data/lib/solargraph/parser/parser_gem/node_processors/sym_node.rb +3 -1
  120. data/lib/solargraph/parser/parser_gem/node_processors/until_node.rb +29 -0
  121. data/lib/solargraph/parser/parser_gem/node_processors/while_node.rb +29 -0
  122. data/lib/solargraph/parser/parser_gem/node_processors.rb +70 -56
  123. data/lib/solargraph/parser/parser_gem.rb +12 -12
  124. data/lib/solargraph/parser/region.rb +69 -66
  125. data/lib/solargraph/parser/snippet.rb +17 -15
  126. data/lib/solargraph/parser.rb +23 -22
  127. data/lib/solargraph/pin/base.rb +729 -378
  128. data/lib/solargraph/pin/base_variable.rb +126 -118
  129. data/lib/solargraph/pin/block.rb +104 -101
  130. data/lib/solargraph/pin/breakable.rb +9 -0
  131. data/lib/solargraph/pin/callable.rb +231 -147
  132. data/lib/solargraph/pin/closure.rb +72 -57
  133. data/lib/solargraph/pin/common.rb +79 -70
  134. data/lib/solargraph/pin/constant.rb +45 -43
  135. data/lib/solargraph/pin/conversions.rb +123 -123
  136. data/lib/solargraph/pin/delegated_method.rb +120 -101
  137. data/lib/solargraph/pin/documenting.rb +114 -98
  138. data/lib/solargraph/pin/instance_variable.rb +34 -34
  139. data/lib/solargraph/pin/keyword.rb +20 -15
  140. data/lib/solargraph/pin/local_variable.rb +75 -67
  141. data/lib/solargraph/pin/method.rb +672 -527
  142. data/lib/solargraph/pin/method_alias.rb +34 -31
  143. data/lib/solargraph/pin/namespace.rb +115 -107
  144. data/lib/solargraph/pin/parameter.rb +275 -212
  145. data/lib/solargraph/pin/proxy_type.rb +39 -29
  146. data/lib/solargraph/pin/reference/override.rb +47 -29
  147. data/lib/solargraph/pin/reference/require.rb +2 -2
  148. data/lib/solargraph/pin/reference/superclass.rb +15 -10
  149. data/lib/solargraph/pin/reference.rb +39 -22
  150. data/lib/solargraph/pin/search.rb +61 -56
  151. data/lib/solargraph/pin/signature.rb +61 -17
  152. data/lib/solargraph/pin/singleton.rb +1 -1
  153. data/lib/solargraph/pin/symbol.rb +53 -47
  154. data/lib/solargraph/pin/until.rb +18 -0
  155. data/lib/solargraph/pin/while.rb +18 -0
  156. data/lib/solargraph/pin.rb +44 -41
  157. data/lib/solargraph/pin_cache.rb +245 -0
  158. data/lib/solargraph/position.rb +132 -107
  159. data/lib/solargraph/range.rb +112 -98
  160. data/lib/solargraph/rbs_map/conversions.rb +823 -646
  161. data/lib/solargraph/rbs_map/core_fills.rb +84 -50
  162. data/lib/solargraph/rbs_map/core_map.rb +58 -28
  163. data/lib/solargraph/rbs_map/stdlib_map.rb +43 -33
  164. data/lib/solargraph/rbs_map.rb +163 -93
  165. data/lib/solargraph/server_methods.rb +16 -16
  166. data/lib/solargraph/shell.rb +363 -269
  167. data/lib/solargraph/source/chain/array.rb +37 -33
  168. data/lib/solargraph/source/chain/block_symbol.rb +1 -1
  169. data/lib/solargraph/source/chain/block_variable.rb +1 -1
  170. data/lib/solargraph/source/chain/call.rb +337 -303
  171. data/lib/solargraph/source/chain/class_variable.rb +13 -13
  172. data/lib/solargraph/source/chain/constant.rb +26 -89
  173. data/lib/solargraph/source/chain/global_variable.rb +13 -13
  174. data/lib/solargraph/source/chain/hash.rb +34 -33
  175. data/lib/solargraph/source/chain/head.rb +1 -1
  176. data/lib/solargraph/source/chain/if.rb +28 -28
  177. data/lib/solargraph/source/chain/instance_variable.rb +13 -13
  178. data/lib/solargraph/source/chain/link.rb +109 -98
  179. data/lib/solargraph/source/chain/literal.rb +48 -28
  180. data/lib/solargraph/source/chain/or.rb +23 -23
  181. data/lib/solargraph/source/chain/q_call.rb +11 -11
  182. data/lib/solargraph/source/chain/variable.rb +13 -13
  183. data/lib/solargraph/source/chain/z_super.rb +30 -30
  184. data/lib/solargraph/source/chain.rb +291 -252
  185. data/lib/solargraph/source/change.rb +82 -82
  186. data/lib/solargraph/source/cursor.rb +166 -167
  187. data/lib/solargraph/source/encoding_fixes.rb +23 -23
  188. data/lib/solargraph/source/source_chainer.rb +194 -194
  189. data/lib/solargraph/source/updater.rb +55 -55
  190. data/lib/solargraph/source.rb +498 -495
  191. data/lib/solargraph/source_map/clip.rb +226 -232
  192. data/lib/solargraph/source_map/data.rb +34 -30
  193. data/lib/solargraph/source_map/mapper.rb +259 -255
  194. data/lib/solargraph/source_map.rb +212 -217
  195. data/lib/solargraph/type_checker/checks.rb +124 -120
  196. data/lib/solargraph/type_checker/param_def.rb +37 -35
  197. data/lib/solargraph/type_checker/problem.rb +32 -32
  198. data/lib/solargraph/type_checker/rules.rb +84 -62
  199. data/lib/solargraph/type_checker.rb +814 -672
  200. data/lib/solargraph/version.rb +5 -5
  201. data/lib/solargraph/views/_method.erb +10 -10
  202. data/lib/solargraph/views/_namespace.erb +3 -3
  203. data/lib/solargraph/views/document.erb +10 -10
  204. data/lib/solargraph/workspace/config.rb +255 -239
  205. data/lib/solargraph/workspace/require_paths.rb +97 -0
  206. data/lib/solargraph/workspace.rb +220 -239
  207. data/lib/solargraph/yard_map/helpers.rb +44 -16
  208. data/lib/solargraph/yard_map/mapper/to_constant.rb +7 -5
  209. data/lib/solargraph/yard_map/mapper/to_method.rb +130 -94
  210. data/lib/solargraph/yard_map/mapper/to_namespace.rb +31 -28
  211. data/lib/solargraph/yard_map/mapper.rb +79 -78
  212. data/lib/solargraph/yard_map/to_method.rb +89 -86
  213. data/lib/solargraph/yard_tags.rb +20 -20
  214. data/lib/solargraph/yardoc.rb +87 -52
  215. data/lib/solargraph.rb +105 -72
  216. data/rbs/fills/bundler/0/bundler.rbs +4271 -0
  217. data/rbs/fills/open3/0/open3.rbs +172 -0
  218. data/rbs/fills/rubygems/0/basic_specification.rbs +326 -0
  219. data/rbs/fills/rubygems/0/errors.rbs +364 -0
  220. data/rbs/fills/rubygems/0/spec_fetcher.rbs +107 -0
  221. data/rbs/fills/rubygems/0/specification.rbs +1753 -0
  222. data/rbs/fills/tuple/tuple.rbs +149 -0
  223. data/rbs/shims/ast/0/node.rbs +5 -0
  224. data/rbs/shims/ast/2.4/.rbs_meta.yaml +9 -0
  225. data/rbs/shims/ast/2.4/ast.rbs +73 -0
  226. data/rbs/shims/parser/3.2.0.1/builders/default.rbs +195 -0
  227. data/rbs/shims/parser/3.2.0.1/manifest.yaml +7 -0
  228. data/rbs/shims/parser/3.2.0.1/parser.rbs +201 -0
  229. data/rbs/shims/parser/3.2.0.1/polyfill.rbs +4 -0
  230. data/rbs/shims/thor/1.2.0.1/.rbs_meta.yaml +9 -0
  231. data/rbs/shims/thor/1.2.0.1/manifest.yaml +7 -0
  232. data/rbs/shims/thor/1.2.0.1/thor.rbs +17 -0
  233. data/rbs_collection.yaml +19 -0
  234. data/solargraph.gemspec +27 -5
  235. metadata +215 -18
  236. data/lib/.rubocop.yml +0 -22
  237. data/lib/solargraph/cache.rb +0 -77
  238. data/lib/solargraph/parser/node_methods.rb +0 -83
@@ -1,255 +1,259 @@
1
- # frozen_string_literal: true
2
-
3
- module Solargraph
4
- class SourceMap
5
- # The Mapper generates pins and other data for SourceMaps.
6
- #
7
- # This class is used internally by the SourceMap class. Users should not
8
- # normally need to call it directly.
9
- #
10
- class Mapper
11
- # include Source::NodeMethods
12
-
13
- private_class_method :new
14
-
15
- DIRECTIVE_REGEXP = /(@\!method|@\!attribute|@\!visibility|@\!domain|@\!macro|@\!parse|@\!override)/.freeze
16
-
17
- # Generate the data.
18
- #
19
- # @param source [Source]
20
- # @return [Array]
21
- def map source
22
- @source = source
23
- @filename = source.filename
24
- @code = source.code
25
- @comments = source.comments
26
- @pins, @locals = Parser.map(source)
27
- @pins.each { |p| p.source = :code }
28
- @locals.each { |l| l.source = :code }
29
- process_comment_directives
30
- [@pins, @locals]
31
- # rescue Exception => e
32
- # Solargraph.logger.warn "Error mapping #{source.filename}: [#{e.class}] #{e.message}"
33
- # Solargraph.logger.warn e.backtrace.join("\n")
34
- # [[], []]
35
- end
36
-
37
- # @param filename [String]
38
- # @param code [String]
39
- # @return [Array]
40
- def unmap filename, code
41
- s = Position.new(0, 0)
42
- e = Position.from_offset(code, code.length)
43
- location = Location.new(filename, Range.new(s, e))
44
- [[Pin::Namespace.new(location: location, name: '')], []]
45
- end
46
-
47
- class << self
48
- # @param source [Source]
49
- # @return [Array]
50
- def map source
51
- return new.unmap(source.filename, source.code) unless source.parsed?
52
- new.map source
53
- end
54
- end
55
-
56
- # @return [Array<Solargraph::Pin::Base>]
57
- def pins
58
- @pins ||= []
59
- end
60
-
61
- # @param position [Solargraph::Position]
62
- # @return [Solargraph::Pin::Closure]
63
- def closure_at(position)
64
- pins.select{|pin| pin.is_a?(Pin::Closure) and pin.location.range.contain?(position)}.last
65
- end
66
-
67
- # @param source_position [Position]
68
- # @param comment_position [Position]
69
- # @param comment [String]
70
- # @return [void]
71
- def process_comment source_position, comment_position, comment
72
- return unless comment.encode('UTF-8', invalid: :replace, replace: '?') =~ DIRECTIVE_REGEXP
73
- cmnt = remove_inline_comment_hashes(comment)
74
- parse = Solargraph::Source.parse_docstring(cmnt)
75
- last_line = 0
76
- # @param d [YARD::Tags::Directive]
77
- parse.directives.each do |d|
78
- line_num = find_directive_line_number(cmnt, d.tag.tag_name, last_line)
79
- pos = Solargraph::Position.new(comment_position.line + line_num - 1, comment_position.column)
80
- process_directive(source_position, pos, d)
81
- last_line = line_num + 1
82
- end
83
- end
84
-
85
- # @param comment [String]
86
- # @param tag [String]
87
- # @param start [Integer]
88
- # @return [Integer]
89
- def find_directive_line_number comment, tag, start
90
- # Avoid overruning the index
91
- return start unless start < comment.lines.length
92
- num = comment.lines[start..-1].find_index do |line|
93
- # Legacy method directives might be `@method` instead of `@!method`
94
- # @todo Legacy syntax should probably emit a warning
95
- line.include?("@!#{tag}") || (tag == 'method' && line.include?("@#{tag}"))
96
- end
97
- num.to_i + start
98
- end
99
-
100
- # @param source_position [Position]
101
- # @param comment_position [Position]
102
- # @param directive [YARD::Tags::Directive]
103
- # @return [void]
104
- def process_directive source_position, comment_position, directive
105
- docstring = Solargraph::Source.parse_docstring(directive.tag.text).to_docstring
106
- location = Location.new(@filename, Range.new(comment_position, comment_position))
107
- case directive.tag.tag_name
108
- when 'method'
109
- namespace = closure_at(source_position) || @pins.first
110
- if namespace.location.range.start.line < comment_position.line
111
- namespace = closure_at(comment_position)
112
- end
113
- begin
114
- src = Solargraph::Source.load_string("def #{directive.tag.name};end", @source.filename)
115
- region = Parser::Region.new(source: src, closure: namespace)
116
- method_gen_pins = Parser.process_node(src.node, region).first.select { |pin| pin.is_a?(Pin::Method) }
117
- gen_pin = method_gen_pins.last
118
- return if gen_pin.nil?
119
- # Move the location to the end of the line so it gets recognized
120
- # as originating from a comment
121
- shifted = Solargraph::Position.new(comment_position.line, @code.lines[comment_position.line].to_s.chomp.length)
122
- # @todo: Smelly instance variable access
123
- gen_pin.instance_variable_set(:@comments, docstring.all.to_s)
124
- gen_pin.instance_variable_set(:@location, Solargraph::Location.new(@filename, Range.new(shifted, shifted)))
125
- gen_pin.instance_variable_set(:@explicit, false)
126
- @pins.push gen_pin
127
- rescue Parser::SyntaxError => e
128
- # @todo Handle error in directive
129
- end
130
- when 'attribute'
131
- return if directive.tag.name.nil?
132
- namespace = closure_at(source_position)
133
- t = (directive.tag.types.nil? || directive.tag.types.empty?) ? nil : directive.tag.types.flatten.join('')
134
- if t.nil? || t.include?('r')
135
- pins.push Solargraph::Pin::Method.new(
136
- location: location,
137
- closure: namespace,
138
- name: directive.tag.name,
139
- comments: docstring.all.to_s,
140
- scope: namespace.is_a?(Pin::Singleton) ? :class : :instance,
141
- visibility: :public,
142
- explicit: false,
143
- attribute: true
144
- )
145
- end
146
- if t.nil? || t.include?('w')
147
- method_pin = Solargraph::Pin::Method.new(
148
- location: location,
149
- closure: namespace,
150
- name: "#{directive.tag.name}=",
151
- comments: docstring.all.to_s,
152
- scope: namespace.is_a?(Pin::Singleton) ? :class : :instance,
153
- visibility: :public,
154
- attribute: true
155
- )
156
- pins.push method_pin
157
- method_pin.parameters.push Pin::Parameter.new(name: 'value', decl: :arg, closure: pins.last)
158
- if pins.last.return_type.defined?
159
- pins.last.docstring.add_tag YARD::Tags::Tag.new(:param, '', pins.last.return_type.to_s.split(', '), 'value')
160
- end
161
- end
162
- when 'visibility'
163
- begin
164
- kind = directive.tag.text&.to_sym
165
- return unless [:private, :protected, :public].include?(kind)
166
-
167
- name = directive.tag.name
168
- closure = closure_at(source_position) || @pins.first
169
- if closure.location.range.start.line < comment_position.line
170
- closure = closure_at(comment_position)
171
- end
172
- if closure.is_a?(Pin::Method) && no_empty_lines?(comment_position.line, source_position.line)
173
- # @todo Smelly instance variable access
174
- closure.instance_variable_set(:@visibility, kind)
175
- else
176
- matches = pins.select{ |pin| pin.is_a?(Pin::Method) && pin.name == name && pin.namespace == namespace && pin.context.scope == namespace.is_a?(Pin::Singleton) ? :class : :instance }
177
- matches.each do |pin|
178
- # @todo Smelly instance variable access
179
- pin.instance_variable_set(:@visibility, kind)
180
- end
181
- end
182
- end
183
- when 'parse'
184
- begin
185
- ns = closure_at(source_position)
186
- src = Solargraph::Source.load_string(directive.tag.text, @source.filename)
187
- region = Parser::Region.new(source: src, closure: ns)
188
- # @todo These pins may need to be marked not explicit
189
- index = @pins.length
190
- loff = if @code.lines[comment_position.line].strip.end_with?('@!parse')
191
- comment_position.line + 1
192
- else
193
- comment_position.line
194
- end
195
- Parser.process_node(src.node, region, @pins)
196
- @pins[index..-1].each do |p|
197
- # @todo Smelly instance variable access
198
- p.location.range.start.instance_variable_set(:@line, p.location.range.start.line + loff)
199
- p.location.range.ending.instance_variable_set(:@line, p.location.range.ending.line + loff)
200
- end
201
- rescue Parser::SyntaxError => e
202
- # @todo Handle parser errors in !parse directives
203
- end
204
- when 'domain'
205
- namespace = closure_at(source_position) || Pin::ROOT_PIN
206
- namespace.domains.concat directive.tag.types unless directive.tag.types.nil?
207
- when 'override'
208
- pins.push Pin::Reference::Override.new(location, directive.tag.name, docstring.tags)
209
- when 'macro'
210
- # @todo Handle macros
211
- end
212
- end
213
-
214
- # @param line1 [Integer]
215
- # @param line2 [Integer]
216
- def no_empty_lines?(line1, line2)
217
- @code.lines[line1..line2].none? { |line| line.strip.empty? }
218
- end
219
-
220
- # @param comment [String]
221
- # @return [String]
222
- def remove_inline_comment_hashes comment
223
- ctxt = ''
224
- num = nil
225
- started = false
226
- comment.lines.each { |l|
227
- # Trim the comment and minimum leading whitespace
228
- p = l.encode('UTF-8', invalid: :replace, replace: '?').gsub(/^#+/, '')
229
- if num.nil? && !p.strip.empty?
230
- num = p.index(/[^ ]/)
231
- started = true
232
- elsif started && !p.strip.empty?
233
- cur = p.index(/[^ ]/)
234
- num = cur if cur < num
235
- end
236
- ctxt += "#{p[num..-1]}" if started
237
- }
238
- ctxt
239
- end
240
-
241
- # @return [void]
242
- def process_comment_directives
243
- return unless @code.encode('UTF-8', invalid: :replace, replace: '?') =~ DIRECTIVE_REGEXP
244
- code_lines = @code.lines
245
- @source.associated_comments.each do |line, comments|
246
- src_pos = line ? Position.new(line, code_lines[line].to_s.chomp.index(/[^\s]/) || 0) : Position.new(code_lines.length, 0)
247
- com_pos = Position.new(line + 1 - comments.lines.length, 0)
248
- process_comment(src_pos, com_pos, comments)
249
- end
250
- rescue StandardError => e
251
- raise e.class, "Error processing comment directives in #{@filename}: #{e.message}"
252
- end
253
- end
254
- end
255
- end
1
+ # frozen_string_literal: true
2
+
3
+ module Solargraph
4
+ class SourceMap
5
+ # The Mapper generates pins and other data for SourceMaps.
6
+ #
7
+ # This class is used internally by the SourceMap class. Users should not
8
+ # normally need to call it directly.
9
+ #
10
+ class Mapper
11
+ # include Source::NodeMethods
12
+
13
+ private_class_method :new
14
+
15
+ DIRECTIVE_REGEXP = /(@\!method|@\!attribute|@\!visibility|@\!domain|@\!macro|@\!parse|@\!override)/.freeze
16
+
17
+ # Generate the data.
18
+ #
19
+ # @param source [Source]
20
+ # @return [Array]
21
+ def map source
22
+ @source = source
23
+ @filename = source.filename
24
+ @code = source.code
25
+ @comments = source.comments
26
+ @pins, @locals = Parser.map(source)
27
+ @pins.each { |p| p.source = :code }
28
+ @locals.each { |l| l.source = :code }
29
+ process_comment_directives
30
+ [@pins, @locals]
31
+ # rescue Exception => e
32
+ # Solargraph.logger.warn "Error mapping #{source.filename}: [#{e.class}] #{e.message}"
33
+ # Solargraph.logger.warn e.backtrace.join("\n")
34
+ # [[], []]
35
+ end
36
+
37
+ # @param filename [String]
38
+ # @param code [String]
39
+ # @return [Array]
40
+ def unmap filename, code
41
+ s = Position.new(0, 0)
42
+ e = Position.from_offset(code, code.length)
43
+ location = Location.new(filename, Range.new(s, e))
44
+ [[Pin::Namespace.new(location: location, name: '', source: :source_map)], []]
45
+ end
46
+
47
+ class << self
48
+ # @param source [Source]
49
+ # @return [Array]
50
+ def map source
51
+ return new.unmap(source.filename, source.code) unless source.parsed?
52
+ new.map source
53
+ end
54
+ end
55
+
56
+ # @return [Array<Solargraph::Pin::Base>]
57
+ def pins
58
+ # @type [Array<Solargraph::Pin::Base>]
59
+ @pins ||= []
60
+ end
61
+
62
+ # @param position [Solargraph::Position]
63
+ # @return [Solargraph::Pin::Closure]
64
+ def closure_at(position)
65
+ pins.select{|pin| pin.is_a?(Pin::Closure) and pin.location.range.contain?(position)}.last
66
+ end
67
+
68
+ # @param source_position [Position]
69
+ # @param comment_position [Position]
70
+ # @param comment [String]
71
+ # @return [void]
72
+ def process_comment source_position, comment_position, comment
73
+ return unless comment.encode('UTF-8', invalid: :replace, replace: '?') =~ DIRECTIVE_REGEXP
74
+ cmnt = remove_inline_comment_hashes(comment)
75
+ parse = Solargraph::Source.parse_docstring(cmnt)
76
+ last_line = 0
77
+ # @param d [YARD::Tags::Directive]
78
+ parse.directives.each do |d|
79
+ line_num = find_directive_line_number(cmnt, d.tag.tag_name, last_line)
80
+ pos = Solargraph::Position.new(comment_position.line + line_num - 1, comment_position.column)
81
+ process_directive(source_position, pos, d)
82
+ last_line = line_num + 1
83
+ end
84
+ end
85
+
86
+ # @param comment [String]
87
+ # @param tag [String]
88
+ # @param start [Integer]
89
+ # @return [Integer]
90
+ def find_directive_line_number comment, tag, start
91
+ # Avoid overruning the index
92
+ return start unless start < comment.lines.length
93
+ num = comment.lines[start..-1].find_index do |line|
94
+ # Legacy method directives might be `@method` instead of `@!method`
95
+ # @todo Legacy syntax should probably emit a warning
96
+ line.include?("@!#{tag}") || (tag == 'method' && line.include?("@#{tag}"))
97
+ end
98
+ num.to_i + start
99
+ end
100
+
101
+ # @param source_position [Position]
102
+ # @param comment_position [Position]
103
+ # @param directive [YARD::Tags::Directive]
104
+ # @return [void]
105
+ def process_directive source_position, comment_position, directive
106
+ docstring = Solargraph::Source.parse_docstring(directive.tag.text).to_docstring
107
+ location = Location.new(@filename, Range.new(comment_position, comment_position))
108
+ case directive.tag.tag_name
109
+ when 'method'
110
+ namespace = closure_at(source_position) || @pins.first
111
+ if namespace.location.range.start.line < comment_position.line
112
+ namespace = closure_at(comment_position)
113
+ end
114
+ begin
115
+ src = Solargraph::Source.load_string("def #{directive.tag.name};end", @source.filename)
116
+ region = Parser::Region.new(source: src, closure: namespace)
117
+ method_gen_pins = Parser.process_node(src.node, region).first.select { |pin| pin.is_a?(Pin::Method) }
118
+ gen_pin = method_gen_pins.last
119
+ return if gen_pin.nil?
120
+ # Move the location to the end of the line so it gets recognized
121
+ # as originating from a comment
122
+ shifted = Solargraph::Position.new(comment_position.line, @code.lines[comment_position.line].to_s.chomp.length)
123
+ # @todo: Smelly instance variable access
124
+ gen_pin.instance_variable_set(:@comments, docstring.all.to_s)
125
+ gen_pin.instance_variable_set(:@location, Solargraph::Location.new(@filename, Range.new(shifted, shifted)))
126
+ gen_pin.instance_variable_set(:@explicit, false)
127
+ @pins.push gen_pin
128
+ rescue Parser::SyntaxError => e
129
+ # @todo Handle error in directive
130
+ end
131
+ when 'attribute'
132
+ return if directive.tag.name.nil?
133
+ namespace = closure_at(source_position)
134
+ t = (directive.tag.types.nil? || directive.tag.types.empty?) ? nil : directive.tag.types.flatten.join('')
135
+ if t.nil? || t.include?('r')
136
+ pins.push Solargraph::Pin::Method.new(
137
+ location: location,
138
+ closure: namespace,
139
+ name: directive.tag.name,
140
+ comments: docstring.all.to_s,
141
+ scope: namespace.is_a?(Pin::Singleton) ? :class : :instance,
142
+ visibility: :public,
143
+ explicit: false,
144
+ attribute: true,
145
+ source: :source_map
146
+ )
147
+ end
148
+ if t.nil? || t.include?('w')
149
+ method_pin = Solargraph::Pin::Method.new(
150
+ location: location,
151
+ closure: namespace,
152
+ name: "#{directive.tag.name}=",
153
+ comments: docstring.all.to_s,
154
+ scope: namespace.is_a?(Pin::Singleton) ? :class : :instance,
155
+ visibility: :public,
156
+ attribute: true,
157
+ source: :source_map
158
+ )
159
+ pins.push method_pin
160
+ method_pin.parameters.push Pin::Parameter.new(name: 'value', decl: :arg, closure: pins.last, source: :source_map)
161
+ if pins.last.return_type.defined?
162
+ pins.last.docstring.add_tag YARD::Tags::Tag.new(:param, '', pins.last.return_type.to_s.split(', '), 'value')
163
+ end
164
+ end
165
+ when 'visibility'
166
+
167
+ kind = directive.tag.text&.to_sym
168
+ return unless [:private, :protected, :public].include?(kind)
169
+
170
+ name = directive.tag.name
171
+ closure = closure_at(source_position) || @pins.first
172
+ if closure.location.range.start.line < comment_position.line
173
+ closure = closure_at(comment_position)
174
+ end
175
+ if closure.is_a?(Pin::Method) && no_empty_lines?(comment_position.line, source_position.line)
176
+ # @todo Smelly instance variable access
177
+ closure.instance_variable_set(:@visibility, kind)
178
+ else
179
+ matches = pins.select{ |pin| pin.is_a?(Pin::Method) && pin.name == name && pin.namespace == namespace && pin.context.scope == namespace.is_a?(Pin::Singleton) ? :class : :instance }
180
+ matches.each do |pin|
181
+ # @todo Smelly instance variable access
182
+ pin.instance_variable_set(:@visibility, kind)
183
+ end
184
+ end
185
+
186
+ when 'parse'
187
+ begin
188
+ ns = closure_at(source_position)
189
+ src = Solargraph::Source.load_string(directive.tag.text, @source.filename)
190
+ region = Parser::Region.new(source: src, closure: ns)
191
+ # @todo These pins may need to be marked not explicit
192
+ index = @pins.length
193
+ loff = if @code.lines[comment_position.line].strip.end_with?('@!parse')
194
+ comment_position.line + 1
195
+ else
196
+ comment_position.line
197
+ end
198
+ Parser.process_node(src.node, region, @pins)
199
+ @pins[index..-1].each do |p|
200
+ # @todo Smelly instance variable access
201
+ p.location.range.start.instance_variable_set(:@line, p.location.range.start.line + loff)
202
+ p.location.range.ending.instance_variable_set(:@line, p.location.range.ending.line + loff)
203
+ end
204
+ rescue Parser::SyntaxError => e
205
+ # @todo Handle parser errors in !parse directives
206
+ end
207
+ when 'domain'
208
+ namespace = closure_at(source_position) || Pin::ROOT_PIN
209
+ namespace.domains.concat directive.tag.types unless directive.tag.types.nil?
210
+ when 'override'
211
+ pins.push Pin::Reference::Override.new(location, directive.tag.name, docstring.tags,
212
+ source: :source_map)
213
+ when 'macro'
214
+ # @todo Handle macros
215
+ end
216
+ end
217
+
218
+ # @param line1 [Integer]
219
+ # @param line2 [Integer]
220
+ def no_empty_lines?(line1, line2)
221
+ @code.lines[line1..line2].none? { |line| line.strip.empty? }
222
+ end
223
+
224
+ # @param comment [String]
225
+ # @return [String]
226
+ def remove_inline_comment_hashes comment
227
+ ctxt = ''
228
+ num = nil
229
+ started = false
230
+ comment.lines.each { |l|
231
+ # Trim the comment and minimum leading whitespace
232
+ p = l.encode('UTF-8', invalid: :replace, replace: '?').gsub(/^#+/, '')
233
+ if num.nil? && !p.strip.empty?
234
+ num = p.index(/[^ ]/)
235
+ started = true
236
+ elsif started && !p.strip.empty?
237
+ cur = p.index(/[^ ]/)
238
+ num = cur if cur < num
239
+ end
240
+ ctxt += "#{p[num..-1]}" if started
241
+ }
242
+ ctxt
243
+ end
244
+
245
+ # @return [void]
246
+ def process_comment_directives
247
+ return unless @code.encode('UTF-8', invalid: :replace, replace: '?') =~ DIRECTIVE_REGEXP
248
+ code_lines = @code.lines
249
+ @source.associated_comments.each do |line, comments|
250
+ src_pos = line ? Position.new(line, code_lines[line].to_s.chomp.index(/[^\s]/) || 0) : Position.new(code_lines.length, 0)
251
+ com_pos = Position.new(line + 1 - comments.lines.length, 0)
252
+ process_comment(src_pos, com_pos, comments)
253
+ end
254
+ rescue StandardError => e
255
+ raise e.class, "Error processing comment directives in #{@filename}: #{e.message}"
256
+ end
257
+ end
258
+ end
259
+ end