solargraph 0.54.0 → 0.58.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 (200) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/linting.yml +127 -0
  3. data/.github/workflows/plugins.yml +184 -6
  4. data/.github/workflows/rspec.yml +55 -5
  5. data/.github/workflows/typecheck.yml +8 -3
  6. data/.gitignore +7 -0
  7. data/.overcommit.yml +72 -0
  8. data/.rspec +1 -0
  9. data/.rubocop.yml +66 -0
  10. data/.rubocop_todo.yml +1279 -0
  11. data/.yardopts +1 -0
  12. data/CHANGELOG.md +171 -0
  13. data/README.md +20 -6
  14. data/Rakefile +125 -13
  15. data/bin/solargraph +8 -5
  16. data/lib/solargraph/api_map/cache.rb +13 -3
  17. data/lib/solargraph/api_map/constants.rb +279 -0
  18. data/lib/solargraph/api_map/index.rb +193 -0
  19. data/lib/solargraph/api_map/source_to_yard.rb +13 -4
  20. data/lib/solargraph/api_map/store.rb +207 -132
  21. data/lib/solargraph/api_map.rb +394 -261
  22. data/lib/solargraph/bench.rb +18 -1
  23. data/lib/solargraph/complex_type/type_methods.rb +29 -12
  24. data/lib/solargraph/complex_type/unique_type.rb +205 -26
  25. data/lib/solargraph/complex_type.rb +126 -26
  26. data/lib/solargraph/convention/active_support_concern.rb +111 -0
  27. data/lib/solargraph/convention/base.rb +20 -3
  28. data/lib/solargraph/convention/data_definition/data_assignment_node.rb +61 -0
  29. data/lib/solargraph/convention/data_definition/data_definition_node.rb +91 -0
  30. data/lib/solargraph/convention/data_definition.rb +105 -0
  31. data/lib/solargraph/convention/gemspec.rb +3 -2
  32. data/lib/solargraph/convention/struct_definition/struct_assignment_node.rb +61 -0
  33. data/lib/solargraph/convention/struct_definition/struct_definition_node.rb +102 -0
  34. data/lib/solargraph/convention/struct_definition.rb +164 -0
  35. data/lib/solargraph/convention.rb +36 -4
  36. data/lib/solargraph/diagnostics/rubocop.rb +6 -1
  37. data/lib/solargraph/diagnostics/rubocop_helpers.rb +5 -3
  38. data/lib/solargraph/doc_map.rb +316 -64
  39. data/lib/solargraph/environ.rb +9 -2
  40. data/lib/solargraph/equality.rb +34 -0
  41. data/lib/solargraph/gem_pins.rb +64 -38
  42. data/lib/solargraph/language_server/host/dispatch.rb +2 -0
  43. data/lib/solargraph/language_server/host/message_worker.rb +54 -5
  44. data/lib/solargraph/language_server/host.rb +36 -18
  45. data/lib/solargraph/language_server/message/base.rb +20 -12
  46. data/lib/solargraph/language_server/message/extended/check_gem_version.rb +2 -0
  47. data/lib/solargraph/language_server/message/extended/document.rb +5 -2
  48. data/lib/solargraph/language_server/message/extended/document_gems.rb +3 -3
  49. data/lib/solargraph/language_server/message/initialize.rb +3 -1
  50. data/lib/solargraph/language_server/message/text_document/completion.rb +0 -3
  51. data/lib/solargraph/language_server/message/text_document/definition.rb +5 -3
  52. data/lib/solargraph/language_server/message/text_document/document_symbol.rb +3 -3
  53. data/lib/solargraph/language_server/message/text_document/formatting.rb +23 -2
  54. data/lib/solargraph/language_server/message/text_document/hover.rb +1 -1
  55. data/lib/solargraph/language_server/message/text_document/type_definition.rb +4 -3
  56. data/lib/solargraph/language_server/message/workspace/did_change_workspace_folders.rb +2 -0
  57. data/lib/solargraph/language_server/message/workspace/workspace_symbol.rb +2 -2
  58. data/lib/solargraph/language_server/progress.rb +27 -2
  59. data/lib/solargraph/language_server/request.rb +4 -1
  60. data/lib/solargraph/library.rb +83 -73
  61. data/lib/solargraph/location.rb +45 -1
  62. data/lib/solargraph/logging.rb +12 -2
  63. data/lib/solargraph/page.rb +3 -0
  64. data/lib/solargraph/parser/comment_ripper.rb +20 -7
  65. data/lib/solargraph/parser/flow_sensitive_typing.rb +255 -0
  66. data/lib/solargraph/parser/node_processor/base.rb +10 -5
  67. data/lib/solargraph/parser/node_processor.rb +26 -8
  68. data/lib/solargraph/parser/parser_gem/class_methods.rb +10 -18
  69. data/lib/solargraph/parser/parser_gem/flawed_builder.rb +1 -0
  70. data/lib/solargraph/parser/parser_gem/node_chainer.rb +13 -11
  71. data/lib/solargraph/parser/parser_gem/node_methods.rb +10 -19
  72. data/lib/solargraph/parser/parser_gem/node_processors/alias_node.rb +2 -1
  73. data/lib/solargraph/parser/parser_gem/node_processors/and_node.rb +22 -0
  74. data/lib/solargraph/parser/parser_gem/node_processors/args_node.rb +26 -20
  75. data/lib/solargraph/parser/parser_gem/node_processors/block_node.rb +7 -4
  76. data/lib/solargraph/parser/parser_gem/node_processors/casgn_node.rb +2 -1
  77. data/lib/solargraph/parser/parser_gem/node_processors/cvasgn_node.rb +2 -1
  78. data/lib/solargraph/parser/parser_gem/node_processors/def_node.rb +6 -3
  79. data/lib/solargraph/parser/parser_gem/node_processors/defs_node.rb +2 -1
  80. data/lib/solargraph/parser/parser_gem/node_processors/gvasgn_node.rb +2 -1
  81. data/lib/solargraph/parser/parser_gem/node_processors/if_node.rb +23 -0
  82. data/lib/solargraph/parser/parser_gem/node_processors/ivasgn_node.rb +4 -2
  83. data/lib/solargraph/parser/parser_gem/node_processors/lvasgn_node.rb +2 -1
  84. data/lib/solargraph/parser/parser_gem/node_processors/masgn_node.rb +14 -2
  85. data/lib/solargraph/parser/parser_gem/node_processors/namespace_node.rb +8 -7
  86. data/lib/solargraph/parser/parser_gem/node_processors/opasgn_node.rb +98 -0
  87. data/lib/solargraph/parser/parser_gem/node_processors/orasgn_node.rb +1 -0
  88. data/lib/solargraph/parser/parser_gem/node_processors/resbody_node.rb +3 -1
  89. data/lib/solargraph/parser/parser_gem/node_processors/sclass_node.rb +16 -6
  90. data/lib/solargraph/parser/parser_gem/node_processors/send_node.rb +64 -32
  91. data/lib/solargraph/parser/parser_gem/node_processors/sym_node.rb +3 -1
  92. data/lib/solargraph/parser/parser_gem/node_processors/until_node.rb +29 -0
  93. data/lib/solargraph/parser/parser_gem/node_processors/while_node.rb +29 -0
  94. data/lib/solargraph/parser/parser_gem/node_processors.rb +14 -0
  95. data/lib/solargraph/parser/region.rb +4 -1
  96. data/lib/solargraph/parser/snippet.rb +2 -0
  97. data/lib/solargraph/parser.rb +3 -5
  98. data/lib/solargraph/pin/base.rb +417 -42
  99. data/lib/solargraph/pin/base_variable.rb +21 -12
  100. data/lib/solargraph/pin/block.rb +9 -26
  101. data/lib/solargraph/pin/breakable.rb +9 -0
  102. data/lib/solargraph/pin/callable.rb +231 -0
  103. data/lib/solargraph/pin/closure.rb +30 -10
  104. data/lib/solargraph/pin/common.rb +12 -7
  105. data/lib/solargraph/pin/constant.rb +2 -0
  106. data/lib/solargraph/pin/conversions.rb +3 -2
  107. data/lib/solargraph/pin/delegated_method.rb +20 -1
  108. data/lib/solargraph/pin/documenting.rb +16 -0
  109. data/lib/solargraph/pin/instance_variable.rb +2 -2
  110. data/lib/solargraph/pin/keyword.rb +7 -2
  111. data/lib/solargraph/pin/local_variable.rb +15 -7
  112. data/lib/solargraph/pin/method.rb +241 -70
  113. data/lib/solargraph/pin/method_alias.rb +3 -0
  114. data/lib/solargraph/pin/namespace.rb +21 -13
  115. data/lib/solargraph/pin/parameter.rb +94 -32
  116. data/lib/solargraph/pin/proxy_type.rb +17 -7
  117. data/lib/solargraph/pin/reference/override.rb +24 -6
  118. data/lib/solargraph/pin/reference/require.rb +2 -2
  119. data/lib/solargraph/pin/reference/superclass.rb +5 -0
  120. data/lib/solargraph/pin/reference.rb +17 -0
  121. data/lib/solargraph/pin/search.rb +6 -1
  122. data/lib/solargraph/pin/signature.rb +39 -121
  123. data/lib/solargraph/pin/singleton.rb +1 -1
  124. data/lib/solargraph/pin/symbol.rb +8 -2
  125. data/lib/solargraph/pin/until.rb +18 -0
  126. data/lib/solargraph/pin/while.rb +18 -0
  127. data/lib/solargraph/pin.rb +8 -2
  128. data/lib/solargraph/pin_cache.rb +245 -0
  129. data/lib/solargraph/position.rb +19 -0
  130. data/lib/solargraph/range.rb +23 -4
  131. data/lib/solargraph/rbs_map/conversions.rb +315 -99
  132. data/lib/solargraph/rbs_map/core_fills.rb +50 -16
  133. data/lib/solargraph/rbs_map/core_map.rb +41 -11
  134. data/lib/solargraph/rbs_map/stdlib_map.rb +15 -5
  135. data/lib/solargraph/rbs_map.rb +87 -16
  136. data/lib/solargraph/shell.rb +117 -17
  137. data/lib/solargraph/source/chain/array.rb +13 -8
  138. data/lib/solargraph/source/chain/block_symbol.rb +1 -1
  139. data/lib/solargraph/source/chain/block_variable.rb +1 -1
  140. data/lib/solargraph/source/chain/call.rb +135 -66
  141. data/lib/solargraph/source/chain/constant.rb +3 -66
  142. data/lib/solargraph/source/chain/hash.rb +9 -3
  143. data/lib/solargraph/source/chain/head.rb +1 -1
  144. data/lib/solargraph/source/chain/if.rb +7 -2
  145. data/lib/solargraph/source/chain/link.rb +38 -6
  146. data/lib/solargraph/source/chain/literal.rb +27 -2
  147. data/lib/solargraph/source/chain/or.rb +2 -2
  148. data/lib/solargraph/source/chain/z_super.rb +1 -1
  149. data/lib/solargraph/source/chain.rb +140 -63
  150. data/lib/solargraph/source/change.rb +2 -2
  151. data/lib/solargraph/source/cursor.rb +4 -4
  152. data/lib/solargraph/source/source_chainer.rb +3 -3
  153. data/lib/solargraph/source.rb +110 -89
  154. data/lib/solargraph/source_map/clip.rb +22 -28
  155. data/lib/solargraph/source_map/data.rb +34 -0
  156. data/lib/solargraph/source_map/mapper.rb +11 -7
  157. data/lib/solargraph/source_map.rb +50 -43
  158. data/lib/solargraph/type_checker/checks.rb +4 -0
  159. data/lib/solargraph/type_checker/param_def.rb +2 -0
  160. data/lib/solargraph/type_checker/rules.rb +35 -8
  161. data/lib/solargraph/type_checker.rb +331 -189
  162. data/lib/solargraph/version.rb +1 -1
  163. data/lib/solargraph/views/_method.erb +10 -10
  164. data/lib/solargraph/views/_namespace.erb +3 -3
  165. data/lib/solargraph/views/document.erb +10 -10
  166. data/lib/solargraph/views/environment.erb +3 -5
  167. data/lib/solargraph/workspace/config.rb +25 -5
  168. data/lib/solargraph/workspace/require_paths.rb +97 -0
  169. data/lib/solargraph/workspace.rb +53 -72
  170. data/lib/solargraph/yard_map/helpers.rb +29 -1
  171. data/lib/solargraph/yard_map/mapper/to_constant.rb +8 -5
  172. data/lib/solargraph/yard_map/mapper/to_method.rb +55 -19
  173. data/lib/solargraph/yard_map/mapper/to_namespace.rb +11 -7
  174. data/lib/solargraph/yard_map/mapper.rb +5 -3
  175. data/lib/solargraph/yard_map/to_method.rb +6 -3
  176. data/lib/solargraph/yardoc.rb +45 -10
  177. data/lib/solargraph.rb +35 -1
  178. data/rbs/fills/bundler/0/bundler.rbs +4271 -0
  179. data/rbs/fills/open3/0/open3.rbs +172 -0
  180. data/rbs/fills/rubygems/0/basic_specification.rbs +326 -0
  181. data/rbs/fills/rubygems/0/errors.rbs +364 -0
  182. data/rbs/fills/rubygems/0/spec_fetcher.rbs +107 -0
  183. data/rbs/fills/rubygems/0/specification.rbs +1753 -0
  184. data/rbs/fills/tuple/tuple.rbs +149 -0
  185. data/rbs_collection.yaml +19 -0
  186. data/sig/shims/ast/0/node.rbs +5 -0
  187. data/sig/shims/ast/2.4/.rbs_meta.yaml +9 -0
  188. data/sig/shims/ast/2.4/ast.rbs +73 -0
  189. data/sig/shims/parser/3.2.0.1/builders/default.rbs +195 -0
  190. data/sig/shims/parser/3.2.0.1/manifest.yaml +7 -0
  191. data/sig/shims/parser/3.2.0.1/parser.rbs +201 -0
  192. data/sig/shims/parser/3.2.0.1/polyfill.rbs +4 -0
  193. data/sig/shims/thor/1.2.0.1/.rbs_meta.yaml +9 -0
  194. data/sig/shims/thor/1.2.0.1/manifest.yaml +7 -0
  195. data/sig/shims/thor/1.2.0.1/thor.rbs +17 -0
  196. data/solargraph.gemspec +32 -10
  197. metadata +237 -37
  198. data/lib/.rubocop.yml +0 -22
  199. data/lib/solargraph/cache.rb +0 -77
  200. data/lib/solargraph/parser/node_methods.rb +0 -83
@@ -13,38 +13,72 @@ module Solargraph
13
13
  'elsif', 'end', 'ensure', 'false', 'for', 'if', 'in', 'module', 'next',
14
14
  'nil', 'not', 'or', 'redo', 'rescue', 'retry', 'return', 'self', 'super',
15
15
  'then', 'true', 'undef', 'unless', 'until', 'when', 'while', 'yield'
16
- ].map { |k| Pin::Keyword.new(k) }
16
+ ].map { |k| Pin::Keyword.new(k, source: :core_fill) }
17
17
 
18
18
  MISSING = [
19
- Solargraph::Pin::Method.new(name: 'tap', scope: :instance,
20
- closure: Solargraph::Pin::Namespace.new(name: 'Object')),
21
19
  Solargraph::Pin::Method.new(name: 'class', scope: :instance,
22
- closure: Solargraph::Pin::Namespace.new(name: 'Object'), comments: '@return [Class<self>]')
20
+ closure: Solargraph::Pin::Namespace.new(name: 'Object', source: :core_fill), comments: '@return [::Class<self>]',
21
+ source: :core_fill)
23
22
  ]
24
23
 
25
24
  OVERRIDES = [
26
- Override.from_comment('BasicObject#instance_eval', '@yieldreceiver [self]'),
27
- Override.from_comment('BasicObject#instance_exec', '@yieldreceiver [self]'),
28
- Override.from_comment('Module#define_method', '@yieldreceiver [Object<self>]'),
29
- Override.from_comment('Module#class_eval', '@yieldreceiver [Class<self>]'),
30
- Override.from_comment('Module#class_exec', '@yieldreceiver [Class<self>]'),
31
- Override.from_comment('Module#module_eval', '@yieldreceiver [Module<self>]'),
32
- Override.from_comment('Module#module_exec', '@yieldreceiver [Module<self>]'),
25
+ Override.from_comment('BasicObject#instance_eval', '@yieldreceiver [self]',
26
+ source: :core_fill),
27
+ Override.from_comment('BasicObject#instance_exec', '@yieldreceiver [self]',
28
+ source: :core_fill),
29
+ Override.from_comment('Module#define_method', '@yieldreceiver [::Object<self>]',
30
+ source: :core_fill),
31
+ Override.from_comment('Module#class_eval', '@yieldreceiver [::Class<self>]',
32
+ source: :core_fill),
33
+ Override.from_comment('Module#class_exec', '@yieldreceiver [::Class<self>]',
34
+ source: :core_fill),
35
+ Override.from_comment('Module#module_eval', '@yieldreceiver [::Module<self>]',
36
+ source: :core_fill),
37
+ Override.from_comment('Module#module_exec', '@yieldreceiver [::Module<self>]',
38
+ source: :core_fill),
33
39
  # RBS does not define Class with a generic, so all calls to
34
40
  # generic() return an 'untyped'. We can do better:
35
- Override.method_return('Class#allocate', 'self')
41
+ Override.method_return('Class#allocate', 'self', source: :core_fill),
42
+ ]
43
+
44
+ # @todo I don't see any direct link in RBS to build this from -
45
+ # presumably RBS is using duck typing to match interfaces
46
+ # against concrete classes
47
+ INCLUDES = [
48
+ Solargraph::Pin::Reference::Include.new(name: '_ToAry',
49
+ closure: Solargraph::Pin::Namespace.new(name: 'Array', source: :core_fill),
50
+ generic_values: ['generic<Elem>'],
51
+ source: :core_fill),
52
+ Solargraph::Pin::Reference::Include.new(name: '_ToAry',
53
+ closure: Solargraph::Pin::Namespace.new(name: 'Set', source: :core_fill),
54
+ generic_values: ['generic<Elem>'],
55
+ source: :core_fill),
56
+ Solargraph::Pin::Reference::Include.new(name: '_Each',
57
+ closure: Solargraph::Pin::Namespace.new(name: 'Array', source: :core_fill),
58
+ generic_values: ['generic<Elem>'],
59
+ source: :core_fill),
60
+ Solargraph::Pin::Reference::Include.new(name: '_Each',
61
+ closure: Solargraph::Pin::Namespace.new(name: 'Set', source: :core_fill),
62
+ generic_values: ['generic<Elem>'],
63
+ source: :core_fill),
64
+ Solargraph::Pin::Reference::Include.new(name: '_ToS',
65
+ closure: Solargraph::Pin::Namespace.new(name: 'Object', source: :core_fill),
66
+ source: :core_fill),
67
+ Solargraph::Pin::Reference::Include.new(name: '_ToS',
68
+ closure: Solargraph::Pin::Namespace.new(name: 'String', source: :core_fill),
69
+ source: :core_fill)
36
70
  ]
37
71
 
38
72
  # HACK: Add Errno exception classes
39
- errno = Solargraph::Pin::Namespace.new(name: 'Errno')
73
+ errno = Solargraph::Pin::Namespace.new(name: 'Errno', source: :core_fill)
40
74
  errnos = []
41
75
  Errno.constants.each do |const|
42
- errnos.push Solargraph::Pin::Namespace.new(type: :class, name: const.to_s, closure: errno)
43
- errnos.push Solargraph::Pin::Reference::Superclass.new(closure: errnos.last, name: 'SystemCallError')
76
+ errnos.push Solargraph::Pin::Namespace.new(type: :class, name: const.to_s, closure: errno, source: :core_fill)
77
+ errnos.push Solargraph::Pin::Reference::Superclass.new(closure: errnos.last, name: 'SystemCallError', source: :core_fill)
44
78
  end
45
79
  ERRNOS = errnos
46
80
 
47
- ALL = KEYWORDS + MISSING + OVERRIDES + ERRNOS
81
+ ALL = KEYWORDS + MISSING + OVERRIDES + ERRNOS + INCLUDES
48
82
  end
49
83
  end
50
84
  end
@@ -5,23 +5,53 @@ module Solargraph
5
5
  # Ruby core pins
6
6
  #
7
7
  class CoreMap
8
- include Conversions
8
+ include Logging
9
9
 
10
- def initialize
11
- cache = Cache.load('core.ser')
10
+ def resolved?
11
+ true
12
+ end
13
+
14
+ FILLS_DIRECTORY = File.expand_path(File.join(File.dirname(__FILE__), '..', '..', '..', 'rbs', 'fills'))
15
+
16
+ def initialize; end
17
+
18
+ # @return [Enumerable<Pin::Base>]
19
+ def pins
20
+ return @pins if @pins
21
+
22
+ @pins = []
23
+ cache = PinCache.deserialize_core
12
24
  if cache
13
- pins.replace cache
25
+ @pins.replace cache
14
26
  else
15
- loader = RBS::EnvironmentLoader.new(repository: RBS::Repository.new(no_stdlib: false))
16
- RBS::Environment.from_loader(loader).resolve_type_names
17
- load_environment_to_pins(loader)
18
- pins.concat RbsMap::CoreFills::ALL
27
+ @pins.concat conversions.pins
28
+
29
+ # Avoid RBS::DuplicatedDeclarationError by loading in a different EnvironmentLoader
30
+ fill_loader = RBS::EnvironmentLoader.new(core_root: nil, repository: RBS::Repository.new(no_stdlib: false))
31
+ fill_loader.add(path: Pathname(FILLS_DIRECTORY))
32
+ fill_conversions = Conversions.new(loader: fill_loader)
33
+ @pins.concat fill_conversions.pins
34
+
35
+ @pins.concat RbsMap::CoreFills::ALL
36
+
19
37
  processed = ApiMap::Store.new(pins).pins.reject { |p| p.is_a?(Solargraph::Pin::Reference::Override) }
20
- processed.each { |pin| pin.source = :rbs }
21
- pins.replace processed
38
+ @pins.replace processed
22
39
 
23
- Cache.save('core.ser', pins)
40
+ PinCache.serialize_core @pins
24
41
  end
42
+ @pins
43
+ end
44
+
45
+ private
46
+
47
+ # @return [RBS::EnvironmentLoader]
48
+ def loader
49
+ @loader ||= RBS::EnvironmentLoader.new(repository: RBS::Repository.new(no_stdlib: false))
50
+ end
51
+
52
+ # @return [Conversions]
53
+ def conversions
54
+ @conversions ||= Conversions.new(loader: loader)
25
55
  end
26
56
  end
27
57
  end
@@ -7,19 +7,29 @@ module Solargraph
7
7
  # Ruby stdlib pins
8
8
  #
9
9
  class StdlibMap < RbsMap
10
+ include Logging
11
+
10
12
  # @type [Hash{String => RbsMap}]
11
13
  @stdlib_maps_hash = {}
12
14
 
13
15
  # @param library [String]
14
16
  def initialize library
15
- cache = Cache.load('stdlib', "#{library}.ser")
16
- if cache
17
- pins.replace cache
17
+ cached_pins = PinCache.deserialize_stdlib_require library
18
+ if cached_pins
19
+ @pins = cached_pins
18
20
  @resolved = true
21
+ @loaded = true
22
+ logger.debug { "Deserialized #{cached_pins.length} cached pins for stdlib require #{library.inspect}" }
19
23
  else
20
24
  super
21
- return unless resolved?
22
- Cache.save('stdlib', "#{library}.ser", pins)
25
+ unless resolved?
26
+ @pins = []
27
+ logger.info { "Could not resolve #{library.inspect}" }
28
+ return
29
+ end
30
+ generated_pins = pins
31
+ logger.debug { "Found #{generated_pins.length} pins for stdlib library #{library}" }
32
+ PinCache.serialize_stdlib_require library, generated_pins
23
33
  end
24
34
  end
25
35
 
@@ -1,5 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'digest'
3
4
  require 'pathname'
4
5
  require 'rbs'
5
6
 
@@ -10,25 +11,86 @@ module Solargraph
10
11
  autoload :CoreFills, 'solargraph/rbs_map/core_fills'
11
12
  autoload :StdlibMap, 'solargraph/rbs_map/stdlib_map'
12
13
 
13
- include Conversions
14
+ include Logging
14
15
 
15
16
  # @type [Hash{String => RbsMap}]
16
17
  @@rbs_maps_hash = {}
17
18
 
18
19
  attr_reader :library
19
20
 
21
+ attr_reader :rbs_collection_paths
22
+
23
+ attr_reader :rbs_collection_config_path
24
+
20
25
  # @param library [String]
21
26
  # @param version [String, nil]
22
- # @param directories [Array<Pathname, String>]
23
- def initialize library, version = nil, directories: []
27
+ # @param rbs_collection_config_path [String, Pathname, nil]
28
+ # @param rbs_collection_paths [Array<Pathname, String>]
29
+ def initialize library, version = nil, rbs_collection_config_path: nil, rbs_collection_paths: []
30
+ if rbs_collection_config_path.nil? && !rbs_collection_paths.empty?
31
+ raise 'Please provide rbs_collection_config_path if you provide rbs_collection_paths'
32
+ end
24
33
  @library = library
25
34
  @version = version
26
- @collection = nil
27
- @directories = directories
28
- loader = RBS::EnvironmentLoader.new(core_root: nil, repository: repository)
35
+ @rbs_collection_config_path = rbs_collection_config_path
36
+ @rbs_collection_paths = rbs_collection_paths
29
37
  add_library loader, library, version
30
- return unless resolved?
31
- load_environment_to_pins(loader)
38
+ end
39
+
40
+ # @return [RBS::EnvironmentLoader]
41
+ def loader
42
+ @loader ||= RBS::EnvironmentLoader.new(core_root: nil, repository: repository)
43
+ end
44
+
45
+ # @return [String] representing the version of the RBS info fetched
46
+ # for the given library. Must change when the RBS info is
47
+ # updated upstream for the same library and version. May change
48
+ # if the config for where information comes form changes.
49
+ def cache_key
50
+ @hextdigest ||= begin
51
+ # @type [String, nil]
52
+ data = nil
53
+ if rbs_collection_config_path
54
+ lockfile_path = RBS::Collection::Config.to_lockfile_path(Pathname.new(rbs_collection_config_path))
55
+ if lockfile_path.exist?
56
+ collection_config = RBS::Collection::Config.from_path lockfile_path
57
+ gem_config = collection_config.gem(library)
58
+ data = gem_config&.to_s
59
+ end
60
+ end
61
+ if data.nil? || data.empty?
62
+ if resolved?
63
+ # definitely came from the gem itself and not elsewhere -
64
+ # only one version per gem
65
+ 'gem-export'
66
+ else
67
+ 'unresolved'
68
+ end
69
+ else
70
+ Digest::SHA1.hexdigest(data)
71
+ end
72
+ end
73
+ end
74
+
75
+ # @param gemspec [Gem::Specification, Bundler::LazySpecification]
76
+ # @param rbs_collection_path [String, Pathname, nil]
77
+ # @param rbs_collection_config_path [String, Pathname, nil]
78
+ # @return [RbsMap]
79
+ def self.from_gemspec gemspec, rbs_collection_path, rbs_collection_config_path
80
+ rbs_map = RbsMap.new(gemspec.name, gemspec.version,
81
+ rbs_collection_paths: [rbs_collection_path].compact,
82
+ rbs_collection_config_path: rbs_collection_config_path)
83
+ return rbs_map if rbs_map.resolved?
84
+
85
+ # try any version of the gem in the collection
86
+ RbsMap.new(gemspec.name, nil,
87
+ rbs_collection_paths: [rbs_collection_path].compact,
88
+ rbs_collection_config_path: rbs_collection_config_path)
89
+ end
90
+
91
+ # @return [Array<Pin::Base>]
92
+ def pins
93
+ @pins ||= resolved? ? conversions.pins : []
32
94
  end
33
95
 
34
96
  # @generic T
@@ -50,11 +112,13 @@ module Solargraph
50
112
  @resolved
51
113
  end
52
114
 
115
+ # @return [RBS::Repository]
53
116
  def repository
54
117
  @repository ||= RBS::Repository.new(no_stdlib: false).tap do |repo|
55
- # @todo Temporarily ignoring external directories due to issues with
56
- # incomplete/broken gem_rbs_collection installations
57
- # @directories.each { |dir| repo.add(Pathname.new(dir)) }
118
+ @rbs_collection_paths.each do |dir|
119
+ dir_path = Pathname.new(dir)
120
+ repo.add(dir_path) if dir_path.exist? && dir_path.directory?
121
+ end
58
122
  end
59
123
  end
60
124
 
@@ -64,22 +128,29 @@ module Solargraph
64
128
  @@rbs_maps_hash[library] ||= RbsMap.new(library)
65
129
  end
66
130
 
67
- def self.from_gemspec(gemspec)
68
- RbsMap.new(gemspec.name, gemspec.version)
131
+ private
132
+
133
+ # @return [RBS::EnvironmentLoader]
134
+ def loader
135
+ @loader ||= RBS::EnvironmentLoader.new(core_root: nil, repository: repository)
69
136
  end
70
137
 
71
- private
138
+ # @return [Conversions]
139
+ def conversions
140
+ @conversions ||= Conversions.new(loader: loader)
141
+ end
72
142
 
73
143
  # @param loader [RBS::EnvironmentLoader]
74
144
  # @param library [String]
145
+ # @param version [String, nil]
75
146
  # @return [Boolean] true if adding the library succeeded
76
147
  def add_library loader, library, version
77
148
  @resolved = if loader.has_library?(library: library, version: version)
78
149
  loader.add library: library, version: version
79
- Solargraph.logger.info "#{short_name} successfully loaded library #{library}"
150
+ logger.debug { "#{short_name} successfully loaded library #{library}:#{version}" }
80
151
  true
81
152
  else
82
- Solargraph.logger.info "#{short_name} failed to load library #{library}"
153
+ logger.info { "#{short_name} did not find data for library #{library}:#{version}" }
83
154
  false
84
155
  end
85
156
  end
@@ -36,6 +36,7 @@ module Solargraph
36
36
  Signal.trap("TERM") do
37
37
  Backport.stop
38
38
  end
39
+ # @sg-ignore Wrong argument type for Backport.prepare_tcp_server: adapter expected Backport::Adapter, received Module<Solargraph::LanguageServer::Transport::Adapter>
39
40
  Backport.prepare_tcp_server host: options[:host], port: port, adapter: Solargraph::LanguageServer::Transport::Adapter
40
41
  STDERR.puts "Solargraph is listening PORT=#{port} PID=#{Process.pid}"
41
42
  end
@@ -52,6 +53,7 @@ module Solargraph
52
53
  Signal.trap("TERM") do
53
54
  Backport.stop
54
55
  end
56
+ # @sg-ignore Wrong argument type for Backport.prepare_stdio_server: adapter expected Backport::Adapter, received Module<Solargraph::LanguageServer::Transport::Adapter>
55
57
  Backport.prepare_stdio_server adapter: Solargraph::LanguageServer::Transport::Adapter
56
58
  STDERR.puts "Solargraph is listening on stdio PID=#{Process.pid}"
57
59
  end
@@ -77,6 +79,7 @@ module Solargraph
77
79
  conf['extensions'].push m
78
80
  end
79
81
  end
82
+ # @param file [File]
80
83
  File.open(File.join(directory, '.solargraph.yml'), 'w') do |file|
81
84
  file.puts conf.to_yaml
82
85
  end
@@ -89,46 +92,66 @@ module Solargraph
89
92
  )
90
93
  # @return [void]
91
94
  def clear
92
- puts "Deleting the cached documentation"
93
- Solargraph::Cache.clear
95
+ puts "Deleting all cached documentation (gems, core and stdlib)"
96
+ Solargraph::PinCache.clear
94
97
  end
95
98
  map 'clear-cache' => :clear
96
99
  map 'clear-cores' => :clear
97
100
 
98
101
  desc 'cache', 'Cache a gem', hide: true
102
+ option :rebuild, type: :boolean, desc: 'Rebuild existing documentation', default: false
99
103
  # @return [void]
100
104
  # @param gem [String]
101
105
  # @param version [String, nil]
102
106
  def cache gem, version = nil
107
+ api_map = Solargraph::ApiMap.load(Dir.pwd)
103
108
  spec = Gem::Specification.find_by_name(gem, version)
104
- pins = GemPins.build(spec)
105
- Cache.save('gems', "#{spec.name}-#{spec.version}.ser", pins)
109
+ api_map.cache_gem(spec, rebuild: options[:rebuild], out: $stdout)
106
110
  end
107
111
 
108
- desc 'uncache GEM [...GEM]', "Delete cached gem documentation"
112
+ desc 'uncache GEM [...GEM]', "Delete specific cached gem documentation"
113
+ long_desc %(
114
+ Specify one or more gem names to clear. 'core' or 'stdlib' may
115
+ also be specified to clear cached system documentation.
116
+ Documentation will be regenerated as needed.
117
+ )
118
+ # @param gems [Array<String>]
109
119
  # @return [void]
110
120
  def uncache *gems
111
121
  raise ArgumentError, 'No gems specified.' if gems.empty?
112
122
  gems.each do |gem|
123
+ if gem == 'core'
124
+ PinCache.uncache_core
125
+ next
126
+ end
127
+
128
+ if gem == 'stdlib'
129
+ PinCache.uncache_stdlib
130
+ next
131
+ end
132
+
113
133
  spec = Gem::Specification.find_by_name(gem)
114
- Cache.uncache('gems', "#{spec.name}-#{spec.version}.ser")
115
- Cache.uncache('gems', "#{spec.name}-#{spec.version}.yardoc")
134
+ PinCache.uncache_gem(spec, out: $stdout)
116
135
  end
117
136
  end
118
137
 
119
138
  desc 'gems [GEM[=VERSION]]', 'Cache documentation for installed gems'
120
139
  option :rebuild, type: :boolean, desc: 'Rebuild existing documentation', default: false
140
+ # @param names [Array<String>]
121
141
  # @return [void]
122
142
  def gems *names
143
+ api_map = ApiMap.load('.')
123
144
  if names.empty?
124
- Gem::Specification.to_a.each { |spec| do_cache spec }
145
+ Gem::Specification.to_a.each { |spec| do_cache spec, api_map }
146
+ STDERR.puts "Documentation cached for all #{Gem::Specification.count} gems."
125
147
  else
126
148
  names.each do |name|
127
149
  spec = Gem::Specification.find_by_name(*name.split('='))
128
- do_cache spec
150
+ do_cache spec, api_map
129
151
  rescue Gem::MissingSpecError
130
152
  warn "Gem '#{name}' not found"
131
153
  end
154
+ STDERR.puts "Documentation cached for #{names.count} gems."
132
155
  end
133
156
  end
134
157
 
@@ -150,6 +173,9 @@ module Solargraph
150
173
  # @return [void]
151
174
  def typecheck *files
152
175
  directory = File.realpath(options[:directory])
176
+ workspace = Solargraph::Workspace.new(directory)
177
+ level = options[:level].to_sym
178
+ rules = workspace.rules(level)
153
179
  api_map = Solargraph::ApiMap.load_with_cache(directory, $stdout)
154
180
  probcount = 0
155
181
  if files.empty?
@@ -161,7 +187,7 @@ module Solargraph
161
187
 
162
188
  time = Benchmark.measure {
163
189
  files.each do |file|
164
- checker = TypeChecker.new(file, api_map: api_map, level: options[:level].to_sym)
190
+ checker = TypeChecker.new(file, api_map: api_map, level: options[:level].to_sym, workspace: workspace)
165
191
  problems = checker.problems
166
192
  next if problems.empty?
167
193
  problems.sort! { |a, b| a.location.range.start.line <=> b.location.range.start.line }
@@ -189,6 +215,7 @@ module Solargraph
189
215
  # @return [void]
190
216
  def scan
191
217
  directory = File.realpath(options[:directory])
218
+ # @type [Solargraph::ApiMap, nil]
192
219
  api_map = nil
193
220
  time = Benchmark.measure {
194
221
  api_map = Solargraph::ApiMap.load_with_cache(directory, $stdout)
@@ -218,6 +245,63 @@ module Solargraph
218
245
  puts "#{workspace.filenames.length} files total."
219
246
  end
220
247
 
248
+ desc 'pin [PATH]', 'Describe a pin', hide: true
249
+ option :rbs, type: :boolean, desc: 'Output the pin as RBS', default: false
250
+ option :typify, type: :boolean, desc: 'Output the calculated return type of the pin from annotations', default: false
251
+ option :references, type: :boolean, desc: 'Show references', default: false
252
+ option :probe, type: :boolean, desc: 'Output the calculated return type of the pin from annotations and inference', default: false
253
+ option :stack, type: :boolean, desc: 'Show entire stack of a method pin by including definitions in superclasses', default: false
254
+ # @param path [String] The path to the method pin, e.g. 'Class#method' or 'Class.method'
255
+ # @return [void]
256
+ def pin path
257
+ api_map = Solargraph::ApiMap.load_with_cache('.', $stderr)
258
+ is_method = path.include?('#') || path.include?('.')
259
+ if is_method && options[:stack]
260
+ scope, ns, meth = if path.include? '#'
261
+ [:instance, *path.split('#', 2)]
262
+ else
263
+ [:class, *path.split('.', 2)]
264
+ end
265
+
266
+ # @sg-ignore Wrong argument type for
267
+ # Solargraph::ApiMap#get_method_stack: rooted_tag
268
+ # expected String, received Array<String>
269
+ pins = api_map.get_method_stack(ns, meth, scope: scope)
270
+ else
271
+ pins = api_map.get_path_pins path
272
+ end
273
+ # @type [Hash{Symbol => Pin::Base}]
274
+ references = {}
275
+ pin = pins.first
276
+ case pin
277
+ when nil
278
+ $stderr.puts "Pin not found for path '#{path}'"
279
+ exit 1
280
+ when Pin::Namespace
281
+ if options[:references]
282
+ superclass_tag = api_map.qualify_superclass(pin.return_type.tag)
283
+ superclass_pin = api_map.get_path_pins(superclass_tag).first if superclass_tag
284
+ references[:superclass] = superclass_pin if superclass_pin
285
+ end
286
+ end
287
+
288
+ pins.each do |pin|
289
+ if options[:typify] || options[:probe]
290
+ type = ComplexType::UNDEFINED
291
+ type = pin.typify(api_map) if options[:typify]
292
+ type = pin.probe(api_map) if options[:probe] && type.undefined?
293
+ print_type(type)
294
+ next
295
+ end
296
+
297
+ print_pin(pin)
298
+ end
299
+ references.each do |key, refpin|
300
+ puts "\n# #{key.to_s.capitalize}:\n\n"
301
+ print_pin(refpin)
302
+ end
303
+ end
304
+
221
305
  private
222
306
 
223
307
  # @param pin [Solargraph::Pin::Base]
@@ -237,15 +321,31 @@ module Solargraph
237
321
  end
238
322
 
239
323
  # @param gemspec [Gem::Specification]
324
+ # @param api_map [ApiMap]
325
+ # @return [void]
326
+ def do_cache gemspec, api_map
327
+ # @todo if the rebuild: option is passed as a positional arg,
328
+ # typecheck doesn't complain on the below line
329
+ api_map.cache_gem(gemspec, rebuild: options.rebuild, out: $stdout)
330
+ end
331
+
332
+ # @param type [ComplexType]
333
+ # @return [void]
334
+ def print_type(type)
335
+ if options[:rbs]
336
+ puts type.to_rbs
337
+ else
338
+ puts type.rooted_tag
339
+ end
340
+ end
341
+
342
+ # @param pin [Solargraph::Pin::Base]
240
343
  # @return [void]
241
- def do_cache gemspec
242
- cached = Yardoc.cached?(gemspec)
243
- if cached && !options.rebuild
244
- puts "Cache already exists for #{gemspec.name} #{gemspec.version}"
344
+ def print_pin(pin)
345
+ if options[:rbs]
346
+ puts pin.to_rbs
245
347
  else
246
- puts "#{cached ? 'Rebuilding' : 'Caching'} gem documentation for #{gemspec.name} #{gemspec.version}"
247
- pins = GemPins.build(gemspec)
248
- Cache.save('gems', "#{gemspec.name}-#{gemspec.version}.ser", pins)
348
+ puts pin.inspect
249
349
  end
250
350
  end
251
351
  end
@@ -3,8 +3,9 @@ module Solargraph
3
3
  class Chain
4
4
  class Array < Literal
5
5
  # @param children [::Array<Chain>]
6
- def initialize children
7
- super('::Array')
6
+ # @param node [Parser::AST::Node]
7
+ def initialize children, node
8
+ super('::Array', node)
8
9
  @children = children
9
10
  end
10
11
 
@@ -14,17 +15,21 @@ module Solargraph
14
15
 
15
16
  # @param api_map [ApiMap]
16
17
  # @param name_pin [Pin::Base]
17
- # @param locals [Enumerable<Pin::LocalVariable>]
18
+ # @param locals [::Array<Pin::Parameter, Pin::LocalVariable>]
18
19
  def resolve api_map, name_pin, locals
19
20
  child_types = @children.map do |child|
20
- child.infer(api_map, name_pin, locals).tag
21
+ child.infer(api_map, name_pin, locals).simplify_literals
21
22
  end
22
- type = if child_types.uniq.length == 1 && child_types.first != 'undefined'
23
- "::Array<#{child_types.first}>"
23
+ type = if child_types.length == 0 || child_types.any?(&:undefined?)
24
+ ComplexType::UniqueType.new('Array', rooted: true)
25
+ elsif child_types.uniq.length == 1 && child_types.first.defined?
26
+ ComplexType::UniqueType.new('Array', [], child_types.uniq, rooted: true, parameters_type: :list)
27
+ elsif child_types.length == 0
28
+ ComplexType::UniqueType.new('Array', rooted: true, parameters_type: :list)
24
29
  else
25
- '::Array'
30
+ ComplexType::UniqueType.new('Array', [], child_types, rooted: true, parameters_type: :fixed)
26
31
  end
27
- [Pin::ProxyType.anonymous(ComplexType.try_parse(type))]
32
+ [Pin::ProxyType.anonymous(type, source: :chain)]
28
33
  end
29
34
  end
30
35
  end
@@ -5,7 +5,7 @@ module Solargraph
5
5
  class Chain
6
6
  class BlockSymbol < Link
7
7
  def resolve api_map, name_pin, locals
8
- [Pin::ProxyType.anonymous(ComplexType.try_parse('Proc'))]
8
+ [Pin::ProxyType.anonymous(ComplexType.try_parse('::Proc'), source: :chain)]
9
9
  end
10
10
  end
11
11
  end
@@ -5,7 +5,7 @@ module Solargraph
5
5
  class Chain
6
6
  class BlockVariable < Link
7
7
  def resolve api_map, name_pin, locals
8
- [Pin::ProxyType.anonymous(ComplexType.try_parse('Proc'))]
8
+ [Pin::ProxyType.anonymous(ComplexType.try_parse('::Proc'), source: :chain)]
9
9
  end
10
10
  end
11
11
  end