Class: RuboCop::AST::Node
Overview
Node
is a subclass of Parser::AST::Node
. It provides
access to parent nodes and an object-oriented way to traverse an AST with
the power of Enumerable
.
It has predicate methods for every node type, like this:
Constant Summary
-
ASSIGNMENTS =
Internal use only
# File 'lib/rubocop/ast/node.rb', line 55(EQUALS_ASSIGNMENTS + SHORTHAND_ASSIGNMENTS).freeze
-
BASIC_CONDITIONALS =
Internal use only
# File 'lib/rubocop/ast/node.rb', line 58%i[if while until].to_set.freeze
-
BASIC_LITERALS =
Internal use only
# File 'lib/rubocop/ast/node.rb', line 42(LITERALS - COMPOSITE_LITERALS).freeze
-
COMPARISON_OPERATORS =
Internal use only
<⇒ isn’t included here, because it doesn’t return a boolean.
%i[== === != <= >= > <].to_set.freeze
-
COMPOSITE_LITERALS =
Internal use only
# File 'lib/rubocop/ast/node.rb', line 39%i[dstr xstr dsym array hash irange erange regexp].to_set.freeze
-
CONDITIONALS =
Internal use only
# File 'lib/rubocop/ast/node.rb', line 60(BASIC_CONDITIONALS + %i[case case_match]).freeze
-
EMPTY_CHILDREN =
private
# File 'lib/rubocop/ast/node.rb', line 84[].freeze
-
EMPTY_PROPERTIES =
private
# File 'lib/rubocop/ast/node.rb', line 85{}.freeze
-
EQUALS_ASSIGNMENTS =
Internal use only
# File 'lib/rubocop/ast/node.rb', line 50%i[lvasgn ivasgn cvasgn gvasgn casgn masgn].to_set.freeze
-
FALSEY_LITERALS =
Internal use only
# File 'lib/rubocop/ast/node.rb', line 35%i[false nil].to_set.freeze
-
GROUP_FOR_TYPE =
private
Internal use only
# File 'lib/rubocop/ast/node.rb', line 89{ def: :any_def, defs: :any_def, arg: :argument, optarg: :argument, restarg: :argument, kwarg: :argument, kwoptarg: :argument, kwrestarg: :argument, blockarg: :argument, forward_arg: :argument, shadowarg: :argument, true: :boolean, false: :boolean, int: :numeric, float: :numeric, rational: :numeric, complex: :numeric, irange: :range, erange: :range, send: :call, csend: :call, block: :any_block, numblock: :any_block, itblock: :any_block, match_pattern: :any_match_pattern, match_pattern_p: :any_match_pattern }.freeze
-
IMMUTABLE_LITERALS =
Internal use only
# File 'lib/rubocop/ast/node.rb', line 47(LITERALS - MUTABLE_LITERALS).freeze
-
KEYWORDS =
Internal use only
# File 'lib/rubocop/ast/node.rb', line 70%i[alias and break case class def defs defined? kwbegin do else ensure for if module next not or postexe redo rescue retry return self super zsuper then undef until when while yield].to_set.freeze
-
LITERALS =
Internal use only
# File 'lib/rubocop/ast/node.rb', line 37(TRUTHY_LITERALS + FALSEY_LITERALS).freeze
-
LITERAL_RECURSIVE_METHODS =
private
# File 'lib/rubocop/ast/node.rb', line 80(COMPARISON_OPERATORS + %i[* ! <=>]).freeze
-
LITERAL_RECURSIVE_TYPES =
private
# File 'lib/rubocop/ast/node.rb', line 81(OPERATOR_KEYWORDS + COMPOSITE_LITERALS + %i[begin pair]).freeze
-
LOOP_TYPES =
Internal use only
# File 'lib/rubocop/ast/node.rb', line 64(POST_CONDITION_LOOP_TYPES + %i[while until for]).freeze
-
MUTABLE_LITERALS =
Internal use only
# File 'lib/rubocop/ast/node.rb', line 44%i[str dstr xstr array hash regexp irange erange].to_set.freeze
-
OPERATOR_KEYWORDS =
Internal use only
# File 'lib/rubocop/ast/node.rb', line 76%i[and or].to_set.freeze
-
POST_CONDITION_LOOP_TYPES =
Internal use only
# File 'lib/rubocop/ast/node.rb', line 62%i[while_post until_post].to_set.freeze
-
REFERENCES =
Internal use only
# File 'lib/rubocop/ast/node.rb', line 68%i[nth_ref back_ref].to_set.freeze
-
SHORTHAND_ASSIGNMENTS =
Internal use only
# File 'lib/rubocop/ast/node.rb', line 53%i[op_asgn or_asgn and_asgn].to_set.freeze
-
SPECIAL_KEYWORDS =
Internal use only
# File 'lib/rubocop/ast/node.rb', line 78%w[__FILE__ __LINE__ __ENCODING__].to_set.freeze
-
TRUTHY_LITERALS =
Internal use only
# File 'lib/rubocop/ast/node.rb', line 31%i[str dstr xstr int float sym dsym array hash regexp true irange erange complex rational regopt].to_set.freeze
-
VARIABLES =
Internal use only
# File 'lib/rubocop/ast/node.rb', line 66%i[ivar gvar cvar lvar].to_set.freeze
Class Method Summary
- .new(type, children = EMPTY_CHILDREN, properties = EMPTY_PROPERTIES) ⇒ Node constructor
-
.def_recursive_literal_predicate(kind)
private
Define a
recursive_?
predicate method for the given node kind.
NodePattern::Macros
- Extended
def_node_matcher | Define a method which applies a pattern to an AST node. |
def_node_search | Define a method which recurses over the descendants of an AST node, checking whether any of them match the provided pattern. |
Instance Attribute Summary
- #any_block_type? ⇒ Boolean readonly
- #any_def_type? ⇒ Boolean readonly
- #any_match_pattern_type? ⇒ Boolean readonly
- #argument? ⇒ Boolean readonly
- #argument_type? ⇒ Boolean readonly
- #assignment? ⇒ Boolean readonly
- #basic_conditional? ⇒ Boolean readonly
- #basic_literal? ⇒ Boolean readonly
- #boolean_type? ⇒ Boolean readonly
- #call_type? ⇒ Boolean readonly
- #chained? ⇒ Boolean readonly
- #complete? ⇒ Boolean readonly
- #conditional? ⇒ Boolean readonly
- #empty_source? ⇒ Boolean readonly
- #equals_asgn? ⇒ Boolean readonly
- #falsey_literal? ⇒ Boolean readonly
- #guard_clause? ⇒ Boolean readonly
- #immutable_literal? ⇒ Boolean readonly
- #keyword? ⇒ Boolean readonly
- #literal? ⇒ Boolean readonly
-
#loop_keyword? ⇒ Boolean
readonly
Note
loop { }
is a normal method call and thus not a loop keyword. -
#multiline? ⇒ Boolean
readonly
Predicates.
- #mutable_literal? ⇒ Boolean readonly
- #numeric_type? ⇒ Boolean readonly
- #operator_keyword? ⇒ Boolean readonly
-
#parent ⇒ Node?
readonly
Returns the parent node, or
nil
if the receiver is a root node. - #parent? ⇒ Boolean readonly
- #parenthesized_call? ⇒ Boolean readonly
- #post_condition_loop? ⇒ Boolean readonly
-
#pure? ⇒ Boolean
readonly
Some expressions are evaluated for their value, some for their side effects, and some for both.
- #range_type? ⇒ Boolean readonly
- #reference? ⇒ Boolean readonly
- #root? ⇒ Boolean readonly
-
#send_type? ⇒ Boolean
readonly
Most nodes are of 'send' type, so this method is defined separately to make this check as fast as possible.
- #shorthand_asgn? ⇒ Boolean readonly
- #single_line? ⇒ Boolean readonly
- #special_keyword? ⇒ Boolean readonly
- #truthy_literal? ⇒ Boolean readonly
-
#value_used? ⇒ Boolean
readonly
Some expressions are evaluated for their value, some for their side effects, and some for both If we know that an expression is useful only for its side effects, that means we can transform it in ways which preserve the side effects, but change the return value So, does the return value of this node matter? If we changed it to
(…; nil)
, might that affect anything? - #variable? ⇒ Boolean readonly
- #begin_value_used? ⇒ Boolean readonly private
- #case_if_value_used? ⇒ Boolean readonly private
- #for_value_used? ⇒ Boolean readonly private
- #while_until_value_used? ⇒ Boolean readonly private
Instance Method Summary
-
#ancestors ⇒ Array<Node>
Returns an array of ancestor nodes.
-
#assignment_or_similar?(node = self)
Some cops treat the shovel operator as a kind of assignment.
- #class_constructor?(node = self)
- #class_definition?(node = self)
- #complete!
- #const_name
- #defined_module
- #defined_module_name
-
#each_ancestor ⇒ self, Enumerator
Calls the given block for each ancestor node from parent to root.
- #first_line
- #global_const?(node = self, name)
- #lambda?(node = self)
- #lambda_or_proc?(node = self)
- #last_line
-
#left_sibling ⇒ Node?
Use is discouraged, this is a potentially slow method and can lead to even slower algorithms.
-
#left_siblings ⇒ Array<Node>
Use is discouraged, this is a potentially slow method and can lead to even slower algorithms.
- #line_count
-
#loc?(which_loc) ⇒ Boolean
Shortcut to safely check if a location is present.
-
#loc_is?(which_loc, str) ⇒ Boolean
Shortcut to safely test a particular location, even if this location does not exist or is
nil
. - #match_guard_clause?(node = self)
- #module_definition?(node = self)
-
#node_parts ⇒ Array<Node>
Common destructuring method.
- #nonempty_line_count
-
#parent_module_name
Searching the AST.
- #proc?(node = self)
- #receiver(node = self)
- #recursive_basic_literal? ⇒ Boolean
- #recursive_literal? ⇒ Boolean
-
#right_sibling ⇒ Node?
Use is discouraged, this is a potentially slow method and can lead to even slower algorithms.
-
#right_siblings ⇒ Array<Node>
Use is discouraged, this is a potentially slow method and can lead to even slower algorithms.
-
#sibling_index ⇒ Integer?
Returns the index of the receiver node in its siblings.
-
#source ⇒ String?
Note
Some rare nodes may have no source, like s(:args)
infoo {}
. - #source_length
- #source_range
- #str_content(node = self)
-
#struct_constructor?(node = self)
deprecated
Deprecated.
Use
:class_constructor?
-
#type?(*types) ⇒ Boolean
Determine if the node is one of several node types in a single query Allows specific single node types, as well as "grouped" types (e.g.
-
#updated(type = nil, children = nil, properties = {})
Override #updated so that
AST::Processor
does not try to mutate our ASTs. - #defined_module0(node = self) private
- #new_class_or_module_block?(node = self) private
- #parent_module_name_for_block(ancestor) private
- #parent_module_name_for_sclass(sclass_node) private
- #parent_module_name_part(node) private
- #visit_ancestors(types) private
Descendence
- Included
#child_nodes | Returns an array of child nodes. |
#descendants | Returns an array of descendant nodes. |
#each_child_node | Calls the given block for each child node. |
#each_descendant | Calls the given block for each descendant node with depth first order. |
#each_node | Calls the given block for the receiver and each descendant node in depth-first order. |
Sexp
- Included
#s | Creates a |
Constructor Details
.new(type, children = EMPTY_CHILDREN, properties = EMPTY_PROPERTIES) ⇒ Node
# File 'lib/rubocop/ast/node.rb', line 148
def initialize(type, children = EMPTY_CHILDREN, properties = EMPTY_PROPERTIES) @mutable_attributes = {} # ::AST::Node#initialize freezes itself. super # #parent= may be invoked multiple times for a node because there are # pending nodes while constructing AST and they are replaced later. # For example, `lvar` and `send` type nodes are initially created as an # `ident` type node and fixed to the appropriate type later. # So, the #parent attribute needs to be mutable. each_child_node do |child_node| child_node.parent = self unless child_node.complete? end end
Class Method Details
.def_recursive_literal_predicate(kind) (private)
Define a recursive_?
predicate method for the given node kind.
# File 'lib/rubocop/ast/node.rb', line 127
private_class_method def self.def_recursive_literal_predicate(kind) # rubocop:disable Metrics/MethodLength recursive_kind = "recursive_#{kind}?" kind_filter = "#{kind}?" class_eval <<~RUBY, __FILE__, __LINE__ + 1 def #{recursive_kind} # def recursive_literal? case type # case type when :send # when :send LITERAL_RECURSIVE_METHODS.include?(method_name) && # LITERAL_RECURSIVE_METHODS.include?(method_name) && receiver.send(:#{recursive_kind}) && # receiver.send(:recursive_literal?) && arguments.all?(&:#{recursive_kind}) # arguments.all?(&:recursive_literal?) when LITERAL_RECURSIVE_TYPES # when LITERAL_RECURSIVE_TYPES children.compact.all?(&:#{recursive_kind}) # children.compact.all?(&:recursive_literal?) else # else send(:#{kind_filter}) # send(:literal?) end # end end # end RUBY end
Instance Attribute Details
#any_block_type? ⇒ Boolean
(readonly)
[ GitHub ]
# File 'lib/rubocop/ast/node.rb', line 542
def any_block_type? GROUP_FOR_TYPE[type] == :any_block end
#any_def_type? ⇒ Boolean
(readonly)
[ GitHub ]
# File 'lib/rubocop/ast/node.rb', line 522
def any_def_type? GROUP_FOR_TYPE[type] == :any_def end
#any_match_pattern_type? ⇒ Boolean
(readonly)
[ GitHub ]
# File 'lib/rubocop/ast/node.rb', line 546
def any_match_pattern_type? GROUP_FOR_TYPE[type] == :any_match_pattern end
#argument? ⇒ Boolean
(readonly)
[ GitHub ]
# File 'lib/rubocop/ast/node.rb', line 518
def argument? parent&.send_type? && parent.arguments.include?(self) end
#argument_type? ⇒ Boolean
(readonly)
[ GitHub ]
# File 'lib/rubocop/ast/node.rb', line 526
def argument_type? GROUP_FOR_TYPE[type] == :argument end
#assignment? ⇒ Boolean
(readonly)
[ GitHub ]
# File 'lib/rubocop/ast/node.rb', line 470
def assignment? ASSIGNMENTS.include?(type) end
#basic_conditional? ⇒ Boolean
(readonly)
[ GitHub ]
# File 'lib/rubocop/ast/node.rb', line 474
def basic_conditional? BASIC_CONDITIONALS.include?(type) end
#basic_literal? ⇒ Boolean
(readonly)
[ GitHub ]
# File 'lib/rubocop/ast/node.rb', line 428
def basic_literal? BASIC_LITERALS.include?(type) end
#begin_value_used? ⇒ Boolean
(readonly, private)
[ GitHub ]
# File 'lib/rubocop/ast/node.rb', line 689
def begin_value_used? # the last child node determines the value of the parent sibling_index == parent.children.size - 1 ? parent.value_used? : false end
#boolean_type? ⇒ Boolean
(readonly)
[ GitHub ]
# File 'lib/rubocop/ast/node.rb', line 530
def boolean_type? GROUP_FOR_TYPE[type] == :boolean end
#call_type? ⇒ Boolean
(readonly)
[ GitHub ]
# File 'lib/rubocop/ast/node.rb', line 510
def call_type? GROUP_FOR_TYPE[type] == :call end
#case_if_value_used? ⇒ Boolean
(readonly, private)
[ GitHub ]
# File 'lib/rubocop/ast/node.rb', line 700
def case_if_value_used? # (case <condition> <when...>) # (if <condition> <truebranch> <falsebranch>) sibling_index.zero? || parent.value_used? end
#chained? ⇒ Boolean
(readonly)
[ GitHub ]
# File 'lib/rubocop/ast/node.rb', line 514
def chained? parent&.call_type? && eql?(parent.receiver) end
#complete? ⇒ Boolean
(readonly)
[ GitHub ]
# File 'lib/rubocop/ast/node.rb', line 215
def complete? @mutable_attributes.frozen? end
#conditional? ⇒ Boolean
(readonly)
[ GitHub ]
# File 'lib/rubocop/ast/node.rb', line 478
def conditional? CONDITIONALS.include?(type) end
#empty_source? ⇒ Boolean
(readonly)
[ GitHub ]
# File 'lib/rubocop/ast/node.rb', line 414
def empty_source? source_length.zero? end
#equals_asgn? ⇒ Boolean
(readonly)
[ GitHub ]
# File 'lib/rubocop/ast/node.rb', line 462
def equals_asgn? EQUALS_ASSIGNMENTS.include?(type) end
#falsey_literal? ⇒ Boolean
(readonly)
[ GitHub ]
# File 'lib/rubocop/ast/node.rb', line 436
def falsey_literal? FALSEY_LITERALS.include?(type) end
#for_value_used? ⇒ Boolean
(readonly, private)
[ GitHub ]
# File 'lib/rubocop/ast/node.rb', line 694
def for_value_used? # `for var in enum; body; end` # (for <var> <enum> <body>) sibling_index == 2 ? parent.value_used? : true end
#guard_clause? ⇒ Boolean
(readonly)
[ GitHub ]
# File 'lib/rubocop/ast/node.rb', line 550
def guard_clause? node = operator_keyword? ? rhs : self node.match_guard_clause? end
#immutable_literal? ⇒ Boolean
(readonly)
[ GitHub ]
# File 'lib/rubocop/ast/node.rb', line 444
def immutable_literal? IMMUTABLE_LITERALS.include?(type) end
#keyword? ⇒ Boolean
(readonly)
[ GitHub ]
# File 'lib/rubocop/ast/node.rb', line 491
def keyword? return true if special_keyword? || (send_type? && prefix_not?) return false unless KEYWORDS.include?(type) !OPERATOR_KEYWORDS.include?(type) || loc.operator.is?(type.to_s) end
#literal? ⇒ Boolean
(readonly)
[ GitHub ]
# File 'lib/rubocop/ast/node.rb', line 424
def literal? LITERALS.include?(type) end
#loop_keyword? ⇒ Boolean
(readonly)
Note
|
loop { } is a normal method call and thus not a loop keyword.
|
# File 'lib/rubocop/ast/node.rb', line 487
def loop_keyword? LOOP_TYPES.include?(type) end
#multiline? ⇒ Boolean
(readonly)
Predicates
# File 'lib/rubocop/ast/node.rb', line 406
def multiline? line_count > 1 end
#mutable_literal? ⇒ Boolean
(readonly)
[ GitHub ]
# File 'lib/rubocop/ast/node.rb', line 440
def mutable_literal? MUTABLE_LITERALS.include?(type) end
#numeric_type? ⇒ Boolean
(readonly)
[ GitHub ]
# File 'lib/rubocop/ast/node.rb', line 534
def numeric_type? GROUP_FOR_TYPE[type] == :numeric end
#operator_keyword? ⇒ Boolean
(readonly)
[ GitHub ]
# File 'lib/rubocop/ast/node.rb', line 502
def operator_keyword? OPERATOR_KEYWORDS.include?(type) end
#parent ⇒ Node
? (rw)
Returns the parent node, or nil
if the receiver is a root node.
# File 'lib/rubocop/ast/node.rb', line 192
def parent @mutable_attributes[:parent] end
#parent? ⇒ Boolean
(rw)
[ GitHub ]
# File 'lib/rubocop/ast/node.rb', line 201
def parent? !!parent end
#parenthesized_call? ⇒ Boolean
(readonly)
[ GitHub ]
# File 'lib/rubocop/ast/node.rb', line 506
def parenthesized_call? loc_is?(:begin, '(') end
#post_condition_loop? ⇒ Boolean
(readonly)
[ GitHub ]
# File 'lib/rubocop/ast/node.rb', line 482
def post_condition_loop? POST_CONDITION_LOOP_TYPES.include?(type) end
#pure? ⇒ Boolean
(readonly)
Some expressions are evaluated for their value, some for their side effects, and some for both. If we know that expressions are useful only for their return values, and have no side effects, that means we can reorder them, change the number of times they are evaluated, or replace them with other expressions which are equivalent in value. So, is evaluation of this node free of side effects?
# File 'lib/rubocop/ast/node.rb', line 662
def pure? # Be conservative and return false if we're not sure case type when :__FILE__, :__LINE__, :const, :cvar, :defined?, :false, :float, :gvar, :int, :ivar, :lvar, :nil, :str, :sym, :true, :regopt true when :and, :array, :begin, :case, :dstr, :dsym, :eflipflop, :ensure, :erange, :for, :hash, :if, :iflipflop, :irange, :kwbegin, :not, :or, :pair, :regexp, :until, :until_post, :when, :while, :while_post child_nodes.all?(&:pure?) else false end end
#range_type? ⇒ Boolean
(readonly)
[ GitHub ]
# File 'lib/rubocop/ast/node.rb', line 538
def range_type? GROUP_FOR_TYPE[type] == :range end
#reference? ⇒ Boolean
(readonly)
[ GitHub ]
# File 'lib/rubocop/ast/node.rb', line 458
def reference? REFERENCES.include?(type) end
#root? ⇒ Boolean
(readonly)
[ GitHub ]
# File 'lib/rubocop/ast/node.rb', line 206
def root? !parent end
#send_type? ⇒ Boolean
(readonly)
Most nodes are of 'send' type, so this method is defined separately to make this check as fast as possible.
# File 'lib/rubocop/ast/node.rb', line 185
def send_type? false end
#shorthand_asgn? ⇒ Boolean
(readonly)
[ GitHub ]
# File 'lib/rubocop/ast/node.rb', line 466
def shorthand_asgn? SHORTHAND_ASSIGNMENTS.include?(type) end
#single_line? ⇒ Boolean
(readonly)
[ GitHub ]
# File 'lib/rubocop/ast/node.rb', line 410
def single_line? line_count == 1 end
#special_keyword? ⇒ Boolean
(readonly)
[ GitHub ]
# File 'lib/rubocop/ast/node.rb', line 498
def special_keyword? SPECIAL_KEYWORDS.include?(source) end
#truthy_literal? ⇒ Boolean
(readonly)
[ GitHub ]
# File 'lib/rubocop/ast/node.rb', line 432
def truthy_literal? TRUTHY_LITERALS.include?(type) end
#value_used? ⇒ Boolean
(readonly)
Some expressions are evaluated for their value, some for their side
effects, and some for both
If we know that an expression is useful only for its side effects, that
means we can transform it in ways which preserve the side effects, but
change the return value
So, does the return value of this node matter? If we changed it to
(…; nil)
, might that affect anything?
# File 'lib/rubocop/ast/node.rb', line 632
def value_used? # rubocop:disable Metrics/MethodLength # Be conservative and return true if we're not sure. return false if parent.nil? case parent.type when :array, :defined?, :dstr, :dsym, :eflipflop, :erange, :float, :hash, :iflipflop, :irange, :not, :pair, :regexp, :str, :sym, :when, :xstr parent.value_used? when :begin, :kwbegin begin_value_used? when :for for_value_used? when :case, :if case_if_value_used? when :while, :until, :while_post, :until_post while_until_value_used? else true end end
#variable? ⇒ Boolean
(readonly)
[ GitHub ]
# File 'lib/rubocop/ast/node.rb', line 454
def variable? VARIABLES.include?(type) end
#while_until_value_used? ⇒ Boolean
(readonly, private)
[ GitHub ]
# File 'lib/rubocop/ast/node.rb', line 706
def while_until_value_used? # (while <condition> <body>) -> always evaluates to `nil` sibling_index.zero? end
Instance Method Details
#ancestors ⇒ Array
<Node
>
Returns an array of ancestor nodes.
This is a shorthand for node.each_ancestor.to_a
.
# File 'lib/rubocop/ast/node.rb', line 313
def ancestors each_ancestor.to_a end
#assignment_or_similar?(node = self)
Some cops treat the shovel operator as a kind of assignment.
# File 'lib/rubocop/ast/node.rb', line 420
def_node_matcher :assignment_or_similar?, <<~PATTERN {assignment? (send _recv :<< ...)} PATTERN
#class_constructor?(node = self)
[ GitHub ]# File 'lib/rubocop/ast/node.rb', line 594
def_node_matcher :class_constructor?, <<~PATTERN { (send #global_const?({:Class :Module :Struct}) :new ...) (send #global_const?(:Data) :define ...) (any_block { (send #global_const?({:Class :Module :Struct}) :new ...) (send #global_const?(:Data) :define ...) } ...) } PATTERN
#class_definition?(node = self)
[ GitHub ]# File 'lib/rubocop/ast/node.rb', line 612
def_node_matcher :class_definition?, <<~PATTERN {(class _ _ $_) (sclass _ $_) (any_block (send #global_const?({:Struct :Class}) :new ...) _ $_)} PATTERN
#complete!
[ GitHub ]# File 'lib/rubocop/ast/node.rb', line 210
def complete! @mutable_attributes.freeze each_child_node(&:complete!) end
#const_name
[ GitHub ]# File 'lib/rubocop/ast/node.rb', line 359
def const_name return unless const_type? || casgn_type? if namespace && !namespace.cbase_type? "#{namespace.const_name}::#{short_name}" else short_name.to_s end end
#defined_module
[ GitHub ]# File 'lib/rubocop/ast/node.rb', line 379
def defined_module namespace, name = *defined_module0 s(:const, namespace, name) if name end
#defined_module0(node = self) (private)
[ GitHub ]# File 'lib/rubocop/ast/node.rb', line 370
def_node_matcher :defined_module0, <<~PATTERN {(class (const $_ $_) ...) (module (const $_ $_) ...) (casgn $_ $_ (send #global_const?({:Class :Module}) :new ...)) (casgn $_ $_ (block (send #global_const?({:Class :Module}) :new ...) ...))} PATTERN
#defined_module_name
[ GitHub ]# File 'lib/rubocop/ast/node.rb', line 384
def defined_module_name (const = defined_module) && const.const_name end
#each_ancestor ⇒ self
, Enumerator
#each_ancestor(type) ⇒ self
, Enumerator
#each_ancestor(type_a, type_b, ...) ⇒ self
, Enumerator
self
, Enumerator
#each_ancestor(type) ⇒ self
, Enumerator
#each_ancestor(type_a, type_b, ...) ⇒ self
, Enumerator
Calls the given block for each ancestor node from parent to root.
If no block is given, an Enumerator
is returned.
# File 'lib/rubocop/ast/node.rb', line 301
def each_ancestor(*types, &block) return to_enum(__method__, *types) unless block visit_ancestors(types, &block) self end
#first_line
[ GitHub ]# File 'lib/rubocop/ast/node.rb', line 327
def first_line loc.line end
#global_const?(node = self, name)
[ GitHub ]# File 'lib/rubocop/ast/node.rb', line 591
def_node_matcher :global_const?, '(const {nil? cbase} %1)'
#lambda?(node = self)
[ GitHub ]# File 'lib/rubocop/ast/node.rb', line 585
def_node_matcher :lambda?, '(any_block (send nil? :lambda) ...)'
#lambda_or_proc?(node = self)
[ GitHub ]# File 'lib/rubocop/ast/node.rb', line 588
def_node_matcher :lambda_or_proc?, '{lambda? proc?}'
#last_line
[ GitHub ]# File 'lib/rubocop/ast/node.rb', line 331
def last_line loc.last_line end
#left_sibling ⇒ Node
?
Use is discouraged, this is a potentially slow method and can lead to even slower algorithms
# File 'lib/rubocop/ast/node.rb', line 253
def left_sibling i = sibling_index return if i.nil? || i.zero? parent.children[i - 1].freeze end
#left_siblings ⇒ Array
<Node
>
Use is discouraged, this is a potentially slow method and can lead to even slower algorithms
# File 'lib/rubocop/ast/node.rb', line 263
def left_siblings return [].freeze unless parent parent.children[0...sibling_index].freeze end
#line_count
[ GitHub ]# File 'lib/rubocop/ast/node.rb', line 335
def line_count return 0 unless source_range source_range.last_line - source_range.first_line + 1 end
#loc?(which_loc) ⇒ Boolean
Shortcut to safely check if a location is present
# File 'lib/rubocop/ast/node.rb', line 558
def loc?(which_loc) return false unless loc.respond_to?(which_loc) !loc.public_send(which_loc).nil? end
#loc_is?(which_loc, str) ⇒ Boolean
Shortcut to safely test a particular location, even if
this location does not exist or is nil
# File 'lib/rubocop/ast/node.rb', line 566
def loc_is?(which_loc, str) return false unless loc?(which_loc) loc.public_send(which_loc).is?(str) end
#match_guard_clause?(node = self)
[ GitHub ]# File 'lib/rubocop/ast/node.rb', line 573
def_node_matcher :match_guard_clause?, <<~PATTERN [${(send nil? {:raise :fail} ...) return break next} single_line?] PATTERN
#module_definition?(node = self)
[ GitHub ]# File 'lib/rubocop/ast/node.rb', line 619
def_node_matcher :module_definition?, <<~PATTERN {(module _ $_) (any_block (send #global_const?(:Module) :new ...) _ $_)} PATTERN
#new_class_or_module_block?(node = self) (private)
[ GitHub ]# File 'lib/rubocop/ast/node.rb', line 750
def_node_matcher :new_class_or_module_block?, <<~PATTERN ^(casgn _ _ (block (send (const _ {:Class :Module}) :new) ...)) PATTERN
#node_parts ⇒ Array
<Node
>
Common destructuring method. This can be used to normalize destructuring for different variations of the node. Some node types override this with their own custom destructuring method.
# File 'lib/rubocop/ast/node.rb', line 284
alias node_parts to_a
#nonempty_line_count
[ GitHub ]# File 'lib/rubocop/ast/node.rb', line 341
def nonempty_line_count source.lines.grep(/\S/).size end
#parent_module_name
Searching the AST
# File 'lib/rubocop/ast/node.rb', line 390
def parent_module_name # what class or module is this method/constant/etc definition in? # returns nil if answer cannot be determined ancestors = each_ancestor(:class, :module, :sclass, :casgn, :block) result = ancestors.filter_map do |ancestor| parent_module_name_part(ancestor) do |full_name| return nil unless full_name full_name end end.reverse.join('::') result.empty? ? 'Object' : result end
#parent_module_name_for_block(ancestor) (private)
[ GitHub ]# File 'lib/rubocop/ast/node.rb', line 736
def parent_module_name_for_block(ancestor) if ancestor.method?(:class_eval) # `class_eval` with no receiver applies to whatever module or class # we are currently in return unless (receiver = ancestor.receiver) yield unless receiver.const_type? receiver.const_name elsif !new_class_or_module_block?(ancestor) yield end end
#parent_module_name_for_sclass(sclass_node) (private)
[ GitHub ]# File 'lib/rubocop/ast/node.rb', line 724
def parent_module_name_for_sclass(sclass_node) # TODO: look for constant definition and see if it is nested # inside a class or module subject = sclass_node.children[0] if subject.const_type? "#<Class:#{subject.const_name}>" elsif subject.self_type? "#<Class:#{sclass_node.parent_module_name}>" end end
#parent_module_name_part(node) (private)
[ GitHub ]# File 'lib/rubocop/ast/node.rb', line 711
def parent_module_name_part(node) case node.type when :class, :module, :casgn # TODO: if constant name has cbase (leading ::), then we don't need # to keep traversing up through nested classes/modules node.defined_module_name when :sclass yield parent_module_name_for_sclass(node) else # block parent_module_name_for_block(node) { yield nil } end end
#proc?(node = self)
[ GitHub ]# File 'lib/rubocop/ast/node.rb', line 578
def_node_matcher :proc?, <<~PATTERN {(block (send nil? :proc) ...) (block (send #global_const?(:Proc) :new) ...) (send #global_const?(:Proc) :new)} PATTERN
#receiver(node = self)
[ GitHub ]# File 'lib/rubocop/ast/node.rb', line 352
def_node_matcher :receiver, <<~PATTERN {(send $_ ...) (any_block (call $_ ...) ...)} PATTERN
#recursive_basic_literal? ⇒ Boolean
# File 'lib/rubocop/ast/node.rb', line 452
def_recursive_literal_predicate :basic_literal
#recursive_literal? ⇒ Boolean
# File 'lib/rubocop/ast/node.rb', line 451
def_recursive_literal_predicate :literal
#right_sibling ⇒ Node
?
Use is discouraged, this is a potentially slow method and can lead to even slower algorithms
# File 'lib/rubocop/ast/node.rb', line 244
def right_sibling return unless parent parent.children[sibling_index + 1].freeze end
#right_siblings ⇒ Array
<Node
>
Use is discouraged, this is a potentially slow method and can lead to even slower algorithms
# File 'lib/rubocop/ast/node.rb', line 272
def right_siblings return [].freeze unless parent parent.children[(sibling_index + 1)..].freeze end
#sibling_index ⇒ Integer
?
Returns the index of the receiver node in its siblings. (Sibling index uses zero based numbering.) Use is discouraged, this is a potentially slow method.
# File 'lib/rubocop/ast/node.rb', line 237
def sibling_index parent&.children&.index { |sibling| sibling.equal?(self) } end
#source ⇒ String
?
Note
|
Some rare nodes may have no source, like s(:args) in foo {}
|
# File 'lib/rubocop/ast/node.rb', line 319
def source loc.expression&.source end
#source_length
[ GitHub ]# File 'lib/rubocop/ast/node.rb', line 345
def source_length source_range ? source_range.size : 0 end
#source_range
[ GitHub ]# File 'lib/rubocop/ast/node.rb', line 323
def source_range loc.expression end
#str_content(node = self)
[ GitHub ]# File 'lib/rubocop/ast/node.rb', line 357
def_node_matcher :str_content, '(str $_)'
#struct_constructor?(node = self)
Use :class_constructor?
# File 'lib/rubocop/ast/node.rb', line 607
def_node_matcher :struct_constructor?, <<~PATTERN (any_block (send #global_const?(:Struct) :new ...) _ $_) PATTERN
#type?(*types) ⇒ Boolean
Determine if the node is one of several node types in a single query
Allows specific single node types, as well as "grouped" types
(e.g. :boolean
for :true
or :false
)
# File 'lib/rubocop/ast/node.rb', line 167
def type?(*types) return true if types.include?(type) group_type = GROUP_FOR_TYPE[type] !group_type.nil? && types.include?(group_type) end
#updated(type = nil, children = nil, properties = {})
Override #updated
so that AST::Processor
does not try to
mutate our ASTs. Since we keep references from children to parents and
not just the other way around, we cannot update an AST and share
identical subtrees. Rather, the entire AST must be copied any time any
part of it is changed.