class Pedant::CheckConditionalContainsAssignment

Public Class Methods

requires() click to toggle source
Calls superclass method Pedant::Check::requires
# File lib/pedant/checks/conditional_contains_assignment.rb, line 29
def self.requires
  super + [:trees]
end

Public Instance Methods

check(file, tree) click to toggle source
# File lib/pedant/checks/conditional_contains_assignment.rb, line 33
def check(file, tree)
  def walk(node, root)
    # Assignments of literals are the most likely to be bugs (determined empirically).
    literals = [
      Nasl::String,
      Nasl::Integer,
      Nasl::Identifier,
      Nasl::Ip,
    ]

    # Recursively descend into the right-hand and left-hand sides of each expression.
    if node.is_a? Nasl::Expression
      [:lhs, :rhs].each { |side| walk(node.send(side), root) }
    end

    if node.is_a?(Nasl::Assignment)
      # A bit of a kludge, here. Because assignment has such a low precedence, we can see two
      # different scenarios: the simpler scenario, where the Assignment's expr is the literal
      # being assigned. Example:
      #   if (a = 5) { ... }  ->  node.expr == <Nasl::Integer>:5
      #
      # In the other scenario, the literal being assigned gets "absorbed" into an Expression
      # with the higher-precedence operators. Example:
      #   if (a = 5 && foo == bar) { ... }  ->  node.expr     == <Nasl::Expression>
      #                                         node.expr.lhs == <Nasl::Integer>:5
      #
      # In this second case, we can look for the literal in the Expression's left-hand side.
      if literals.include?(node.expr.class) or
         node.expr.is_a?(Nasl::Expression) && literals.include?(node.expr.lhs.class)

        fail
        report(:error, "A conditional statement contains an assignment operation.")
        report(:error, node.op.context(root))
      end
    end
  end

  cond_stmts = [:For, :Repeat, :While, :If].map { |cls| tree.all(cls) }.flatten
  cond_stmts.each { |cond_stmt| walk(cond_stmt.cond, cond_stmt) }
end
run() click to toggle source
# File lib/pedant/checks/conditional_contains_assignment.rb, line 74
def run
  # This check will pass by default.
  pass

  # Run this check on the tree from every file.
  @kb[:trees].each { |file, tree| check(file, tree) }
end
walk(node, root) click to toggle source
# File lib/pedant/checks/conditional_contains_assignment.rb, line 34
def walk(node, root)
  # Assignments of literals are the most likely to be bugs (determined empirically).
  literals = [
    Nasl::String,
    Nasl::Integer,
    Nasl::Identifier,
    Nasl::Ip,
  ]

  # Recursively descend into the right-hand and left-hand sides of each expression.
  if node.is_a? Nasl::Expression
    [:lhs, :rhs].each { |side| walk(node.send(side), root) }
  end

  if node.is_a?(Nasl::Assignment)
    # A bit of a kludge, here. Because assignment has such a low precedence, we can see two
    # different scenarios: the simpler scenario, where the Assignment's expr is the literal
    # being assigned. Example:
    #   if (a = 5) { ... }  ->  node.expr == <Nasl::Integer>:5
    #
    # In the other scenario, the literal being assigned gets "absorbed" into an Expression
    # with the higher-precedence operators. Example:
    #   if (a = 5 && foo == bar) { ... }  ->  node.expr     == <Nasl::Expression>
    #                                         node.expr.lhs == <Nasl::Integer>:5
    #
    # In this second case, we can look for the literal in the Expression's left-hand side.
    if literals.include?(node.expr.class) or
       node.expr.is_a?(Nasl::Expression) && literals.include?(node.expr.lhs.class)

      fail
      report(:error, "A conditional statement contains an assignment operation.")
      report(:error, node.op.context(root))
    end
  end
end