# encoding: utf-8# frozen_string_literal: truemoduleRuboCopmoduleCopmoduleLint# This cop checks for redundant access modifiers, including those with no# code, those which are repeated, and leading `public` modifiers in a# class or module body. Conditionally-defined methods are considered as# always being defined, and thus access modifiers guarding such methods# are not redundant.## @example## class Foo# public # this is redundant (default access is public)## def method# end## private # this is not redundant (a method is defined)# def method2# end## private # this is redundant (no following methods are defined)# end## @example## class Foo# # The following is not redundant (conditionally defined methods are# # considered as always defining a method)# private## if condition?# def method# end# end## protected # this is not redundant (method is defined)## define_method(:method2) do# end## protected # this is redundant (repeated from previous modifier)## [1,2,3].each do |i|# define_method("foo#{i}") do# end# end## # The following is redundant (methods defined on the class'# # singleton class are not affected by the public modifier)# public## def self.method3# end# endclassUselessAccessModifier<CopMSG='Useless `%s` access modifier.'.freezedefon_class(node)check_node(node.children[2])# class bodyenddefon_module(node)check_node(node.children[1])# module bodyenddefon_block(node)returnunlessinstance_eval_or_new_call?(node)check_node(node.children[2])# block bodyenddefon_sclass(node)check_node(node.children[1])# singleton class bodyendprivatedef_node_matcher:access_modifier,<<-PATTERN
(send nil ${:public :protected :private})
PATTERNdef_node_matcher:static_method_definition?,<<-PATTERN
{def (send nil {:attr :attr_reader :attr_writer :attr_accessor} ...)}
PATTERNdef_node_matcher:dynamic_method_definition?,<<-PATTERN
{(send nil :define_method ...) (block (send nil :define_method ...) ...)}
PATTERNdef_node_matcher:class_or_instance_eval?,<<-PATTERN
(block (send _ {:class_eval :instance_eval}) ...)
PATTERNdef_node_matcher:class_or_module_or_struct_new_call?,<<-PATTERN
(block (send (const nil {:Class :Module :Struct}) :new ...) ...)
PATTERNdefcheck_node(node)returnifnode.nil?ifnode.begin_type?check_scope(node)elsif(vis=access_modifier(node))add_offense(node,:expression,format(MSG,vis))endenddefcheck_scope(node)cur_vis,unused=check_child_nodes(node,nil,:public)add_offense(unused,:expression,format(MSG,cur_vis))ifunusedenddefcheck_child_nodes(node,unused,cur_vis)node.child_nodes.eachdo|child|if(new_vis=access_modifier(child))cur_vis,unused=check_new_visibility(child,unused,new_vis,cur_vis)elsifmethod_definition?(child)unused=nilelsifstart_of_new_scope?(child)check_scope(child)elsif!child.defs_type?cur_vis,unused=check_child_nodes(child,unused,cur_vis)endend[cur_vis,unused]enddefcheck_new_visibility(node,unused,new_vis,cur_vis)# does this modifier just repeat the existing visibility?ifnew_vis==cur_visadd_offense(node,:expression,format(MSG,cur_vis))else# was the previous modifier never applied to any defs?add_offense(unused,:expression,format(MSG,cur_vis))ifunused# once we have already warned about a certain modifier, don't# warn again even if it is never applied to any method defsunused=nodeend[new_vis,unused]enddefmethod_definition?(child)static_method_definition?(child)||dynamic_method_definition?(child)enddefstart_of_new_scope?(child)child.module_type?||child.class_type?||child.sclass_type?||instance_eval_or_new_call?(child)enddefinstance_eval_or_new_call?(child)class_or_instance_eval?(child)||class_or_module_or_struct_new_call?(child)endendendendend