steep 0.37.0 → 0.42.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (221) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ruby.yml +1 -1
  3. data/CHANGELOG.md +34 -0
  4. data/Rakefile +5 -2
  5. data/bin/output_rebaseline.rb +34 -0
  6. data/bin/output_test.rb +53 -0
  7. data/lib/steep.rb +95 -14
  8. data/lib/steep/ast/types/bot.rb +1 -1
  9. data/lib/steep/ast/types/class.rb +4 -0
  10. data/lib/steep/ast/types/factory.rb +10 -0
  11. data/lib/steep/ast/types/logic.rb +16 -3
  12. data/lib/steep/ast/types/top.rb +1 -1
  13. data/lib/steep/cli.rb +31 -7
  14. data/lib/steep/diagnostic/helper.rb +17 -0
  15. data/lib/steep/diagnostic/lsp_formatter.rb +16 -0
  16. data/lib/steep/diagnostic/ruby.rb +619 -0
  17. data/lib/steep/diagnostic/signature.rb +357 -0
  18. data/lib/steep/drivers/annotations.rb +19 -28
  19. data/lib/steep/drivers/check.rb +182 -60
  20. data/lib/steep/drivers/diagnostic_printer.rb +99 -0
  21. data/lib/steep/drivers/langserver.rb +3 -8
  22. data/lib/steep/drivers/print_project.rb +10 -9
  23. data/lib/steep/drivers/stats.rb +124 -32
  24. data/lib/steep/drivers/trace_printer.rb +5 -1
  25. data/lib/steep/drivers/utils/jobs_count.rb +9 -0
  26. data/lib/steep/drivers/validate.rb +31 -13
  27. data/lib/steep/drivers/watch.rb +69 -48
  28. data/lib/steep/drivers/worker.rb +16 -8
  29. data/lib/steep/expectations.rb +159 -0
  30. data/lib/steep/index/rbs_index.rb +334 -0
  31. data/lib/steep/index/signature_symbol_provider.rb +162 -0
  32. data/lib/steep/index/source_index.rb +100 -0
  33. data/lib/steep/project.rb +0 -30
  34. data/lib/steep/project/dsl.rb +5 -3
  35. data/lib/steep/project/options.rb +4 -4
  36. data/lib/steep/project/pattern.rb +56 -0
  37. data/lib/steep/project/target.rb +9 -214
  38. data/lib/steep/range_extension.rb +29 -0
  39. data/lib/steep/server/base_worker.rb +43 -7
  40. data/lib/steep/server/change_buffer.rb +63 -0
  41. data/lib/steep/server/interaction_worker.rb +73 -56
  42. data/lib/steep/server/master.rb +245 -109
  43. data/lib/steep/server/type_check_worker.rb +122 -0
  44. data/lib/steep/server/worker_process.rb +17 -15
  45. data/lib/steep/{project → services}/completion_provider.rb +3 -3
  46. data/lib/steep/services/content_change.rb +61 -0
  47. data/lib/steep/services/file_loader.rb +48 -0
  48. data/lib/steep/{project → services}/hover_content.rb +14 -16
  49. data/lib/steep/services/path_assignment.rb +29 -0
  50. data/lib/steep/services/signature_service.rb +369 -0
  51. data/lib/steep/services/stats_calculator.rb +69 -0
  52. data/lib/steep/services/type_check_service.rb +342 -0
  53. data/lib/steep/signature/validator.rb +174 -32
  54. data/lib/steep/subtyping/check.rb +248 -47
  55. data/lib/steep/subtyping/constraints.rb +2 -2
  56. data/lib/steep/type_construction.rb +565 -295
  57. data/lib/steep/type_inference/constant_env.rb +5 -1
  58. data/lib/steep/type_inference/local_variable_type_env.rb +26 -12
  59. data/lib/steep/type_inference/logic_type_interpreter.rb +99 -26
  60. data/lib/steep/type_inference/type_env.rb +43 -17
  61. data/lib/steep/typing.rb +8 -2
  62. data/lib/steep/version.rb +1 -1
  63. data/smoke/alias/a.rb +0 -3
  64. data/smoke/alias/b.rb +0 -1
  65. data/smoke/alias/c.rb +0 -2
  66. data/smoke/alias/test_expectations.yml +96 -0
  67. data/smoke/and/a.rb +0 -3
  68. data/smoke/and/test_expectations.yml +31 -0
  69. data/smoke/array/a.rb +0 -3
  70. data/smoke/array/b.rb +0 -2
  71. data/smoke/array/c.rb +0 -1
  72. data/smoke/array/test_expectations.yml +103 -0
  73. data/smoke/block/a.rb +0 -2
  74. data/smoke/block/b.rb +0 -2
  75. data/smoke/block/d.rb +0 -4
  76. data/smoke/block/test_expectations.yml +125 -0
  77. data/smoke/case/a.rb +0 -3
  78. data/smoke/case/test_expectations.yml +47 -0
  79. data/smoke/class/a.rb +0 -3
  80. data/smoke/class/c.rb +0 -1
  81. data/smoke/class/f.rb +0 -1
  82. data/smoke/class/g.rb +0 -2
  83. data/smoke/class/i.rb +0 -2
  84. data/smoke/class/test_expectations.yml +120 -0
  85. data/smoke/const/a.rb +0 -3
  86. data/smoke/const/b.rb +7 -0
  87. data/smoke/const/b.rbs +5 -0
  88. data/smoke/const/test_expectations.yml +139 -0
  89. data/smoke/diagnostics-rbs-duplicated/Steepfile +5 -0
  90. data/smoke/diagnostics-rbs-duplicated/a.rbs +5 -0
  91. data/smoke/diagnostics-rbs-duplicated/test_expectations.yml +13 -0
  92. data/smoke/diagnostics-rbs/Steepfile +8 -0
  93. data/smoke/diagnostics-rbs/duplicated-method-definition.rbs +20 -0
  94. data/smoke/diagnostics-rbs/generic-parameter-mismatch.rbs +7 -0
  95. data/smoke/diagnostics-rbs/invalid-method-overload.rbs +3 -0
  96. data/smoke/diagnostics-rbs/invalid-type-application.rbs +7 -0
  97. data/smoke/diagnostics-rbs/invalid_variance_annotation.rbs +3 -0
  98. data/smoke/diagnostics-rbs/recursive-alias.rbs +5 -0
  99. data/smoke/diagnostics-rbs/recursive-class.rbs +8 -0
  100. data/smoke/diagnostics-rbs/superclass-mismatch.rbs +7 -0
  101. data/smoke/diagnostics-rbs/test_expectations.yml +231 -0
  102. data/smoke/diagnostics-rbs/unknown-method-alias.rbs +3 -0
  103. data/smoke/diagnostics-rbs/unknown-type-name-2.rbs +5 -0
  104. data/smoke/diagnostics-rbs/unknown-type-name.rbs +13 -0
  105. data/smoke/diagnostics/Steepfile +5 -0
  106. data/smoke/diagnostics/a.rbs +26 -0
  107. data/smoke/diagnostics/argument_type_mismatch.rb +1 -0
  108. data/smoke/diagnostics/block_body_type_mismatch.rb +1 -0
  109. data/smoke/diagnostics/block_type_mismatch.rb +3 -0
  110. data/smoke/diagnostics/break_type_mismatch.rb +1 -0
  111. data/smoke/diagnostics/else_on_exhaustive_case.rb +12 -0
  112. data/smoke/diagnostics/incompatible_annotation.rb +6 -0
  113. data/smoke/diagnostics/incompatible_argument.rb +1 -0
  114. data/smoke/diagnostics/incompatible_assignment.rb +8 -0
  115. data/smoke/diagnostics/method_arity_mismatch.rb +11 -0
  116. data/smoke/diagnostics/method_body_type_mismatch.rb +6 -0
  117. data/smoke/diagnostics/method_definition_missing.rb +2 -0
  118. data/smoke/diagnostics/method_return_type_annotation_mismatch.rb +7 -0
  119. data/smoke/diagnostics/missing_keyword.rb +1 -0
  120. data/smoke/diagnostics/no_method.rb +1 -0
  121. data/smoke/diagnostics/required_block_missing.rb +1 -0
  122. data/smoke/diagnostics/return_type_mismatch.rb +6 -0
  123. data/smoke/diagnostics/test_expectations.yml +477 -0
  124. data/smoke/diagnostics/unexpected_block_given.rb +1 -0
  125. data/smoke/diagnostics/unexpected_dynamic_method.rb +3 -0
  126. data/smoke/diagnostics/unexpected_jump.rb +4 -0
  127. data/smoke/diagnostics/unexpected_jump_value.rb +3 -0
  128. data/smoke/diagnostics/unexpected_keyword.rb +1 -0
  129. data/smoke/diagnostics/unexpected_splat.rb +1 -0
  130. data/smoke/diagnostics/unexpected_yield.rb +6 -0
  131. data/smoke/diagnostics/unknown_constant_assigned.rb +7 -0
  132. data/smoke/diagnostics/unresolved_overloading.rb +1 -0
  133. data/smoke/diagnostics/unsatisfiable_constraint.rb +7 -0
  134. data/smoke/diagnostics/unsupported_syntax.rb +2 -0
  135. data/smoke/dstr/a.rb +0 -1
  136. data/smoke/dstr/test_expectations.yml +13 -0
  137. data/smoke/ensure/a.rb +0 -4
  138. data/smoke/ensure/test_expectations.yml +62 -0
  139. data/smoke/enumerator/a.rb +0 -6
  140. data/smoke/enumerator/b.rb +0 -3
  141. data/smoke/enumerator/test_expectations.yml +135 -0
  142. data/smoke/extension/a.rb +0 -1
  143. data/smoke/extension/b.rb +0 -2
  144. data/smoke/extension/c.rb +0 -1
  145. data/smoke/extension/f.rb +2 -0
  146. data/smoke/extension/f.rbs +3 -0
  147. data/smoke/extension/test_expectations.yml +73 -0
  148. data/smoke/hash/b.rb +0 -1
  149. data/smoke/hash/c.rb +0 -3
  150. data/smoke/hash/d.rb +0 -1
  151. data/smoke/hash/e.rb +0 -1
  152. data/smoke/hash/test_expectations.yml +81 -0
  153. data/smoke/hello/hello.rb +0 -2
  154. data/smoke/hello/test_expectations.yml +25 -0
  155. data/smoke/if/a.rb +0 -2
  156. data/smoke/if/test_expectations.yml +34 -0
  157. data/smoke/implements/a.rb +0 -2
  158. data/smoke/implements/test_expectations.yml +23 -0
  159. data/smoke/initialize/test_expectations.yml +1 -0
  160. data/smoke/integer/a.rb +0 -7
  161. data/smoke/integer/test_expectations.yml +101 -0
  162. data/smoke/interface/a.rb +0 -2
  163. data/smoke/interface/test_expectations.yml +23 -0
  164. data/smoke/kwbegin/a.rb +0 -1
  165. data/smoke/kwbegin/test_expectations.yml +17 -0
  166. data/smoke/lambda/a.rb +1 -4
  167. data/smoke/lambda/test_expectations.yml +39 -0
  168. data/smoke/literal/a.rb +0 -5
  169. data/smoke/literal/b.rb +0 -2
  170. data/smoke/literal/test_expectations.yml +106 -0
  171. data/smoke/map/test_expectations.yml +1 -0
  172. data/smoke/method/a.rb +0 -5
  173. data/smoke/method/b.rb +0 -1
  174. data/smoke/method/test_expectations.yml +90 -0
  175. data/smoke/module/a.rb +0 -2
  176. data/smoke/module/b.rb +0 -2
  177. data/smoke/module/c.rb +0 -1
  178. data/smoke/module/d.rb +0 -1
  179. data/smoke/module/f.rb +0 -2
  180. data/smoke/module/test_expectations.yml +75 -0
  181. data/smoke/regexp/a.rb +0 -38
  182. data/smoke/regexp/b.rb +0 -26
  183. data/smoke/regexp/test_expectations.yml +615 -0
  184. data/smoke/regression/set_divide.rb +0 -4
  185. data/smoke/regression/test_expectations.yml +43 -0
  186. data/smoke/rescue/a.rb +0 -5
  187. data/smoke/rescue/test_expectations.yml +79 -0
  188. data/smoke/self/a.rb +0 -2
  189. data/smoke/self/test_expectations.yml +23 -0
  190. data/smoke/skip/skip.rb +0 -2
  191. data/smoke/skip/test_expectations.yml +23 -0
  192. data/smoke/stdout/test_expectations.yml +1 -0
  193. data/smoke/super/a.rb +0 -4
  194. data/smoke/super/test_expectations.yml +79 -0
  195. data/smoke/toplevel/a.rb +0 -1
  196. data/smoke/toplevel/test_expectations.yml +15 -0
  197. data/smoke/tsort/Steepfile +2 -0
  198. data/smoke/tsort/a.rb +0 -3
  199. data/smoke/tsort/test_expectations.yml +63 -0
  200. data/smoke/type_case/a.rb +0 -4
  201. data/smoke/type_case/test_expectations.yml +48 -0
  202. data/smoke/unexpected/Steepfile +5 -0
  203. data/smoke/unexpected/test_expectations.yml +25 -0
  204. data/smoke/unexpected/unexpected.rb +1 -0
  205. data/smoke/unexpected/unexpected.rbs +3 -0
  206. data/smoke/yield/a.rb +0 -3
  207. data/smoke/yield/b.rb +6 -0
  208. data/smoke/yield/test_expectations.yml +68 -0
  209. data/steep.gemspec +4 -3
  210. metadata +144 -29
  211. data/bin/smoke_runner.rb +0 -139
  212. data/lib/steep/drivers/signature_error_printer.rb +0 -25
  213. data/lib/steep/errors.rb +0 -565
  214. data/lib/steep/project/file_loader.rb +0 -68
  215. data/lib/steep/project/signature_file.rb +0 -33
  216. data/lib/steep/project/source_file.rb +0 -129
  217. data/lib/steep/server/code_worker.rb +0 -137
  218. data/lib/steep/server/signature_worker.rb +0 -152
  219. data/lib/steep/server/utils.rb +0 -69
  220. data/lib/steep/signature/errors.rb +0 -82
  221. data/lib/steep/type_assignability.rb +0 -367
@@ -0,0 +1,162 @@
1
+ module Steep
2
+ module Index
3
+ class SignatureSymbolProvider
4
+ LSP = LanguageServer::Protocol
5
+ SymbolInformation = Struct.new(:name, :kind, :container_name, :location, keyword_init: true)
6
+
7
+ attr_reader :indexes
8
+
9
+ def initialize()
10
+ @indexes = []
11
+ end
12
+
13
+ def self.test_type_name(query, type_name)
14
+ case
15
+ when query == ""
16
+ true
17
+ else
18
+ type_name.to_s.upcase.include?(query.upcase)
19
+ end
20
+ end
21
+
22
+ class <<self
23
+ alias test_const_name test_type_name
24
+ alias test_global_name test_type_name
25
+ end
26
+
27
+ def self.test_method_name(query, method_name)
28
+ case
29
+ when query == ""
30
+ true
31
+ else
32
+ method_name.to_s.upcase.include?(query.upcase)
33
+ end
34
+ end
35
+
36
+ def query_symbol(query, assignment:)
37
+ symbols = []
38
+
39
+ indexes.each do |index|
40
+ index.each_entry do |entry|
41
+ case entry
42
+ when RBSIndex::TypeEntry
43
+ next unless SignatureSymbolProvider.test_type_name(query, entry.type_name)
44
+
45
+ container_name = entry.type_name.namespace.relative!.to_s.delete_suffix("::")
46
+ name = entry.type_name.name.to_s
47
+
48
+ entry.declarations.each do |decl|
49
+ next unless assignment =~ decl.location.buffer.name
50
+
51
+ case decl
52
+ when RBS::AST::Declarations::Class
53
+ symbols << SymbolInformation.new(
54
+ name: name,
55
+ location: decl.location,
56
+ kind: LSP::Constant::SymbolKind::CLASS,
57
+ container_name: container_name
58
+ )
59
+ when RBS::AST::Declarations::Module
60
+ symbols << SymbolInformation.new(
61
+ name: name,
62
+ location: decl.location,
63
+ kind: LSP::Constant::SymbolKind::MODULE,
64
+ container_name: container_name
65
+ )
66
+ when RBS::AST::Declarations::Interface
67
+ symbols << SymbolInformation.new(
68
+ name: name,
69
+ location: decl.location,
70
+ kind: LSP::Constant::SymbolKind::INTERFACE,
71
+ container_name: container_name
72
+ )
73
+ when RBS::AST::Declarations::Alias
74
+ symbols << SymbolInformation.new(
75
+ name: name,
76
+ location: decl.location,
77
+ kind: LSP::Constant::SymbolKind::ENUM,
78
+ container_name: container_name
79
+ )
80
+ end
81
+ end
82
+ when RBSIndex::MethodEntry
83
+ next unless SignatureSymbolProvider.test_method_name(query, entry.method_name)
84
+
85
+ name = case entry.method_name
86
+ when InstanceMethodName
87
+ "##{entry.method_name.method_name}"
88
+ when SingletonMethodName
89
+ ".#{entry.method_name.method_name}"
90
+ end
91
+ container_name = entry.method_name.type_name.relative!.to_s
92
+
93
+ entry.declarations.each do |decl|
94
+ next unless assignment =~ decl.location.buffer.name
95
+
96
+ case decl
97
+ when RBS::AST::Members::MethodDefinition
98
+ symbols << SymbolInformation.new(
99
+ name: name,
100
+ location: decl.location,
101
+ kind: LSP::Constant::SymbolKind::METHOD,
102
+ container_name: container_name
103
+ )
104
+ when RBS::AST::Members::Alias
105
+ symbols << SymbolInformation.new(
106
+ name: name,
107
+ location: decl.location,
108
+ kind: LSP::Constant::SymbolKind::METHOD,
109
+ container_name: container_name
110
+ )
111
+ when RBS::AST::Members::AttrAccessor, RBS::AST::Members::AttrReader, RBS::AST::Members::AttrWriter
112
+ symbols << SymbolInformation.new(
113
+ name: name,
114
+ location: decl.location,
115
+ kind: LSP::Constant::SymbolKind::PROPERTY,
116
+ container_name: container_name
117
+ )
118
+
119
+ if decl.ivar_name
120
+ symbols << SymbolInformation.new(
121
+ name: decl.ivar_name.to_s,
122
+ location: decl.location,
123
+ kind: LSP::Constant::SymbolKind::FIELD,
124
+ container_name: container_name
125
+ )
126
+ end
127
+ end
128
+ end
129
+ when RBSIndex::ConstantEntry
130
+ next unless SignatureSymbolProvider.test_const_name(query, entry.const_name)
131
+
132
+ entry.declarations.each do |decl|
133
+ next unless assignment =~ decl.location.buffer.name
134
+
135
+ symbols << SymbolInformation.new(
136
+ name: entry.const_name.name.to_s,
137
+ location: decl.location,
138
+ kind: LSP::Constant::SymbolKind::CONSTANT,
139
+ container_name: entry.const_name.namespace.relative!.to_s.delete_suffix("::")
140
+ )
141
+ end
142
+ when RBSIndex::GlobalEntry
143
+ next unless SignatureSymbolProvider.test_global_name(query, entry.global_name)
144
+
145
+ entry.declarations.each do |decl|
146
+ next unless assignment =~ decl.location.buffer.name
147
+
148
+ symbols << SymbolInformation.new(
149
+ name: decl.name.to_s,
150
+ location: decl.location,
151
+ kind: LSP::Constant::SymbolKind::VARIABLE
152
+ )
153
+ end
154
+ end
155
+ end
156
+ end
157
+
158
+ symbols.uniq {|symbol| [symbol.name, symbol.location] }.sort_by {|symbol| symbol.name.to_s }
159
+ end
160
+ end
161
+ end
162
+ end
@@ -0,0 +1,100 @@
1
+ module Steep
2
+ module Index
3
+ class SourceIndex
4
+ class ConstantEntry
5
+ attr_reader :name
6
+
7
+ attr_reader :definitions
8
+ attr_reader :references
9
+
10
+ def initialize(name:)
11
+ @name = name
12
+
13
+ @definitions = Set[].compare_by_identity
14
+ @references = Set[].compare_by_identity
15
+ end
16
+
17
+ def add_definition(node)
18
+ case node.type
19
+ when :casgn, :class, :module
20
+ @definitions << node
21
+ else
22
+ raise "Unexpected constant definition: #{node.type}"
23
+ end
24
+
25
+ self
26
+ end
27
+
28
+ def add_reference(node)
29
+ case node.type
30
+ when :const
31
+ @references << node
32
+ else
33
+ raise "Unexpected constant reference: #{node.type}"
34
+ end
35
+
36
+ self
37
+ end
38
+
39
+ def merge!(other)
40
+ definitions.merge(other.definitions)
41
+ references.merge(other.references)
42
+ self
43
+ end
44
+ end
45
+
46
+ attr_reader :source
47
+ attr_reader :constant_index
48
+
49
+ attr_reader :parent
50
+ attr_reader :count
51
+ attr_reader :parent_count
52
+
53
+ def initialize(source:, parent: nil)
54
+ @source = source
55
+ @parent = parent
56
+ @parent_count = parent&.count
57
+
58
+ @count = @parent_count || 0
59
+
60
+ @constant_index = {}
61
+ end
62
+
63
+ def new_child
64
+ SourceIndex.new(source: source, parent: self)
65
+ end
66
+
67
+ def merge!(child)
68
+ raise unless child.parent == self
69
+ raise unless child.parent_count == count
70
+
71
+ constant_index.merge!(child.constant_index) do |_, entry, child_entry|
72
+ entry.merge!(child_entry)
73
+ end
74
+
75
+ @count = child.count + 1
76
+ end
77
+
78
+ def add_definition(constant:, definition:)
79
+ @count += 1
80
+ entry(constant: constant).add_definition(definition)
81
+ self
82
+ end
83
+
84
+ def add_reference(constant:, ref:)
85
+ @count += 1
86
+ entry(constant: constant).add_reference(ref)
87
+ self
88
+ end
89
+
90
+ def entry(constant:)
91
+ case
92
+ when constant
93
+ constant_index[constant] ||= ConstantEntry.new(name: constant)
94
+ else
95
+ raise
96
+ end
97
+ end
98
+ end
99
+ end
100
+ end
data/lib/steep/project.rb CHANGED
@@ -42,35 +42,5 @@ module Steep
42
42
  ]
43
43
  end
44
44
  end
45
-
46
- def all_source_files
47
- targets.each.with_object(Set[]) do |target, paths|
48
- paths.merge(target.source_files.keys)
49
- end
50
- end
51
-
52
- def type_of_node(path:, line:, column:)
53
- source_file = targets.map {|target| target.source_files[path] }.compact[0]
54
-
55
- if source_file
56
-
57
- case (status = source_file.status)
58
- when SourceFile::TypeCheckStatus
59
- node = status.source.find_node(line: line, column: column)
60
-
61
- type = begin
62
- status.typing.type_of(node: node)
63
- rescue RuntimeError
64
- AST::Builtin.any_type
65
- end
66
-
67
- if block_given?
68
- yield type, node
69
- else
70
- type
71
- end
72
- end
73
- end
74
- end
75
45
  end
76
46
  end
@@ -120,11 +120,13 @@ module Steep
120
120
 
121
121
  target.instance_eval(&block) if block_given?
122
122
 
123
+ source_pattern = Pattern.new(patterns: target.sources, ignores: target.ignored_sources, ext: ".rb")
124
+ signature_pattern = Pattern.new(patterns: target.signatures, ext: ".rbs")
125
+
123
126
  Project::Target.new(
124
127
  name: target.name,
125
- source_patterns: target.sources,
126
- ignore_patterns: target.ignored_sources,
127
- signature_patterns: target.signatures,
128
+ source_pattern: source_pattern,
129
+ signature_pattern: signature_pattern,
128
130
  options: Options.new.tap do |options|
129
131
  options.libraries.push(*target.libraries)
130
132
  options.repository_paths.push(*target.repo_paths)
@@ -40,13 +40,13 @@ module Steep
40
40
 
41
41
  def error_to_report?(error)
42
42
  case
43
- when error.is_a?(Errors::FallbackAny)
43
+ when error.is_a?(Diagnostic::Ruby::FallbackAny)
44
44
  !allow_fallback_any
45
- when error.is_a?(Errors::MethodDefinitionMissing)
45
+ when error.is_a?(Diagnostic::Ruby::MethodDefinitionMissing)
46
46
  !allow_missing_definitions
47
- when error.is_a?(Errors::NoMethod)
47
+ when error.is_a?(Diagnostic::Ruby::NoMethod)
48
48
  !allow_unknown_method_calls
49
- when error.is_a?(Errors::UnknownConstantAssigned)
49
+ when error.is_a?(Diagnostic::Ruby::UnknownConstantAssigned)
50
50
  !allow_unknown_constant_assignment
51
51
  else
52
52
  true
@@ -0,0 +1,56 @@
1
+ module Steep
2
+ class Project
3
+ class Pattern
4
+ attr_reader :patterns
5
+ attr_reader :ignores
6
+ attr_reader :prefixes
7
+ attr_reader :ignore_prefixes
8
+ attr_reader :ext
9
+
10
+ def initialize(patterns:, ignores: [], ext:)
11
+ @patterns = patterns
12
+ @ignores = ignores
13
+ @ext = ext
14
+
15
+ @prefixes = patterns.map do |pat|
16
+ if pat == "." || pat == "./"
17
+ ""
18
+ else
19
+ pat.delete_prefix("./").delete_suffix(File::Separator) << File::Separator
20
+ end
21
+ end
22
+ @ignore_prefixes = ignores.map do |pat|
23
+ if pat == "." || pat == "./"
24
+ ""
25
+ else
26
+ pat.delete_prefix("./").delete_suffix(File::Separator) << File::Separator
27
+ end
28
+ end
29
+ end
30
+
31
+ def =~(path)
32
+ unless path.is_a?(Pathname)
33
+ path = Pathname(path.to_s)
34
+ end
35
+
36
+ match?(path) && !ignore?(path)
37
+ end
38
+
39
+ def match?(path)
40
+ test_string(path, patterns, prefixes)
41
+ end
42
+
43
+ def ignore?(path)
44
+ test_string(path, ignores, ignore_prefixes)
45
+ end
46
+
47
+ def test_string(path, patterns, prefixes)
48
+ string = path.to_s
49
+ extension = path.extname
50
+
51
+ patterns.any? {|pat| File.fnmatch(pat, string) } ||
52
+ prefixes.any? {|prefix| string.start_with?(prefix) && extension == ext }
53
+ end
54
+ end
55
+ end
56
+ end
@@ -4,114 +4,29 @@ module Steep
4
4
  attr_reader :name
5
5
  attr_reader :options
6
6
 
7
- attr_reader :source_patterns
8
- attr_reader :ignore_patterns
9
- attr_reader :signature_patterns
7
+ attr_reader :source_pattern
8
+ attr_reader :signature_pattern
10
9
 
11
- attr_reader :source_files
12
- attr_reader :signature_files
13
-
14
- attr_reader :status
15
-
16
- SignatureSyntaxErrorStatus = Struct.new(:timestamp, :errors, keyword_init: true)
17
- SignatureValidationErrorStatus = Struct.new(:timestamp, :errors, keyword_init: true)
18
- SignatureOtherErrorStatus = Struct.new(:timestamp, :error, keyword_init: true)
19
- TypeCheckStatus = Struct.new(:environment, :subtyping, :type_check_sources, :timestamp, keyword_init: true)
20
-
21
- def initialize(name:, options:, source_patterns:, ignore_patterns:, signature_patterns:)
10
+ def initialize(name:, options:, source_pattern:, signature_pattern:)
22
11
  @name = name
23
12
  @options = options
24
- @source_patterns = source_patterns
25
- @ignore_patterns = ignore_patterns
26
- @signature_patterns = signature_patterns
13
+ @source_pattern = source_pattern
14
+ @signature_pattern = signature_pattern
27
15
 
28
16
  @source_files = {}
29
17
  @signature_files = {}
30
18
  end
31
19
 
32
- def add_source(path, content = "")
33
- file = SourceFile.new(path: path)
34
-
35
- if block_given?
36
- file.content = yield
37
- else
38
- file.content = content
39
- end
40
-
41
- source_files[path] = file
42
- end
43
-
44
- def remove_source(path)
45
- source_files.delete(path)
46
- end
47
-
48
- def update_source(path, content = nil)
49
- file = source_files[path]
50
- if block_given?
51
- file.content = yield(file.content)
52
- else
53
- file.content = content || file.content
54
- end
55
- end
56
-
57
- def add_signature(path, content = "")
58
- file = SignatureFile.new(path: path)
59
- if block_given?
60
- file.content = yield
61
- else
62
- file.content = content
63
- end
64
- signature_files[path] = file
65
- end
66
-
67
- def remove_signature(path)
68
- signature_files.delete(path)
69
- end
70
-
71
- def update_signature(path, content = nil)
72
- file = signature_files[path]
73
- if block_given?
74
- file.content = yield(file.content)
75
- else
76
- file.content = content || file.content
77
- end
78
- end
79
-
80
- def source_file?(path)
81
- source_files.key?(path)
82
- end
83
-
84
- def signature_file?(path)
85
- signature_files.key?(path)
86
- end
87
-
88
20
  def possible_source_file?(path)
89
- self.class.test_pattern(source_patterns, path, ext: ".rb") &&
90
- !self.class.test_pattern(ignore_patterns, path, ext: ".rb")
21
+ source_pattern =~ path
91
22
  end
92
23
 
93
24
  def possible_signature_file?(path)
94
- self.class.test_pattern(signature_patterns, path, ext: ".rbs")
25
+ signature_pattern =~ path
95
26
  end
96
27
 
97
- def self.test_pattern(patterns, path, ext:)
98
- patterns.any? do |pattern|
99
- p = pattern.end_with?(File::Separator) ? pattern : pattern + File::Separator
100
- p.delete_prefix!('./')
101
- (path.to_s.start_with?(p) && path.extname == ext) || File.fnmatch(pattern, path.to_s)
102
- end
103
- end
104
-
105
- def type_check(target_sources: source_files.values, validate_signatures: true)
106
- Steep.logger.tagged "target#type_check(target_sources: [#{target_sources.map(&:path).join(", ")}], validate_signatures: #{validate_signatures})" do
107
- Steep.measure "load signature and type check" do
108
- load_signatures(validate: validate_signatures) do |env, check, timestamp|
109
- Steep.measure "type checking #{target_sources.size} files" do
110
- run_type_check(env, check, timestamp, target_sources: target_sources)
111
- end
112
- end
113
- end
114
- end
28
+ def new_env_loader
29
+ Target.construct_env_loader(options: options)
115
30
  end
116
31
 
117
32
  def self.construct_env_loader(options:)
@@ -132,126 +47,6 @@ module Steep
132
47
 
133
48
  loader
134
49
  end
135
-
136
- def environment
137
- @environment ||= RBS::Environment.from_loader(Target.construct_env_loader(options: options))
138
- end
139
-
140
- def load_signatures(validate:)
141
- timestamp = case status
142
- when TypeCheckStatus
143
- status.timestamp
144
- end
145
- now = Time.now
146
-
147
- updated_files = []
148
-
149
- signature_files.each_value do |file|
150
- if !timestamp || file.content_updated_at >= timestamp
151
- updated_files << file
152
- file.load!()
153
- end
154
- end
155
-
156
- if signature_files.each_value.all? {|file| file.status.is_a?(SignatureFile::DeclarationsStatus) }
157
- if status.is_a?(TypeCheckStatus) && updated_files.empty?
158
- yield status.environment, status.subtyping, status.timestamp
159
- else
160
- begin
161
- env = environment.dup
162
-
163
- signature_files.each_value do |file|
164
- if file.status.is_a?(SignatureFile::DeclarationsStatus)
165
- file.status.declarations.each do |decl|
166
- env << decl
167
- end
168
- end
169
- end
170
-
171
- env = env.resolve_type_names
172
-
173
- definition_builder = RBS::DefinitionBuilder.new(env: env)
174
- factory = AST::Types::Factory.new(builder: definition_builder)
175
- check = Subtyping::Check.new(factory: factory)
176
-
177
- if validate
178
- validator = Signature::Validator.new(checker: check)
179
- validator.validate()
180
-
181
- if validator.no_error?
182
- yield env, check, now
183
- else
184
- @status = SignatureValidationErrorStatus.new(
185
- errors: validator.each_error.to_a,
186
- timestamp: now
187
- )
188
- end
189
- else
190
- yield env, check, Time.now
191
- end
192
- rescue RBS::DuplicatedDeclarationError => exn
193
- @status = SignatureValidationErrorStatus.new(
194
- errors: [
195
- Signature::Errors::DuplicatedDefinitionError.new(
196
- name: exn.name,
197
- location: exn.decls[0].location
198
- )
199
- ],
200
- timestamp: now
201
- )
202
- rescue => exn
203
- Steep.log_error exn
204
- @status = SignatureOtherErrorStatus.new(error: exn, timestamp: now)
205
- end
206
- end
207
-
208
- else
209
- errors = signature_files.each_value.with_object([]) do |file, errors|
210
- if file.status.is_a?(SignatureFile::ParseErrorStatus)
211
- errors << file.status.error
212
- end
213
- end
214
-
215
- @status = SignatureSyntaxErrorStatus.new(
216
- errors: errors,
217
- timestamp: Time.now
218
- )
219
- end
220
- end
221
-
222
- def run_type_check(env, check, timestamp, target_sources: source_files.values)
223
- type_check_sources = []
224
-
225
- target_sources.each do |file|
226
- Steep.logger.tagged("path=#{file.path}") do
227
- if file.type_check(check, timestamp)
228
- type_check_sources << file
229
- end
230
- end
231
- end
232
-
233
- @status = TypeCheckStatus.new(
234
- environment: env,
235
- subtyping: check,
236
- type_check_sources: type_check_sources,
237
- timestamp: timestamp
238
- )
239
- end
240
-
241
- def no_error?
242
- source_files.all? do |_, file|
243
- file.status.is_a?(Project::SourceFile::TypeCheckStatus)
244
- end
245
- end
246
-
247
- def errors
248
- case status
249
- when TypeCheckStatus
250
- source_files.each_value.flat_map(&:errors).select { |error | options.error_to_report?(error) }
251
- else
252
- []
253
- end
254
- end
255
50
  end
256
51
  end
257
52
  end