steep 0.43.1 → 0.46.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 (109) hide show
  1. checksums.yaml +4 -4
  2. data/.github/dependabot.yml +8 -0
  3. data/.github/workflows/ruby.yml +4 -2
  4. data/.gitignore +0 -1
  5. data/CHANGELOG.md +41 -0
  6. data/Gemfile +0 -1
  7. data/Gemfile.lock +77 -0
  8. data/bin/output_test.rb +8 -2
  9. data/lib/steep/ast/builtin.rb +7 -1
  10. data/lib/steep/ast/types/factory.rb +19 -25
  11. data/lib/steep/cli.rb +7 -1
  12. data/lib/steep/diagnostic/lsp_formatter.rb +59 -6
  13. data/lib/steep/diagnostic/ruby.rb +188 -60
  14. data/lib/steep/diagnostic/signature.rb +34 -0
  15. data/lib/steep/drivers/check.rb +3 -0
  16. data/lib/steep/drivers/init.rb +10 -3
  17. data/lib/steep/drivers/utils/driver_helper.rb +15 -0
  18. data/lib/steep/drivers/validate.rb +1 -1
  19. data/lib/steep/drivers/watch.rb +3 -0
  20. data/lib/steep/equatable.rb +21 -0
  21. data/lib/steep/index/source_index.rb +55 -5
  22. data/lib/steep/interface/block.rb +4 -0
  23. data/lib/steep/interface/function.rb +798 -579
  24. data/lib/steep/project/dsl.rb +105 -33
  25. data/lib/steep/project/options.rb +12 -53
  26. data/lib/steep/project/target.rb +21 -8
  27. data/lib/steep/server/interaction_worker.rb +239 -20
  28. data/lib/steep/server/master.rb +22 -1
  29. data/lib/steep/server/type_check_worker.rb +74 -9
  30. data/lib/steep/services/file_loader.rb +26 -19
  31. data/lib/steep/services/goto_service.rb +322 -0
  32. data/lib/steep/services/hover_content.rb +132 -80
  33. data/lib/steep/services/type_check_service.rb +25 -0
  34. data/lib/steep/source.rb +7 -10
  35. data/lib/steep/type_construction.rb +496 -518
  36. data/lib/steep/type_inference/block_params.rb +2 -5
  37. data/lib/steep/type_inference/method_params.rb +483 -0
  38. data/lib/steep/type_inference/send_args.rb +610 -128
  39. data/lib/steep/typing.rb +46 -21
  40. data/lib/steep/version.rb +1 -1
  41. data/lib/steep.rb +4 -1
  42. data/sample/Steepfile +10 -3
  43. data/sig/steep/type_inference/send_args.rbs +42 -0
  44. data/smoke/alias/Steepfile +2 -1
  45. data/smoke/and/Steepfile +2 -1
  46. data/smoke/array/Steepfile +2 -1
  47. data/smoke/array/test_expectations.yml +3 -3
  48. data/smoke/block/Steepfile +2 -2
  49. data/smoke/block/c.rb +0 -1
  50. data/smoke/case/Steepfile +2 -1
  51. data/smoke/class/Steepfile +2 -1
  52. data/smoke/class/test_expectations.yml +12 -15
  53. data/smoke/const/Steepfile +2 -1
  54. data/smoke/const/test_expectations.yml +0 -10
  55. data/smoke/diagnostics/Steepfile +2 -1
  56. data/smoke/diagnostics/a.rbs +0 -4
  57. data/smoke/diagnostics/different_method_parameter_kind.rb +9 -0
  58. data/smoke/diagnostics/method_arity_mismatch.rb +2 -2
  59. data/smoke/diagnostics/method_parameter_mismatch.rb +10 -0
  60. data/smoke/diagnostics/test_expectations.yml +108 -57
  61. data/smoke/diagnostics-rbs/Steepfile +1 -1
  62. data/smoke/diagnostics-rbs/mixin-class-error.rbs +6 -0
  63. data/smoke/diagnostics-rbs/test_expectations.yml +12 -0
  64. data/smoke/diagnostics-rbs-duplicated/Steepfile +2 -1
  65. data/smoke/diagnostics-ruby-unsat/Steepfile +6 -0
  66. data/smoke/diagnostics-ruby-unsat/a.rbs +3 -0
  67. data/smoke/diagnostics-ruby-unsat/test_expectations.yml +27 -0
  68. data/smoke/{diagnostics → diagnostics-ruby-unsat}/unsatisfiable_constraint.rb +0 -1
  69. data/smoke/dstr/Steepfile +2 -1
  70. data/smoke/ensure/Steepfile +2 -1
  71. data/smoke/ensure/test_expectations.yml +3 -3
  72. data/smoke/enumerator/Steepfile +2 -1
  73. data/smoke/enumerator/test_expectations.yml +1 -1
  74. data/smoke/extension/Steepfile +2 -1
  75. data/smoke/hash/Steepfile +2 -1
  76. data/smoke/hello/Steepfile +2 -1
  77. data/smoke/if/Steepfile +2 -1
  78. data/smoke/implements/Steepfile +2 -1
  79. data/smoke/initialize/Steepfile +2 -1
  80. data/smoke/integer/Steepfile +2 -1
  81. data/smoke/interface/Steepfile +2 -1
  82. data/smoke/kwbegin/Steepfile +2 -1
  83. data/smoke/lambda/Steepfile +2 -1
  84. data/smoke/literal/Steepfile +2 -1
  85. data/smoke/literal/test_expectations.yml +2 -2
  86. data/smoke/map/Steepfile +2 -1
  87. data/smoke/method/Steepfile +2 -1
  88. data/smoke/method/test_expectations.yml +11 -10
  89. data/smoke/module/Steepfile +2 -1
  90. data/smoke/regexp/Steepfile +2 -1
  91. data/smoke/regression/Steepfile +2 -1
  92. data/smoke/regression/issue_372.rb +8 -0
  93. data/smoke/regression/issue_372.rbs +4 -0
  94. data/smoke/regression/test_expectations.yml +0 -12
  95. data/smoke/rescue/Steepfile +2 -1
  96. data/smoke/rescue/test_expectations.yml +3 -3
  97. data/smoke/self/Steepfile +2 -1
  98. data/smoke/skip/Steepfile +2 -1
  99. data/smoke/stdout/Steepfile +2 -1
  100. data/smoke/super/Steepfile +2 -1
  101. data/smoke/toplevel/Steepfile +2 -1
  102. data/smoke/toplevel/test_expectations.yml +3 -3
  103. data/smoke/tsort/Steepfile +4 -5
  104. data/smoke/tsort/test_expectations.yml +2 -2
  105. data/smoke/type_case/Steepfile +2 -1
  106. data/smoke/unexpected/Steepfile +2 -1
  107. data/smoke/yield/Steepfile +2 -1
  108. data/steep.gemspec +2 -2
  109. metadata +24 -10
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 7af0aaa9c4c7b0dd2bae9104603131370d976133d866e3d7760c4b2fa581e694
4
- data.tar.gz: eb1421e3b07c1f06e427073bb72d55138eda935e2269874f5727eecb035a00fb
3
+ metadata.gz: e43c16938ef0238a9b3e44934a3e183ec663722b4c1161f9bd016dfcd2442b9b
4
+ data.tar.gz: 20168ebc69417b83c9eff010d44aac53ac43f47c572c8acc99d52d08ec11866d
5
5
  SHA512:
6
- metadata.gz: 815776632903ca2679af4ae7e7b4a22fa4388956b56706b862f21d76bea6edbbb928d8423504a99a352db71bf7d777e1148a57fe803b582814f1f1526cc45358
7
- data.tar.gz: 70839258fe699f8b246b66cf5e865cb33a9231b5d34e12b40f880bc6b3c50566fe53e0df74645785a3bf1091cbbe34ad4e216ac9d37fdcc3bb3ef32532ab5363
6
+ metadata.gz: 33c2bd116ea87f549ffb29fbc2382e7c000405a74280fcc4a1a8553ae52e6b7af3d5611a150c828d494fe50f37e120e58e45f286bd374bbd35958ee0c760c872
7
+ data.tar.gz: 0466f3f59d18bf0ba34ce522bc6a1cceed85c1f6ca4df66b6647a557bec165c64dd9d594f673833dc24a0b5a9d0eb04795bff37dc391e22cf560b566c6f08319
@@ -0,0 +1,8 @@
1
+ version: 2
2
+ updates:
3
+ - package-ecosystem: bundler
4
+ directory: "/"
5
+ schedule:
6
+ interval: daily
7
+ time: "20:00"
8
+ open-pull-requests-limit: 10
@@ -12,8 +12,10 @@ jobs:
12
12
  strategy:
13
13
  matrix:
14
14
  container_tag:
15
- - 2.6.5-bionic
16
- - 2.7.0-bionic
15
+ - "2.6"
16
+ - "2.7"
17
+ - "3.0"
18
+ - "master-nightly-focal"
17
19
  task:
18
20
  - test
19
21
  - test:output
data/.gitignore CHANGED
@@ -1,6 +1,5 @@
1
1
  /.bundle/
2
2
  /.yardoc
3
- /Gemfile.lock
4
3
  /_yardoc/
5
4
  /coverage/
6
5
  /doc/
data/CHANGELOG.md CHANGED
@@ -2,6 +2,47 @@
2
2
 
3
3
  ## master
4
4
 
5
+ ## 0.46.0 (2021-08-30)
6
+
7
+ This release updates Steepfile DSL syntax, introducing `stdlib_path` and `configure_code_diagnostics` syntax (methods).
8
+
9
+ * `stdlib_path` allows configuring core/stdlib RBS file locations.
10
+ * `configure_code_diagnostics` allows configuring _severity_ of each type errors.
11
+
12
+ See the PRs for the explanation of these methods.
13
+ You can try `steep init` to generate updated `Steepfile` template.
14
+
15
+ * Flexible diagnostics configuration ([\#422](https://github.com/soutaro/steep/pull/422), [\#423](https://github.com/soutaro/steep/pull/423))
16
+ * Revise Steepfile _path_ DSL ([\#421](https://github.com/soutaro/steep/pull/421))
17
+ * Avoid to stop process by invalid jobs_count ([\#419](https://github.com/soutaro/steep/pull/419))
18
+ * Fix `Steep::Typing::UnknownNodeError` when hover method with numblock ([\#415](https://github.com/soutaro/steep/pull/415))
19
+
20
+ ## 0.45.0 (2021-08-22)
21
+
22
+ * Fix error reporting on `RBS::MixinClassError` ([\#411](https://github.com/soutaro/steep/pull/411))
23
+ * Compact error reporting for method body type mismatch ([\#414](https://github.com/soutaro/steep/pull/414))
24
+ * Fix NoMethodError with csend/numblock ([\#412](https://github.com/soutaro/steep/pull/412))
25
+ * LSP completion for RBS files ([\#404](https://github.com/soutaro/steep/pull/404))
26
+ * Allow break without value from bot methods ([\#398](https://github.com/soutaro/steep/pull/398))
27
+ * Type check on lvar assignments ([\#390](https://github.com/soutaro/steep/pull/390))
28
+ * Assign different error code to break without value ([\#387](https://github.com/soutaro/steep/pull/387))
29
+ * Support Ruby3 Keyword Arguments ([\#386](https://github.com/soutaro/steep/pull/386))
30
+ * LSP hover for RBS files ([\#385](https://github.com/soutaro/steep/pull/385), [\#397](https://github.com/soutaro/steep/pull/397))
31
+ * Fix FileLoader to skip files not matching to the given pattern ([\#382](https://github.com/soutaro/steep/pull/382))
32
+ * Ruby3 support for numbered block parameters and end-less def ([\#381](https://github.com/soutaro/steep/pull/381))
33
+
34
+ ## 0.44.1 (2021-04-23)
35
+
36
+ * Disable goto declaration and goto type declaration (because they are not implemented) ([#377](https://github.com/soutaro/steep/pull/377))
37
+ * Fix goto from block calls ([#378](https://github.com/soutaro/steep/pull/378))
38
+
39
+ ## 0.44.0 (2021-04-22)
40
+
41
+ * Implement LSP go to definition/implementation ([#371](https://github.com/soutaro/steep/pull/371), [#375](https://github.com/soutaro/steep/pull/375))
42
+ * Fix typing on passing optional block ([#373](https://github.com/soutaro/steep/pull/373))
43
+ * Do not crash when completion request `context` is missing ([#370](https://github.com/soutaro/steep/pull/370))
44
+ * Update RBS ([#376](https://github.com/soutaro/steep/pull/376))
45
+
5
46
  ## 0.43.1 (2021-04-01)
6
47
 
7
48
  * Fix LSP `textDocument/didSave` notification handling ([#368](https://github.com/soutaro/steep/issues/368))
data/Gemfile CHANGED
@@ -9,6 +9,5 @@ gem "without_steep_types", path: "test/gems/without_steep_types"
9
9
  gem "rake"
10
10
  gem "minitest", "~> 5.0"
11
11
  gem "racc", "~> 1.4"
12
- gem "minitest-reporters"
13
12
  gem "minitest-hooks"
14
13
  gem "stackprof"
data/Gemfile.lock ADDED
@@ -0,0 +1,77 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ steep (0.46.0)
5
+ activesupport (>= 5.1)
6
+ language_server-protocol (>= 3.15, < 4.0)
7
+ listen (~> 3.0)
8
+ parallel (>= 1.0.0)
9
+ parser (>= 3.0)
10
+ rainbow (>= 2.2.2, < 4.0)
11
+ rbs (>= 1.2.0)
12
+ terminal-table (>= 2, < 4)
13
+
14
+ PATH
15
+ remote: test/gems/with_steep_types
16
+ specs:
17
+ with_steep_types (1.0.0)
18
+
19
+ PATH
20
+ remote: test/gems/without_steep_types
21
+ specs:
22
+ without_steep_types (1.0.0)
23
+
24
+ GEM
25
+ remote: https://rubygems.org/
26
+ specs:
27
+ activesupport (6.1.4.1)
28
+ concurrent-ruby (~> 1.0, >= 1.0.2)
29
+ i18n (>= 1.6, < 2)
30
+ minitest (>= 5.1)
31
+ tzinfo (~> 2.0)
32
+ zeitwerk (~> 2.3)
33
+ ast (2.4.2)
34
+ concurrent-ruby (1.1.9)
35
+ ffi (1.15.3)
36
+ i18n (1.8.10)
37
+ concurrent-ruby (~> 1.0)
38
+ language_server-protocol (3.16.0.2)
39
+ listen (3.7.0)
40
+ rb-fsevent (~> 0.10, >= 0.10.3)
41
+ rb-inotify (~> 0.9, >= 0.9.10)
42
+ minitest (5.14.4)
43
+ minitest-hooks (1.5.0)
44
+ minitest (> 5.3)
45
+ parallel (1.20.1)
46
+ parser (3.0.2.0)
47
+ ast (~> 2.4.1)
48
+ racc (1.5.2)
49
+ rainbow (3.0.0)
50
+ rake (13.0.6)
51
+ rb-fsevent (0.11.0)
52
+ rb-inotify (0.10.1)
53
+ ffi (~> 1.0)
54
+ rbs (1.5.1)
55
+ stackprof (0.2.17)
56
+ terminal-table (3.0.1)
57
+ unicode-display_width (>= 1.1.1, < 3)
58
+ tzinfo (2.0.4)
59
+ concurrent-ruby (~> 1.0)
60
+ unicode-display_width (2.0.0)
61
+ zeitwerk (2.4.2)
62
+
63
+ PLATFORMS
64
+ ruby
65
+
66
+ DEPENDENCIES
67
+ minitest (~> 5.0)
68
+ minitest-hooks
69
+ racc (~> 1.4)
70
+ rake
71
+ stackprof
72
+ steep!
73
+ with_steep_types!
74
+ without_steep_types!
75
+
76
+ BUNDLED WITH
77
+ 2.2.22
data/bin/output_test.rb CHANGED
@@ -16,6 +16,8 @@ end
16
16
 
17
17
  failed_tests = []
18
18
 
19
+ ALLOW_FAILURE = ["diagnostics-ruby-unsat"]
20
+
19
21
  test_dirs.each do |dir|
20
22
  puts "Running test #{dir}..."
21
23
 
@@ -30,8 +32,12 @@ test_dirs.each do |dir|
30
32
  output, status = Open3.capture2(*command, chdir: dir.to_s)
31
33
 
32
34
  unless status.success?
33
- failed_tests << dir.basename
34
- puts " Failed! 🤕"
35
+ unless ALLOW_FAILURE.include?(dir.basename.to_s)
36
+ failed_tests << dir.basename
37
+ puts " Failed! 🤕"
38
+ else
39
+ puts " Failed! 🤕 (ALLOW_FAILURE)"
40
+ end
35
41
  else
36
42
  puts " Succeed! 👍"
37
43
  end
@@ -10,8 +10,14 @@ module Steep
10
10
  @arity = arity
11
11
  end
12
12
 
13
- def instance_type(*args)
13
+ def instance_type(*args, fill_untyped: false)
14
+ if fill_untyped
15
+ (arity - args.size).times do
16
+ args << Builtin.any_type
17
+ end
18
+ end
14
19
  arity == args.size or raise "Mulformed instance type: name=#{module_name}, args=#{args}"
20
+
15
21
  Types::Name::Instance.new(name: module_name, args: args)
16
22
  end
17
23
 
@@ -194,7 +194,7 @@ module Steep
194
194
  end
195
195
 
196
196
  def params(type)
197
- Interface::Function::Params.new(
197
+ Interface::Function::Params.build(
198
198
  required: type.required_positionals.map {|param| type(param.type) },
199
199
  optional: type.optional_positionals.map {|param| type(param.type) },
200
200
  rest: type.rest_positionals&.yield_self {|param| type(param.type) },
@@ -621,12 +621,7 @@ module Steep
621
621
  Interface::MethodType.new(
622
622
  type_params: [],
623
623
  type: Interface::Function.new(
624
- params: Interface::Function::Params.new(required: [AST::Types::Literal.new(value: index)],
625
- optional: [],
626
- rest: nil,
627
- required_keywords: {},
628
- optional_keywords: {},
629
- rest_keywords: nil),
624
+ params: Interface::Function::Params.build(required: [AST::Types::Literal.new(value: index)]),
630
625
  return_type: elem_type,
631
626
  location: nil
632
627
  ),
@@ -643,12 +638,7 @@ module Steep
643
638
  Interface::MethodType.new(
644
639
  type_params: [],
645
640
  type: Interface::Function.new(
646
- params: Interface::Function::Params.new(required: [AST::Types::Literal.new(value: index), elem_type],
647
- optional: [],
648
- rest: nil,
649
- required_keywords: {},
650
- optional_keywords: {},
651
- rest_keywords: nil),
641
+ params: Interface::Function::Params.build(required: [AST::Types::Literal.new(value: index), elem_type]),
652
642
  return_type: elem_type,
653
643
  location: nil
654
644
  ),
@@ -712,12 +702,14 @@ module Steep
712
702
  Interface::MethodType.new(
713
703
  type_params: [],
714
704
  type: Interface::Function.new(
715
- params: Interface::Function::Params.new(required: [key_type],
716
- optional: [],
717
- rest: nil,
718
- required_keywords: {},
719
- optional_keywords: {},
720
- rest_keywords: nil),
705
+ params: Interface::Function::Params.build(
706
+ required: [key_type],
707
+ optional: [],
708
+ rest: nil,
709
+ required_keywords: {},
710
+ optional_keywords: {},
711
+ rest_keywords: nil
712
+ ),
721
713
  return_type: value_type,
722
714
  location: nil
723
715
  ),
@@ -735,12 +727,14 @@ module Steep
735
727
  Interface::MethodType.new(
736
728
  type_params: [],
737
729
  type: Interface::Function.new(
738
- params: Interface::Function::Params.new(required: [key_type, value_type],
739
- optional: [],
740
- rest: nil,
741
- required_keywords: {},
742
- optional_keywords: {},
743
- rest_keywords: nil),
730
+ params: Interface::Function::Params.build(
731
+ required: [key_type, value_type],
732
+ optional: [],
733
+ rest: nil,
734
+ required_keywords: {},
735
+ optional_keywords: {},
736
+ rest_keywords: nil
737
+ ),
744
738
  return_type: value_type,
745
739
  location: nil),
746
740
  block: nil,
data/lib/steep/cli.rb CHANGED
@@ -70,7 +70,7 @@ module Steep
70
70
  default = physical_processor_count + modifier
71
71
  command.jobs_count = default
72
72
  opts.on("-j N", "--jobs=N", "Specify the number of type check workers (defaults: #{default})") do |count|
73
- command.jobs_count = Integer(count)
73
+ command.jobs_count = Integer(count) if Integer(count) > 0
74
74
  end
75
75
  end
76
76
 
@@ -99,6 +99,9 @@ module Steep
99
99
  opts.on("--save-expectations[=PATH]", "Save expectations with current type check result to PATH (or steep_expectations.yml)") do |path|
100
100
  check.save_expectations_path = Pathname(path || "steep_expectations.yml")
101
101
  end
102
+ opts.on("--severity-level=LEVEL", /^error|warning|information|hint$/, "Specify the minimum diagnostic severity to be recognized as an error (defaults: warning): error, warning, information, or hint") do |level|
103
+ check.severity_level = level.to_sym
104
+ end
102
105
  handle_jobs_option check, opts
103
106
  handle_logging_options opts
104
107
  end.parse!(argv)
@@ -155,6 +158,9 @@ module Steep
155
158
  Drivers::Watch.new(stdout: stdout, stderr: stderr).tap do |command|
156
159
  OptionParser.new do |opts|
157
160
  opts.banner = "Usage: steep watch [options] [dirs]"
161
+ opts.on("--severity-level=LEVEL", /^error|warning|information|hint$/, "Specify the minimum diagnostic severity to be recognized as an error (defaults: warning): error, warning, information, or hint") do |level|
162
+ command.severity_level = level.to_sym
163
+ end
158
164
  handle_jobs_option command, opts
159
165
  handle_logging_options opts
160
166
  end.parse!(argv)
@@ -3,13 +3,66 @@ module Steep
3
3
  class LSPFormatter
4
4
  LSP = LanguageServer::Protocol
5
5
 
6
+ attr_reader :config
7
+ attr_reader :default_severity
8
+
9
+ ERROR = :error
10
+ WARNING = :warning
11
+ INFORMATION = :information
12
+ HINT = :hint
13
+
14
+ def initialize(config = {}, default_severity: ERROR)
15
+ @config = config
16
+ @default_severity = default_severity
17
+
18
+ config.each do |klass, severity|
19
+ validate_severity(klass, severity)
20
+ validate_class(klass)
21
+ end
22
+ validate_severity(:default, default_severity)
23
+ end
24
+
25
+ def validate_class(klass)
26
+ unless klass < Diagnostic::Ruby::Base
27
+ raise "Unexpected diagnostics class `#{klass}` given"
28
+ end
29
+ end
30
+
31
+ def validate_severity(klass, severity)
32
+ case severity
33
+ when ERROR, WARNING, INFORMATION, HINT, nil
34
+ # ok
35
+ else
36
+ raise "Unexpected severity `#{severity}` is specified for #{klass}"
37
+ end
38
+ end
39
+
6
40
  def format(diagnostic)
7
- LSP::Interface::Diagnostic.new(
8
- message: diagnostic.full_message,
9
- code: diagnostic.diagnostic_code,
10
- severity: LSP::Constant::DiagnosticSeverity::ERROR,
11
- range: diagnostic.location.as_lsp_range
12
- ).to_hash
41
+ severity = severity_for(diagnostic)
42
+
43
+ if severity
44
+ LSP::Interface::Diagnostic.new(
45
+ message: diagnostic.full_message,
46
+ code: diagnostic.diagnostic_code,
47
+ severity: severity,
48
+ range: diagnostic.location.as_lsp_range
49
+ ).to_hash
50
+ end
51
+ end
52
+
53
+ def severity_for(diagnostic)
54
+ case config.fetch(diagnostic.class, default_severity)
55
+ when ERROR
56
+ LSP::Constant::DiagnosticSeverity::ERROR
57
+ when WARNING
58
+ LSP::Constant::DiagnosticSeverity::WARNING
59
+ when INFORMATION
60
+ LSP::Constant::DiagnosticSeverity::INFORMATION
61
+ when HINT
62
+ LSP::Constant::DiagnosticSeverity::HINT
63
+ when nil
64
+ nil
65
+ end
13
66
  end
14
67
  end
15
68
  end
@@ -71,46 +71,104 @@ module Steep
71
71
  end
72
72
  end
73
73
 
74
- class IncompatibleArguments < Base
74
+ class UnexpectedPositionalArgument < Base
75
75
  attr_reader :node
76
+ attr_reader :method_type
76
77
  attr_reader :method_name
77
- attr_reader :receiver_type
78
- attr_reader :method_types
79
78
 
80
- def initialize(node:, method_name:, receiver_type:, method_types:)
81
- location = case node.type
82
- when :send
83
- node.loc.selector
84
- when :block
85
- node.children[0].yield_self do |node|
86
- node.loc.selector
87
- end
88
- when :super
89
- node.loc.expression
90
- else
91
- Steep.logger.error { "Unexpected node given: #{node.type} (IncompatibleArguments#initialize)"}
92
- node.loc.expression
93
- end
94
- super(node: node, location: location)
95
- @receiver_type = receiver_type
96
- @method_types = method_types
79
+ def initialize(node:, method_name:, method_type:)
80
+ super(node: node)
97
81
  @method_name = method_name
82
+ @method_type = method_type
98
83
  end
99
84
 
100
85
  def header_line
101
- "Cannot find method `#{method_name}` of type `#{receiver_type}` with compatible arity"
86
+ "Unexpected positional argument"
102
87
  end
88
+ end
103
89
 
104
- def detail_lines
105
- StringIO.new.tap do |io|
106
- io.puts "Method types:"
107
- first_type, *rest_types = method_types
108
- defn = " def #{method_name}"
109
- io.puts "#{defn}: #{first_type}"
110
- rest_types.each do |method_type|
111
- io.puts "#{" " * defn.size}| #{method_type}"
112
- end
113
- end.string.chomp
90
+ class InsufficientPositionalArguments < Base
91
+ attr_reader :node
92
+ attr_reader :method_name
93
+ attr_reader :method_type
94
+
95
+ def initialize(node:, method_name:, method_type:)
96
+ send = case node.type
97
+ when :send, :csend
98
+ node
99
+ when :block, :numblock
100
+ node.children[0]
101
+ end
102
+
103
+ loc = if send
104
+ send.loc.selector.with(end_pos: send.loc.expression.end_pos)
105
+ else
106
+ node.loc.expression
107
+ end
108
+
109
+ super(node: node, location: loc)
110
+ @method_name = method_name
111
+ @method_type = method_type
112
+ end
113
+
114
+ def header_line
115
+ "More positional arguments are required"
116
+ end
117
+ end
118
+
119
+ class UnexpectedKeywordArgument < Base
120
+ attr_reader :node
121
+ attr_reader :method_name
122
+ attr_reader :method_type
123
+
124
+ def initialize(node:, method_name:, method_type:)
125
+ loc = case node.type
126
+ when :pair
127
+ node.children[0].location.expression
128
+ when :kwsplat
129
+ node.location.expression
130
+ else
131
+ raise
132
+ end
133
+ super(node: node, location: loc)
134
+ @method_name = method_name
135
+ @method_type = method_type
136
+ end
137
+
138
+ def header_line
139
+ "Unexpected keyword argument"
140
+ end
141
+ end
142
+
143
+ class InsufficientKeywordArguments < Base
144
+ attr_reader :node
145
+ attr_reader :method_name
146
+ attr_reader :method_type
147
+ attr_reader :missing_keywords
148
+
149
+ def initialize(node:, method_name:, method_type:, missing_keywords:)
150
+ send = case node.type
151
+ when :send, :csend
152
+ node
153
+ when :block, :numblock
154
+ node.children[0]
155
+ end
156
+
157
+ loc = if send
158
+ send.loc.selector.with(end_pos: send.loc.expression.end_pos)
159
+ else
160
+ node.loc.expression
161
+ end
162
+
163
+ super(node: node, location: loc)
164
+
165
+ @method_name = method_name
166
+ @method_type = method_type
167
+ @missing_keywords = missing_keywords
168
+ end
169
+
170
+ def header_line
171
+ "More keyword arguments are required: #{missing_keywords.join(", ")}"
114
172
  end
115
173
  end
116
174
 
@@ -292,6 +350,23 @@ module Steep
292
350
  end
293
351
  end
294
352
 
353
+ class ImplicitBreakValueMismatch < Base
354
+ attr_reader :jump_type
355
+ attr_reader :result
356
+
357
+ include ResultPrinter
358
+
359
+ def initialize(node:, jump_type:, result:)
360
+ super(node: node)
361
+ @jump_type = jump_type
362
+ @result = result
363
+ end
364
+
365
+ def header_line
366
+ "Breaking without a value may result an error because a value of type `#{jump_type}` is expected"
367
+ end
368
+ end
369
+
295
370
  class UnexpectedJump < Base
296
371
  def header_line
297
372
  "Cannot jump from here"
@@ -323,6 +398,36 @@ module Steep
323
398
  end
324
399
  end
325
400
 
401
+ class MethodParameterMismatch < Base
402
+ attr_reader :method_param
403
+ attr_reader :method_type
404
+
405
+ def initialize(method_param:, method_type:)
406
+ super(node: method_param.node)
407
+ @method_param = method_param
408
+ @method_type = method_type
409
+ end
410
+
411
+ def header_line
412
+ "The method parameter is incompatible with the declaration `#{method_type}`"
413
+ end
414
+ end
415
+
416
+ class DifferentMethodParameterKind < Base
417
+ attr_reader :method_param
418
+ attr_reader :method_type
419
+
420
+ def initialize(method_param:, method_type:)
421
+ super(node: method_param.node)
422
+ @method_param = method_param
423
+ @method_type = method_type
424
+ end
425
+
426
+ def header_line
427
+ "The method parameter has different kind from the declaration `#{method_type}`"
428
+ end
429
+ end
430
+
326
431
  class IncompatibleMethodTypeAnnotation < Base
327
432
  attr_reader :interface_method
328
433
  attr_reader :annotation_method
@@ -366,7 +471,7 @@ module Steep
366
471
  include ResultPrinter
367
472
 
368
473
  def initialize(node:, expected:, actual:, result:)
369
- super(node: node)
474
+ super(node: node, location: node.loc.name)
370
475
  @expected = expected
371
476
  @actual = actual
372
477
  @result = result
@@ -552,34 +657,6 @@ module Steep
552
657
  end
553
658
  end
554
659
 
555
- class UnexpectedKeyword < Base
556
- attr_reader :unexpected_keywords
557
-
558
- def initialize(node:, unexpected_keywords:)
559
- super(node: node)
560
- @unexpected_keywords = unexpected_keywords
561
- end
562
-
563
- def header_line
564
- keywords = unexpected_keywords.sort.map {|x| "`#{x}`" }
565
- "Cannot specify unexpected keyword arguments: #{keywords.join(", ")}"
566
- end
567
- end
568
-
569
- class MissingKeyword < Base
570
- attr_reader :missing_keywords
571
-
572
- def initialize(node:, missing_keywords:)
573
- super(node: node)
574
- @missing_keywords = missing_keywords
575
- end
576
-
577
- def header_line
578
- keywords = missing_keywords.sort.map {|x| "`#{x}`" }
579
- "Cannot omit required keywords: #{keywords.join(", ")}"
580
- end
581
- end
582
-
583
660
  class UnsupportedSyntax < Base
584
661
  attr_reader :message
585
662
 
@@ -623,6 +700,57 @@ module Steep
623
700
  "SyntaxError: #{message}"
624
701
  end
625
702
  end
703
+
704
+ ALL = ObjectSpace.each_object(Class).with_object([]) do |klass, array|
705
+ if klass < Base
706
+ array << klass
707
+ end
708
+ end
709
+
710
+ def self.all_error
711
+ @all_error ||= ALL.each.with_object({}) do |klass, hash|
712
+ hash[klass] = LSPFormatter::ERROR
713
+ end.freeze
714
+ end
715
+
716
+ def self.default
717
+ @default ||= all_error.merge(
718
+ {
719
+ ImplicitBreakValueMismatch => :warning,
720
+ FallbackAny => :information,
721
+ ElseOnExhaustiveCase => :warning,
722
+ UnknownConstantAssigned => :warning,
723
+ MethodDefinitionMissing => :information
724
+ }
725
+ ).freeze
726
+ end
727
+
728
+ def self.strict
729
+ @strict ||= all_error.merge(
730
+ {
731
+ NoMethod => nil,
732
+ ImplicitBreakValueMismatch => nil,
733
+ FallbackAny => nil,
734
+ ElseOnExhaustiveCase => nil,
735
+ UnknownConstantAssigned => nil,
736
+ MethodDefinitionMissing => nil
737
+ }
738
+ ).freeze
739
+ end
740
+
741
+ def self.lenient
742
+ @lenient ||= all_error.merge(
743
+ {
744
+ NoMethod => nil,
745
+ ImplicitBreakValueMismatch => nil,
746
+ FallbackAny => nil,
747
+ ElseOnExhaustiveCase => nil,
748
+ UnknownConstantAssigned => nil,
749
+ MethodDefinitionMissing => nil,
750
+ UnexpectedJump => nil
751
+ }
752
+ ).freeze
753
+ end
626
754
  end
627
755
  end
628
756
  end