rubocop 0.83.0 → 0.84.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (138) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +2 -2
  3. data/config/default.yml +20 -3
  4. data/lib/rubocop.rb +6 -59
  5. data/lib/rubocop/ast_aliases.rb +8 -0
  6. data/lib/rubocop/cli/command/show_cops.rb +2 -6
  7. data/lib/rubocop/config.rb +1 -3
  8. data/lib/rubocop/config_loader.rb +3 -9
  9. data/lib/rubocop/config_loader_resolver.rb +2 -6
  10. data/lib/rubocop/cop/autocorrect_logic.rb +1 -2
  11. data/lib/rubocop/cop/corrector.rb +1 -3
  12. data/lib/rubocop/cop/correctors/alignment_corrector.rb +2 -6
  13. data/lib/rubocop/cop/correctors/parentheses_corrector.rb +1 -3
  14. data/lib/rubocop/cop/correctors/space_corrector.rb +1 -3
  15. data/lib/rubocop/cop/gemspec/ordered_dependencies.rb +1 -3
  16. data/lib/rubocop/cop/generator.rb +1 -1
  17. data/lib/rubocop/cop/ignored_node.rb +1 -3
  18. data/lib/rubocop/cop/layout/empty_lines_around_access_modifier.rb +2 -6
  19. data/lib/rubocop/cop/layout/empty_lines_around_attribute_accessor.rb +62 -4
  20. data/lib/rubocop/cop/layout/first_argument_indentation.rb +0 -2
  21. data/lib/rubocop/cop/layout/first_array_element_indentation.rb +1 -3
  22. data/lib/rubocop/cop/layout/first_method_argument_line_break.rb +1 -3
  23. data/lib/rubocop/cop/layout/heredoc_argument_closing_parenthesis.rb +2 -6
  24. data/lib/rubocop/cop/layout/indentation_width.rb +1 -3
  25. data/lib/rubocop/cop/layout/multiline_block_layout.rb +1 -3
  26. data/lib/rubocop/cop/layout/multiline_method_argument_line_breaks.rb +1 -3
  27. data/lib/rubocop/cop/layout/space_around_method_call_operator.rb +2 -6
  28. data/lib/rubocop/cop/layout/space_before_comment.rb +1 -3
  29. data/lib/rubocop/cop/layout/space_inside_array_literal_brackets.rb +1 -3
  30. data/lib/rubocop/cop/layout/space_inside_reference_brackets.rb +2 -6
  31. data/lib/rubocop/cop/lint/ambiguous_operator.rb +4 -2
  32. data/lib/rubocop/cop/lint/deprecated_open_ssl_constant.rb +133 -0
  33. data/lib/rubocop/cop/lint/erb_new_arguments.rb +2 -6
  34. data/lib/rubocop/cop/lint/parentheses_as_grouped_expression.rb +11 -3
  35. data/lib/rubocop/cop/lint/percent_string_array.rb +1 -3
  36. data/lib/rubocop/cop/lint/suppressed_exception.rb +12 -1
  37. data/lib/rubocop/cop/lint/syntax.rb +1 -3
  38. data/lib/rubocop/cop/lint/useless_access_modifier.rb +1 -3
  39. data/lib/rubocop/cop/migration/department_name.rb +5 -9
  40. data/lib/rubocop/cop/mixin/alignment.rb +1 -3
  41. data/lib/rubocop/cop/mixin/array_min_size.rb +2 -6
  42. data/lib/rubocop/cop/mixin/check_line_breakable.rb +4 -12
  43. data/lib/rubocop/cop/mixin/configurable_enforced_style.rb +1 -3
  44. data/lib/rubocop/cop/mixin/configurable_formatting.rb +1 -3
  45. data/lib/rubocop/cop/mixin/multiline_element_indentation.rb +1 -3
  46. data/lib/rubocop/cop/mixin/surrounding_space.rb +1 -3
  47. data/lib/rubocop/cop/mixin/trailing_comma.rb +1 -3
  48. data/lib/rubocop/cop/naming/file_name.rb +1 -3
  49. data/lib/rubocop/cop/registry.rb +2 -6
  50. data/lib/rubocop/cop/severity.rb +1 -3
  51. data/lib/rubocop/cop/style/and_or.rb +2 -2
  52. data/lib/rubocop/cop/style/attr.rb +1 -3
  53. data/lib/rubocop/cop/style/block_delimiters.rb +2 -8
  54. data/lib/rubocop/cop/style/conditional_assignment.rb +1 -3
  55. data/lib/rubocop/cop/style/double_negation.rb +41 -4
  56. data/lib/rubocop/cop/style/empty_literal.rb +1 -3
  57. data/lib/rubocop/cop/style/frozen_string_literal_comment.rb +2 -4
  58. data/lib/rubocop/cop/style/hash_syntax.rb +12 -5
  59. data/lib/rubocop/cop/style/method_call_with_args_parentheses/require_parentheses.rb +1 -3
  60. data/lib/rubocop/cop/style/method_call_without_args_parentheses.rb +1 -3
  61. data/lib/rubocop/cop/style/one_line_conditional.rb +2 -6
  62. data/lib/rubocop/cop/style/redundant_parentheses.rb +2 -6
  63. data/lib/rubocop/cop/style/safe_navigation.rb +2 -6
  64. data/lib/rubocop/cop/style/slicing_with_range.rb +1 -1
  65. data/lib/rubocop/cop/style/special_global_vars.rb +2 -6
  66. data/lib/rubocop/cop/style/ternary_parentheses.rb +1 -3
  67. data/lib/rubocop/cop/style/trailing_underscore_variable.rb +2 -6
  68. data/lib/rubocop/cop/variable_force.rb +3 -9
  69. data/lib/rubocop/cop/variable_force/branch.rb +2 -6
  70. data/lib/rubocop/cop/variable_force/variable.rb +2 -6
  71. data/lib/rubocop/ext/processed_source.rb +18 -0
  72. data/lib/rubocop/formatter/base_formatter.rb +0 -4
  73. data/lib/rubocop/formatter/disabled_config_formatter.rb +4 -12
  74. data/lib/rubocop/formatter/formatter_set.rb +1 -3
  75. data/lib/rubocop/options.rb +2 -8
  76. data/lib/rubocop/remote_config.rb +1 -3
  77. data/lib/rubocop/result_cache.rb +1 -3
  78. data/lib/rubocop/rspec/cop_helper.rb +1 -3
  79. data/lib/rubocop/rspec/expect_offense.rb +3 -9
  80. data/lib/rubocop/rspec/shared_contexts.rb +54 -16
  81. data/lib/rubocop/runner.rb +8 -10
  82. data/lib/rubocop/target_finder.rb +2 -6
  83. data/lib/rubocop/version.rb +5 -3
  84. metadata +19 -56
  85. data/lib/rubocop/ast/builder.rb +0 -85
  86. data/lib/rubocop/ast/node.rb +0 -637
  87. data/lib/rubocop/ast/node/alias_node.rb +0 -24
  88. data/lib/rubocop/ast/node/and_node.rb +0 -29
  89. data/lib/rubocop/ast/node/args_node.rb +0 -29
  90. data/lib/rubocop/ast/node/array_node.rb +0 -70
  91. data/lib/rubocop/ast/node/block_node.rb +0 -121
  92. data/lib/rubocop/ast/node/break_node.rb +0 -17
  93. data/lib/rubocop/ast/node/case_match_node.rb +0 -56
  94. data/lib/rubocop/ast/node/case_node.rb +0 -56
  95. data/lib/rubocop/ast/node/class_node.rb +0 -31
  96. data/lib/rubocop/ast/node/def_node.rb +0 -82
  97. data/lib/rubocop/ast/node/defined_node.rb +0 -17
  98. data/lib/rubocop/ast/node/ensure_node.rb +0 -17
  99. data/lib/rubocop/ast/node/float_node.rb +0 -12
  100. data/lib/rubocop/ast/node/for_node.rb +0 -53
  101. data/lib/rubocop/ast/node/forward_args_node.rb +0 -18
  102. data/lib/rubocop/ast/node/hash_node.rb +0 -109
  103. data/lib/rubocop/ast/node/if_node.rb +0 -175
  104. data/lib/rubocop/ast/node/int_node.rb +0 -12
  105. data/lib/rubocop/ast/node/keyword_splat_node.rb +0 -45
  106. data/lib/rubocop/ast/node/mixin/basic_literal_node.rb +0 -16
  107. data/lib/rubocop/ast/node/mixin/binary_operator_node.rb +0 -43
  108. data/lib/rubocop/ast/node/mixin/collection_node.rb +0 -15
  109. data/lib/rubocop/ast/node/mixin/conditional_node.rb +0 -45
  110. data/lib/rubocop/ast/node/mixin/hash_element_node.rb +0 -125
  111. data/lib/rubocop/ast/node/mixin/method_dispatch_node.rb +0 -269
  112. data/lib/rubocop/ast/node/mixin/method_identifier_predicates.rb +0 -114
  113. data/lib/rubocop/ast/node/mixin/modifier_node.rb +0 -17
  114. data/lib/rubocop/ast/node/mixin/numeric_node.rb +0 -21
  115. data/lib/rubocop/ast/node/mixin/parameterized_node.rb +0 -61
  116. data/lib/rubocop/ast/node/mixin/predicate_operator_node.rb +0 -35
  117. data/lib/rubocop/ast/node/module_node.rb +0 -24
  118. data/lib/rubocop/ast/node/or_node.rb +0 -29
  119. data/lib/rubocop/ast/node/pair_node.rb +0 -63
  120. data/lib/rubocop/ast/node/range_node.rb +0 -18
  121. data/lib/rubocop/ast/node/regexp_node.rb +0 -33
  122. data/lib/rubocop/ast/node/resbody_node.rb +0 -24
  123. data/lib/rubocop/ast/node/retry_node.rb +0 -17
  124. data/lib/rubocop/ast/node/return_node.rb +0 -24
  125. data/lib/rubocop/ast/node/self_class_node.rb +0 -24
  126. data/lib/rubocop/ast/node/send_node.rb +0 -17
  127. data/lib/rubocop/ast/node/str_node.rb +0 -16
  128. data/lib/rubocop/ast/node/super_node.rb +0 -21
  129. data/lib/rubocop/ast/node/symbol_node.rb +0 -12
  130. data/lib/rubocop/ast/node/until_node.rb +0 -35
  131. data/lib/rubocop/ast/node/when_node.rb +0 -53
  132. data/lib/rubocop/ast/node/while_node.rb +0 -35
  133. data/lib/rubocop/ast/node/yield_node.rb +0 -21
  134. data/lib/rubocop/ast/sexp.rb +0 -16
  135. data/lib/rubocop/ast/traversal.rb +0 -202
  136. data/lib/rubocop/node_pattern.rb +0 -887
  137. data/lib/rubocop/processed_source.rb +0 -213
  138. data/lib/rubocop/token.rb +0 -114
@@ -54,9 +54,7 @@ module RuboCop
54
54
  # @return [Array] Array of filenames
55
55
  def target_files_in_dir(base_dir = Dir.pwd)
56
56
  # Support Windows: Backslashes from command-line -> forward slashes
57
- if File::ALT_SEPARATOR
58
- base_dir = base_dir.gsub(File::ALT_SEPARATOR, File::SEPARATOR)
59
- end
57
+ base_dir = base_dir.gsub(File::ALT_SEPARATOR, File::SEPARATOR) if File::ALT_SEPARATOR
60
58
  all_files = find_files(base_dir, File::FNM_DOTMATCH)
61
59
  hidden_files = Set.new(all_files - find_files(base_dir, 0))
62
60
  base_dir_config = @config_store.for(base_dir)
@@ -172,9 +170,7 @@ module RuboCop
172
170
  def process_explicit_path(path, mode)
173
171
  files = path.include?('*') ? Dir[path] : [path]
174
172
 
175
- if mode == :only_recognized_file_types || force_exclusion?
176
- files.select! { |file| included_file?(file) }
177
- end
173
+ files.select! { |file| included_file?(file) } if mode == :only_recognized_file_types || force_exclusion?
178
174
 
179
175
  return files unless force_exclusion?
180
176
 
@@ -3,14 +3,16 @@
3
3
  module RuboCop
4
4
  # This module holds the RuboCop version information.
5
5
  module Version
6
- STRING = '0.83.0'
6
+ STRING = '0.84.0'
7
7
 
8
- MSG = '%<version>s (using Parser %<parser_version>s, running on ' \
9
- '%<ruby_engine>s %<ruby_version>s %<ruby_platform>s)'
8
+ MSG = '%<version>s (using Parser %<parser_version>s, '\
9
+ 'rubocop-ast %<rubocop_ast_version>s, ' \
10
+ 'running on %<ruby_engine>s %<ruby_version>s %<ruby_platform>s)'
10
11
 
11
12
  def self.version(debug = false)
12
13
  if debug
13
14
  format(MSG, version: STRING, parser_version: Parser::VERSION,
15
+ rubocop_ast_version: RuboCop::AST::Version::STRING,
14
16
  ruby_engine: RUBY_ENGINE, ruby_version: RUBY_VERSION,
15
17
  ruby_platform: RUBY_PLATFORM)
16
18
  else
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rubocop
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.83.0
4
+ version: 0.84.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Bozhidar Batsov
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: exe
12
12
  cert_chain: []
13
- date: 2020-05-11 00:00:00.000000000 Z
13
+ date: 2020-05-21 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: parallel
@@ -74,6 +74,20 @@ dependencies:
74
74
  - - ">="
75
75
  - !ruby/object:Gem::Version
76
76
  version: '0'
77
+ - !ruby/object:Gem::Dependency
78
+ name: rubocop-ast
79
+ requirement: !ruby/object:Gem::Requirement
80
+ requirements:
81
+ - - ">="
82
+ - !ruby/object:Gem::Version
83
+ version: 0.0.3
84
+ type: :runtime
85
+ prerelease: false
86
+ version_requirements: !ruby/object:Gem::Requirement
87
+ requirements:
88
+ - - ">="
89
+ - !ruby/object:Gem::Version
90
+ version: 0.0.3
77
91
  - !ruby/object:Gem::Dependency
78
92
  name: ruby-progressbar
79
93
  requirement: !ruby/object:Gem::Requirement
@@ -148,57 +162,7 @@ files:
148
162
  - config/default.yml
149
163
  - exe/rubocop
150
164
  - lib/rubocop.rb
151
- - lib/rubocop/ast/builder.rb
152
- - lib/rubocop/ast/node.rb
153
- - lib/rubocop/ast/node/alias_node.rb
154
- - lib/rubocop/ast/node/and_node.rb
155
- - lib/rubocop/ast/node/args_node.rb
156
- - lib/rubocop/ast/node/array_node.rb
157
- - lib/rubocop/ast/node/block_node.rb
158
- - lib/rubocop/ast/node/break_node.rb
159
- - lib/rubocop/ast/node/case_match_node.rb
160
- - lib/rubocop/ast/node/case_node.rb
161
- - lib/rubocop/ast/node/class_node.rb
162
- - lib/rubocop/ast/node/def_node.rb
163
- - lib/rubocop/ast/node/defined_node.rb
164
- - lib/rubocop/ast/node/ensure_node.rb
165
- - lib/rubocop/ast/node/float_node.rb
166
- - lib/rubocop/ast/node/for_node.rb
167
- - lib/rubocop/ast/node/forward_args_node.rb
168
- - lib/rubocop/ast/node/hash_node.rb
169
- - lib/rubocop/ast/node/if_node.rb
170
- - lib/rubocop/ast/node/int_node.rb
171
- - lib/rubocop/ast/node/keyword_splat_node.rb
172
- - lib/rubocop/ast/node/mixin/basic_literal_node.rb
173
- - lib/rubocop/ast/node/mixin/binary_operator_node.rb
174
- - lib/rubocop/ast/node/mixin/collection_node.rb
175
- - lib/rubocop/ast/node/mixin/conditional_node.rb
176
- - lib/rubocop/ast/node/mixin/hash_element_node.rb
177
- - lib/rubocop/ast/node/mixin/method_dispatch_node.rb
178
- - lib/rubocop/ast/node/mixin/method_identifier_predicates.rb
179
- - lib/rubocop/ast/node/mixin/modifier_node.rb
180
- - lib/rubocop/ast/node/mixin/numeric_node.rb
181
- - lib/rubocop/ast/node/mixin/parameterized_node.rb
182
- - lib/rubocop/ast/node/mixin/predicate_operator_node.rb
183
- - lib/rubocop/ast/node/module_node.rb
184
- - lib/rubocop/ast/node/or_node.rb
185
- - lib/rubocop/ast/node/pair_node.rb
186
- - lib/rubocop/ast/node/range_node.rb
187
- - lib/rubocop/ast/node/regexp_node.rb
188
- - lib/rubocop/ast/node/resbody_node.rb
189
- - lib/rubocop/ast/node/retry_node.rb
190
- - lib/rubocop/ast/node/return_node.rb
191
- - lib/rubocop/ast/node/self_class_node.rb
192
- - lib/rubocop/ast/node/send_node.rb
193
- - lib/rubocop/ast/node/str_node.rb
194
- - lib/rubocop/ast/node/super_node.rb
195
- - lib/rubocop/ast/node/symbol_node.rb
196
- - lib/rubocop/ast/node/until_node.rb
197
- - lib/rubocop/ast/node/when_node.rb
198
- - lib/rubocop/ast/node/while_node.rb
199
- - lib/rubocop/ast/node/yield_node.rb
200
- - lib/rubocop/ast/sexp.rb
201
- - lib/rubocop/ast/traversal.rb
165
+ - lib/rubocop/ast_aliases.rb
202
166
  - lib/rubocop/cached_data.rb
203
167
  - lib/rubocop/cli.rb
204
168
  - lib/rubocop/cli/command.rb
@@ -356,6 +320,7 @@ files:
356
320
  - lib/rubocop/cop/lint/circular_argument_reference.rb
357
321
  - lib/rubocop/cop/lint/debugger.rb
358
322
  - lib/rubocop/cop/lint/deprecated_class_methods.rb
323
+ - lib/rubocop/cop/lint/deprecated_open_ssl_constant.rb
359
324
  - lib/rubocop/cop/lint/disjunctive_assignment_in_constructor.rb
360
325
  - lib/rubocop/cop/lint/duplicate_case_condition.rb
361
326
  - lib/rubocop/cop/lint/duplicate_hash_key.rb
@@ -721,6 +686,7 @@ files:
721
686
  - lib/rubocop/cop/variable_force/variable_table.rb
722
687
  - lib/rubocop/core_ext/string.rb
723
688
  - lib/rubocop/error.rb
689
+ - lib/rubocop/ext/processed_source.rb
724
690
  - lib/rubocop/file_finder.rb
725
691
  - lib/rubocop/formatter/auto_gen_config_formatter.rb
726
692
  - lib/rubocop/formatter/base_formatter.rb
@@ -744,11 +710,9 @@ files:
744
710
  - lib/rubocop/formatter/worst_offenders_formatter.rb
745
711
  - lib/rubocop/magic_comment.rb
746
712
  - lib/rubocop/name_similarity.rb
747
- - lib/rubocop/node_pattern.rb
748
713
  - lib/rubocop/options.rb
749
714
  - lib/rubocop/path_util.rb
750
715
  - lib/rubocop/platform.rb
751
- - lib/rubocop/processed_source.rb
752
716
  - lib/rubocop/rake_task.rb
753
717
  - lib/rubocop/remote_config.rb
754
718
  - lib/rubocop/result_cache.rb
@@ -761,7 +725,6 @@ files:
761
725
  - lib/rubocop/string_interpreter.rb
762
726
  - lib/rubocop/target_finder.rb
763
727
  - lib/rubocop/target_ruby.rb
764
- - lib/rubocop/token.rb
765
728
  - lib/rubocop/version.rb
766
729
  - lib/rubocop/warning.rb
767
730
  - lib/rubocop/yaml_duplication_checker.rb
@@ -1,85 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module RuboCop
4
- module AST
5
- # `RuboCop::AST::Builder` is an AST builder that is utilized to let `Parser`
6
- # generate ASTs with {RuboCop::AST::Node}.
7
- #
8
- # @example
9
- # buffer = Parser::Source::Buffer.new('(string)')
10
- # buffer.source = 'puts :foo'
11
- #
12
- # builder = RuboCop::AST::Builder.new
13
- # require 'parser/ruby25'
14
- # parser = Parser::Ruby25.new(builder)
15
- # root_node = parser.parse(buffer)
16
- class Builder < Parser::Builders::Default
17
- NODE_MAP = {
18
- and: AndNode,
19
- alias: AliasNode,
20
- args: ArgsNode,
21
- array: ArrayNode,
22
- block: BlockNode,
23
- numblock: BlockNode,
24
- break: BreakNode,
25
- case_match: CaseMatchNode,
26
- case: CaseNode,
27
- class: ClassNode,
28
- def: DefNode,
29
- defined?: DefinedNode,
30
- defs: DefNode,
31
- ensure: EnsureNode,
32
- for: ForNode,
33
- forward_args: ForwardArgsNode,
34
- float: FloatNode,
35
- hash: HashNode,
36
- if: IfNode,
37
- int: IntNode,
38
- irange: RangeNode,
39
- erange: RangeNode,
40
- kwsplat: KeywordSplatNode,
41
- module: ModuleNode,
42
- or: OrNode,
43
- pair: PairNode,
44
- regexp: RegexpNode,
45
- resbody: ResbodyNode,
46
- retry: RetryNode,
47
- return: ReturnNode,
48
- csend: SendNode,
49
- send: SendNode,
50
- str: StrNode,
51
- dstr: StrNode,
52
- xstr: StrNode,
53
- sclass: SelfClassNode,
54
- super: SuperNode,
55
- zsuper: SuperNode,
56
- sym: SymbolNode,
57
- until: UntilNode,
58
- until_post: UntilNode,
59
- when: WhenNode,
60
- while: WhileNode,
61
- while_post: WhileNode,
62
- yield: YieldNode
63
- }.freeze
64
-
65
- # Generates {Node} from the given information.
66
- #
67
- # @return [Node] the generated node
68
- def n(type, children, source_map)
69
- node_klass(type).new(type, children, location: source_map)
70
- end
71
-
72
- # TODO: Figure out what to do about literal encoding handling...
73
- # More details here https://github.com/whitequark/parser/issues/283
74
- def string_value(token)
75
- value(token)
76
- end
77
-
78
- private
79
-
80
- def node_klass(type)
81
- NODE_MAP[type] || Node
82
- end
83
- end
84
- end
85
- end
@@ -1,637 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module RuboCop
4
- module AST
5
- # `RuboCop::AST::Node` is a subclass of `Parser::AST::Node`. It provides
6
- # access to parent nodes and an object-oriented way to traverse an AST with
7
- # the power of `Enumerable`.
8
- #
9
- # It has predicate methods for every node type, like this:
10
- #
11
- # @example
12
- # node.send_type? # Equivalent to: `node.type == :send`
13
- # node.op_asgn_type? # Equivalent to: `node.type == :op_asgn`
14
- #
15
- # # Non-word characters (other than a-zA-Z0-9_) in type names are omitted.
16
- # node.defined_type? # Equivalent to: `node.type == :defined?`
17
- #
18
- # # Find the first lvar node under the receiver node.
19
- # lvar_node = node.each_descendant.find(&:lvar_type?)
20
- #
21
- class Node < Parser::AST::Node # rubocop:disable Metrics/ClassLength
22
- include RuboCop::AST::Sexp
23
- extend NodePattern::Macros
24
-
25
- # <=> isn't included here, because it doesn't return a boolean.
26
- COMPARISON_OPERATORS = %i[== === != <= >= > <].freeze
27
-
28
- TRUTHY_LITERALS = %i[str dstr xstr int float sym dsym array
29
- hash regexp true irange erange complex
30
- rational regopt].freeze
31
- FALSEY_LITERALS = %i[false nil].freeze
32
- LITERALS = (TRUTHY_LITERALS + FALSEY_LITERALS).freeze
33
- COMPOSITE_LITERALS = %i[dstr xstr dsym array hash irange
34
- erange regexp].freeze
35
- BASIC_LITERALS = (LITERALS - COMPOSITE_LITERALS).freeze
36
- MUTABLE_LITERALS = %i[str dstr xstr array hash
37
- regexp irange erange].freeze
38
- IMMUTABLE_LITERALS = (LITERALS - MUTABLE_LITERALS).freeze
39
-
40
- EQUALS_ASSIGNMENTS = %i[lvasgn ivasgn cvasgn gvasgn
41
- casgn masgn].freeze
42
- SHORTHAND_ASSIGNMENTS = %i[op_asgn or_asgn and_asgn].freeze
43
- ASSIGNMENTS = (EQUALS_ASSIGNMENTS + SHORTHAND_ASSIGNMENTS).freeze
44
-
45
- BASIC_CONDITIONALS = %i[if while until].freeze
46
- CONDITIONALS = [*BASIC_CONDITIONALS, :case].freeze
47
- VARIABLES = %i[ivar gvar cvar lvar].freeze
48
- REFERENCES = %i[nth_ref back_ref].freeze
49
- KEYWORDS = %i[alias and break case class def defs defined?
50
- kwbegin do else ensure for if module next
51
- not or postexe redo rescue retry return self
52
- super zsuper then undef until when while
53
- yield].freeze
54
- OPERATOR_KEYWORDS = %i[and or].freeze
55
- SPECIAL_KEYWORDS = %w[__FILE__ __LINE__ __ENCODING__].freeze
56
-
57
- # @see https://www.rubydoc.info/gems/ast/AST/Node:initialize
58
- def initialize(type, children = [], properties = {})
59
- @mutable_attributes = {}
60
-
61
- # ::AST::Node#initialize freezes itself.
62
- super
63
-
64
- # #parent= may be invoked multiple times for a node because there are
65
- # pending nodes while constructing AST and they are replaced later.
66
- # For example, `lvar` and `send` type nodes are initially created as an
67
- # `ident` type node and fixed to the appropriate type later.
68
- # So, the #parent attribute needs to be mutable.
69
- each_child_node do |child_node|
70
- child_node.parent = self unless child_node.complete?
71
- end
72
- end
73
-
74
- Parser::Meta::NODE_TYPES.each do |node_type|
75
- method_name = "#{node_type.to_s.gsub(/\W/, '')}_type?"
76
- define_method(method_name) do
77
- type == node_type
78
- end
79
- end
80
-
81
- # Returns the parent node, or `nil` if the receiver is a root node.
82
- #
83
- # @return [Node, nil] the parent node or `nil`
84
- def parent
85
- @mutable_attributes[:parent]
86
- end
87
-
88
- def parent=(node)
89
- @mutable_attributes[:parent] = node
90
- end
91
-
92
- def complete!
93
- @mutable_attributes.freeze
94
- each_child_node(&:complete!)
95
- end
96
-
97
- def complete?
98
- @mutable_attributes.frozen?
99
- end
100
-
101
- protected :parent=
102
-
103
- # Override `AST::Node#updated` so that `AST::Processor` does not try to
104
- # mutate our ASTs. Since we keep references from children to parents and
105
- # not just the other way around, we cannot update an AST and share
106
- # identical subtrees. Rather, the entire AST must be copied any time any
107
- # part of it is changed.
108
- def updated(type = nil, children = nil, properties = {})
109
- properties[:location] ||= @location
110
- klass = RuboCop::AST::Builder::NODE_MAP[type || @type] || Node
111
- klass.new(type || @type, children || @children, properties)
112
- end
113
-
114
- # Returns the index of the receiver node in its siblings. (Sibling index
115
- # uses zero based numbering.)
116
- #
117
- # @return [Integer] the index of the receiver node in its siblings
118
- def sibling_index
119
- parent&.children&.index { |sibling| sibling.equal?(self) }
120
- end
121
-
122
- # Common destructuring method. This can be used to normalize
123
- # destructuring for different variations of the node.
124
- # Some node types override this with their own custom
125
- # destructuring method.
126
- #
127
- # @return [Array<Node>] the different parts of the ndde
128
- def node_parts
129
- to_a
130
- end
131
-
132
- # Calls the given block for each ancestor node from parent to root.
133
- # If no block is given, an `Enumerator` is returned.
134
- #
135
- # @overload each_ancestor
136
- # Yield all nodes.
137
- # @overload each_ancestor(type)
138
- # Yield only nodes matching the type.
139
- # @param [Symbol] type a node type
140
- # @overload each_ancestor(type_a, type_b, ...)
141
- # Yield only nodes matching any of the types.
142
- # @param [Symbol] type_a a node type
143
- # @param [Symbol] type_b a node type
144
- # @yieldparam [Node] node each ancestor node
145
- # @return [self] if a block is given
146
- # @return [Enumerator] if no block is given
147
- def each_ancestor(*types, &block)
148
- return to_enum(__method__, *types) unless block_given?
149
-
150
- visit_ancestors(types, &block)
151
-
152
- self
153
- end
154
-
155
- # Returns an array of ancestor nodes.
156
- # This is a shorthand for `node.each_ancestor.to_a`.
157
- #
158
- # @return [Array<Node>] an array of ancestor nodes
159
- def ancestors
160
- each_ancestor.to_a
161
- end
162
-
163
- # Calls the given block for each child node.
164
- # If no block is given, an `Enumerator` is returned.
165
- #
166
- # Note that this is different from `node.children.each { |child| ... }`
167
- # which yields all children including non-node elements.
168
- #
169
- # @overload each_child_node
170
- # Yield all nodes.
171
- # @overload each_child_node(type)
172
- # Yield only nodes matching the type.
173
- # @param [Symbol] type a node type
174
- # @overload each_child_node(type_a, type_b, ...)
175
- # Yield only nodes matching any of the types.
176
- # @param [Symbol] type_a a node type
177
- # @param [Symbol] type_b a node type
178
- # @yieldparam [Node] node each child node
179
- # @return [self] if a block is given
180
- # @return [Enumerator] if no block is given
181
- def each_child_node(*types)
182
- return to_enum(__method__, *types) unless block_given?
183
-
184
- children.each do |child|
185
- next unless child.is_a?(Node)
186
-
187
- yield child if types.empty? || types.include?(child.type)
188
- end
189
-
190
- self
191
- end
192
-
193
- # Returns an array of child nodes.
194
- # This is a shorthand for `node.each_child_node.to_a`.
195
- #
196
- # @return [Array<Node>] an array of child nodes
197
- def child_nodes
198
- each_child_node.to_a
199
- end
200
-
201
- # Calls the given block for each descendant node with depth first order.
202
- # If no block is given, an `Enumerator` is returned.
203
- #
204
- # @overload each_descendant
205
- # Yield all nodes.
206
- # @overload each_descendant(type)
207
- # Yield only nodes matching the type.
208
- # @param [Symbol] type a node type
209
- # @overload each_descendant(type_a, type_b, ...)
210
- # Yield only nodes matching any of the types.
211
- # @param [Symbol] type_a a node type
212
- # @param [Symbol] type_b a node type
213
- # @yieldparam [Node] node each descendant node
214
- # @return [self] if a block is given
215
- # @return [Enumerator] if no block is given
216
- def each_descendant(*types, &block)
217
- return to_enum(__method__, *types) unless block_given?
218
-
219
- visit_descendants(types, &block)
220
-
221
- self
222
- end
223
-
224
- # Returns an array of descendant nodes.
225
- # This is a shorthand for `node.each_descendant.to_a`.
226
- #
227
- # @return [Array<Node>] an array of descendant nodes
228
- def descendants
229
- each_descendant.to_a
230
- end
231
-
232
- # Calls the given block for the receiver and each descendant node in
233
- # depth-first order.
234
- # If no block is given, an `Enumerator` is returned.
235
- #
236
- # This method would be useful when you treat the receiver node as the root
237
- # of a tree and want to iterate over all nodes in the tree.
238
- #
239
- # @overload each_node
240
- # Yield all nodes.
241
- # @overload each_node(type)
242
- # Yield only nodes matching the type.
243
- # @param [Symbol] type a node type
244
- # @overload each_node(type_a, type_b, ...)
245
- # Yield only nodes matching any of the types.
246
- # @param [Symbol] type_a a node type
247
- # @param [Symbol] type_b a node type
248
- # @yieldparam [Node] node each node
249
- # @return [self] if a block is given
250
- # @return [Enumerator] if no block is given
251
- def each_node(*types, &block)
252
- return to_enum(__method__, *types) unless block_given?
253
-
254
- yield self if types.empty? || types.include?(type)
255
-
256
- visit_descendants(types, &block)
257
-
258
- self
259
- end
260
-
261
- def source
262
- loc.expression.source
263
- end
264
-
265
- def source_range
266
- loc.expression
267
- end
268
-
269
- def first_line
270
- loc.line
271
- end
272
-
273
- def last_line
274
- loc.last_line
275
- end
276
-
277
- def line_count
278
- return 0 unless source_range
279
-
280
- source_range.last_line - source_range.first_line + 1
281
- end
282
-
283
- def nonempty_line_count
284
- source.lines.grep(/\S/).size
285
- end
286
-
287
- def source_length
288
- source_range ? source_range.size : 0
289
- end
290
-
291
- ## Destructuring
292
-
293
- def_node_matcher :receiver, <<~PATTERN
294
- {(send $_ ...) ({block numblock} (send $_ ...) ...)}
295
- PATTERN
296
-
297
- def_node_matcher :str_content, '(str $_)'
298
-
299
- def const_name
300
- return unless const_type?
301
-
302
- namespace, name = *self
303
- if namespace && !namespace.cbase_type?
304
- "#{namespace.const_name}::#{name}"
305
- else
306
- name.to_s
307
- end
308
- end
309
-
310
- def_node_matcher :defined_module0, <<~PATTERN
311
- {(class (const $_ $_) ...)
312
- (module (const $_ $_) ...)
313
- (casgn $_ $_ (send (const nil? {:Class :Module}) :new ...))
314
- (casgn $_ $_ (block (send (const nil? {:Class :Module}) :new ...) ...))}
315
- PATTERN
316
-
317
- private :defined_module0
318
-
319
- def defined_module
320
- namespace, name = *defined_module0
321
- s(:const, namespace, name) if name
322
- end
323
-
324
- def defined_module_name
325
- (const = defined_module) && const.const_name
326
- end
327
-
328
- ## Searching the AST
329
-
330
- def parent_module_name
331
- # what class or module is this method/constant/etc definition in?
332
- # returns nil if answer cannot be determined
333
- ancestors = each_ancestor(:class, :module, :sclass, :casgn, :block)
334
- result = ancestors.map do |ancestor|
335
- parent_module_name_part(ancestor) { |full_name| return full_name }
336
- end.compact.reverse.join('::')
337
- result.empty? ? 'Object' : result
338
- end
339
-
340
- ## Predicates
341
-
342
- def multiline?
343
- line_count > 1
344
- end
345
-
346
- def single_line?
347
- line_count == 1
348
- end
349
-
350
- def empty_source?
351
- source_length.zero?
352
- end
353
-
354
- # Some cops treat the shovel operator as a kind of assignment.
355
- def_node_matcher :assignment_or_similar?, <<~PATTERN
356
- {assignment? (send _recv :<< ...)}
357
- PATTERN
358
-
359
- def literal?
360
- LITERALS.include?(type)
361
- end
362
-
363
- def basic_literal?
364
- BASIC_LITERALS.include?(type)
365
- end
366
-
367
- def truthy_literal?
368
- TRUTHY_LITERALS.include?(type)
369
- end
370
-
371
- def falsey_literal?
372
- FALSEY_LITERALS.include?(type)
373
- end
374
-
375
- def mutable_literal?
376
- MUTABLE_LITERALS.include?(type)
377
- end
378
-
379
- def immutable_literal?
380
- IMMUTABLE_LITERALS.include?(type)
381
- end
382
-
383
- %i[literal basic_literal].each do |kind|
384
- recursive_kind = :"recursive_#{kind}?"
385
- kind_filter = :"#{kind}?"
386
- define_method(recursive_kind) do
387
- case type
388
- when :send
389
- [*COMPARISON_OPERATORS, :!, :<=>].include?(method_name) &&
390
- receiver.send(recursive_kind) &&
391
- arguments.all?(&recursive_kind)
392
- when :begin, :pair, *OPERATOR_KEYWORDS, *COMPOSITE_LITERALS
393
- children.compact.all?(&recursive_kind)
394
- else
395
- send(kind_filter)
396
- end
397
- end
398
- end
399
-
400
- def variable?
401
- VARIABLES.include?(type)
402
- end
403
-
404
- def reference?
405
- REFERENCES.include?(type)
406
- end
407
-
408
- def equals_asgn?
409
- EQUALS_ASSIGNMENTS.include?(type)
410
- end
411
-
412
- def shorthand_asgn?
413
- SHORTHAND_ASSIGNMENTS.include?(type)
414
- end
415
-
416
- def assignment?
417
- ASSIGNMENTS.include?(type)
418
- end
419
-
420
- def basic_conditional?
421
- BASIC_CONDITIONALS.include?(type)
422
- end
423
-
424
- def conditional?
425
- CONDITIONALS.include?(type)
426
- end
427
-
428
- def keyword?
429
- return true if special_keyword? || send_type? && prefix_not?
430
- return false unless KEYWORDS.include?(type)
431
-
432
- !OPERATOR_KEYWORDS.include?(type) || loc.operator.is?(type.to_s)
433
- end
434
-
435
- def special_keyword?
436
- SPECIAL_KEYWORDS.include?(source)
437
- end
438
-
439
- def operator_keyword?
440
- OPERATOR_KEYWORDS.include?(type)
441
- end
442
-
443
- def parenthesized_call?
444
- loc.respond_to?(:begin) && loc.begin && loc.begin.is?('(')
445
- end
446
-
447
- def call_type?
448
- send_type? || csend_type?
449
- end
450
-
451
- def chained?
452
- parent&.call_type? && eql?(parent.receiver)
453
- end
454
-
455
- def argument?
456
- parent&.send_type? && parent.arguments.include?(self)
457
- end
458
-
459
- def boolean_type?
460
- true_type? || false_type?
461
- end
462
-
463
- def numeric_type?
464
- int_type? || float_type?
465
- end
466
-
467
- def range_type?
468
- irange_type? || erange_type?
469
- end
470
-
471
- def guard_clause?
472
- node = and_type? || or_type? ? rhs : self
473
-
474
- node.match_guard_clause?
475
- end
476
-
477
- def_node_matcher :match_guard_clause?, <<~PATTERN
478
- [${(send nil? {:raise :fail} ...) return break next} single_line?]
479
- PATTERN
480
-
481
- def_node_matcher :proc?, <<~PATTERN
482
- {(block (send nil? :proc) ...)
483
- (block (send (const nil? :Proc) :new) ...)
484
- (send (const nil? :Proc) :new)}
485
- PATTERN
486
-
487
- def_node_matcher :lambda?, '({block numblock} (send nil? :lambda) ...)'
488
- def_node_matcher :lambda_or_proc?, '{lambda? proc?}'
489
-
490
- def_node_matcher :class_constructor?, <<~PATTERN
491
- { (send (const nil? {:Class :Module}) :new ...)
492
- (block (send (const nil? {:Class :Module}) :new ...) ...)}
493
- PATTERN
494
-
495
- # Some expressions are evaluated for their value, some for their side
496
- # effects, and some for both
497
- # If we know that an expression is useful only for its side effects, that
498
- # means we can transform it in ways which preserve the side effects, but
499
- # change the return value
500
- # So, does the return value of this node matter? If we changed it to
501
- # `(...; nil)`, might that affect anything?
502
- #
503
- # rubocop:disable Metrics/MethodLength, Metrics/CyclomaticComplexity
504
- def value_used?
505
- # Be conservative and return true if we're not sure.
506
- return false if parent.nil?
507
-
508
- case parent.type
509
- when :array, :defined?, :dstr, :dsym, :eflipflop, :erange, :float,
510
- :hash, :iflipflop, :irange, :not, :pair, :regexp, :str, :sym,
511
- :when, :xstr
512
- parent.value_used?
513
- when :begin, :kwbegin
514
- begin_value_used?
515
- when :for
516
- for_value_used?
517
- when :case, :if
518
- case_if_value_used?
519
- when :while, :until, :while_post, :until_post
520
- while_until_value_used?
521
- else
522
- true
523
- end
524
- end
525
- # rubocop:enable Metrics/MethodLength, Metrics/CyclomaticComplexity
526
-
527
- # Some expressions are evaluated for their value, some for their side
528
- # effects, and some for both.
529
- # If we know that expressions are useful only for their return values,
530
- # and have no side effects, that means we can reorder them, change the
531
- # number of times they are evaluated, or replace them with other
532
- # expressions which are equivalent in value.
533
- # So, is evaluation of this node free of side effects?
534
- #
535
- def pure?
536
- # Be conservative and return false if we're not sure
537
- case type
538
- when :__FILE__, :__LINE__, :const, :cvar, :defined?, :false, :float,
539
- :gvar, :int, :ivar, :lvar, :nil, :str, :sym, :true, :regopt
540
- true
541
- when :and, :array, :begin, :case, :dstr, :dsym, :eflipflop, :ensure,
542
- :erange, :for, :hash, :if, :iflipflop, :irange, :kwbegin, :not,
543
- :or, :pair, :regexp, :until, :until_post, :when, :while,
544
- :while_post
545
- child_nodes.all?(&:pure?)
546
- else
547
- false
548
- end
549
- end
550
-
551
- protected
552
-
553
- def visit_descendants(types, &block)
554
- each_child_node do |child|
555
- yield child if types.empty? || types.include?(child.type)
556
- child.visit_descendants(types, &block)
557
- end
558
- end
559
-
560
- private
561
-
562
- def visit_ancestors(types)
563
- last_node = self
564
-
565
- while (current_node = last_node.parent)
566
- yield current_node if types.empty? ||
567
- types.include?(current_node.type)
568
- last_node = current_node
569
- end
570
- end
571
-
572
- def begin_value_used?
573
- # the last child node determines the value of the parent
574
- sibling_index == parent.children.size - 1 ? parent.value_used? : false
575
- end
576
-
577
- def for_value_used?
578
- # `for var in enum; body; end`
579
- # (for <var> <enum> <body>)
580
- sibling_index == 2 ? parent.value_used? : true
581
- end
582
-
583
- def case_if_value_used?
584
- # (case <condition> <when...>)
585
- # (if <condition> <truebranch> <falsebranch>)
586
- sibling_index.zero? ? true : parent.value_used?
587
- end
588
-
589
- def while_until_value_used?
590
- # (while <condition> <body>) -> always evaluates to `nil`
591
- sibling_index.zero?
592
- end
593
-
594
- def parent_module_name_part(node)
595
- case node.type
596
- when :class, :module, :casgn
597
- # TODO: if constant name has cbase (leading ::), then we don't need
598
- # to keep traversing up through nested classes/modules
599
- node.defined_module_name
600
- when :sclass
601
- yield parent_module_name_for_sclass(node)
602
- else # block
603
- parent_module_name_for_block(node) { yield nil }
604
- end
605
- end
606
-
607
- def parent_module_name_for_sclass(sclass_node)
608
- # TODO: look for constant definition and see if it is nested
609
- # inside a class or module
610
- subject = sclass_node.children[0]
611
-
612
- if subject.const_type?
613
- "#<Class:#{subject.const_name}>"
614
- elsif subject.self_type?
615
- "#<Class:#{sclass_node.parent_module_name}>"
616
- end
617
- end
618
-
619
- def parent_module_name_for_block(ancestor)
620
- if ancestor.method?(:class_eval)
621
- # `class_eval` with no receiver applies to whatever module or class
622
- # we are currently in
623
- return unless (receiver = ancestor.receiver)
624
-
625
- yield unless receiver.const_type?
626
- receiver.const_name
627
- elsif !new_class_or_module_block?(ancestor)
628
- yield
629
- end
630
- end
631
-
632
- def_node_matcher :new_class_or_module_block?, <<~PATTERN
633
- ^(casgn _ _ (block (send (const _ {:Class :Module}) :new) ...))
634
- PATTERN
635
- end
636
- end
637
- end