mirror of
				https://gitea.invidious.io/iv-org/shard-ameba.git
				synced 2024-08-15 00:53:29 +00:00 
			
		
		
		
	Merge pull request #386 from crystal-ameba/fix-issue-385
This commit is contained in:
		
						commit
						21051acfff
					
				
					 2 changed files with 127 additions and 0 deletions
				
			
		
							
								
								
									
										57
									
								
								spec/ameba/rule/performance/excessive_allocations_spec.cr
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										57
									
								
								spec/ameba/rule/performance/excessive_allocations_spec.cr
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,57 @@ | |||
| require "../../../spec_helper" | ||||
| 
 | ||||
| module Ameba::Rule::Performance | ||||
|   subject = ExcessiveAllocations.new | ||||
| 
 | ||||
|   describe ExcessiveAllocations do | ||||
|     it "passes if there is no potential performance improvements" do | ||||
|       expect_no_issues subject, <<-CRYSTAL | ||||
|         "Alice".chars.each(arg) { |c| puts c } | ||||
|         "Alice".chars(arg).each { |c| puts c } | ||||
|         "Alice\nBob".lines.each(arg) { |l| puts l } | ||||
|         "Alice\nBob".lines(arg).each { |l| puts l } | ||||
|         CRYSTAL | ||||
|     end | ||||
| 
 | ||||
|     it "reports if there is a collection method followed by each" do | ||||
|       source = expect_issue subject, <<-CRYSTAL | ||||
|         "Alice".chars.each { |c| puts c } | ||||
|               # ^^^^^^^^^^ error: Use `each_char {...}` instead of `chars.each {...}` to avoid excessive allocation | ||||
|         "Alice\nBob".lines.each { |l| puts l } | ||||
|            # ^^^^^^^^^^ error: Use `each_line {...}` instead of `lines.each {...}` to avoid excessive allocation | ||||
|         CRYSTAL | ||||
| 
 | ||||
|       expect_correction source, <<-CRYSTAL | ||||
|         "Alice".each_char { |c| puts c } | ||||
|         "Alice\nBob".each_line { |l| puts l } | ||||
|         CRYSTAL | ||||
|     end | ||||
| 
 | ||||
|     it "does not report if source is a spec" do | ||||
|       expect_no_issues subject, <<-CRYSTAL, "source_spec.cr" | ||||
|         "Alice".chars.each { |c| puts c } | ||||
|         CRYSTAL | ||||
|     end | ||||
| 
 | ||||
|     context "properties" do | ||||
|       it "#call_names" do | ||||
|         rule = ExcessiveAllocations.new | ||||
|         rule.call_names = { | ||||
|           "children" => "each_child", | ||||
|         } | ||||
| 
 | ||||
|         expect_no_issues rule, <<-CRYSTAL | ||||
|           "Alice".chars.each { |c| puts c } | ||||
|           CRYSTAL | ||||
|       end | ||||
|     end | ||||
| 
 | ||||
|     context "macro" do | ||||
|       it "doesn't report in macro scope" do | ||||
|         expect_no_issues subject, <<-CRYSTAL | ||||
|           {{ "Alice".chars.each { |c| puts c } }} | ||||
|           CRYSTAL | ||||
|       end | ||||
|     end | ||||
|   end | ||||
| end | ||||
							
								
								
									
										70
									
								
								src/ameba/rule/performance/excessive_allocations.cr
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										70
									
								
								src/ameba/rule/performance/excessive_allocations.cr
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,70 @@ | |||
| require "./base" | ||||
| 
 | ||||
| module Ameba::Rule::Performance | ||||
|   # This rule is used to identify excessive collection allocations, | ||||
|   # that can be avoided by using `each_<member>` instead of `<collection>.each`. | ||||
|   # | ||||
|   # For example, this is considered inefficient: | ||||
|   # | ||||
|   # ``` | ||||
|   # "Alice".chars.each { |c| puts c } | ||||
|   # "Alice\nBob".lines.each { |l| puts l } | ||||
|   # ``` | ||||
|   # | ||||
|   # And can be written as this: | ||||
|   # | ||||
|   # ``` | ||||
|   # "Alice".each_char { |c| puts c } | ||||
|   # "Alice\nBob".each_line { |l| puts l } | ||||
|   # ``` | ||||
|   # | ||||
|   # YAML configuration example: | ||||
|   # | ||||
|   # ``` | ||||
|   # Performance/ExcessiveAllocations: | ||||
|   #   Enabled: true | ||||
|   #   CallNames: | ||||
|   #     codepoints: each_codepoint | ||||
|   #     graphemes: each_grapheme | ||||
|   #     chars: each_char | ||||
|   #     lines: each_line | ||||
|   # ``` | ||||
|   class ExcessiveAllocations < Base | ||||
|     include AST::Util | ||||
| 
 | ||||
|     properties do | ||||
|       description "Identifies usage of excessive collection allocations" | ||||
|       call_names({ | ||||
|         "codepoints" => "each_codepoint", | ||||
|         "graphemes"  => "each_grapheme", | ||||
|         "chars"      => "each_char", | ||||
|         "lines"      => "each_line", | ||||
|         # "keys"       => "each_key", | ||||
|         # "values"     => "each_value", | ||||
|         # "children"   => "each_child", | ||||
|       }) | ||||
|     end | ||||
| 
 | ||||
|     MSG = "Use `%s {...}` instead of `%s.each {...}` to avoid excessive allocation" | ||||
| 
 | ||||
|     def test(source) | ||||
|       AST::NodeVisitor.new self, source, skip: :macro | ||||
|     end | ||||
| 
 | ||||
|     def test(source, node : Crystal::Call) | ||||
|       return unless node.name == "each" && node.args.empty? | ||||
|       return unless (obj = node.obj).is_a?(Crystal::Call) | ||||
|       return unless obj.args.empty? && obj.block.nil? | ||||
|       return unless method = call_names[obj.name]? | ||||
| 
 | ||||
|       return unless name_location = obj.name_location | ||||
|       return unless end_location = name_end_location(node) | ||||
| 
 | ||||
|       msg = MSG % {method, obj.name} | ||||
| 
 | ||||
|       issue_for name_location, end_location, msg do |corrector| | ||||
|         corrector.replace(name_location, end_location, method) | ||||
|       end | ||||
|     end | ||||
|   end | ||||
| end | ||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue