rbs-trace 0.3.2 → 0.4.1
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.
- checksums.yaml +4 -4
- data/.rubocop.yml +12 -1
- data/CHANGELOG.md +34 -0
- data/README.md +44 -24
- data/Rakefile +7 -0
- data/exe/rbs-trace +8 -0
- data/lib/rbs/trace/builder.rb +136 -0
- data/lib/rbs/trace/cli/inline.rb +62 -0
- data/lib/rbs/trace/cli/merge.rb +102 -0
- data/lib/rbs/trace/cli.rb +40 -0
- data/lib/rbs/trace/file.rb +66 -21
- data/lib/rbs/trace/helpers.rb +67 -0
- data/lib/rbs/trace/inline_comment_visitor.rb +63 -0
- data/lib/rbs/trace/overload_compact.rb +93 -0
- data/lib/rbs/trace/return_value_visitor.rb +66 -0
- data/lib/rbs/trace/version.rb +2 -2
- data/lib/rbs/trace.rb +156 -4
- data/rbs_collection.lock.yaml +0 -4
- data/sig/generated/rbs/trace/builder.rbs +40 -0
- data/sig/generated/rbs/trace/cli/inline.rbs +19 -0
- data/sig/generated/rbs/trace/cli/merge.rbs +24 -0
- data/sig/generated/rbs/trace/cli.rbs +17 -0
- data/sig/generated/rbs/trace/file.rbs +20 -9
- data/sig/generated/rbs/trace/helpers.rbs +28 -0
- data/sig/generated/rbs/trace/inline_comment_visitor.rbs +27 -0
- data/sig/generated/rbs/trace/overload_compact.rbs +24 -0
- data/sig/generated/rbs/trace/return_value_visitor.rbs +27 -0
- data/sig/generated/rbs/trace/version.rbs +1 -1
- data/sig/generated/rbs/trace.rbs +63 -1
- data/tmp/.keep +0 -0
- metadata +38 -11
- data/lib/rbs/trace/declaration.rb +0 -107
- data/lib/rbs/trace/definition.rb +0 -33
- data/lib/rbs/trace/method_tracing.rb +0 -182
- data/sig/generated/rbs/trace/declaration.rbs +0 -36
- data/sig/generated/rbs/trace/definition.rbs +0 -25
- data/sig/generated/rbs/trace/method_tracing.rbs +0 -63
data/lib/rbs/trace/file.rb
CHANGED
@@ -1,29 +1,43 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require "stringio"
|
4
|
+
|
3
5
|
module RBS
|
4
|
-
|
6
|
+
class Trace
|
5
7
|
class File
|
6
|
-
|
7
|
-
|
8
|
+
include Helpers
|
9
|
+
|
10
|
+
# @rbs (String, ?Hash[TypeName, AST::Declarations::t]) -> void
|
11
|
+
def initialize(path, decls = {})
|
8
12
|
@path = path
|
13
|
+
@decls = decls
|
14
|
+
@members = {} #: Hash[TypeName, AST::Declarations::t]
|
9
15
|
end
|
10
16
|
|
11
|
-
# @rbs () ->
|
12
|
-
def
|
13
|
-
|
17
|
+
# @rbs (untyped, Class, Symbol) -> AST::Members::MethodDefinition?
|
18
|
+
def find_or_new_method_definition(object, defined_class, name)
|
19
|
+
klass = defined_class.singleton_class? ? object : defined_class
|
20
|
+
receiver_decl = find_or_new_receiver_decl(klass)
|
21
|
+
return unless receiver_decl
|
22
|
+
|
23
|
+
kind = defined_class.singleton_class? ? :singleton : :instance
|
24
|
+
key = [receiver_decl.name, name, kind]
|
25
|
+
@members[key] ||= new_method_definition(name:, kind:).tap do |member| # steep:ignore ArgumentTypeMismatch
|
26
|
+
receiver_decl.members << member
|
27
|
+
end
|
14
28
|
end
|
15
29
|
|
16
30
|
# @rbs () -> String
|
17
31
|
def with_rbs
|
18
|
-
|
19
|
-
|
20
|
-
|
32
|
+
result = Prism.parse_file(@path)
|
33
|
+
comments = {} #: Hash[Integer, String]
|
34
|
+
result.value.accept(InlineCommentVisitor.new(@decls, comments))
|
21
35
|
|
22
|
-
|
23
|
-
|
24
|
-
next
|
36
|
+
lines = result.source.source.lines
|
37
|
+
comments.keys.sort.reverse_each do |i|
|
38
|
+
next if skip_insert?(lines, i)
|
25
39
|
|
26
|
-
lines.insert(
|
40
|
+
lines.insert(i, comments[i])
|
27
41
|
end
|
28
42
|
lines.join
|
29
43
|
end
|
@@ -33,22 +47,53 @@ module RBS
|
|
33
47
|
::File.write(@path, with_rbs)
|
34
48
|
end
|
35
49
|
|
50
|
+
# @rbs () -> String
|
51
|
+
def to_rbs
|
52
|
+
out = StringIO.new
|
53
|
+
writer = Writer.new(out:)
|
54
|
+
writer.write(@decls.values)
|
55
|
+
|
56
|
+
out.string
|
57
|
+
end
|
58
|
+
|
59
|
+
# @rbs (String) -> void
|
60
|
+
def save_rbs(out_dir)
|
61
|
+
rbs_path = calc_rbs_path(out_dir)
|
62
|
+
|
63
|
+
rbs_path.parent.mkpath unless rbs_path.parent.exist?
|
64
|
+
rbs_path.write(to_rbs)
|
65
|
+
end
|
66
|
+
|
36
67
|
private
|
37
68
|
|
38
|
-
# @rbs (Array[String],
|
39
|
-
def skip_insert?(lines,
|
40
|
-
current = definition.lineno - 1
|
69
|
+
# @rbs (Array[String], Integer) -> boolish
|
70
|
+
def skip_insert?(lines, current)
|
41
71
|
prev = current - 1
|
42
72
|
|
43
|
-
|
44
|
-
lines[prev]&.include?("# @rbs") ||
|
73
|
+
lines[prev]&.include?("# @rbs") ||
|
45
74
|
lines[prev]&.include?("#:") ||
|
46
75
|
lines[current]&.include?("#:")
|
47
76
|
end
|
48
77
|
|
49
|
-
# @rbs () ->
|
50
|
-
def
|
51
|
-
|
78
|
+
# @rbs (Class | Module) -> (AST::Declarations::Class | AST::Declarations::Module)?
|
79
|
+
def find_or_new_receiver_decl(klass)
|
80
|
+
return unless klass.name
|
81
|
+
return if klass.name.is_a?(Symbol)
|
82
|
+
|
83
|
+
# Remove anonymous class names
|
84
|
+
class_name = klass.name.to_s.split("::").grep_v(/^#/).join("::")
|
85
|
+
name = TypeName.parse(class_name)
|
86
|
+
|
87
|
+
@decls[name.absolute!] ||= klass.is_a?(Class) ? new_class_decl(name:) : new_module_decl(name:)
|
88
|
+
end
|
89
|
+
|
90
|
+
# @rbs (String) -> Pathname
|
91
|
+
def calc_rbs_path(out_dir)
|
92
|
+
rb_path = Pathname(@path).sub(Pathname.pwd.to_s, "")
|
93
|
+
rb_path = rb_path.relative_path_from("/") if rb_path.absolute?
|
94
|
+
rbs_path = rb_path.sub_ext(".rbs")
|
95
|
+
|
96
|
+
Pathname(out_dir) + rbs_path
|
52
97
|
end
|
53
98
|
end
|
54
99
|
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RBS
|
4
|
+
class Trace
|
5
|
+
module Helpers
|
6
|
+
# @rbs (name: TypeName) -> AST::Declarations::Module
|
7
|
+
def new_module_decl(name:)
|
8
|
+
AST::Declarations::Module.new(
|
9
|
+
name:,
|
10
|
+
type_params: [],
|
11
|
+
self_types: [],
|
12
|
+
members: [],
|
13
|
+
annotations: [],
|
14
|
+
location: nil,
|
15
|
+
comment: nil
|
16
|
+
)
|
17
|
+
end
|
18
|
+
|
19
|
+
# @rbs (name: TypeName) -> AST::Declarations::Class
|
20
|
+
def new_class_decl(name:)
|
21
|
+
AST::Declarations::Class.new(
|
22
|
+
name:,
|
23
|
+
type_params: [],
|
24
|
+
super_class: nil,
|
25
|
+
members: [],
|
26
|
+
annotations: [],
|
27
|
+
location: nil,
|
28
|
+
comment: nil
|
29
|
+
)
|
30
|
+
end
|
31
|
+
|
32
|
+
# @rbs (name: Symbol, kind: (:singleton | :instance)) -> AST::Members::MethodDefinition
|
33
|
+
def new_method_definition(name:, kind:)
|
34
|
+
AST::Members::MethodDefinition.new(
|
35
|
+
name:,
|
36
|
+
kind:,
|
37
|
+
overloads: [],
|
38
|
+
annotations: [],
|
39
|
+
location: nil,
|
40
|
+
comment: nil,
|
41
|
+
overloading: false,
|
42
|
+
visibility: nil
|
43
|
+
)
|
44
|
+
end
|
45
|
+
|
46
|
+
# @rbs () -> Types::Bases::Void
|
47
|
+
def type_void
|
48
|
+
@type_void = Types::Bases::Void.new(location: nil)
|
49
|
+
end
|
50
|
+
|
51
|
+
# @rbs () -> Types::Bases::Nil
|
52
|
+
def type_nil
|
53
|
+
@type_nil ||= Types::Bases::Nil.new(location: nil)
|
54
|
+
end
|
55
|
+
|
56
|
+
# @rbs () -> Types::Bases::Bool
|
57
|
+
def type_bool
|
58
|
+
@type_bool ||= Types::Bases::Bool.new(location: nil)
|
59
|
+
end
|
60
|
+
|
61
|
+
# @rbs () -> Types::Bases::Any
|
62
|
+
def type_untyped
|
63
|
+
@type_untyped ||= Types::Bases::Any.new(location: nil)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RBS
|
4
|
+
class Trace
|
5
|
+
class InlineCommentVisitor < Prism::Visitor
|
6
|
+
# @rbs (Hash[TypeName, AST::Declarations::t], Hash[Integer, String]) -> void
|
7
|
+
def initialize(decls, comments)
|
8
|
+
@decls = decls
|
9
|
+
@comments = comments
|
10
|
+
@context = [] #: Array[Symbol]
|
11
|
+
|
12
|
+
super()
|
13
|
+
end
|
14
|
+
|
15
|
+
# @rbs override
|
16
|
+
# @rbs (Prism::Node) -> void
|
17
|
+
def visit_class_node(node)
|
18
|
+
@context.push(node.name)
|
19
|
+
super
|
20
|
+
@context.pop
|
21
|
+
end
|
22
|
+
|
23
|
+
# @rbs override
|
24
|
+
# @rbs (Prism::Node) -> void
|
25
|
+
def visit_module_node(node)
|
26
|
+
@context.push(node.name)
|
27
|
+
super
|
28
|
+
@context.pop
|
29
|
+
end
|
30
|
+
|
31
|
+
# @rbs override
|
32
|
+
# @rbs (Prism::Node) -> void
|
33
|
+
def visit_def_node(node)
|
34
|
+
member = find_method_definition(node.name)
|
35
|
+
if member
|
36
|
+
lineno = node.location.start_line - 1
|
37
|
+
indent = " " * node.location.start_column
|
38
|
+
overloads = OverloadCompact.new(member.overloads).call
|
39
|
+
comment = overloads.map(&:method_type).join(" | ")
|
40
|
+
|
41
|
+
@comments[lineno] = "#{indent}# @rbs #{comment}\n"
|
42
|
+
end
|
43
|
+
|
44
|
+
super
|
45
|
+
end
|
46
|
+
|
47
|
+
private
|
48
|
+
|
49
|
+
# @rbs (Symbol) -> AST::Members::MethodDefinition?
|
50
|
+
def find_method_definition(name)
|
51
|
+
return if @context.empty?
|
52
|
+
|
53
|
+
type_name = TypeName.parse("::#{@context.join("::")}")
|
54
|
+
decl = @decls[type_name]
|
55
|
+
return unless decl
|
56
|
+
|
57
|
+
decl.members.find do |member|
|
58
|
+
member.is_a?(AST::Members::MethodDefinition) && member.name == name
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,93 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RBS
|
4
|
+
class Trace
|
5
|
+
class OverloadCompact
|
6
|
+
# @rbs (Array[AST::Members::MethodDefinition::Overload]) -> void
|
7
|
+
def initialize(overloads)
|
8
|
+
@overloads = overloads
|
9
|
+
end
|
10
|
+
|
11
|
+
# @rbs () -> Array[AST::Members::MethodDefinition::Overload]
|
12
|
+
def call
|
13
|
+
method_type = merge_method_types(@overloads.map(&:method_type))
|
14
|
+
[AST::Members::MethodDefinition::Overload.new(method_type:, annotations: [])]
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
# @rbs (Array[MethodType]) -> MethodType
|
20
|
+
def merge_method_types(method_types) # rubocop:disable Metrics
|
21
|
+
# steep:ignore:start
|
22
|
+
base = method_types.first
|
23
|
+
return base if method_types.one?
|
24
|
+
|
25
|
+
required_positionals = base.type.required_positionals.map.with_index do |_, i|
|
26
|
+
types = method_types.map { |method_type| method_type.type.required_positionals[i].type }.uniq
|
27
|
+
Types::Function::Param.new(name: nil, type: merge_types(types))
|
28
|
+
end
|
29
|
+
|
30
|
+
optional_positionals = base.type.optional_positionals.map.with_index do |_, i|
|
31
|
+
types = method_types.map { |method_type| method_type.type.optional_positionals[i].type }.uniq
|
32
|
+
Types::Function::Param.new(name: nil, type: merge_types(types))
|
33
|
+
end
|
34
|
+
|
35
|
+
types = method_types.filter_map { |method_type| method_type.type.rest_positionals }.uniq
|
36
|
+
rest_positionals = Types::Function::Param.new(name: nil, type: merge_types(types)) unless types.empty?
|
37
|
+
|
38
|
+
required_keywords = base.type.required_keywords.keys.to_h do |key|
|
39
|
+
types = method_types.map { |method_type| method_type.type.required_keywords[key] }.uniq
|
40
|
+
[key, Types::Function::Param.new(name: nil, type: merge_types(types))]
|
41
|
+
end
|
42
|
+
|
43
|
+
optional_keywords = base.type.optional_keywords.keys.to_h do |key|
|
44
|
+
types = method_types.map { |method_type| method_type.type.optional_keywords[key] }.uniq
|
45
|
+
[key, Types::Function::Param.new(name: nil, type: merge_types(types))]
|
46
|
+
end
|
47
|
+
|
48
|
+
types = method_types.filter_map { |method_type| method_type.type.rest_keywords }.uniq
|
49
|
+
rest_keywords = Types::Function::Param.new(name: nil, type: merge_types(types)) unless types.empty?
|
50
|
+
|
51
|
+
return_types = method_types.map { |method_type| method_type.type.return_type }.uniq
|
52
|
+
return_type = merge_types(return_types)
|
53
|
+
# steep:ignore:end
|
54
|
+
|
55
|
+
fn = Types::Function.new(
|
56
|
+
required_positionals:,
|
57
|
+
optional_positionals:,
|
58
|
+
rest_positionals:,
|
59
|
+
trailing_positionals: [],
|
60
|
+
required_keywords:,
|
61
|
+
optional_keywords:,
|
62
|
+
rest_keywords:,
|
63
|
+
return_type:
|
64
|
+
)
|
65
|
+
MethodType.new(
|
66
|
+
type_params: [],
|
67
|
+
type: fn,
|
68
|
+
block: nil,
|
69
|
+
location: nil
|
70
|
+
)
|
71
|
+
end
|
72
|
+
|
73
|
+
# @rbs (Array[Types::t]) -> Types::t
|
74
|
+
def merge_types(types)
|
75
|
+
types = compact_types(types)
|
76
|
+
return types.first if types.one?
|
77
|
+
|
78
|
+
optional = types.any?(Types::Bases::Nil)
|
79
|
+
types = types.reject { |type| type.is_a?(Types::Bases::Nil) }
|
80
|
+
type = types.one? ? types.first : Types::Union.new(types:, location: nil) #: Types::t
|
81
|
+
|
82
|
+
optional ? Types::Optional.new(type:, location: nil) : type
|
83
|
+
end
|
84
|
+
|
85
|
+
# @rbs (Array[Types::t]) -> Array[Types::t]
|
86
|
+
def compact_types(types)
|
87
|
+
types = types.reject { |t| t.is_a?(Types::Bases::Void) } if types.any? { |t| !t.is_a?(Types::Bases::Void) }
|
88
|
+
types.reject! { |t| t.is_a?(Types::Bases::Any) } if types.any? { |t| !t.is_a?(Types::Bases::Any) }
|
89
|
+
types
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RBS
|
4
|
+
class Trace
|
5
|
+
class ReturnValueVisitor < Prism::BasicVisitor
|
6
|
+
class << self
|
7
|
+
# @rbs (String) -> ReturnValueVisitor
|
8
|
+
def parse_file(path)
|
9
|
+
new.tap do |visitor|
|
10
|
+
result = Prism.parse_file(path)
|
11
|
+
visitor.visit(result.value)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
# @void_types: Hash[Array[Integer, Symbol], bool]
|
17
|
+
# @parents: Array[Prism::Node]
|
18
|
+
|
19
|
+
# @rbs () -> void
|
20
|
+
def initialize
|
21
|
+
@void_types = {} #: Hash[Array[Integer|Symbol], bool]
|
22
|
+
@parents = [] #: Array[Prism::Node]
|
23
|
+
super
|
24
|
+
end
|
25
|
+
|
26
|
+
# @rbs (Integer, Symbol) -> bool
|
27
|
+
def void_type?(lineno, name)
|
28
|
+
@void_types.fetch([lineno, name], false)
|
29
|
+
end
|
30
|
+
|
31
|
+
# @rbs (Prism::Node) -> void
|
32
|
+
def visit_child_nodes(node)
|
33
|
+
@parents.push(node)
|
34
|
+
super
|
35
|
+
@parents.pop
|
36
|
+
end
|
37
|
+
|
38
|
+
# @rbs (Prism::CallNode) -> void
|
39
|
+
def visit_call_node(node)
|
40
|
+
key = [node.location.start_line, node.name]
|
41
|
+
@void_types[key] = void?(node)
|
42
|
+
|
43
|
+
visit_child_nodes(node)
|
44
|
+
end
|
45
|
+
|
46
|
+
(Prism::Visitor.instance_methods.grep(/^visit_/) - instance_methods).each do |m|
|
47
|
+
alias_method(m, :visit_child_nodes)
|
48
|
+
end
|
49
|
+
|
50
|
+
private
|
51
|
+
|
52
|
+
# @rbs (Prism::CallNode) -> bool
|
53
|
+
def void?(node)
|
54
|
+
parent_node = @parents[-1]
|
55
|
+
next_parent_node = @parents[-2]
|
56
|
+
return true if parent_node.nil? || next_parent_node.nil?
|
57
|
+
|
58
|
+
if next_parent_node.type == :program_node
|
59
|
+
parent_node.type == :statements_node
|
60
|
+
else
|
61
|
+
parent_node.type == :statements_node && parent_node.child_nodes[-1] != node
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
data/lib/rbs/trace/version.rb
CHANGED
data/lib/rbs/trace.rb
CHANGED
@@ -2,16 +2,168 @@
|
|
2
2
|
|
3
3
|
require "bundler"
|
4
4
|
require "logger"
|
5
|
+
require "optparse"
|
5
6
|
require "prism"
|
7
|
+
require "rbs"
|
6
8
|
|
7
|
-
require_relative "trace/
|
8
|
-
require_relative "trace/
|
9
|
+
require_relative "trace/helpers"
|
10
|
+
require_relative "trace/builder"
|
11
|
+
require_relative "trace/cli"
|
12
|
+
require_relative "trace/cli/inline"
|
13
|
+
require_relative "trace/cli/merge"
|
9
14
|
require_relative "trace/file"
|
10
|
-
require_relative "trace/
|
15
|
+
require_relative "trace/inline_comment_visitor"
|
16
|
+
require_relative "trace/overload_compact"
|
17
|
+
require_relative "trace/return_value_visitor"
|
11
18
|
require_relative "trace/version"
|
12
19
|
|
13
20
|
module RBS
|
14
|
-
|
21
|
+
class Trace
|
15
22
|
class Error < StandardError; end
|
23
|
+
# steep:ignore:start
|
24
|
+
BUNDLE_PATH = Bundler.bundle_path.to_s #: String
|
25
|
+
# steep:ignore:end
|
26
|
+
RUBY_LIB_PATH = RbConfig::CONFIG["rubylibdir"] #: String
|
27
|
+
PATH_INTERNAL = "<internal" #: String
|
28
|
+
PATH_EVAL = "(eval" #: String
|
29
|
+
PATH_INLINE_TEMPLATE = "inline template" #: String
|
30
|
+
|
31
|
+
private_constant :BUNDLE_PATH, :RUBY_LIB_PATH, :PATH_INTERNAL, :PATH_EVAL, :PATH_INLINE_TEMPLATE
|
32
|
+
|
33
|
+
# @rbs (?log_level: Symbol, ?raises: bool) -> void
|
34
|
+
def initialize(log_level: nil, raises: false)
|
35
|
+
@log_level = log_level
|
36
|
+
@log_level ||= ENV["RBS_TRACE_DEBUG"] ? :debug : :info
|
37
|
+
@raises = raises
|
38
|
+
end
|
39
|
+
|
40
|
+
# @rbs [T] () { () -> T } -> T
|
41
|
+
def enable(&)
|
42
|
+
trace.enable(&)
|
43
|
+
end
|
44
|
+
|
45
|
+
# @rbs () -> void
|
46
|
+
def disable
|
47
|
+
trace.disable
|
48
|
+
end
|
49
|
+
|
50
|
+
# @rbs () -> Hash[String, File]
|
51
|
+
def files
|
52
|
+
@files ||= {}
|
53
|
+
end
|
54
|
+
|
55
|
+
# @rbs () -> void
|
56
|
+
def save_comments
|
57
|
+
files.each_value(&:rewrite)
|
58
|
+
end
|
59
|
+
|
60
|
+
# @rbs (out_dir: String) -> void
|
61
|
+
def save_files(out_dir:)
|
62
|
+
files.each_value { |file| file.save_rbs(out_dir) }
|
63
|
+
end
|
64
|
+
|
65
|
+
private
|
66
|
+
|
67
|
+
# @rbs () -> TracePoint
|
68
|
+
def trace
|
69
|
+
@trace ||= TracePoint.new(:call, :return) { |tp| record(tp) }
|
70
|
+
end
|
71
|
+
|
72
|
+
# @rbs () -> Logger
|
73
|
+
def logger
|
74
|
+
@logger ||= Logger.new($stdout, level: @log_level)
|
75
|
+
end
|
76
|
+
|
77
|
+
# @rbs () -> Builder
|
78
|
+
def builder
|
79
|
+
@builder ||= Builder.new
|
80
|
+
end
|
81
|
+
|
82
|
+
# @rbs (String) -> File
|
83
|
+
def find_or_new_file(path)
|
84
|
+
files[path] ||= File.new(path)
|
85
|
+
end
|
86
|
+
|
87
|
+
# @rbs (TracePoint) -> void
|
88
|
+
def record(tp) # rubocop:disable Metrics/MethodLength
|
89
|
+
return if ignore_path?(tp.path)
|
90
|
+
|
91
|
+
file = find_or_new_file(tp.path)
|
92
|
+
# steep:ignore:start
|
93
|
+
member = file.find_or_new_method_definition(tp.self, tp.defined_class, tp.method_id)
|
94
|
+
# steep:ignore:end
|
95
|
+
return unless member
|
96
|
+
|
97
|
+
case tp.event
|
98
|
+
when :call
|
99
|
+
call_event(tp, member)
|
100
|
+
when :return
|
101
|
+
return_event(tp, member)
|
102
|
+
end
|
103
|
+
rescue StandardError => e
|
104
|
+
logger.debug(e)
|
105
|
+
raise(e) if @raises
|
106
|
+
end
|
107
|
+
|
108
|
+
# @rbs (TracePoint, AST::Members::MethodDefinition) -> void
|
109
|
+
def call_event(tp, member)
|
110
|
+
# steep:ignore:start
|
111
|
+
void = member.overloads.all? { |overload| overload.method_type.type.return_type.is_a?(Types::Bases::Void) } &&
|
112
|
+
void_return_type?(tp.path, tp.method_id)
|
113
|
+
|
114
|
+
builder.method_call(
|
115
|
+
bind: tp.binding,
|
116
|
+
parameters: tp.parameters,
|
117
|
+
void:
|
118
|
+
)
|
119
|
+
# steep:ignore:end
|
120
|
+
end
|
121
|
+
|
122
|
+
# @rbs (TracePoint, AST::Members::MethodDefinition) -> void
|
123
|
+
def return_event(tp, member)
|
124
|
+
overload = builder.method_return(tp.return_value)
|
125
|
+
return if member.overloads.include?(overload)
|
126
|
+
|
127
|
+
member.overloads << overload
|
128
|
+
end
|
129
|
+
|
130
|
+
# @rbs (String) -> bool
|
131
|
+
def ignore_path?(path)
|
132
|
+
path.start_with?(
|
133
|
+
PATH_INTERNAL,
|
134
|
+
PATH_EVAL,
|
135
|
+
PATH_INLINE_TEMPLATE,
|
136
|
+
BUNDLE_PATH,
|
137
|
+
RUBY_LIB_PATH,
|
138
|
+
__FILE__
|
139
|
+
)
|
140
|
+
end
|
141
|
+
|
142
|
+
# @rbs (String, Symbol) -> bool
|
143
|
+
def void_return_type?(path, method_id)
|
144
|
+
return true if method_id == :initialize
|
145
|
+
|
146
|
+
loc = find_caller_location(path, method_id.to_s)
|
147
|
+
# If the caller is not found, assume the return value is used.
|
148
|
+
return false unless loc
|
149
|
+
|
150
|
+
caller_path = loc.path.to_s
|
151
|
+
# Returns true if the file does not exist (eval, etc.)
|
152
|
+
return true unless ::File.exist?(caller_path)
|
153
|
+
|
154
|
+
# If the file is not Ruby, assume the return value is used. (erb, haml, etc.)
|
155
|
+
return false if ::File.extname(caller_path) != ".rb"
|
156
|
+
|
157
|
+
@return_value_visitors ||= {} #: Hash[String, ReturnValueVisitor]
|
158
|
+
v = @return_value_visitors.fetch(caller_path) { ReturnValueVisitor.parse_file(caller_path) }
|
159
|
+
v.void_type?(loc.lineno, method_id)
|
160
|
+
end
|
161
|
+
|
162
|
+
# @rbs (String, String) -> Thread::Backtrace::Location?
|
163
|
+
def find_caller_location(path, label)
|
164
|
+
locations = caller_locations || []
|
165
|
+
i = locations.index { |loc| loc.path == path && loc.label == label }
|
166
|
+
locations[i + 1] if i
|
167
|
+
end
|
16
168
|
end
|
17
169
|
end
|
data/rbs_collection.lock.yaml
CHANGED
@@ -0,0 +1,40 @@
|
|
1
|
+
# Generated from lib/rbs/trace/builder.rb with RBS::Inline
|
2
|
+
|
3
|
+
module RBS
|
4
|
+
class Trace
|
5
|
+
class Builder
|
6
|
+
include Helpers
|
7
|
+
|
8
|
+
UNBOUND_CLASS_METHOD: untyped
|
9
|
+
|
10
|
+
UNBOUND_NAME_METHOD: untyped
|
11
|
+
|
12
|
+
GENERICS_SIZE: untyped
|
13
|
+
|
14
|
+
# @rbs (bind: Binding, parameters: Array[__todo__], void: bool) -> Array[__todo__]
|
15
|
+
def method_call: (bind: Binding, parameters: Array[__todo__], void: bool) -> Array[__todo__]
|
16
|
+
|
17
|
+
# @rbs (__todo__) -> AST::Members::MethodDefinition::Overload
|
18
|
+
def method_return: (__todo__) -> AST::Members::MethodDefinition::Overload
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
def stack_traces: () -> untyped
|
23
|
+
|
24
|
+
# @rbs (Binding, Array[__todo__]) -> MethodType
|
25
|
+
def parse_parameters: (Binding, Array[__todo__]) -> MethodType
|
26
|
+
|
27
|
+
# @rbs (Array[untyped]) -> Types::t
|
28
|
+
def parse_classes: (Array[untyped]) -> Types::t
|
29
|
+
|
30
|
+
# @rbs (untyped) -> Types::t
|
31
|
+
def parse_class: (untyped) -> Types::t
|
32
|
+
|
33
|
+
# @rbs (BasicObject) -> Types::t
|
34
|
+
def parse_object: (BasicObject) -> Types::t
|
35
|
+
|
36
|
+
# @rbs (BasicObject) -> Class
|
37
|
+
def obj_to_class: (BasicObject) -> Class
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# Generated from lib/rbs/trace/cli/inline.rb with RBS::Inline
|
2
|
+
|
3
|
+
module RBS
|
4
|
+
class Trace
|
5
|
+
class CLI
|
6
|
+
class Inline
|
7
|
+
BANNER: ::String
|
8
|
+
|
9
|
+
# @rbs (Array[String]) -> void
|
10
|
+
def run: (Array[String]) -> void
|
11
|
+
|
12
|
+
private
|
13
|
+
|
14
|
+
# @rbs (String) -> Environment
|
15
|
+
def load_env: (String) -> Environment
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# Generated from lib/rbs/trace/cli/merge.rb with RBS::Inline
|
2
|
+
|
3
|
+
module RBS
|
4
|
+
class Trace
|
5
|
+
class CLI
|
6
|
+
class Merge
|
7
|
+
BANNER: ::String
|
8
|
+
|
9
|
+
# @rbs (Array[String]) -> void
|
10
|
+
def run: (Array[String]) -> void
|
11
|
+
|
12
|
+
# @rbs (Array[Environment]) -> Environment
|
13
|
+
def merge_envs: (Array[Environment]) -> Environment
|
14
|
+
|
15
|
+
private
|
16
|
+
|
17
|
+
# @rbs (String) -> Environment
|
18
|
+
def load_env: (String) -> Environment
|
19
|
+
|
20
|
+
def merge: (untyped decl, untyped member) -> untyped
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|