예제 #1
0
def only_use_own_priv_vars(ast):
    """Check that all private variables used are defined here."""
    used_privs = []

    global_set_vars = find_variables_in_scopes.set_in_tree(ast)
    global_used_vars = find_variables_in_scopes.used_in_tree(ast)

    _, global_definitions = find_all.private_calls_and_definitions(ast)

    # The big assumption here is that the "scopes" structure in both
    # trees are the same
    def _scope_visitor(set_vars_scope, used_vars_scope):
        """Visit scope's set vars and used vars.

        If a var was private and used, but not set in this scope or any
        parents, then report an error
        """
        assert len(set_vars_scope.scopes) == len(used_vars_scope.scopes)

        for index in range(0, len(set_vars_scope.scopes)):
            _scope_visitor(set_vars_scope.scopes[index],
                           used_vars_scope.scopes[index])

        for variable in used_vars_scope.used_vars:
            used_privs.extend(list(_find_violating_priv_uses(variable,
                                                             set_vars_scope)))

    _scope_visitor(global_set_vars, global_used_vars)

    # Filter out definitions of private functions of the same name
    # as functions can be used as variables.
    used_privs = [up for up in used_privs if up[0] not in global_definitions]

    err_msg = "Referenced external private variable {0}"
    return [LinterFailure(err_msg.format(u[0]), u[1]) for u in used_privs]
예제 #2
0
    def _call_handler(name, node):
        """Handle function calls."""
        assert name == "FunctionCall"

        if node.name.lower() != node.name:
            msg = "{0} is not lowercase".format(node.name)
            replacement = util.replace_word(contents[node.line - 1],
                                            node.col - 1, node.name,
                                            node.name.lower())
            errors.append(LinterFailure(msg, node.line, replacement))
 def _generate_error(node):
     """Generate an error and replacement for node in violation."""
     msg = "Path {0} must be quoted".format(node.contents)
     line_index = node.line - 1
     col_index = node.col - 1
     quoted = "\"{0}\""
     replacement = util.replace_word(contents[line_index], col_index,
                                     node.contents,
                                     quoted.format(node.contents))
     return LinterFailure(msg, node.line, replacement)
예제 #4
0
    def _word_visitor(name, node):
        """Visit all arguments."""
        assert name == "Word"

        if node.type == WordType.String:
            if not _RE_DOUBLE_OUTER_QUOTES.match(node.contents):
                msg = "{0} must use double quotes".format(node.contents)
                replacement_word = "\"{0}\"".format(node.contents[1:-1])
                replacement = util.replace_word(contents[node.line - 1],
                                                node.col - 1, node.contents,
                                                replacement_word)
                errors.append(LinterFailure(msg, node.line, replacement))
예제 #5
0
 def _visit_function_call(node, depth):
     """Handle function calls."""
     col = node.col
     expected = 1 + (depth * indent)
     if node.col != expected:
         delta = expected - node.col
         msg = "Expected {0} to be on column {1}".format(
             node.name, expected)
         replacement = util.replace_word(contents[node.line - 1],
                                         col - 1 + min(0, delta),
                                         " " * max(0, delta * -1),
                                         " " * max(0, delta))
         errors.append(LinterFailure(msg, node.line, replacement))
예제 #6
0
def only_use_own_privates(abstract_syntax_tree):
    """Check that all private definitions used are defined here."""
    calls, defs = find_all.private_calls_and_definitions(abstract_syntax_tree)

    errors = []

    for call, info in calls.items():
        if call not in defs.keys():
            for line in info:
                msg = "Used external private definition {0}".format(call)
                errors.append(LinterFailure(msg, line))

    return errors
예제 #7
0
    def _definition_handler(name, node):
        """Handle function calls and macro definitions."""
        assert name == "FunctionDefinition" or name == "MacroDefinition"

        definition_name_word = node.header.arguments[0]
        definition_name = definition_name_word.contents

        if definition_name.lower() != definition_name:
            msg = "{0} name {1} is not lowercase".format(name, definition_name)
            line_index = definition_name_word.line - 1
            col_index = definition_name_word.col - 1
            replacement = util.replace_word(contents[line_index], col_index,
                                            definition_name,
                                            definition_name.lower())
            errors.append(
                LinterFailure(msg, definition_name_word.line, replacement))
예제 #8
0
    def _definition_visitor(name, node):
        """Visit all definitions."""
        assert name == "FunctionDefinition" or name == "MacroDefinition"

        if len(node.header.arguments) < 2:
            return

        for arg in node.header.arguments[1:]:
            if arg.contents.upper() != arg.contents:
                msg = "{0} must be uppercase".format(arg.contents)
                line_index = arg.line - 1
                col_index = arg.col - 1
                replacement = util.replace_word(contents[line_index],
                                                col_index, arg.contents,
                                                arg.contents.upper())
                errors.append(LinterFailure(msg, arg.line, replacement))
    def _scope_visitor(set_scope, used_scope):
        """Visit both scopes at the same level."""
        assert len(set_scope.scopes) == len(used_scope.scopes)

        # Ignore the global scope
        if id(set_scopes) != id(set_scope):
            for var in set_scope.set_vars:
                if var.node.type != WordType.Variable:
                    return

                if not _variable_used_in_scope(var.node.contents, var.node,
                                               used_scope):
                    msg = "Unused local variable {0}".format(var.node.contents)
                    errors.append(LinterFailure(msg, var.node.line))

        for index in range(0, len(set_scope.scopes)):
            _scope_visitor(set_scope.scopes[index], used_scope.scopes[index])
def private_definitions_used(abstract_syntax_tree):
    """Check that all private definitions are used by this module."""
    calls, defs = find_all.private_calls_and_definitions(abstract_syntax_tree)

    errors = []

    # There's no scoping of functions defined within other functions, so
    # we search from the root of the tree.
    global_scope = find_variables_in_scopes.used_in_tree(abstract_syntax_tree)

    for definition, info in defs.items():
        not_in_function_calls = definition not in calls.keys()
        not_used_as_variable = not _variable_used_in_scope(
            definition, None, global_scope)
        if not_in_function_calls and not_used_as_variable:
            for line in info:
                msg = "Unused private definition {0}".format(definition)
                errors.append(LinterFailure(msg, line))

    return errors
예제 #11
0
def _check_horizontal_space(node, index, contents):
    """Check horizontal space between arguments on same line."""
    if index > 0:
        current_column = node.arguments[index].col - 1
        previous_column = node.arguments[index - 1].col - 1
        previous_len = len(node.arguments[index - 1].contents)
        spaces_start = previous_column + previous_len
        num_spaces = current_column - (previous_column + previous_len)

        line_number = node.arguments[index].line - 1

        if num_spaces != 1:
            cur = node.arguments[index].contents
            prev = node.arguments[index - 1].contents

            msg = "Must be a single space between {0} and {1}".format(
                cur, prev)
            replacement = util.replace_word(contents[line_number],
                                            spaces_start, " " * num_spaces,
                                            " ")
            return LinterFailure(msg, node.line, replacement)
예제 #12
0
def set_variables_capitalized(contents, abstract_syntax_tree):
    """Check that each variable mutated is capitalized."""
    errors = []

    variables = find_set_variables.in_tree(abstract_syntax_tree)
    for evaluate in variables:

        evaluate_upper = evaluate.contents.upper()

        # Argument should be either String or Variable and a transformation
        # to uppercase should have no effect
        if (util.is_word_sink_variable(evaluate.type)
                and evaluate_upper != evaluate.contents):
            desc = "{0} must be uppercase".format(evaluate.contents)
            line = evaluate.line - 1
            replacement = util.replace_word(contents[line], evaluate.col - 1,
                                            evaluate.contents, evaluate_upper)
            errors.append(LinterFailure(desc, evaluate.line, replacement))
            break

    return errors
예제 #13
0
    def _definition_handler(name, node, depth):
        """Visit all definitions."""
        assert name == "FunctionDefinition" or name == "MacroDefinition"
        assert len(node.header.arguments) > 0

        del depth

        definition = node.header.arguments[0]
        def_name = definition.contents

        if not def_name.startswith((namespace, "_" + namespace)):
            msg = "Definition {0} does not start with {1}".format(def_name,
                                                                  namespace)
            replacement_name = "{0}_{1}".format(namespace, def_name)
            if def_name.startswith("_"):
                replacement_name = "_{0}".format(replacement_name)

            replacement = util.replace_word(contents[node.line - 1],
                                            definition.col - 1,
                                            def_name,
                                            replacement_name)

            errors.append(LinterFailure(msg, node.line, replacement))
예제 #14
0
def _check_alignment(arg, last_align, baseline_col, baseline_line, contents):
    """Check alignment of arg."""
    align = _expected_alignment(arg, baseline_col, baseline_line, last_align)

    misaligned_col = align.col and align.col != arg.col
    misaligned_line = align.line and align.line != arg.line

    def _offset_with_space(line, align_col, arg_col):
        """Insert spaces as required to place arg at align_col."""
        offset = max(0, arg_col - align_col)
        spaces = max(0, align_col - arg_col)
        return util.replace_word(line, arg_col - 1 - offset, " " * offset,
                                 " " * spaces)

    if ((misaligned_col or not align.col)
            and (misaligned_line or not align.line)):

        msg_parts_append_table = [
            (lambda: misaligned_line is not None,
             "line {0}".format(align.line)),
            (lambda: misaligned_col is not None, "col {0}".format(align.col)),
            (lambda: align.col != baseline_col, "col {0}".format(baseline_col))
        ]

        replacement = None
        msg_parts = [msg for c, msg in msg_parts_append_table if c()]

        if misaligned_col and align.col == baseline_col:
            replacement = _offset_with_space(contents[arg.line - 1], align.col,
                                             arg.col)

        msg = ("Argument {0} must fall on any of: "
               "{1}".format(arg.contents, ", ".join(msg_parts)))
        return align, LinterFailure(msg, arg.line, replacement)

    return align, None