From 91196c23d86d58a042a82b1c610be414312ff05e Mon Sep 17 00:00:00 2001 From: Josh Brody Date: Mon, 7 Aug 2023 11:10:11 -0500 Subject: [PATCH 1/2] handle method definitions with constants; close #20 --- Gemfile.lock | 1 + app/models/visitor.rb | 37 +++++++++++++++++++++++++++++++++---- 2 files changed, 34 insertions(+), 4 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index d3f340e1..985b13bd 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -283,6 +283,7 @@ GEM zeitwerk (2.6.11) PLATFORMS + arm64-darwin-21 arm64-darwin-22 x86_64-darwin-22 x86_64-linux diff --git a/app/models/visitor.rb b/app/models/visitor.rb index 926baf4f..e214a9fe 100644 --- a/app/models/visitor.rb +++ b/app/models/visitor.rb @@ -131,7 +131,7 @@ def visit_def(node) elsif @modules.any? @modules.last else - @analyzer + inferred_context_for(target) end method_definition_args = { @@ -143,10 +143,12 @@ def visit_def(node) defined_files: [current_path], } - if target == "self" - context.class_methods << ClassMethod.new(**method_definition_args) - else + # the method can define itself onto "self", or can have a target of a constant + # to define the class there. see #inferred_context_for for more + if target.nil? context.instance_methods << InstanceMethod.new(**method_definition_args) + else + context.class_methods << ClassMethod.new(**method_definition_args) end @comments = [] @@ -188,4 +190,31 @@ def visit_command(node) super end + + + private + + # handle method names like `Skiptrace.current_bindings` where the constant + # wasn't already visited + def inferred_context_for(target) + if existing = @analyzer.modules.detect { |name| name.qualified_name == target } + if prev = @modules.find { |mod| mod.qualified_name == existing.qualified_name } + return prev + else + @modules << existing + @namespace << existing + return existing + end + elsif existing = @analyzer.classes.detect { |name| name.qualified_name == target } + if prev = @classes.find { |klass| klass.qualified_name == existing.qualified_name } + return prev + else + @classes << existing + return existing + end + end + + @analyzer + end + end From a038b479233d1a262a327db20a5d302601a0317f Mon Sep 17 00:00:00 2001 From: Josh Brody Date: Mon, 7 Aug 2023 15:23:16 -0500 Subject: [PATCH 2/2] cop --- app/models/visitor.rb | 29 +++++++++++++---------------- 1 file changed, 13 insertions(+), 16 deletions(-) diff --git a/app/models/visitor.rb b/app/models/visitor.rb index e214a9fe..e8942541 100644 --- a/app/models/visitor.rb +++ b/app/models/visitor.rb @@ -191,30 +191,27 @@ def visit_command(node) super end - private # handle method names like `Skiptrace.current_bindings` where the constant # wasn't already visited + # rubocop:disable Lint/AssignmentInCondition def inferred_context_for(target) if existing = @analyzer.modules.detect { |name| name.qualified_name == target } - if prev = @modules.find { |mod| mod.qualified_name == existing.qualified_name } - return prev - else - @modules << existing - @namespace << existing - return existing - end + return prev if @modules.find { |mod| mod.qualified_name == existing.qualified_name } + + @modules << existing + @namespace << existing + return existing + elsif existing = @analyzer.classes.detect { |name| name.qualified_name == target } - if prev = @classes.find { |klass| klass.qualified_name == existing.qualified_name } - return prev - else - @classes << existing - return existing - end - end + return prev if @classes.find { |klass| klass.qualified_name == existing.qualified_name } + + @classes << existing + return existing + end @analyzer end - + # rubocop:enable Lint/AssignmentInCondition end