mirror of
				https://gitea.invidious.io/iv-org/shard-ameba.git
				synced 2024-08-15 00:53:29 +00:00 
			
		
		
		
	Merge pull request #137 from crystal-ameba/feat/redundant-string-coercion
New rule: Lint/RedundantStringCoercion
This commit is contained in:
		
						commit
						9c6bc2a376
					
				
					 2 changed files with 133 additions and 0 deletions
				
			
		
							
								
								
									
										90
									
								
								spec/ameba/rule/lint/redundant_string_cercion_spec.cr
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										90
									
								
								spec/ameba/rule/lint/redundant_string_cercion_spec.cr
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,90 @@
 | 
				
			||||||
 | 
					require "../../../spec_helper"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					module Ameba::Rule::Lint
 | 
				
			||||||
 | 
					  describe RedundantStringCoercion do
 | 
				
			||||||
 | 
					    subject = RedundantStringCoercion.new
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    it "does not report if there is no redundant string coersion" do
 | 
				
			||||||
 | 
					      s = Source.new %(
 | 
				
			||||||
 | 
					        "Hello, #{name}"
 | 
				
			||||||
 | 
					      )
 | 
				
			||||||
 | 
					      subject.catch(s).should be_valid
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    it "reports if there is a redundant string coersion" do
 | 
				
			||||||
 | 
					      s = Source.new %q(
 | 
				
			||||||
 | 
					        "Hello, #{name.to_s}"
 | 
				
			||||||
 | 
					      )
 | 
				
			||||||
 | 
					      subject.catch(s).should_not be_valid
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    it "does not report if coersion is used in binary op" do
 | 
				
			||||||
 | 
					      s = Source.new %q(
 | 
				
			||||||
 | 
					        "Hello, #{3.to_s + 's'}"
 | 
				
			||||||
 | 
					      )
 | 
				
			||||||
 | 
					      subject.catch(s).should be_valid
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    it "reports if coercion is used with symbol literals" do
 | 
				
			||||||
 | 
					      s = Source.new %q("Hello, #{:symbol.to_s}")
 | 
				
			||||||
 | 
					      subject.catch(s).should_not be_valid
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    it "reports if coercion is used with number literals" do
 | 
				
			||||||
 | 
					      s = Source.new %q("Hello, #{42.to_s}")
 | 
				
			||||||
 | 
					      subject.catch(s).should_not be_valid
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    it "reports if coercion is used with boolean literals" do
 | 
				
			||||||
 | 
					      s = Source.new %q("Hello, #{false.to_s}")
 | 
				
			||||||
 | 
					      subject.catch(s).should_not be_valid
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    it "reports if coercion is used with char literals" do
 | 
				
			||||||
 | 
					      s = Source.new %q("Hello, #{'t'.to_s}")
 | 
				
			||||||
 | 
					      subject.catch(s).should_not be_valid
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    it "reports redundant coercion in regex" do
 | 
				
			||||||
 | 
					      s = Source.new %q(
 | 
				
			||||||
 | 
					        /\w #{name.to_s}/
 | 
				
			||||||
 | 
					      )
 | 
				
			||||||
 | 
					      subject.catch(s).should_not be_valid
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    it "doesn't report if Object#to_s is called with arguments" do
 | 
				
			||||||
 | 
					      s = Source.new %q(
 | 
				
			||||||
 | 
					        /\w #{name.to_s(io)}/
 | 
				
			||||||
 | 
					      )
 | 
				
			||||||
 | 
					      subject.catch(s).should be_valid
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    it "doesn't report if Object#to_s is called without receiver" do
 | 
				
			||||||
 | 
					      s = Source.new %q(
 | 
				
			||||||
 | 
					        /\w #{to_s}/
 | 
				
			||||||
 | 
					      )
 | 
				
			||||||
 | 
					      subject.catch(s).should be_valid
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    it "reports rule, location and message" do
 | 
				
			||||||
 | 
					      s = Source.new %q(
 | 
				
			||||||
 | 
					        "Hello, #{name1.to_s}"
 | 
				
			||||||
 | 
					        "Hello, #{name2.to_s}"
 | 
				
			||||||
 | 
					      ), "source.cr"
 | 
				
			||||||
 | 
					      subject.catch(s).should_not be_valid
 | 
				
			||||||
 | 
					      s.issues.size.should eq 2
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      issue = s.issues[0]
 | 
				
			||||||
 | 
					      issue.rule.should_not be_nil
 | 
				
			||||||
 | 
					      issue.location.to_s.should eq "source.cr:1:17"
 | 
				
			||||||
 | 
					      issue.end_location.to_s.should eq "source.cr:1:20"
 | 
				
			||||||
 | 
					      issue.message.should eq RedundantStringCoercion::MSG
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      issue = s.issues[1]
 | 
				
			||||||
 | 
					      issue.rule.should_not be_nil
 | 
				
			||||||
 | 
					      issue.location.to_s.should eq "source.cr:2:17"
 | 
				
			||||||
 | 
					      issue.end_location.to_s.should eq "source.cr:2:20"
 | 
				
			||||||
 | 
					      issue.message.should eq RedundantStringCoercion::MSG
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					end
 | 
				
			||||||
							
								
								
									
										43
									
								
								src/ameba/rule/lint/redundant_string_coercion.cr
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										43
									
								
								src/ameba/rule/lint/redundant_string_coercion.cr
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,43 @@
 | 
				
			||||||
 | 
					module Ameba::Rule::Lint
 | 
				
			||||||
 | 
					  # A rule that disallows string conversion in string interpolation,
 | 
				
			||||||
 | 
					  # which is redundant.
 | 
				
			||||||
 | 
					  #
 | 
				
			||||||
 | 
					  # For example, this is considered invalid:
 | 
				
			||||||
 | 
					  #
 | 
				
			||||||
 | 
					  # ```
 | 
				
			||||||
 | 
					  # "Hello, #{name.to_s}"
 | 
				
			||||||
 | 
					  # ```
 | 
				
			||||||
 | 
					  #
 | 
				
			||||||
 | 
					  # And this is valid:
 | 
				
			||||||
 | 
					  #
 | 
				
			||||||
 | 
					  # ```
 | 
				
			||||||
 | 
					  # "Hello, #{name}"
 | 
				
			||||||
 | 
					  # ```
 | 
				
			||||||
 | 
					  #
 | 
				
			||||||
 | 
					  # YAML configuration example:
 | 
				
			||||||
 | 
					  #
 | 
				
			||||||
 | 
					  # ```
 | 
				
			||||||
 | 
					  # Lint/RedundantStringCoersion
 | 
				
			||||||
 | 
					  #   Enabled: true
 | 
				
			||||||
 | 
					  # ```
 | 
				
			||||||
 | 
					  #
 | 
				
			||||||
 | 
					  struct RedundantStringCoercion < Base
 | 
				
			||||||
 | 
					    include AST::Util
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    properties do
 | 
				
			||||||
 | 
					      description "Disallows redundant string conversions in interpolation"
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    MSG = "Redundant use of `Object#to_s` in interpolation"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test(source, node : Crystal::StringInterpolation)
 | 
				
			||||||
 | 
					      string_coercion_nodes(node).each { |n| issue_for n.name_location, n.end_location, MSG }
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private def string_coercion_nodes(node)
 | 
				
			||||||
 | 
					      node.expressions.select do |e|
 | 
				
			||||||
 | 
					        e.is_a?(Crystal::Call) && e.name == "to_s" && e.args.size.zero? && e.obj
 | 
				
			||||||
 | 
					      end
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					end
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue