mirror of
				https://gitea.invidious.io/iv-org/shard-ameba.git
				synced 2024-08-15 00:53:29 +00:00 
			
		
		
		
	Prevent false positiveness cause by macro literals
https://github.com/crystal-lang/crystal/pull/6055#issuecomment-386376227
This commit is contained in:
		
							parent
							
								
									6579c8f573
								
							
						
					
					
						commit
						415432713a
					
				
					 5 changed files with 47 additions and 25 deletions
				
			
		| 
						 | 
					@ -820,6 +820,37 @@ module Ameba::Rule
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
        subject.catch(s).should be_valid
 | 
					        subject.catch(s).should be_valid
 | 
				
			||||||
      end
 | 
					      end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      it "doesn't report if assignment is referenced in macro def" do
 | 
				
			||||||
 | 
					        s = Source.new %(
 | 
				
			||||||
 | 
					          macro macro_call
 | 
				
			||||||
 | 
					            puts x
 | 
				
			||||||
 | 
					          end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          def foo
 | 
				
			||||||
 | 
					            x = 1
 | 
				
			||||||
 | 
					            macro_call
 | 
				
			||||||
 | 
					          end
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					        subject.catch(s).should be_valid
 | 
				
			||||||
 | 
					      end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      it "reports if assignment is referenced in macro def in a different scope" do
 | 
				
			||||||
 | 
					        s = Source.new %(
 | 
				
			||||||
 | 
					          class Foo
 | 
				
			||||||
 | 
					            def foo
 | 
				
			||||||
 | 
					              x = 1
 | 
				
			||||||
 | 
					            end
 | 
				
			||||||
 | 
					          end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          class Bar
 | 
				
			||||||
 | 
					            macro macro_call
 | 
				
			||||||
 | 
					              puts x
 | 
				
			||||||
 | 
					            end
 | 
				
			||||||
 | 
					          end
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					        subject.catch(s).should_not be_valid
 | 
				
			||||||
 | 
					      end
 | 
				
			||||||
    end
 | 
					    end
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
end
 | 
					end
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -19,6 +19,9 @@ module Ameba::AST
 | 
				
			||||||
    # The actual AST node that represents a current scope.
 | 
					    # The actual AST node that represents a current scope.
 | 
				
			||||||
    getter node : Crystal::ASTNode
 | 
					    getter node : Crystal::ASTNode
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # Macro literals in current scope
 | 
				
			||||||
 | 
					    getter macro_literals = [] of Crystal::MacroLiteral
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    delegate to_s, to: node
 | 
					    delegate to_s, to: node
 | 
				
			||||||
    delegate location, to: node
 | 
					    delegate location, to: node
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -89,7 +89,7 @@ module Ameba::AST
 | 
				
			||||||
      end
 | 
					      end
 | 
				
			||||||
    end
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    # Returns true if the current assignment is referenced in
 | 
					    # Returns true if the current var is referenced in
 | 
				
			||||||
    # in the block. For example this variable is captured
 | 
					    # in the block. For example this variable is captured
 | 
				
			||||||
    # by block:
 | 
					    # by block:
 | 
				
			||||||
    #
 | 
					    #
 | 
				
			||||||
| 
						 | 
					@ -113,6 +113,16 @@ module Ameba::AST
 | 
				
			||||||
      false
 | 
					      false
 | 
				
			||||||
    end
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # Returns true if current variable potentially referenced in a macro literal,
 | 
				
			||||||
 | 
					    # false if not.
 | 
				
			||||||
 | 
					    def used_in_macro?(scope = @scope)
 | 
				
			||||||
 | 
					      scope.inner_scopes.each do |inner_scope|
 | 
				
			||||||
 | 
					        return true if inner_scope.macro_literals.any? { |literal| literal.value.includes?(name) }
 | 
				
			||||||
 | 
					      end
 | 
				
			||||||
 | 
					      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,
 | 
					    # Returns true if the variable is a target (on the left) of the assignment,
 | 
				
			||||||
    # false otherwise.
 | 
					    # false otherwise.
 | 
				
			||||||
    def target_of?(assign)
 | 
					    def target_of?(assign)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -120,7 +120,7 @@ module Ameba::AST
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    # :nodoc:
 | 
					    # :nodoc:
 | 
				
			||||||
    def visit(node : Crystal::MacroLiteral)
 | 
					    def visit(node : Crystal::MacroLiteral)
 | 
				
			||||||
      MacroLiteralVarVisitor.new(node).vars.each { |var| visit(var) }
 | 
					      @current_scope.macro_literals << node
 | 
				
			||||||
    end
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    # :nodoc:
 | 
					    # :nodoc:
 | 
				
			||||||
| 
						 | 
					@ -134,26 +134,4 @@ module Ameba::AST
 | 
				
			||||||
      true
 | 
					      true
 | 
				
			||||||
    end
 | 
					    end
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					 | 
				
			||||||
  private class MacroLiteralVarVisitor < Crystal::Visitor
 | 
					 | 
				
			||||||
    getter vars = [] of Crystal::Var
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def initialize(literal)
 | 
					 | 
				
			||||||
      Crystal::Parser.new(literal.value).parse.accept self
 | 
					 | 
				
			||||||
    rescue
 | 
					 | 
				
			||||||
      nil
 | 
					 | 
				
			||||||
    end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def visit(node : Crystal::ASTNode)
 | 
					 | 
				
			||||||
      true
 | 
					 | 
				
			||||||
    end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def visit(node : Crystal::Var)
 | 
					 | 
				
			||||||
      vars << node
 | 
					 | 
				
			||||||
    end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def visit(node : Crystal::Call)
 | 
					 | 
				
			||||||
      vars << Crystal::Var.new(node.name).at(node.location)
 | 
					 | 
				
			||||||
    end
 | 
					 | 
				
			||||||
  end
 | 
					 | 
				
			||||||
end
 | 
					end
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -39,7 +39,7 @@ module Ameba::Rule
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test(source, node, scope : AST::Scope)
 | 
					    def test(source, node, scope : AST::Scope)
 | 
				
			||||||
      scope.variables.each do |var|
 | 
					      scope.variables.each do |var|
 | 
				
			||||||
        next if var.captured_by_block?
 | 
					        next if var.captured_by_block? || var.used_in_macro?
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        var.assignments.each do |assign|
 | 
					        var.assignments.each do |assign|
 | 
				
			||||||
          next if assign.referenced?
 | 
					          next if assign.referenced?
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue