Skip to content

Commit 100e0a8

Browse files
authored
Merge pull request #177 from vinistock/vs/fix_other_environment_cases
Fix other environment cases
2 parents 8763c18 + bd42046 commit 100e0a8

File tree

2 files changed

+207
-11
lines changed

2 files changed

+207
-11
lines changed

lib/syntax_tree/visitor/with_environment.rb

+18-11
Original file line numberDiff line numberDiff line change
@@ -44,8 +44,12 @@ def visit_module(node)
4444
with_new_environment { super }
4545
end
4646

47+
# When we find a method invocation with a block, only the code that happens
48+
# inside of the block needs a fresh environment. The method invocation
49+
# itself happens in the same environment
4750
def visit_method_add_block(node)
48-
with_new_environment { super }
51+
visit(node.call)
52+
with_new_environment { visit(node.block) }
4953
end
5054

5155
def visit_def(node)
@@ -63,9 +67,7 @@ def visit_def_endless(node)
6367
# Visit for keeping track of local arguments, such as method and block
6468
# arguments
6569
def visit_params(node)
66-
node.requireds.each do |param|
67-
current_environment.add_local_definition(param, :argument)
68-
end
70+
add_argument_definitions(node.requireds)
6971

7072
node.posts.each do |param|
7173
current_environment.add_local_definition(param, :argument)
@@ -117,13 +119,6 @@ def visit_var_field(node)
117119
alias visit_pinned_var_ref visit_var_field
118120

119121
# Visits for keeping track of variable and argument usages
120-
def visit_aref_field(node)
121-
name = node.collection.value
122-
current_environment.add_local_usage(name, :variable) if name
123-
124-
super
125-
end
126-
127122
def visit_var_ref(node)
128123
value = node.value
129124

@@ -137,5 +132,17 @@ def visit_var_ref(node)
137132

138133
super
139134
end
135+
136+
private
137+
138+
def add_argument_definitions(list)
139+
list.each do |param|
140+
if param.is_a?(SyntaxTree::MLHSParen)
141+
add_argument_definitions(param.contents.parts)
142+
else
143+
current_environment.add_local_definition(param, :argument)
144+
end
145+
end
146+
end
140147
end
141148
end

test/visitor_with_environment_test.rb

+189
Original file line numberDiff line numberDiff line change
@@ -426,5 +426,194 @@ def test_variables_in_the_top_level
426426
assert_equal(1, variable.definitions[0].start_line)
427427
assert_equal(2, variable.usages[0].start_line)
428428
end
429+
430+
def test_aref_field
431+
tree = SyntaxTree.parse(<<~RUBY)
432+
object = {}
433+
object["name"] = "something"
434+
RUBY
435+
436+
visitor = Collector.new
437+
visitor.visit(tree)
438+
439+
assert_equal(0, visitor.arguments.length)
440+
assert_equal(1, visitor.variables.length)
441+
442+
variable = visitor.variables["object"]
443+
assert_equal(1, variable.definitions.length)
444+
assert_equal(1, variable.usages.length)
445+
446+
assert_equal(1, variable.definitions[0].start_line)
447+
assert_equal(2, variable.usages[0].start_line)
448+
end
449+
450+
def test_aref_on_a_method_call
451+
tree = SyntaxTree.parse(<<~RUBY)
452+
object = MyObject.new
453+
object.attributes["name"] = "something"
454+
RUBY
455+
456+
visitor = Collector.new
457+
visitor.visit(tree)
458+
459+
assert_equal(0, visitor.arguments.length)
460+
assert_equal(1, visitor.variables.length)
461+
462+
variable = visitor.variables["object"]
463+
assert_equal(1, variable.definitions.length)
464+
assert_equal(1, variable.usages.length)
465+
466+
assert_equal(1, variable.definitions[0].start_line)
467+
assert_equal(2, variable.usages[0].start_line)
468+
end
469+
470+
def test_aref_with_two_accesses
471+
tree = SyntaxTree.parse(<<~RUBY)
472+
object = MyObject.new
473+
object["first"]["second"] ||= []
474+
RUBY
475+
476+
visitor = Collector.new
477+
visitor.visit(tree)
478+
479+
assert_equal(0, visitor.arguments.length)
480+
assert_equal(1, visitor.variables.length)
481+
482+
variable = visitor.variables["object"]
483+
assert_equal(1, variable.definitions.length)
484+
assert_equal(1, variable.usages.length)
485+
486+
assert_equal(1, variable.definitions[0].start_line)
487+
assert_equal(2, variable.usages[0].start_line)
488+
end
489+
490+
def test_aref_on_a_method_call_with_arguments
491+
tree = SyntaxTree.parse(<<~RUBY)
492+
object = MyObject.new
493+
object.instance_variable_get(:@attributes)[:something] = :other_thing
494+
RUBY
495+
496+
visitor = Collector.new
497+
visitor.visit(tree)
498+
499+
assert_equal(0, visitor.arguments.length)
500+
assert_equal(1, visitor.variables.length)
501+
502+
variable = visitor.variables["object"]
503+
assert_equal(1, variable.definitions.length)
504+
assert_equal(1, variable.usages.length)
505+
506+
assert_equal(1, variable.definitions[0].start_line)
507+
assert_equal(2, variable.usages[0].start_line)
508+
end
509+
510+
def test_double_aref_on_method_call
511+
tree = SyntaxTree.parse(<<~RUBY)
512+
object = MyObject.new
513+
object["attributes"].find { |a| a["field"] == "expected" }["value"] = "changed"
514+
RUBY
515+
516+
visitor = Collector.new
517+
visitor.visit(tree)
518+
519+
assert_equal(1, visitor.arguments.length)
520+
assert_equal(1, visitor.variables.length)
521+
522+
variable = visitor.variables["object"]
523+
assert_equal(1, variable.definitions.length)
524+
assert_equal(1, variable.usages.length)
525+
526+
assert_equal(1, variable.definitions[0].start_line)
527+
assert_equal(2, variable.usages[0].start_line)
528+
529+
argument = visitor.arguments["a"]
530+
assert_equal(1, argument.definitions.length)
531+
assert_equal(1, argument.usages.length)
532+
533+
assert_equal(2, argument.definitions[0].start_line)
534+
assert_equal(2, argument.usages[0].start_line)
535+
end
536+
537+
def test_nested_arguments
538+
tree = SyntaxTree.parse(<<~RUBY)
539+
[[1, [2, 3]]].each do |one, (two, three)|
540+
one
541+
two
542+
three
543+
end
544+
RUBY
545+
546+
visitor = Collector.new
547+
visitor.visit(tree)
548+
549+
assert_equal(3, visitor.arguments.length)
550+
assert_equal(0, visitor.variables.length)
551+
552+
argument = visitor.arguments["one"]
553+
assert_equal(1, argument.definitions.length)
554+
assert_equal(1, argument.usages.length)
555+
556+
assert_equal(1, argument.definitions[0].start_line)
557+
assert_equal(2, argument.usages[0].start_line)
558+
559+
argument = visitor.arguments["two"]
560+
assert_equal(1, argument.definitions.length)
561+
assert_equal(1, argument.usages.length)
562+
563+
assert_equal(1, argument.definitions[0].start_line)
564+
assert_equal(3, argument.usages[0].start_line)
565+
566+
argument = visitor.arguments["three"]
567+
assert_equal(1, argument.definitions.length)
568+
assert_equal(1, argument.usages.length)
569+
570+
assert_equal(1, argument.definitions[0].start_line)
571+
assert_equal(4, argument.usages[0].start_line)
572+
end
573+
574+
def test_double_nested_arguments
575+
tree = SyntaxTree.parse(<<~RUBY)
576+
[[1, [2, 3]]].each do |one, (two, (three, four))|
577+
one
578+
two
579+
three
580+
four
581+
end
582+
RUBY
583+
584+
visitor = Collector.new
585+
visitor.visit(tree)
586+
587+
assert_equal(4, visitor.arguments.length)
588+
assert_equal(0, visitor.variables.length)
589+
590+
argument = visitor.arguments["one"]
591+
assert_equal(1, argument.definitions.length)
592+
assert_equal(1, argument.usages.length)
593+
594+
assert_equal(1, argument.definitions[0].start_line)
595+
assert_equal(2, argument.usages[0].start_line)
596+
597+
argument = visitor.arguments["two"]
598+
assert_equal(1, argument.definitions.length)
599+
assert_equal(1, argument.usages.length)
600+
601+
assert_equal(1, argument.definitions[0].start_line)
602+
assert_equal(3, argument.usages[0].start_line)
603+
604+
argument = visitor.arguments["three"]
605+
assert_equal(1, argument.definitions.length)
606+
assert_equal(1, argument.usages.length)
607+
608+
assert_equal(1, argument.definitions[0].start_line)
609+
assert_equal(4, argument.usages[0].start_line)
610+
611+
argument = visitor.arguments["four"]
612+
assert_equal(1, argument.definitions.length)
613+
assert_equal(1, argument.usages.length)
614+
615+
assert_equal(1, argument.definitions[0].start_line)
616+
assert_equal(5, argument.usages[0].start_line)
617+
end
429618
end
430619
end

0 commit comments

Comments
 (0)