mirror of
				https://gitea.invidious.io/iv-org/shard-ameba.git
				synced 2024-08-15 00:53:29 +00:00 
			
		
		
		
	Followup to #185
This commit is contained in:
		
							parent
							
								
									fd4b2f309c
								
							
						
					
					
						commit
						af5d825015
					
				
					 21 changed files with 32 additions and 31 deletions
				
			
		| 
						 | 
				
			
			@ -175,7 +175,7 @@ module Ameba::AST
 | 
			
		|||
      end
 | 
			
		||||
 | 
			
		||||
      def references?(node : Crystal::Var)
 | 
			
		||||
        @macro_literals.any? { |literal| literal.value.includes? node.name }
 | 
			
		||||
        @macro_literals.any?(&.value.includes?(node.name))
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      def visit(node : Crystal::ASTNode)
 | 
			
		||||
| 
						 | 
				
			
			@ -190,7 +190,7 @@ module Ameba::AST
 | 
			
		|||
    private def update_assign_reference!
 | 
			
		||||
      if @assign_before_reference.nil? &&
 | 
			
		||||
         references.size <= assignments.size &&
 | 
			
		||||
         assignments.none? { |ass| ass.op_assign? }
 | 
			
		||||
         assignments.none?(&.op_assign?)
 | 
			
		||||
        @assign_before_reference = assignments.find { |ass| !ass.in_branch? }.try &.node
 | 
			
		||||
      end
 | 
			
		||||
    end
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -18,7 +18,6 @@ module Ameba::AST
 | 
			
		|||
      if flow_expression?(node, in_loop?)
 | 
			
		||||
        @rule.test @source, node, FlowExpression.new(node, in_loop?)
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      true
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -40,7 +40,7 @@ module Ameba::AST
 | 
			
		|||
    @skip : Array(Crystal::ASTNode.class)?
 | 
			
		||||
 | 
			
		||||
    def initialize(@rule, @source, skip = nil)
 | 
			
		||||
      @skip = skip.try &.map { |el| el.as(Crystal::ASTNode.class) }
 | 
			
		||||
      @skip = skip.try &.map(&.as(Crystal::ASTNode.class))
 | 
			
		||||
      super @rule, @source
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -54,7 +54,7 @@ module Ameba::AST
 | 
			
		|||
    {% end %}
 | 
			
		||||
 | 
			
		||||
    def visit(node)
 | 
			
		||||
      return true unless (skip = @skip)
 | 
			
		||||
      return true unless skip = @skip
 | 
			
		||||
      !skip.includes?(node.class)
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -28,8 +28,6 @@ module Ameba::AST
 | 
			
		|||
      when Crystal::Case                then traverse_case node
 | 
			
		||||
      when Crystal::BinaryOp            then traverse_binary_op node
 | 
			
		||||
      when Crystal::ExceptionHandler    then traverse_exception_handler node
 | 
			
		||||
      else
 | 
			
		||||
        # ok
 | 
			
		||||
      end
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -7,7 +7,6 @@ module Ameba::AST
 | 
			
		|||
    RECORD_NODE_NAME = "record"
 | 
			
		||||
 | 
			
		||||
    @scope_queue = [] of Scope
 | 
			
		||||
 | 
			
		||||
    @current_scope : Scope
 | 
			
		||||
 | 
			
		||||
    def initialize(@rule, @source)
 | 
			
		||||
| 
						 | 
				
			
			@ -169,7 +168,6 @@ module Ameba::AST
 | 
			
		|||
            variable.reference(variable.node, @current_scope).explicit = false
 | 
			
		||||
          end
 | 
			
		||||
        end
 | 
			
		||||
 | 
			
		||||
        true
 | 
			
		||||
      when @current_scope.top_level? && record_macro?(node)
 | 
			
		||||
        false
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -89,11 +89,11 @@ module Ameba::Formatter
 | 
			
		|||
 | 
			
		||||
    private def final_message(sources, failed_sources)
 | 
			
		||||
      total = sources.size
 | 
			
		||||
      failures = failed_sources.map { |f| f.issues.size }.sum
 | 
			
		||||
      failures = failed_sources.sum(&.issues.size)
 | 
			
		||||
      color = failures == 0 ? :green : :red
 | 
			
		||||
      s = failures != 1 ? "s" : ""
 | 
			
		||||
 | 
			
		||||
      "#{total} inspected, #{failures} failure#{s}.\n".colorize color
 | 
			
		||||
      "#{total} inspected, #{failures} failure#{s}.\n".colorize(color)
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -38,7 +38,7 @@ module Ameba
 | 
			
		|||
    # ```
 | 
			
		||||
    #
 | 
			
		||||
    def location_disabled?(location, rule)
 | 
			
		||||
      return false if Rule::SPECIAL.includes?(rule.name)
 | 
			
		||||
      return false if rule.name.in?(Rule::SPECIAL)
 | 
			
		||||
      return false unless line_number = location.try &.line_number.try &.- 1
 | 
			
		||||
      return false unless line = lines[line_number]?
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -107,11 +107,11 @@ module Ameba::Rule
 | 
			
		|||
    # ```
 | 
			
		||||
    #
 | 
			
		||||
    def special?
 | 
			
		||||
      SPECIAL.includes? name
 | 
			
		||||
      name.in?(SPECIAL)
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    def ==(other)
 | 
			
		||||
      name == other.try &.name
 | 
			
		||||
      name == other.try(&.name)
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    def hash
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -23,9 +23,9 @@ module Ameba::Rule::Layout
 | 
			
		|||
      source_lines_size = source_lines.size
 | 
			
		||||
      return if source_lines_size == 1 && last_source_line.empty?
 | 
			
		||||
 | 
			
		||||
      last_line_not_empty = !last_source_line.empty?
 | 
			
		||||
      if source_lines_size >= 1 && (source_lines.last(2).join.strip.empty? || last_line_not_empty)
 | 
			
		||||
        issue_for({source_lines_size - 1, 1}, last_line_not_empty ? MSG_FINAL_NEWLINE : MSG)
 | 
			
		||||
      last_line_empty = last_source_line.empty?
 | 
			
		||||
      if source_lines_size >= 1 && (source_lines.last(2).join.blank? || !last_line_empty)
 | 
			
		||||
        issue_for({source_lines_size - 1, 1}, last_line_empty ? MSG : MSG_FINAL_NEWLINE)
 | 
			
		||||
      end
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -30,7 +30,7 @@ module Ameba::Rule::Lint
 | 
			
		|||
 | 
			
		||||
    def test(source, node : Crystal::Call)
 | 
			
		||||
      comparison = node.name.in?(OP_NAMES)
 | 
			
		||||
      to_boolean = node.args.first?.try &.is_a?(Crystal::BoolLiteral) ||
 | 
			
		||||
      to_boolean = node.args.first?.try(&.is_a?(Crystal::BoolLiteral)) ||
 | 
			
		||||
                   node.obj.is_a?(Crystal::BoolLiteral)
 | 
			
		||||
 | 
			
		||||
      issue_for node, MSG if comparison && to_boolean
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -31,8 +31,8 @@ module Ameba::Rule::Lint
 | 
			
		|||
    include AST::Util
 | 
			
		||||
 | 
			
		||||
    properties do
 | 
			
		||||
      description "Disallows empty expressions"
 | 
			
		||||
      enabled false
 | 
			
		||||
      description "Disallows empty expressions"
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    MSG      = "Avoid empty expression %s"
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -26,6 +26,7 @@ module Ameba::Rule::Lint
 | 
			
		|||
  struct PercentArrays < Base
 | 
			
		||||
    properties do
 | 
			
		||||
      description "Disallows some unwanted symbols in percent array literals"
 | 
			
		||||
 | 
			
		||||
      string_array_unwanted_symbols %(,")
 | 
			
		||||
      symbol_array_unwanted_symbols %(,:)
 | 
			
		||||
    end
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -51,7 +51,7 @@ module Ameba::Rule::Lint
 | 
			
		|||
      previous_exceptions = [] of String
 | 
			
		||||
 | 
			
		||||
      exceptions.reduce([] of String) do |shadowed, excs|
 | 
			
		||||
        excs = excs ? excs.map(&.to_s) : ["Exception"]
 | 
			
		||||
        excs = excs.try(&.map(&.to_s)) || %w[Exception]
 | 
			
		||||
 | 
			
		||||
        if exception_found
 | 
			
		||||
          shadowed.concat excs
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -26,8 +26,8 @@ module Ameba::Rule::Performance
 | 
			
		|||
  # ```
 | 
			
		||||
  struct AnyAfterFilter < Base
 | 
			
		||||
    properties do
 | 
			
		||||
      filter_names : Array(String) = %w(select reject)
 | 
			
		||||
      description "Identifies usage of `any?` calls that follow filters."
 | 
			
		||||
      filter_names : Array(String) = %w(select reject)
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    ANY_NAME = "any?"
 | 
			
		||||
| 
						 | 
				
			
			@ -36,7 +36,7 @@ module Ameba::Rule::Performance
 | 
			
		|||
    def test(source, node : Crystal::Call)
 | 
			
		||||
      return unless node.name == ANY_NAME && (obj = node.obj)
 | 
			
		||||
      return unless obj.is_a?(Crystal::Call) && obj.block && node.block.nil?
 | 
			
		||||
      return unless filter_names.includes?(obj.name)
 | 
			
		||||
      return unless obj.name.in?(filter_names)
 | 
			
		||||
 | 
			
		||||
      issue_for obj.name_location, node.name_end_location, MSG % obj.name
 | 
			
		||||
    end
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -25,8 +25,8 @@ module Ameba::Rule::Performance
 | 
			
		|||
  # ```
 | 
			
		||||
  struct FirstLastAfterFilter < Base
 | 
			
		||||
    properties do
 | 
			
		||||
      filter_names : Array(String) = %w(select)
 | 
			
		||||
      description "Identifies usage of `first/last/first?/last?` calls that follow filters."
 | 
			
		||||
      filter_names : Array(String) = %w(select)
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    CALL_NAMES  = %w(first last first? last?)
 | 
			
		||||
| 
						 | 
				
			
			@ -43,10 +43,10 @@ module Ameba::Rule::Performance
 | 
			
		|||
    end
 | 
			
		||||
 | 
			
		||||
    def test(source, node : Crystal::Call)
 | 
			
		||||
      return unless CALL_NAMES.includes?(node.name) && (obj = node.obj)
 | 
			
		||||
      return unless node.name.in?(CALL_NAMES) && (obj = node.obj)
 | 
			
		||||
      return unless obj.is_a?(Crystal::Call) && obj.block
 | 
			
		||||
      return if !node.block.nil? || node.args.any?
 | 
			
		||||
      return unless filter_names.includes?(obj.name)
 | 
			
		||||
      return unless obj.name.in?(filter_names)
 | 
			
		||||
 | 
			
		||||
      message = node.name.includes?(CALL_NAMES.first) ? MSG : MSG_REVERSE
 | 
			
		||||
      issue_for obj.name_location, node.name_end_location, message % {obj.name, node.name}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -32,8 +32,8 @@ module Ameba::Rule::Performance
 | 
			
		|||
  # ```
 | 
			
		||||
  struct SizeAfterFilter < Base
 | 
			
		||||
    properties do
 | 
			
		||||
      filter_names : Array(String) = %w(select reject)
 | 
			
		||||
      description "Identifies usage of `size` calls that follow filter"
 | 
			
		||||
      filter_names : Array(String) = %w(select reject)
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    SIZE_NAME = "size"
 | 
			
		||||
| 
						 | 
				
			
			@ -51,7 +51,7 @@ module Ameba::Rule::Performance
 | 
			
		|||
    def test(source, node : Crystal::Call)
 | 
			
		||||
      return unless node.name == SIZE_NAME && (obj = node.obj)
 | 
			
		||||
      return unless obj.is_a?(Crystal::Call) && obj.block
 | 
			
		||||
      return unless filter_names.includes?(obj.name)
 | 
			
		||||
      return unless obj.name.in?(filter_names)
 | 
			
		||||
 | 
			
		||||
      issue_for obj.name_location, node.name_end_location, MSG % obj.name
 | 
			
		||||
    end
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -28,9 +28,9 @@ module Ameba::Rule::Style
 | 
			
		|||
  # ```
 | 
			
		||||
  struct LargeNumbers < Base
 | 
			
		||||
    properties do
 | 
			
		||||
      enabled false
 | 
			
		||||
      description "Disallows usage of large numbers without underscore"
 | 
			
		||||
      int_min_digits 5
 | 
			
		||||
      enabled false
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    MSG = "Large numbers should be written with underscores: %s"
 | 
			
		||||
| 
						 | 
				
			
			@ -82,7 +82,7 @@ module Ameba::Rule::Style
 | 
			
		|||
    end
 | 
			
		||||
 | 
			
		||||
    private def parse_sign(value)
 | 
			
		||||
      if "+-".includes?(value[0])
 | 
			
		||||
      if value[0].in?('+', '-')
 | 
			
		||||
        sign = value[0]
 | 
			
		||||
        value = value[1..-1]
 | 
			
		||||
      end
 | 
			
		||||
| 
						 | 
				
			
			@ -90,7 +90,7 @@ module Ameba::Rule::Style
 | 
			
		|||
    end
 | 
			
		||||
 | 
			
		||||
    private def parse_suffix(value)
 | 
			
		||||
      if pos = (value =~ /e/ || value =~ /_?(i|u|f)/)
 | 
			
		||||
      if pos = (value =~ /(e|_?(i|u|f))/)
 | 
			
		||||
        suffix = value[pos..-1]
 | 
			
		||||
        value = value[0..pos - 1]
 | 
			
		||||
      end
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -30,8 +30,8 @@ module Ameba::Rule::Style
 | 
			
		|||
  # ```
 | 
			
		||||
  struct PredicateName < Base
 | 
			
		||||
    properties do
 | 
			
		||||
      description "Disallows tautological predicate names"
 | 
			
		||||
      enabled false
 | 
			
		||||
      description "Disallows tautological predicate names"
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    MSG = "Favour method name '%s?' over '%s'"
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -57,6 +57,7 @@ module Ameba::Rule::Style
 | 
			
		|||
  # ```
 | 
			
		||||
  struct RedundantBegin < Base
 | 
			
		||||
    include AST::Util
 | 
			
		||||
 | 
			
		||||
    properties do
 | 
			
		||||
      description "Disallows redundant begin blocks"
 | 
			
		||||
    end
 | 
			
		||||
| 
						 | 
				
			
			@ -102,6 +103,7 @@ module Ameba::Rule::Style
 | 
			
		|||
    private def def_redundant_begin?(code)
 | 
			
		||||
      lexer = Crystal::Lexer.new code
 | 
			
		||||
      in_body = in_argument_list = false
 | 
			
		||||
 | 
			
		||||
      loop do
 | 
			
		||||
        token = lexer.next_token
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -117,6 +119,7 @@ module Ameba::Rule::Style
 | 
			
		|||
        when :NEWLINE
 | 
			
		||||
          in_body = true unless in_argument_list
 | 
			
		||||
        when :SPACE
 | 
			
		||||
          # ignore
 | 
			
		||||
        else
 | 
			
		||||
          return false if in_body
 | 
			
		||||
        end
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -99,6 +99,7 @@ module Ameba::Rule::Style
 | 
			
		|||
  struct RedundantNext < Base
 | 
			
		||||
    properties do
 | 
			
		||||
      description "Reports redundant next expressions"
 | 
			
		||||
 | 
			
		||||
      allow_multi_next true
 | 
			
		||||
      allow_empty_next true
 | 
			
		||||
    end
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -96,6 +96,7 @@ module Ameba::Rule::Style
 | 
			
		|||
  struct RedundantReturn < Base
 | 
			
		||||
    properties do
 | 
			
		||||
      description "Reports redundant return expressions"
 | 
			
		||||
 | 
			
		||||
      allow_multi_return true
 | 
			
		||||
      allow_empty_return true
 | 
			
		||||
    end
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue