steep 1.5.0.pre.5 → 1.5.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +36 -0
- data/Gemfile.lock +1 -1
- data/README.md +1 -1
- data/lib/steep/ast/node/type_application.rb +5 -3
- data/lib/steep/ast/node/type_assertion.rb +7 -3
- data/lib/steep/ast/types/factory.rb +7 -0
- data/lib/steep/diagnostic/ruby.rb +161 -33
- data/lib/steep/drivers/init.rb +3 -2
- data/lib/steep/node_helper.rb +23 -0
- data/lib/steep/project/dsl.rb +0 -21
- data/lib/steep/server/interaction_worker.rb +13 -0
- data/lib/steep/server/lsp_formatter.rb +13 -0
- data/lib/steep/services/completion_provider.rb +85 -3
- data/lib/steep/services/hover_provider/ruby.rb +1 -1
- data/lib/steep/services/signature_help_provider.rb +100 -5
- data/lib/steep/source.rb +8 -13
- data/lib/steep/type_construction.rb +58 -28
- data/lib/steep/type_inference/logic_type_interpreter.rb +8 -6
- data/lib/steep/type_inference/send_args.rb +9 -1
- data/lib/steep/version.rb +1 -1
- data/sig/steep/ast/node/type_application.rbs +1 -1
- data/sig/steep/ast/node/type_assertion.rbs +1 -1
- data/sig/steep/ast/types/factory.rbs +1 -2
- data/sig/steep/diagnostic/ruby.rbs +28 -6
- data/sig/steep/node_helper.rbs +9 -0
- data/sig/steep/project/dsl.rbs +7 -2
- data/sig/steep/services/completion_provider.rbs +15 -1
- data/sig/steep/services/signature_help_provider.rbs +12 -2
- data/sig/steep/signature/validator.rbs +2 -2
- metadata +4 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 77aea7baf36285cf4a5b0941e63cc8f5f95d52132d3a5d4933a396a79b949721
|
4
|
+
data.tar.gz: 2506370595dde6633abbab74b1e370d435579415a154b4a82b4da3bb1b065627
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6f3190f0ca65a931f9c88d99cbd67836478d754439b5630b1b68f89e9fa6d84a84cc8bde32335d4bdb38b3f13aefaeaf93a75b53722a0b6841eab27e9b689ed8
|
7
|
+
data.tar.gz: 94576f1eedcb8c46ca8228e84e4100e860c0e3ed2a28dc209afa80abdeeed188118f1589dcb15d0a8edb0cd8c751f611035a15b613d284113c8cbebcce42dc6e
|
data/CHANGELOG.md
CHANGED
@@ -2,6 +2,42 @@
|
|
2
2
|
|
3
3
|
## master
|
4
4
|
|
5
|
+
## 1.5.0 (2023-07-13)
|
6
|
+
|
7
|
+
### Type checker core
|
8
|
+
|
9
|
+
* Fix for the case `untyped` is the proc type hint ([#868](https://github.com/soutaro/steep/pull/868))
|
10
|
+
* Type case with type variable ([#869](https://github.com/soutaro/steep/pull/869))
|
11
|
+
* Filx `nil?` unreachability detection ([#867](https://github.com/soutaro/steep/pull/867))
|
12
|
+
|
13
|
+
### Commandline tool
|
14
|
+
|
15
|
+
* Update `#configure_code_diagnostics` type ([#873](https://github.com/soutaro/steep/pull/873))
|
16
|
+
* Update diagnostics templates ([#871](https://github.com/soutaro/steep/pull/871))
|
17
|
+
* Removed "set" from "libray" in init.rb and README ([#870](https://github.com/soutaro/steep/pull/870))
|
18
|
+
|
19
|
+
### Language server
|
20
|
+
|
21
|
+
* Use RBS::Buffer method to calculate position ([#872](https://github.com/soutaro/steep/pull/872))
|
22
|
+
|
23
|
+
## 1.5.0.pre.6 (2023-07-11)
|
24
|
+
|
25
|
+
### Type checker core
|
26
|
+
|
27
|
+
* Report RBS validation errors in Ruby code ([#859](https://github.com/soutaro/steep/pull/859))
|
28
|
+
* Fix proc type assignment ([#858](https://github.com/soutaro/steep/pull/858))
|
29
|
+
* Report `UnexpectedKeywordArgument` even if no keyword param is accepted ([#856](https://github.com/soutaro/steep/pull/856))
|
30
|
+
* Unfold type alias on unwrap optional ([#855](https://github.com/soutaro/steep/pull/855))
|
31
|
+
|
32
|
+
### Language server
|
33
|
+
|
34
|
+
* Keyword completion in block call ([#865](https://github.com/soutaro/steep/pull/865))
|
35
|
+
* Indicate the current or next argument on signature help ([#850](https://github.com/soutaro/steep/pull/850))
|
36
|
+
* Support completion for keyword arguments ([#851](https://github.com/soutaro/steep/pull/851))
|
37
|
+
* Let hover show the type of method call node ([#864](https://github.com/soutaro/steep/pull/864))
|
38
|
+
* Fix UnknownNodeError in SignatureHelp ([#863](https://github.com/soutaro/steep/pull/863))
|
39
|
+
* hover: Fix NoMethodError on generating hover for not supported files ([#853](https://github.com/soutaro/steep/pull/853))
|
40
|
+
|
5
41
|
## 1.5.0.pre.5 (2023-07-07)
|
6
42
|
|
7
43
|
### Type checker core
|
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -37,10 +37,12 @@ module Steep
|
|
37
37
|
ty = ty.map_type_name {|name| resolver.resolve(name, context: context) || name.absolute! }
|
38
38
|
|
39
39
|
validator = Signature::Validator.new(checker: subtyping)
|
40
|
-
validator.
|
40
|
+
validator.rescue_validation_errors do
|
41
|
+
validator.validate_type(ty)
|
42
|
+
end
|
41
43
|
|
42
44
|
if validator.has_error?
|
43
|
-
return
|
45
|
+
return validator.each_error
|
44
46
|
end
|
45
47
|
|
46
48
|
ty = subtyping.factory.type(ty)
|
@@ -58,7 +60,7 @@ module Steep
|
|
58
60
|
|
59
61
|
def types?(context, subtyping, type_vars)
|
60
62
|
case types = types(context, subtyping, type_vars)
|
61
|
-
when RBS::ParsingError
|
63
|
+
when RBS::ParsingError, Enumerator
|
62
64
|
nil
|
63
65
|
else
|
64
66
|
types
|
@@ -22,10 +22,14 @@ module Steep
|
|
22
22
|
ty = ty.map_type_name {|name| resolver.resolve(name, context: context) || name.absolute! }
|
23
23
|
|
24
24
|
validator = Signature::Validator.new(checker: subtyping)
|
25
|
-
validator.
|
25
|
+
validator.rescue_validation_errors do
|
26
|
+
validator.validate_type(ty)
|
27
|
+
end
|
26
28
|
|
27
29
|
unless validator.has_error?
|
28
30
|
subtyping.factory.type(ty)
|
31
|
+
else
|
32
|
+
validator.each_error.to_a
|
29
33
|
end
|
30
34
|
else
|
31
35
|
nil
|
@@ -37,7 +41,7 @@ module Steep
|
|
37
41
|
def type_syntax?
|
38
42
|
RBS::Parser.parse_type(type_location.buffer, range: type_location.range, variables: [], require_eof: true)
|
39
43
|
true
|
40
|
-
rescue::RBS::ParsingError
|
44
|
+
rescue ::RBS::ParsingError
|
41
45
|
false
|
42
46
|
end
|
43
47
|
|
@@ -45,7 +49,7 @@ module Steep
|
|
45
49
|
type = type(context, subtyping, type_vars)
|
46
50
|
|
47
51
|
case type
|
48
|
-
when RBS::ParsingError, nil
|
52
|
+
when RBS::ParsingError, nil, Array
|
49
53
|
nil
|
50
54
|
else
|
51
55
|
type
|
@@ -964,6 +964,19 @@ module Steep
|
|
964
964
|
end
|
965
965
|
end
|
966
966
|
|
967
|
+
class RBSError < Base
|
968
|
+
attr_reader :error
|
969
|
+
|
970
|
+
def initialize(error:, node:, location:)
|
971
|
+
@error = error
|
972
|
+
super(node: node, location: location)
|
973
|
+
end
|
974
|
+
|
975
|
+
def header_line
|
976
|
+
error.header_line
|
977
|
+
end
|
978
|
+
end
|
979
|
+
|
967
980
|
ALL = ObjectSpace.each_object(Class).with_object([]) do |klass, array|
|
968
981
|
if klass < Base
|
969
982
|
array << klass
|
@@ -979,20 +992,57 @@ module Steep
|
|
979
992
|
def self.default
|
980
993
|
@default ||= _ = all_error.merge(
|
981
994
|
{
|
982
|
-
|
983
|
-
|
984
|
-
|
985
|
-
|
995
|
+
ArgumentTypeMismatch => :error,
|
996
|
+
BlockBodyTypeMismatch => :hint,
|
997
|
+
BlockTypeMismatch => :hint,
|
998
|
+
BreakTypeMismatch => :hint,
|
999
|
+
DifferentMethodParameterKind => :hint,
|
1000
|
+
FallbackAny => :hint,
|
1001
|
+
FalseAssertion => :hint,
|
1002
|
+
ImplicitBreakValueMismatch => :hint,
|
1003
|
+
IncompatibleAnnotation => :hint,
|
1004
|
+
IncompatibleArgumentForwarding => :warning,
|
1005
|
+
IncompatibleAssignment => :hint,
|
1006
|
+
IncompatibleMethodTypeAnnotation => :hint,
|
1007
|
+
IncompatibleTypeCase => :hint,
|
1008
|
+
InsufficientKeywordArguments => :error,
|
1009
|
+
InsufficientPositionalArguments => :error,
|
1010
|
+
InsufficientTypeArgument => :hint,
|
1011
|
+
MethodArityMismatch => :error,
|
1012
|
+
MethodBodyTypeMismatch => :error,
|
1013
|
+
MethodDefinitionMissing => nil,
|
1014
|
+
MethodParameterMismatch => :error,
|
1015
|
+
MethodReturnTypeAnnotationMismatch => :hint,
|
1016
|
+
MultipleAssignmentConversionError => :hint,
|
1017
|
+
NoMethod => :error,
|
1018
|
+
ProcHintIgnored => :hint,
|
1019
|
+
ProcTypeExpected => :hint,
|
1020
|
+
RBSError => :information,
|
1021
|
+
RequiredBlockMissing => :error,
|
1022
|
+
ReturnTypeMismatch => :error,
|
1023
|
+
SetterBodyTypeMismatch => :information,
|
1024
|
+
SetterReturnTypeMismatch => :information,
|
1025
|
+
SyntaxError => :hint,
|
1026
|
+
TypeArgumentMismatchError => :hint,
|
1027
|
+
UnexpectedBlockGiven => :warning,
|
1028
|
+
UnexpectedDynamicMethod => :hint,
|
1029
|
+
UnexpectedError => :hint,
|
1030
|
+
UnexpectedJump => :hint,
|
1031
|
+
UnexpectedJumpValue => :hint,
|
1032
|
+
UnexpectedKeywordArgument => :error,
|
1033
|
+
UnexpectedPositionalArgument => :error,
|
1034
|
+
UnexpectedSplat => :hint,
|
1035
|
+
UnexpectedSuper => :information,
|
1036
|
+
UnexpectedTypeArgument => :hint,
|
1037
|
+
UnexpectedYield => :warning,
|
986
1038
|
UnknownConstant => :warning,
|
987
|
-
|
988
|
-
|
989
|
-
|
990
|
-
|
991
|
-
|
992
|
-
|
993
|
-
|
994
|
-
SetterBodyTypeMismatch => nil,
|
995
|
-
SetterReturnTypeMismatch => nil
|
1039
|
+
UnknownGlobalVariable => :warning,
|
1040
|
+
UnknownInstanceVariable => :information,
|
1041
|
+
UnreachableBranch => :hint,
|
1042
|
+
UnreachableValueBranch => :hint,
|
1043
|
+
UnresolvedOverloading => :error,
|
1044
|
+
UnsatisfiableConstraint => :hint,
|
1045
|
+
UnsupportedSyntax => :hint,
|
996
1046
|
}
|
997
1047
|
).freeze
|
998
1048
|
end
|
@@ -1000,17 +1050,57 @@ module Steep
|
|
1000
1050
|
def self.strict
|
1001
1051
|
@strict ||= _ = all_error.merge(
|
1002
1052
|
{
|
1003
|
-
|
1004
|
-
|
1005
|
-
|
1006
|
-
|
1007
|
-
|
1008
|
-
|
1009
|
-
|
1010
|
-
|
1011
|
-
|
1053
|
+
ArgumentTypeMismatch => :error,
|
1054
|
+
BlockBodyTypeMismatch => :error,
|
1055
|
+
BlockTypeMismatch => :error,
|
1056
|
+
BreakTypeMismatch => :error,
|
1057
|
+
DifferentMethodParameterKind => :error,
|
1058
|
+
FallbackAny => :warning,
|
1059
|
+
FalseAssertion => :error,
|
1060
|
+
ImplicitBreakValueMismatch => :information,
|
1061
|
+
IncompatibleAnnotation => :error,
|
1062
|
+
IncompatibleArgumentForwarding => :error,
|
1063
|
+
IncompatibleAssignment => :error,
|
1064
|
+
IncompatibleMethodTypeAnnotation => :error,
|
1065
|
+
IncompatibleTypeCase => :error,
|
1066
|
+
InsufficientKeywordArguments => :error,
|
1067
|
+
InsufficientPositionalArguments => :error,
|
1068
|
+
InsufficientTypeArgument => :error,
|
1069
|
+
MethodArityMismatch => :error,
|
1070
|
+
MethodBodyTypeMismatch => :error,
|
1071
|
+
MethodDefinitionMissing => :hint,
|
1072
|
+
MethodParameterMismatch => :error,
|
1073
|
+
MethodReturnTypeAnnotationMismatch => :error,
|
1074
|
+
MultipleAssignmentConversionError => :error,
|
1075
|
+
NoMethod => :error,
|
1076
|
+
ProcHintIgnored => :information,
|
1077
|
+
ProcTypeExpected => :error,
|
1078
|
+
RBSError => :error,
|
1079
|
+
RequiredBlockMissing => :error,
|
1080
|
+
ReturnTypeMismatch => :error,
|
1012
1081
|
SetterBodyTypeMismatch => :error,
|
1013
|
-
SetterReturnTypeMismatch => :error
|
1082
|
+
SetterReturnTypeMismatch => :error,
|
1083
|
+
SyntaxError => :hint,
|
1084
|
+
TypeArgumentMismatchError => :error,
|
1085
|
+
UnexpectedBlockGiven => :error,
|
1086
|
+
UnexpectedDynamicMethod => :information,
|
1087
|
+
UnexpectedError => :information,
|
1088
|
+
UnexpectedJump => :error,
|
1089
|
+
UnexpectedJumpValue => :error,
|
1090
|
+
UnexpectedKeywordArgument => :error,
|
1091
|
+
UnexpectedPositionalArgument => :error,
|
1092
|
+
UnexpectedSplat => :warning,
|
1093
|
+
UnexpectedSuper => :error,
|
1094
|
+
UnexpectedTypeArgument => :error,
|
1095
|
+
UnexpectedYield => :error,
|
1096
|
+
UnknownConstant => :error,
|
1097
|
+
UnknownGlobalVariable => :error,
|
1098
|
+
UnknownInstanceVariable => :error,
|
1099
|
+
UnreachableBranch => :information,
|
1100
|
+
UnreachableValueBranch => :warning,
|
1101
|
+
UnresolvedOverloading => :error,
|
1102
|
+
UnsatisfiableConstraint => :error,
|
1103
|
+
UnsupportedSyntax => :information,
|
1014
1104
|
}
|
1015
1105
|
).freeze
|
1016
1106
|
end
|
@@ -1018,19 +1108,57 @@ module Steep
|
|
1018
1108
|
def self.lenient
|
1019
1109
|
@lenient ||= _ = all_error.merge(
|
1020
1110
|
{
|
1021
|
-
|
1022
|
-
|
1111
|
+
ArgumentTypeMismatch => :information,
|
1112
|
+
BlockBodyTypeMismatch => :hint,
|
1113
|
+
BlockTypeMismatch => :hint,
|
1114
|
+
BreakTypeMismatch => :hint,
|
1115
|
+
DifferentMethodParameterKind => nil,
|
1023
1116
|
FallbackAny => nil,
|
1024
|
-
|
1025
|
-
|
1026
|
-
|
1117
|
+
FalseAssertion => nil,
|
1118
|
+
ImplicitBreakValueMismatch => nil,
|
1119
|
+
IncompatibleAnnotation => nil,
|
1120
|
+
IncompatibleArgumentForwarding => :information,
|
1121
|
+
IncompatibleAssignment => :hint,
|
1122
|
+
IncompatibleMethodTypeAnnotation => nil,
|
1123
|
+
IncompatibleTypeCase => nil,
|
1124
|
+
InsufficientKeywordArguments => :information,
|
1125
|
+
InsufficientPositionalArguments => :information,
|
1126
|
+
InsufficientTypeArgument => nil,
|
1127
|
+
MethodArityMismatch => :information,
|
1128
|
+
MethodBodyTypeMismatch => :warning,
|
1027
1129
|
MethodDefinitionMissing => nil,
|
1028
|
-
|
1029
|
-
|
1030
|
-
|
1031
|
-
|
1130
|
+
MethodParameterMismatch => :warning,
|
1131
|
+
MethodReturnTypeAnnotationMismatch => nil,
|
1132
|
+
MultipleAssignmentConversionError => nil,
|
1133
|
+
NoMethod => :information,
|
1134
|
+
ProcHintIgnored => nil,
|
1135
|
+
ProcTypeExpected => nil,
|
1136
|
+
RBSError => :information,
|
1137
|
+
RequiredBlockMissing => :hint,
|
1138
|
+
ReturnTypeMismatch => :warning,
|
1032
1139
|
SetterBodyTypeMismatch => nil,
|
1033
|
-
SetterReturnTypeMismatch => nil
|
1140
|
+
SetterReturnTypeMismatch => nil,
|
1141
|
+
SyntaxError => :hint,
|
1142
|
+
TypeArgumentMismatchError => nil,
|
1143
|
+
UnexpectedBlockGiven => :hint,
|
1144
|
+
UnexpectedDynamicMethod => nil,
|
1145
|
+
UnexpectedError => :hint,
|
1146
|
+
UnexpectedJump => nil,
|
1147
|
+
UnexpectedJumpValue => nil,
|
1148
|
+
UnexpectedKeywordArgument => :information,
|
1149
|
+
UnexpectedPositionalArgument => :information,
|
1150
|
+
UnexpectedSplat => nil,
|
1151
|
+
UnexpectedSuper => nil,
|
1152
|
+
UnexpectedTypeArgument => nil,
|
1153
|
+
UnexpectedYield => :information,
|
1154
|
+
UnknownConstant => :hint,
|
1155
|
+
UnknownGlobalVariable => :hint,
|
1156
|
+
UnknownInstanceVariable => :hint,
|
1157
|
+
UnreachableBranch => :hint,
|
1158
|
+
UnreachableValueBranch => :hint,
|
1159
|
+
UnresolvedOverloading => :information,
|
1160
|
+
UnsatisfiableConstraint => :hint,
|
1161
|
+
UnsupportedSyntax => :hint,
|
1034
1162
|
}
|
1035
1163
|
).freeze
|
1036
1164
|
end
|
data/lib/steep/drivers/init.rb
CHANGED
@@ -18,9 +18,10 @@ module Steep
|
|
18
18
|
# check "app/models/**/*.rb" # Glob
|
19
19
|
# # ignore "lib/templates/*.rb"
|
20
20
|
#
|
21
|
-
# # library "pathname"
|
21
|
+
# # library "pathname" # Standard libraries
|
22
22
|
# # library "strong_json" # Gems
|
23
23
|
#
|
24
|
+
# # configure_code_diagnostics(D::Ruby.default) # `default` diagnostics setting (applies by default)
|
24
25
|
# # configure_code_diagnostics(D::Ruby.strict) # `strict` diagnostics setting
|
25
26
|
# # configure_code_diagnostics(D::Ruby.lenient) # `lenient` diagnostics setting
|
26
27
|
# # configure_code_diagnostics(D::Ruby.silent) # `silent` diagnostics setting
|
@@ -34,7 +35,7 @@ module Steep
|
|
34
35
|
#
|
35
36
|
# check "test"
|
36
37
|
#
|
37
|
-
# # library "pathname"
|
38
|
+
# # library "pathname" # Standard libraries
|
38
39
|
# end
|
39
40
|
EOF
|
40
41
|
|
data/lib/steep/node_helper.rb
CHANGED
@@ -217,5 +217,28 @@ module Steep
|
|
217
217
|
false
|
218
218
|
end
|
219
219
|
end
|
220
|
+
|
221
|
+
def deconstruct_sendish_and_block_nodes(*nodes)
|
222
|
+
send_node, block_node = nodes.take(2)
|
223
|
+
|
224
|
+
if send_node
|
225
|
+
case send_node.type
|
226
|
+
when :send, :csend, :super
|
227
|
+
if block_node
|
228
|
+
case block_node.type
|
229
|
+
when :block, :numblock
|
230
|
+
if send_node.equal?(block_node.children[0])
|
231
|
+
return [send_node, block_node]
|
232
|
+
end
|
233
|
+
end
|
234
|
+
end
|
235
|
+
|
236
|
+
[send_node, nil]
|
237
|
+
when :zsuper
|
238
|
+
# zsuper doesn't receive block
|
239
|
+
[send_node, nil]
|
240
|
+
end
|
241
|
+
end
|
242
|
+
end
|
220
243
|
end
|
221
244
|
end
|
data/lib/steep/project/dsl.rb
CHANGED
@@ -143,27 +143,6 @@ module Steep
|
|
143
143
|
@repo_paths.push(*paths.map {|s| Pathname(s) })
|
144
144
|
end
|
145
145
|
|
146
|
-
# Configure the code diagnostics printing setup.
|
147
|
-
#
|
148
|
-
# Yields a hash, and the update the hash in the block.
|
149
|
-
#
|
150
|
-
# ```rb
|
151
|
-
# D = Steep::Diagnostic
|
152
|
-
#
|
153
|
-
# configure_code_diagnostics do |hash|
|
154
|
-
# # Assign one of :error, :warning, :information, :hint or :nil to error classes.
|
155
|
-
# hash[D::Ruby::UnexpectedPositionalArgument] = :error
|
156
|
-
# end
|
157
|
-
# ```
|
158
|
-
#
|
159
|
-
# Passing a hash is also allowed.
|
160
|
-
#
|
161
|
-
# ```rb
|
162
|
-
# D = Steep::Diagnostic
|
163
|
-
#
|
164
|
-
# configure_code_diagnostics(D::Ruby.lenient)
|
165
|
-
# ```
|
166
|
-
#
|
167
146
|
def configure_code_diagnostics(hash = nil)
|
168
147
|
if hash
|
169
148
|
code_diagnostics_config.merge!(hash)
|
@@ -361,6 +361,17 @@ module Steep
|
|
361
361
|
new_text: item.identifier.to_s
|
362
362
|
)
|
363
363
|
)
|
364
|
+
when Services::CompletionProvider::KeywordArgumentItem
|
365
|
+
LSP::Interface::CompletionItem.new(
|
366
|
+
label: item.identifier.to_s,
|
367
|
+
kind: LSP::Constant::CompletionItemKind::FIELD,
|
368
|
+
label_details: LSP::Interface::CompletionItemLabelDetails.new(description: 'Keyword argument'),
|
369
|
+
documentation: LSPFormatter.markup_content { LSPFormatter.format_completion_docs(item) },
|
370
|
+
text_edit: LSP::Interface::TextEdit.new(
|
371
|
+
range: range,
|
372
|
+
new_text: item.identifier.to_s
|
373
|
+
)
|
374
|
+
)
|
364
375
|
when Services::CompletionProvider::TypeNameItem
|
365
376
|
kind =
|
366
377
|
case
|
@@ -397,6 +408,8 @@ module Steep
|
|
397
408
|
signatures = items.map do |item|
|
398
409
|
LSP::Interface::SignatureInformation.new(
|
399
410
|
label: "(#{item.method_type.type.param_to_s})",
|
411
|
+
parameters: item.parameters.map { |param| LSP::Interface::ParameterInformation.new(label: param)},
|
412
|
+
active_parameter: item.active_parameter,
|
400
413
|
documentation: item.comment&.yield_self do |comment|
|
401
414
|
LSP::Interface::MarkupContent.new(
|
402
415
|
kind: LSP::Constant::MarkupKind::MARKDOWN,
|
@@ -28,7 +28,16 @@ module Steep
|
|
28
28
|
|
29
29
|
case call
|
30
30
|
when TypeInference::MethodCall::Typed
|
31
|
+
io.puts <<~MD
|
32
|
+
```rbs
|
33
|
+
#{call.actual_method_type.type.return_type}
|
34
|
+
```
|
35
|
+
|
36
|
+
----
|
37
|
+
MD
|
38
|
+
|
31
39
|
method_types = call.method_decls.map(&:method_type)
|
40
|
+
|
32
41
|
if call.is_a?(TypeInference::MethodCall::Special)
|
33
42
|
method_types = [
|
34
43
|
call.actual_method_type.with(
|
@@ -250,6 +259,10 @@ module Steep
|
|
250
259
|
end
|
251
260
|
|
252
261
|
io.string
|
262
|
+
when Services::CompletionProvider::KeywordArgumentItem
|
263
|
+
<<~MD
|
264
|
+
**Keyword argument**: `#{item.identifier}`
|
265
|
+
MD
|
253
266
|
end
|
254
267
|
end
|
255
268
|
|
@@ -1,6 +1,8 @@
|
|
1
1
|
module Steep
|
2
2
|
module Services
|
3
3
|
class CompletionProvider
|
4
|
+
include NodeHelper
|
5
|
+
|
4
6
|
Position = _ = Struct.new(:line, :column, keyword_init: true) do
|
5
7
|
# @implements Position
|
6
8
|
def -(size)
|
@@ -11,6 +13,7 @@ module Steep
|
|
11
13
|
Range = _ = Struct.new(:start, :end, keyword_init: true)
|
12
14
|
|
13
15
|
InstanceVariableItem = _ = Struct.new(:identifier, :range, :type, keyword_init: true)
|
16
|
+
KeywordArgumentItem = _ = Struct.new(:identifier, :range, keyword_init: true)
|
14
17
|
LocalVariableItem = _ = Struct.new(:identifier, :range, :type, keyword_init: true)
|
15
18
|
ConstantItem = _ = Struct.new(:env, :identifier, :range, :type, :full_name, keyword_init: true) do
|
16
19
|
# @implements ConstantItem
|
@@ -267,7 +270,9 @@ module Steep
|
|
267
270
|
[]
|
268
271
|
end
|
269
272
|
else
|
270
|
-
[]
|
273
|
+
items = [] #: Array[item]
|
274
|
+
items_for_following_keyword_arguments(source_text, index: index, line: line, column: column, items: items)
|
275
|
+
items
|
271
276
|
end
|
272
277
|
end
|
273
278
|
end
|
@@ -302,10 +307,10 @@ module Steep
|
|
302
307
|
end
|
303
308
|
|
304
309
|
def items_for_trigger(position:)
|
305
|
-
node, *
|
310
|
+
node, *parents = source.find_nodes(line: position.line, column: position.column)
|
306
311
|
node ||= source.node
|
307
312
|
|
308
|
-
return [] unless node
|
313
|
+
return [] unless node && parents
|
309
314
|
|
310
315
|
items = [] #: Array[item]
|
311
316
|
|
@@ -319,6 +324,16 @@ module Steep
|
|
319
324
|
method_items_for_receiver_type(context.self_type, include_private: true, prefix: prefix, position: position, items: items)
|
320
325
|
local_variable_items_for_context(context, position: position, prefix: prefix, items: items)
|
321
326
|
|
327
|
+
if (send_node, block_node = deconstruct_sendish_and_block_nodes(*parents))
|
328
|
+
keyword_argument_items_for_method(
|
329
|
+
call_node: block_node || send_node,
|
330
|
+
send_node: send_node,
|
331
|
+
position: position,
|
332
|
+
prefix: prefix,
|
333
|
+
items: items
|
334
|
+
)
|
335
|
+
end
|
336
|
+
|
322
337
|
when node.type == :lvar && at_end?(position, of: node.loc)
|
323
338
|
# foo ← (lvar)
|
324
339
|
local_variable_items_for_context(context, position: position, prefix: node.children[0].to_s, items: items)
|
@@ -527,6 +542,37 @@ module Steep
|
|
527
542
|
items
|
528
543
|
end
|
529
544
|
|
545
|
+
def items_for_following_keyword_arguments(text, index:, line:, column:, items:)
|
546
|
+
return if text[index - 1] !~ /[a-zA-Z0-9]/
|
547
|
+
|
548
|
+
text = text.dup
|
549
|
+
argname = [] #: Array[String]
|
550
|
+
while text[index - 1] =~ /[a-zA-Z0-9]/
|
551
|
+
argname.unshift(text[index - 1] || '')
|
552
|
+
source_text[index - 1] = " "
|
553
|
+
index -= 1
|
554
|
+
end
|
555
|
+
|
556
|
+
begin
|
557
|
+
type_check!(source_text, line: line, column: column)
|
558
|
+
rescue Parser::SyntaxError
|
559
|
+
return
|
560
|
+
end
|
561
|
+
|
562
|
+
if nodes = source.find_nodes(line: line, column: column)
|
563
|
+
if (send_node, block_node = deconstruct_sendish_and_block_nodes(*nodes))
|
564
|
+
position = Position.new(line: line, column: column)
|
565
|
+
keyword_argument_items_for_method(
|
566
|
+
call_node: block_node || send_node,
|
567
|
+
send_node: send_node,
|
568
|
+
position: position,
|
569
|
+
prefix: argname.join,
|
570
|
+
items: items
|
571
|
+
)
|
572
|
+
end
|
573
|
+
end
|
574
|
+
end
|
575
|
+
|
530
576
|
def method_items_for_receiver_type(type, include_private:, prefix:, position:, items:)
|
531
577
|
range = range_for(position, prefix: prefix)
|
532
578
|
context = typing.context_at(line: position.line, column: position.column)
|
@@ -641,6 +687,42 @@ module Steep
|
|
641
687
|
end
|
642
688
|
end
|
643
689
|
|
690
|
+
def keyword_argument_items_for_method(call_node:, send_node:, position:, prefix:, items:)
|
691
|
+
receiver_node, method_name, argument_nodes = deconstruct_send_node!(send_node)
|
692
|
+
|
693
|
+
call = typing.call_of(node: call_node)
|
694
|
+
|
695
|
+
case call
|
696
|
+
when TypeInference::MethodCall::Typed, TypeInference::MethodCall::Error
|
697
|
+
type = call.receiver_type
|
698
|
+
shape = subtyping.builder.shape(
|
699
|
+
type,
|
700
|
+
public_only: !!receiver_node,
|
701
|
+
config: Interface::Builder::Config.new(self_type: type, class_type: nil, instance_type: nil, variable_bounds: {})
|
702
|
+
)
|
703
|
+
if shape
|
704
|
+
if method = shape.methods[call.method_name]
|
705
|
+
method.method_types.each.with_index do |method_type, i|
|
706
|
+
defn = method_type.method_decls.to_a[0]&.method_def
|
707
|
+
if defn
|
708
|
+
range = range_for(position, prefix: prefix)
|
709
|
+
kwargs = argument_nodes.find { |arg| arg.type == :kwargs }&.children || []
|
710
|
+
used_kwargs = kwargs.filter_map { |arg| arg.type == :pair && arg.children.first.children.first }
|
711
|
+
|
712
|
+
kwargs = defn.type.type.required_keywords.keys + defn.type.type.optional_keywords.keys
|
713
|
+
kwargs.each do |name|
|
714
|
+
if name.to_s.start_with?(prefix) && !used_kwargs.include?(name)
|
715
|
+
items << KeywordArgumentItem.new(identifier: "#{name}:", range: range)
|
716
|
+
end
|
717
|
+
end
|
718
|
+
end
|
719
|
+
end
|
720
|
+
end
|
721
|
+
end
|
722
|
+
end
|
723
|
+
end
|
724
|
+
|
725
|
+
|
644
726
|
def index_for(string, line:, column:)
|
645
727
|
index = 0
|
646
728
|
|
@@ -110,7 +110,7 @@ module Steep
|
|
110
110
|
end
|
111
111
|
|
112
112
|
def content_for(target:, path:, line:, column:)
|
113
|
-
file = service.source_files[path]
|
113
|
+
file = service.source_files[path] or return
|
114
114
|
typing = typecheck(target, path: path, content: file.content, line: line, column: column) or return
|
115
115
|
node, *parents = typing.source.find_nodes(line: line, column: column)
|
116
116
|
|