mirror of
				https://gitea.invidious.io/iv-org/shard-ameba.git
				synced 2024-08-15 00:53:29 +00:00 
			
		
		
		
	Merge pull request #300 from crystal-ameba/Sija/some-refactors
Misc refactors
This commit is contained in:
		
						commit
						04b19a60db
					
				
					 33 changed files with 119 additions and 87 deletions
				
			
		|  | @ -191,7 +191,7 @@ module Ameba::AST | |||
|     it "returns true if node is nested to Crystal::Macro" do | ||||
|       nodes = as_nodes %( | ||||
|         macro included | ||||
|           {{@type.each do |type| a = type end}} | ||||
|           {{ @type.each do |type| a = type end }} | ||||
|         end | ||||
|       ) | ||||
|       outer_scope = Scope.new nodes.macro_nodes.first | ||||
|  |  | |||
|  | @ -40,7 +40,9 @@ module Ameba | |||
|           --- | ||||
|           Globs: 100 | ||||
|           CONFIG | ||||
|         expect_raises(Exception, "incorrect 'Globs' section in a config file") { Config.new(yml) } | ||||
|         expect_raises(Exception, "Incorrect 'Globs' section in a config file") do | ||||
|           Config.new(yml) | ||||
|         end | ||||
|       end | ||||
| 
 | ||||
|       it "initializes excluded as string" do | ||||
|  | @ -68,7 +70,9 @@ module Ameba | |||
|           --- | ||||
|           Excluded: true | ||||
|           CONFIG | ||||
|         expect_raises(Exception, "incorrect 'Excluded' section in a config file") { Config.new(yml) } | ||||
|         expect_raises(Exception, "Incorrect 'Excluded' section in a config file") do | ||||
|           Config.new(yml) | ||||
|         end | ||||
|       end | ||||
|     end | ||||
| 
 | ||||
|  |  | |||
|  | @ -211,11 +211,13 @@ module Ameba::Rule::Lint | |||
|               end | ||||
| 
 | ||||
|               def bar | ||||
|                 {{@type.instance_vars.map do |ivar| | ||||
|                 {{ | ||||
|                   @type.instance_vars.map do |ivar| | ||||
|                     ivar.annotations(Name).each do |ann| | ||||
|                       puts ann.args | ||||
|                     end | ||||
|                   end}} | ||||
|                   end | ||||
|                 }} | ||||
|               end | ||||
|             end | ||||
|           end | ||||
|  |  | |||
|  | @ -218,11 +218,11 @@ module Ameba::Rule::Lint | |||
|         s = Source.new %( | ||||
|           record X do | ||||
|             macro foo(a, b) | ||||
|               {{a}} + {{b}} | ||||
|               {{ a }} + {{ b }} | ||||
|             end | ||||
| 
 | ||||
|             macro bar(a, b, c) | ||||
|               {{a}} + {{b}} + {{c}} | ||||
|               {{ a }} + {{ b }} + {{ c }} | ||||
|             end | ||||
|           end | ||||
|         ) | ||||
|  |  | |||
|  | @ -949,7 +949,7 @@ module Ameba::Rule::Lint | |||
|           foo = 22 | ||||
| 
 | ||||
|           {% for x in %w(foo) %} | ||||
|             add({{x.id}}) | ||||
|             add({{ x.id }}) | ||||
|           {% end %} | ||||
|         ) | ||||
|         subject.catch(s).should be_valid | ||||
|  |  | |||
|  | @ -190,7 +190,7 @@ module Ameba | |||
|     def test(source, node : Crystal::ClassDef) | ||||
|       return unless location = node.location | ||||
| 
 | ||||
|       end_location = location.adjust(column_number: {{"class".size - 1}}) | ||||
|       end_location = location.adjust(column_number: {{ "class".size - 1 }}) | ||||
| 
 | ||||
|       issue_for(location, end_location, message: "class to module") do |corrector| | ||||
|         corrector.replace(location, end_location, "module") | ||||
|  | @ -208,7 +208,7 @@ module Ameba | |||
|     def test(source, node : Crystal::ModuleDef) | ||||
|       return unless location = node.location | ||||
| 
 | ||||
|       end_location = location.adjust(column_number: {{"module".size - 1}}) | ||||
|       end_location = location.adjust(column_number: {{ "module".size - 1 }}) | ||||
| 
 | ||||
|       issue_for(location, end_location, message: "module to class") do |corrector| | ||||
|         corrector.replace(location, end_location, "class") | ||||
|  | @ -265,12 +265,12 @@ module Ameba | |||
|     end | ||||
| 
 | ||||
|     {% for node in NODES %} | ||||
|       {{getter_name = node.stringify.split("::").last.underscore + "_nodes"}} | ||||
|       {{ getter_name = node.stringify.split("::").last.underscore + "_nodes" }} | ||||
| 
 | ||||
|       getter {{getter_name.id}} = [] of {{node}} | ||||
|       getter {{ getter_name.id }} = [] of {{ node }} | ||||
| 
 | ||||
|       def visit(node : {{node}}) | ||||
|         {{getter_name.id}} << node | ||||
|       def visit(node : {{ node }}) | ||||
|         {{ getter_name.id }} << node | ||||
|         true | ||||
|       end | ||||
|     {% end %} | ||||
|  |  | |||
|  | @ -58,7 +58,9 @@ module Ameba::AST | |||
|           control_flow_found ||= !loop?(exp) && flow_expression?(exp, in_loop?) | ||||
|         end | ||||
|       when Crystal::BinaryOp | ||||
|         unreachable_nodes << current_node.right if flow_expression?(current_node.left, in_loop?) | ||||
|         if flow_expression?(current_node.left, in_loop?) | ||||
|           unreachable_nodes << current_node.right | ||||
|         end | ||||
|       end | ||||
| 
 | ||||
|       unreachable_nodes | ||||
|  |  | |||
|  | @ -106,6 +106,7 @@ module Ameba::AST | |||
|     # ``` | ||||
|     def spawn_block? | ||||
|       return false unless node.is_a?(Crystal::Block) | ||||
| 
 | ||||
|       call = node.as(Crystal::Block).call | ||||
|       call.try(&.name) == "spawn" | ||||
|     end | ||||
|  |  | |||
|  | @ -32,7 +32,6 @@ module Ameba::AST::Util | |||
|   # to determine and cut a piece of source of the node. | ||||
|   def node_source(node, code_lines) | ||||
|     loc, end_loc = node.location, node.end_location | ||||
| 
 | ||||
|     return unless loc && end_loc | ||||
| 
 | ||||
|     source_between(loc, end_loc, code_lines) | ||||
|  | @ -46,7 +45,7 @@ module Ameba::AST::Util | |||
|     first_line, last_line = node_lines[0]?, node_lines[-1]? | ||||
| 
 | ||||
|     return if first_line.nil? || last_line.nil? | ||||
|     return if first_line.size < column # compiler reports incorrection location | ||||
|     return if first_line.size < column # compiler reports incorrect location | ||||
| 
 | ||||
|     node_lines[0] = first_line.sub(0...column, "") | ||||
| 
 | ||||
|  | @ -162,11 +161,11 @@ module Ameba::AST::Util | |||
|   # Returns the exp code of a control expression. | ||||
|   # Wraps implicit tuple literal with curly brackets (e.g. multi-return). | ||||
|   def control_exp_code(node : Crystal::ControlExpression, code_lines) | ||||
|     return unless (exp = node.exp) | ||||
|     return unless (exp_code = node_source(exp, code_lines)) | ||||
|     return unless exp = node.exp | ||||
|     return unless exp_code = node_source(exp, code_lines) | ||||
|     return exp_code unless exp.is_a?(Crystal::TupleLiteral) && exp_code[0] != '{' | ||||
|     return unless (exp_start = exp.elements.first.location) | ||||
|     return unless (exp_end = exp.end_location) | ||||
|     return unless exp_start = exp.elements.first.location | ||||
|     return unless exp_end = exp.end_location | ||||
| 
 | ||||
|     "{#{source_between(exp_start, exp_end, code_lines)}}" | ||||
|   end | ||||
|  |  | |||
|  | @ -39,10 +39,10 @@ module Ameba::AST | |||
|     # Name of the argument. | ||||
|     def name | ||||
|       case current_node = node | ||||
|       when Crystal::Var then current_node.name | ||||
|       when Crystal::Arg then current_node.name | ||||
|       when Crystal::Var, Crystal::Arg | ||||
|         current_node.name | ||||
|       else | ||||
|         raise ArgumentError.new "invalid node" | ||||
|         raise ArgumentError.new "Invalid node" | ||||
|       end | ||||
|     end | ||||
|   end | ||||
|  |  | |||
|  | @ -97,6 +97,7 @@ module Ameba::AST | |||
|       return false unless (assign = node).is_a?(Crystal::Assign) | ||||
|       return false unless (value = assign.value).is_a?(Crystal::Call) | ||||
|       return false unless (obj = value.obj).is_a?(Crystal::Var) | ||||
| 
 | ||||
|       obj.name.starts_with? "__arg" | ||||
|     end | ||||
|   end | ||||
|  |  | |||
|  | @ -1,8 +1,8 @@ | |||
| module Ameba::AST | ||||
|   # Represents the existence of the local variable. | ||||
|   # Holds the var node and variable assigments. | ||||
|   # Holds the var node and variable assignments. | ||||
|   class Variable | ||||
|     # List of the assigments of this variable. | ||||
|     # List of the assignments of this variable. | ||||
|     getter assignments = [] of Assignment | ||||
| 
 | ||||
|     # List of the references of this variable. | ||||
|  | @ -30,7 +30,7 @@ module Ameba::AST | |||
|     def initialize(@node, @scope) | ||||
|     end | ||||
| 
 | ||||
|     # Returns true if it is a special variable, i.e `$?`. | ||||
|     # Returns `true` if it is a special variable, i.e `$?`. | ||||
|     def special? | ||||
|       @node.special_var? | ||||
|     end | ||||
|  | @ -50,7 +50,7 @@ module Ameba::AST | |||
|       update_assign_reference! | ||||
|     end | ||||
| 
 | ||||
|     # Returns true if variable has any reference. | ||||
|     # Returns `true` if variable has any reference. | ||||
|     # | ||||
|     # ``` | ||||
|     # variable = Variable.new(node, scope) | ||||
|  | @ -85,7 +85,7 @@ module Ameba::AST | |||
|       consumed_branches = Set(Branch).new | ||||
| 
 | ||||
|       assignments.reverse_each do |assignment| | ||||
|         next if consumed_branches.includes?(assignment.branch) | ||||
|         next if assignment.branch.in?(consumed_branches) | ||||
|         assignment.referenced = true | ||||
| 
 | ||||
|         break unless branch = assignment.branch | ||||
|  | @ -93,7 +93,7 @@ module Ameba::AST | |||
|       end | ||||
|     end | ||||
| 
 | ||||
|     # Returns true if the current var is referenced in | ||||
|     # Returns `true` if the current var is referenced in | ||||
|     # in the block. For example this variable is captured | ||||
|     # by block: | ||||
|     # | ||||
|  | @ -110,26 +110,29 @@ module Ameba::AST | |||
|     # ``` | ||||
|     def captured_by_block?(scope = @scope) | ||||
|       scope.inner_scopes.each do |inner_scope| | ||||
|         return true if inner_scope.block? && inner_scope.references?(self, check_inner_scopes: false) | ||||
|         return true if inner_scope.block? && | ||||
|                        inner_scope.references?(self, check_inner_scopes: false) | ||||
|         return true if captured_by_block?(inner_scope) | ||||
|       end | ||||
| 
 | ||||
|       false | ||||
|     end | ||||
| 
 | ||||
|     # Returns true if current variable potentially referenced in a macro, | ||||
|     # false if not. | ||||
|     # Returns `true` if current variable potentially referenced in a macro, | ||||
|     # `false` if not. | ||||
|     def used_in_macro?(scope = @scope) | ||||
|       scope.inner_scopes.each do |inner_scope| | ||||
|         return true if MacroReferenceFinder.new(inner_scope.node, node.name).references | ||||
|       end | ||||
|       return true if MacroReferenceFinder.new(scope.node, node.name).references | ||||
|       return true if (outer_scope = scope.outer_scope) && used_in_macro?(outer_scope) | ||||
|       return true if (outer_scope = scope.outer_scope) && | ||||
|                      used_in_macro?(outer_scope) | ||||
| 
 | ||||
|       false | ||||
|     end | ||||
| 
 | ||||
|     # Returns true if the variable is a target (on the left) of the assignment, | ||||
|     # false otherwise. | ||||
|     # Returns `true` if the variable is a target (on the left) of the assignment, | ||||
|     # `false` otherwise. | ||||
|     def target_of?(assign) | ||||
|       case assign | ||||
|       when Crystal::Assign           then eql?(assign.target) | ||||
|  | @ -141,12 +144,12 @@ module Ameba::AST | |||
|       end | ||||
|     end | ||||
| 
 | ||||
|     # Returns true if the name starts with '_', false if not. | ||||
|     # Returns `true` if the name starts with '_', `false` if not. | ||||
|     def ignored? | ||||
|       name.starts_with? '_' | ||||
|     end | ||||
| 
 | ||||
|     # Returns true if the `node` represents exactly | ||||
|     # Returns `true` if the `node` represents exactly | ||||
|     # the same Crystal node as `@node`. | ||||
|     def eql?(node) | ||||
|       node.is_a?(Crystal::Var) && | ||||
|  | @ -154,7 +157,7 @@ module Ameba::AST | |||
|         node.location == @node.location | ||||
|     end | ||||
| 
 | ||||
|     # Returns true if the variable is declared before the `node`. | ||||
|     # Returns `true` if the variable is declared before the `node`. | ||||
|     def declared_before?(node) | ||||
|       var_location, node_location = location, node.location | ||||
| 
 | ||||
|  |  | |||
|  | @ -2,6 +2,7 @@ module Ameba::AST | |||
|   # AST Visitor that counts occurrences of certain keywords | ||||
|   class CountingVisitor < Crystal::Visitor | ||||
|     DEFAULT_COMPLEXITY = 1 | ||||
| 
 | ||||
|     getter macro_condition = false | ||||
| 
 | ||||
|     # Creates a new counting visitor | ||||
|  | @ -44,6 +45,7 @@ module Ameba::AST | |||
|     def visit(node : Crystal::MacroIf | Crystal::MacroFor) | ||||
|       @macro_condition = true | ||||
|       @complexity = DEFAULT_COMPLEXITY | ||||
| 
 | ||||
|       false | ||||
|     end | ||||
|   end | ||||
|  |  | |||
|  | @ -45,11 +45,11 @@ module Ameba::AST | |||
|     end | ||||
| 
 | ||||
|     {% for name in NODES %} | ||||
|       # A visit callback for `Crystal::{{name}}` node. | ||||
|       # A visit callback for `Crystal::{{ name }}` node. | ||||
|       # | ||||
|       # Returns `true` if the child nodes should be traversed as well, | ||||
|       # `false` otherwise. | ||||
|       def visit(node : Crystal::{{name}}) | ||||
|       def visit(node : Crystal::{{ name }}) | ||||
|         return false if skip?(node) | ||||
| 
 | ||||
|         @rule.test @source, node | ||||
|  |  | |||
|  | @ -48,7 +48,8 @@ module Ameba::AST | |||
|     end | ||||
| 
 | ||||
|     private def on_assign_end(target, node) | ||||
|       target.is_a?(Crystal::Var) && @current_scope.assign_variable(target.name, node) | ||||
|       target.is_a?(Crystal::Var) && | ||||
|         @current_scope.assign_variable(target.name, node) | ||||
|     end | ||||
| 
 | ||||
|     # :nodoc: | ||||
|  | @ -58,7 +59,7 @@ module Ameba::AST | |||
| 
 | ||||
|     {% for name in NODES %} | ||||
|       # :nodoc: | ||||
|       def visit(node : Crystal::{{name}}) | ||||
|       def visit(node : Crystal::{{ name }}) | ||||
|         on_scope_enter(node) | ||||
|       end | ||||
|     {% end %} | ||||
|  | @ -96,13 +97,15 @@ module Ameba::AST | |||
| 
 | ||||
|     # :nodoc: | ||||
|     def visit(node : Crystal::TypeDeclaration) | ||||
|       return if @current_scope.type_definition? || !(var = node.var).is_a?(Crystal::Var) | ||||
|       @current_scope.add_variable var | ||||
|       return if @current_scope.type_definition? | ||||
|       return if !(var = node.var).is_a?(Crystal::Var) | ||||
| 
 | ||||
|       @current_scope.add_variable(var) | ||||
|     end | ||||
| 
 | ||||
|     # :nodoc: | ||||
|     def visit(node : Crystal::Arg) | ||||
|       @current_scope.add_argument node | ||||
|       @current_scope.add_argument(node) | ||||
|     end | ||||
| 
 | ||||
|     # :nodoc: | ||||
|  | @ -114,11 +117,12 @@ module Ameba::AST | |||
|     def visit(node : Crystal::Var) | ||||
|       variable = @current_scope.find_variable node.name | ||||
| 
 | ||||
|       if @current_scope.arg?(node) # node is an argument | ||||
|       case | ||||
|       when @current_scope.arg?(node) # node is an argument | ||||
|         @current_scope.add_argument(node) | ||||
|       elsif variable.nil? && @current_assign # node is a variable | ||||
|       when variable.nil? && @current_assign # node is a variable | ||||
|         @current_scope.add_variable(node) | ||||
|       elsif variable # node is a reference | ||||
|       when variable # node is a reference | ||||
|         reference = variable.reference node, @current_scope | ||||
|         if @current_assign.is_a?(Crystal::OpAssign) || !reference.target_of?(@current_assign) | ||||
|           variable.reference_assignments! | ||||
|  |  | |||
|  | @ -123,10 +123,10 @@ class Ameba::Config | |||
|   # config.formatter = :progress | ||||
|   # ``` | ||||
|   def formatter=(name : String | Symbol) | ||||
|     unless f = AVAILABLE_FORMATTERS[name]? | ||||
|     unless formatter = AVAILABLE_FORMATTERS[name]? | ||||
|       raise "Unknown formatter `#{name}`. Use one of #{Config.formatter_names}." | ||||
|     end | ||||
|     @formatter = f.new | ||||
|     @formatter = formatter.new | ||||
|   end | ||||
| 
 | ||||
|   # Updates rule properties. | ||||
|  | @ -180,7 +180,7 @@ class Ameba::Config | |||
|     when .as_s? then [value.to_s] | ||||
|     when .as_a? then value.as_a.map(&.as_s) | ||||
|     else | ||||
|       raise "incorrect '#{section_name}' section in a config files" | ||||
|       raise "Incorrect '#{section_name}' section in a config files" | ||||
|     end | ||||
|   end | ||||
| 
 | ||||
|  | @ -241,8 +241,8 @@ class Ameba::Config | |||
| 
 | ||||
|         {% properties[name] = {key: key, default: value, type: type, converter: converter} %} | ||||
| 
 | ||||
|         @[YAML::Field(key: {{key}}, converter: {{converter}}, type: {{type}})] | ||||
|         property {{name}} : {{type}} = {{value}} | ||||
|         @[YAML::Field(key: {{ key }}, converter: {{ converter }}, type: {{ type }})] | ||||
|         property {{ name }} : {{ type }} = {{ value }} | ||||
|       {% end %} | ||||
| 
 | ||||
|       {% if properties["enabled".id] == nil %} | ||||
|  | @ -253,7 +253,7 @@ class Ameba::Config | |||
|       {% if properties["severity".id] == nil %} | ||||
|         {% default = @type.name.starts_with?("Ameba::Rule::Lint") ? "Ameba::Severity::Warning".id : "Ameba::Severity::Convention".id %} | ||||
|         @[YAML::Field(key: "Severity", converter: Ameba::SeverityYamlConverter)] | ||||
|         property severity = {{default}} | ||||
|         property severity = {{ default }} | ||||
|       {% end %} | ||||
| 
 | ||||
|       {% if properties["excluded".id] == nil %} | ||||
|  |  | |||
|  | @ -38,7 +38,7 @@ module Ameba::Formatter | |||
|     private def explain(source, issue) | ||||
|       rule = issue.rule | ||||
| 
 | ||||
|       return unless (location = issue.location) | ||||
|       return unless location = issue.location | ||||
| 
 | ||||
|       output_title "ISSUE INFO" | ||||
|       output_paragraph [ | ||||
|  |  | |||
|  | @ -41,7 +41,7 @@ module Ameba::Formatter | |||
|     end | ||||
| 
 | ||||
|     def affected_code(issue : Issue, context_lines = 0, max_length = 120, ellipsis = " ...", prompt = "> ") | ||||
|       return unless (location = issue.location) | ||||
|       return unless location = issue.location | ||||
| 
 | ||||
|       affected_code(issue.code, location, issue.end_location, context_lines, max_length, ellipsis, prompt) | ||||
|     end | ||||
|  |  | |||
|  | @ -1,7 +1,8 @@ | |||
| module Ameba | ||||
|   # A module that utilizes inline comments parsing and processing logic. | ||||
|   module InlineComments | ||||
|     COMMENT_DIRECTIVE_REGEX = /# ameba:(?<action>\w+) (?<rules>\w+(?:\/\w+)?(?:,? \w+(?:\/\w+)?)*)/ | ||||
|     COMMENT_DIRECTIVE_REGEX = | ||||
|       /# ameba:(?<action>\w+) (?<rules>\w+(?:\/\w+)?(?:,? \w+(?:\/\w+)?)*)/ | ||||
| 
 | ||||
|     # Available actions in the inline comments | ||||
|     enum Action | ||||
|  | @ -87,15 +88,17 @@ module Ameba | |||
|       return false unless directive = parse_inline_directive(line) | ||||
|       return false unless Action.parse?(directive[:action]).try(&.disable?) | ||||
| 
 | ||||
|       directive[:rules].includes?(rule.name) || | ||||
|         directive[:rules].includes?(rule.group) | ||||
|       rules = directive[:rules] | ||||
|       rules.includes?(rule.name) || rules.includes?(rule.group) | ||||
|     end | ||||
| 
 | ||||
|     private def commented_out?(line) | ||||
|       commented = false | ||||
| 
 | ||||
|       lexer = Crystal::Lexer.new(line).tap(&.comments_enabled = true) | ||||
|       Tokenizer.new(lexer).run { |t| commented = true if t.type.comment? } | ||||
|       Tokenizer.new(lexer).run do |token| | ||||
|         commented = true if token.type.comment? | ||||
|       end | ||||
|       commented | ||||
|     end | ||||
|   end | ||||
|  |  | |||
|  | @ -33,7 +33,7 @@ module Ameba::Rule | |||
|     # that are tested by this rule, it should add an issue. | ||||
|     # | ||||
|     # Be default it uses a node visitor to traverse all the nodes in the source. | ||||
|     # Must be overriten for other type of rules. | ||||
|     # NOTE: Must be overridden for other type of rules. | ||||
|     def test(source : Source) | ||||
|       AST::NodeVisitor.new self, source | ||||
|     end | ||||
|  | @ -64,7 +64,7 @@ module Ameba::Rule | |||
|     # MyRule.new.name # => "MyRule" | ||||
|     # ``` | ||||
|     def name | ||||
|       {{@type}}.rule_name | ||||
|       {{ @type }}.rule_name | ||||
|     end | ||||
| 
 | ||||
|     # Returns a group this rule belong to. | ||||
|  | @ -77,7 +77,7 @@ module Ameba::Rule | |||
|     # MyGroup::MyRule.new.group # => "MyGroup" | ||||
|     # ``` | ||||
|     def group | ||||
|       {{@type}}.group_name | ||||
|       {{ @type }}.group_name | ||||
|     end | ||||
| 
 | ||||
|     # Checks whether the source is excluded from this rule. | ||||
|  | @ -113,7 +113,7 @@ module Ameba::Rule | |||
|     end | ||||
| 
 | ||||
|     macro issue_for(*args, **kwargs, &block) | ||||
|       source.add_issue(self, {{*args}}, {{**kwargs}}) {{block}} | ||||
|       source.add_issue(self, {{ *args }}, {{ **kwargs }}) {{ block }} | ||||
|     end | ||||
| 
 | ||||
|     protected def self.rule_name | ||||
|  |  | |||
|  | @ -1,5 +1,5 @@ | |||
| module Ameba::Rule::Layout | ||||
|   # A rule that disallows trailing whitespaces. | ||||
|   # A rule that disallows trailing whitespace. | ||||
|   # | ||||
|   # YAML configuration example: | ||||
|   # | ||||
|  |  | |||
|  | @ -23,7 +23,7 @@ module Ameba::Rule::Lint | |||
|     def test(source) | ||||
|       nodes = AST::TopLevelNodesVisitor.new(source.ast).require_nodes | ||||
|       nodes.each_with_object([] of String) do |node, processed_require_strings| | ||||
|         issue_for(node, MSG % node.string) if processed_require_strings.includes?(node.string) | ||||
|         issue_for(node, MSG % node.string) if node.string.in?(processed_require_strings) | ||||
|         processed_require_strings << node.string | ||||
|       end | ||||
|     end | ||||
|  |  | |||
|  | @ -54,7 +54,7 @@ module Ameba::Rule::Lint | |||
| 
 | ||||
|       issue_for name_location, end_location, msg do |corrector| | ||||
|         corrector.insert_after(name_location_end, '!') | ||||
|         corrector.remove_trailing(node, ".not_nil!".size) | ||||
|         corrector.remove_trailing(node, {{ ".not_nil!".size }}) | ||||
|       end | ||||
|     end | ||||
|   end | ||||
|  |  | |||
|  | @ -75,8 +75,8 @@ module Ameba::Rule::Style | |||
|         end | ||||
| 
 | ||||
|       case final_expression | ||||
|       when Crystal::If     then check_ending_if(source, final_expression) | ||||
|       when Crystal::Unless then check_ending_if(source, final_expression) | ||||
|       when Crystal::If, Crystal::Unless | ||||
|         check_ending_if(source, final_expression) | ||||
|       end | ||||
|     end | ||||
| 
 | ||||
|  | @ -92,7 +92,8 @@ module Ameba::Rule::Style | |||
| 
 | ||||
|       return unless guard_clause && parent && conditional_keyword | ||||
| 
 | ||||
|       report_issue(source, node, guard_clause_source(source, guard_clause, parent), conditional_keyword) | ||||
|       guard_clause_source = guard_clause_source(source, guard_clause, parent) | ||||
|       report_issue(source, node, guard_clause_source, conditional_keyword) | ||||
|     end | ||||
| 
 | ||||
|     private def check_ending_if(source, node) | ||||
|  | @ -113,10 +114,11 @@ module Ameba::Rule::Style | |||
|       if node.else.is_a?(Crystal::Nop) | ||||
|         return unless end_end_loc = node.end_location | ||||
| 
 | ||||
|         end_loc = end_end_loc.adjust(column_number: {{1 - "end".size}}) | ||||
|         end_loc = end_end_loc.adjust(column_number: {{ 1 - "end".size }}) | ||||
| 
 | ||||
|         issue_for keyword_loc, keyword_end_loc, MSG % example do |corrector| | ||||
|           corrector.replace(keyword_loc, keyword_end_loc, "#{scope_exiting_keyword} #{conditional_keyword}") | ||||
|           replacement = "#{scope_exiting_keyword} #{conditional_keyword}" | ||||
|           corrector.replace(keyword_loc, keyword_end_loc, replacement) | ||||
|           corrector.remove(end_loc, end_end_loc) | ||||
|         end | ||||
|       else | ||||
|  |  | |||
|  | @ -59,8 +59,8 @@ module Ameba::Rule::Style | |||
| 
 | ||||
|     def test(source, node : Crystal::Call) | ||||
|       return unless node.name.in?(filter_names) | ||||
|       return unless (filter_location = node.name_location) | ||||
|       return unless (block = node.block) | ||||
|       return unless filter_location = node.name_location | ||||
|       return unless block = node.block | ||||
|       return unless (body = block.body).is_a?(Crystal::IsA) | ||||
|       return unless (path = body.const).is_a?(Crystal::Path) | ||||
|       return unless body.obj.is_a?(Crystal::Var) | ||||
|  |  | |||
|  | @ -116,7 +116,7 @@ module Ameba::Rule::Style | |||
|       return if allow_multi_next && node.exp.is_a?(Crystal::TupleLiteral) | ||||
|       return if allow_empty_next && (node.exp.nil? || node.exp.try(&.nop?)) | ||||
| 
 | ||||
|       if (exp_code = control_exp_code(node, source.lines)) | ||||
|       if exp_code = control_exp_code(node, source.lines) | ||||
|         issue_for node, MSG do |corrector| | ||||
|           corrector.replace(node, exp_code) | ||||
|         end | ||||
|  |  | |||
|  | @ -113,7 +113,7 @@ module Ameba::Rule::Style | |||
|       return if allow_multi_return && node.exp.is_a?(Crystal::TupleLiteral) | ||||
|       return if allow_empty_return && (node.exp.nil? || node.exp.try(&.nop?)) | ||||
| 
 | ||||
|       if (exp_code = control_exp_code(node, source.lines)) | ||||
|       if exp_code = control_exp_code(node, source.lines) | ||||
|         issue_for node, MSG do |corrector| | ||||
|           corrector.replace(node, exp_code) | ||||
|         end | ||||
|  |  | |||
|  | @ -55,11 +55,11 @@ module Ameba::Rule::Style | |||
|       private getter var_locations = [] of Crystal::Location | ||||
| 
 | ||||
|       def visit(node : Crystal::Var) | ||||
|         !var_locations.includes?(node.location) && super | ||||
|         !node.location.in?(var_locations) && super | ||||
|       end | ||||
| 
 | ||||
|       def visit(node : Crystal::InstanceVar | Crystal::ClassVar) | ||||
|         if (location = node.location) | ||||
|         if location = node.location | ||||
|           var_locations << location | ||||
|         end | ||||
|         super | ||||
|  |  | |||
|  | @ -34,8 +34,8 @@ module Ameba::Rule::Style | |||
| 
 | ||||
|     def test(source, node : Crystal::While) | ||||
|       return unless node.cond.true_literal? | ||||
|       return unless (location = node.location) | ||||
|       return unless (end_location = node.cond.end_location) | ||||
|       return unless location = node.location | ||||
|       return unless end_location = node.cond.end_location | ||||
| 
 | ||||
|       issue_for node, MSG do |corrector| | ||||
|         corrector.replace(location, end_location, "loop do") | ||||
|  |  | |||
|  | @ -87,6 +87,7 @@ module Ameba | |||
|     # ``` | ||||
|     def run | ||||
|       @formatter.started @sources | ||||
| 
 | ||||
|       channels = @sources.map { Channel(Exception?).new } | ||||
|       @sources.each_with_index do |source, idx| | ||||
|         channel = channels[idx] | ||||
|  | @ -219,7 +220,9 @@ module Ameba | |||
|     end | ||||
| 
 | ||||
|     private def check_unneeded_directives(source) | ||||
|       return unless (rule = @unneeded_disable_directive_rule) && rule.enabled | ||||
|       return unless rule = @unneeded_disable_directive_rule | ||||
|       return unless rule.enabled | ||||
| 
 | ||||
|       rule.test(source) | ||||
|     end | ||||
|   end | ||||
|  |  | |||
|  | @ -36,7 +36,7 @@ module Ameba | |||
|       true | ||||
|     end | ||||
| 
 | ||||
|     # Returns lines of code splitted by new line character. | ||||
|     # Returns lines of code split by new line character. | ||||
|     # Since `code` is immutable and can't be changed, this | ||||
|     # method caches lines in an instance variable, so calling | ||||
|     # it second time will not perform a split, but will return | ||||
|  |  | |||
|  | @ -32,10 +32,12 @@ class Ameba::Source::Rewriter | |||
| 
 | ||||
|     def empty? | ||||
|       replacement = @replacement | ||||
| 
 | ||||
|       @insert_before.empty? && | ||||
|         @insert_after.empty? && | ||||
|         @children.empty? && | ||||
|         (replacement.nil? || (replacement.empty? && @begin_pos == @end_pos)) | ||||
|         (replacement.nil? || | ||||
|           (replacement.empty? && @begin_pos == @end_pos)) | ||||
|     end | ||||
| 
 | ||||
|     def ordered_replacements | ||||
|  | @ -50,7 +52,10 @@ class Ameba::Source::Rewriter | |||
| 
 | ||||
|     def insertion? | ||||
|       replacement = @replacement | ||||
|       !@insert_before.empty? || !@insert_after.empty? || (replacement && !replacement.empty?) | ||||
| 
 | ||||
|       !@insert_before.empty? || | ||||
|         !@insert_after.empty? || | ||||
|         (replacement && !replacement.empty?) | ||||
|     end | ||||
| 
 | ||||
|     protected def with(*, | ||||
|  |  | |||
|  | @ -17,12 +17,13 @@ class Ameba::Spec::AnnotatedSource | |||
|     annotations = [] of {Int32, String, String} | ||||
|     code_lines = annotated_code.split('\n') # must preserve trailing newline | ||||
|     code_lines.each do |code_line| | ||||
|       if (annotation_match = ANNOTATION_PATTERN_1.match(code_line)) | ||||
|       case | ||||
|       when annotation_match = ANNOTATION_PATTERN_1.match(code_line) | ||||
|         message_index = annotation_match.end | ||||
|         prefix = code_line[0...message_index] | ||||
|         message = code_line[message_index...] | ||||
|         annotations << {lines.size, prefix, message} | ||||
|       elsif (annotation_index = code_line.index(ANNOTATION_PATTERN_2)) | ||||
|       when annotation_index = code_line.index(ANNOTATION_PATTERN_2) | ||||
|         lines << code_line[...annotation_index] | ||||
|         message_index = annotation_index + ANNOTATION_PATTERN_2.size | ||||
|         message = code_line[message_index...] | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue