Beispiel #1
0
    def is_valid(self, node, lint_context):
        """ Whether the specified node is valid to the policy.

        In this policy, comparing between a string and any value by
        'ignorecase'-sensitive is invalid. This policy can detect following
        script: variable =~ '1'

        But detecting exactly string comparison without evaluation is very hard.
        So this policy often get false-positive/negative results.
            False-positive case is: '1' =~ 1
            False-negative case is: ('1') =~ 1
        """
        node_type = NodeType(node['type'])

        left_type = NodeType(node['left']['type'])
        right_type = NodeType(node['right']['type'])

        is_like_string_comparison = left_type is NodeType.STRING \
            or right_type is NodeType.STRING

        is_valid = not is_like_string_comparison

        if not is_valid:
            self._make_description(node_type)

        return is_valid
Beispiel #2
0
        def enter_handler(node):
            node_type = NodeType(node['type'])
            if node_type is not NodeType.CALL:
                return

            called_function_identifier = node['left']

            # Name node of the "map" or "filter" functions are always IDENTIFIER.
            if NodeType(called_function_identifier['type']
                        ) is not NodeType.IDENTIFIER:
                return

            is_map_or_function_call = called_function_identifier.get(
                'value') in {
                    'map': True,
                    'filter': True,
                }

            if not is_map_or_function_call:
                return

            string_expr_node = node['rlist'][1]

            # We can analyze only STRING nodes by static analyzing.
            if NodeType(string_expr_node['type']) is not NodeType.STRING:
                return

            parser = Parser()
            string_expr_content_nodes = parser.parse_string_expr(
                string_expr_node)
            node[STRING_EXPR_CONTENT] = string_expr_content_nodes
        def enter_handler(node):
            node_type = NodeType(node['type'])
            if node_type is not NodeType.CALL:
                return

            called_function_identifier = node['left']

            # Name node of the "map" or "filter" functions are always IDENTIFIER.
            if NodeType(called_function_identifier['type']) is not NodeType.IDENTIFIER:
                return

            is_map_or_function_call = called_function_identifier.get('value') in {
                'map': True,
                'filter': True,
            }

            if not is_map_or_function_call:
                return

            args = node['rlist']

            # Prevent crash. See https://github.com/Kuniwak/vint/issues/256.
            if len(args) < 2:
                return

            string_expr_node = args[1]

            # We can analyze only STRING nodes by static analyzing.
            if NodeType(string_expr_node['type']) is not NodeType.STRING:
                return

            parser = Parser()
            string_expr_content_nodes = parser.parse_string_expr(string_expr_node)
            node[STRING_EXPR_CONTENT] = string_expr_content_nodes
Beispiel #4
0
        def on_enter(node):
            actual_order_of_events.append({
                'node_type': NodeType(node['type']),
                'handler': 'enter',
            })

            if NodeType(node['type']) is NodeType.WHILE:
                return SKIP_CHILDREN
    def _pre_mark_accessor_children(self, node, is_on_lambda_body,
                                    is_on_lambda_str):
        node_type = NodeType(node['type'])
        dict_node = node['left']

        if NodeType(dict_node['type']) in AccessorLikeNodeTypes:
            self._pre_mark_accessor_children(
                dict_node,
                is_on_lambda_str=is_on_lambda_str,
                is_on_lambda_body=is_on_lambda_body,
            )

        if node_type is NodeType.SLICE:
            for member_node in node['rlist']:
                # In VimLParser spec, an empty array means null.
                #   list[1:] => {rlist: [node, []]}
                if type(member_node) is list:
                    continue

                if NodeType(member_node['type']) is NodeType.IDENTIFIER:
                    # Only the identifier should be flagged as a member that
                    # the variable is an accessor for a list or dictionary.
                    # For example, the variable that is "l:end" in list[0 : l:end]
                    # is not accessor for the symbol table of the variable "list",
                    # but it is a variable symbol table accessor.
                    continue

                self._pre_mark_member_node(
                    member_node,
                    is_on_lambda_str=is_on_lambda_str,
                    is_on_lambda_body=is_on_lambda_body,
                )
            return

        member_node = node['right']
        if node_type is NodeType.SUBSCRIPT:
            if NodeType(member_node['type']) is NodeType.IDENTIFIER:
                # Only the identifier should be flagged as a member that
                # the variable is an accessor for a list or dictionary.
                # For example, the variable that is "l:key" in dict[l:key]
                # is not accessor for the symbol table of the variable "dict",
                # but it is a variable symbol table accessor.
                return

        self._pre_mark_member_node(
            member_node,
            is_on_lambda_str=is_on_lambda_str,
            is_on_lambda_body=is_on_lambda_body,
        )
Beispiel #6
0
 def enter_handler(node):
     # NOTE: We need this flag only string nodes, because this flag is only for
     # ProhibitUnnecessaryDoubleQuote.
     if NodeType(node['type']) is NodeType.STRING:
         node[STRING_EXPR_CONTEXT] = {
             STRING_EXPR_CONTEXT_FLAG: True,
         }
Beispiel #7
0
    def _enter_handler(self, node):
        node_type = NodeType(node['type'])

        if node_type is NodeType.FUNCTION:
            return self._handle_function_node(node)

        self._find_variable_like_nodes(node)
Beispiel #8
0
    def _enter_identifier_like_node(self, node, is_on_lambda_body, is_on_lambda_str, is_declarative=None,
                                    is_function=None, is_declarative_parameter=None):
        node_type = NodeType(node['type'])

        if node_type in AccessorLikeNodeTypes:
            id_like_node = node
            self._enter_accessor_node(
                id_like_node,
                is_declarative=is_declarative,
                is_function=is_function,
                is_declarative_parameter=is_declarative_parameter,
                is_on_lambda_str=is_on_lambda_str,
                is_on_lambda_body=is_on_lambda_body,
            )
            return

        if node_type in IdentifierTerminateNodeTypes:
            id_like_node = node
            self._enter_identifier_terminate_node(
                id_like_node,
                is_declarative=is_declarative,
                is_function=is_function,
                is_declarative_parameter=is_declarative_parameter,
                is_on_lambda_body=is_on_lambda_body,
                is_on_lambda_str=is_on_lambda_str,
            )
            return
Beispiel #9
0
    def test_parse_redir_with_dot(self):
        parser = Parser()
        redir_cmd_node = {
            'type': NodeType.EXCMD.value,
            'ea': {
                'argpos': {
                    'col': 7,
                    'i': 6,
                    'lnum': 1
                },
            },
            'str': 'redir => s:dict.redir',
        }
        ast = parser.parse_redir(redir_cmd_node)

        expected_pos = {
            'col': 16,
            'i': 15,
            'lnum': 1,
            'offset': 11,
        }
        expected_node_type = NodeType.DOT

        self.assertEqual(expected_node_type, NodeType(ast['type']))
        self.assertEqual(expected_pos, ast['pos'])
Beispiel #10
0
    def _enter_declarative_node(self, node, is_on_lambda_body, is_on_lambda_str):
        node_type = NodeType(node['type'])

        if node_type is NodeType.FUNCTION:
            self._enter_function_node(
                node,
                is_on_lambda_str=is_on_lambda_str,
                is_on_lambda_body=is_on_lambda_body,
            )

        elif node_type is NodeType.LET:
            self._enter_let_node(
                node,
                is_on_lambda_str=is_on_lambda_str,
                is_on_lambda_body=is_on_lambda_body,
            )

        elif node_type is NodeType.FOR:
            self._enter_for_node(
                node,
                is_on_lambda_str=is_on_lambda_str,
                is_on_lambda_body=is_on_lambda_body
            )

        elif node_type is NodeType.EXCMD:
            self._enter_excmd_node(
                node,
                is_on_lambda_str=is_on_lambda_str,
                is_on_lambda_body=is_on_lambda_body,
            )
Beispiel #11
0
def traverse(node, on_enter=None, on_leave=None):
    """ Traverses the specified Vim script AST node (depth first order).
    The on_enter/on_leave handler will be called with the specified node and
    the children. You can skip traversing child nodes by returning
    SKIP_CHILDREN.
    """
    node_type = NodeType(node['type'])

    if node_type not in ChildNodeAccessorMap:
        raise UnknownNodeTypeException(node_type)

    if on_enter:
        should_traverse_children = on_enter(node) is not SKIP_CHILDREN
    else:
        should_traverse_children = True

    if should_traverse_children:
        for property_accessor in ChildNodeAccessorMap[node_type]:
            accessor_func = property_accessor['accessor']
            prop_name = property_accessor['property_name']

            accessor_func(lambda child_node: traverse(child_node, on_enter, on_leave),
                          node[prop_name])

        for handler in _traverser_extensions:
            handler(node, on_enter=on_enter, on_leave=on_leave)

    if on_leave:
        on_leave(node)
Beispiel #12
0
def normalize_variable_name(node, reachability_tester):
    # type: (Dict[str, Any], ReferenceReachabilityTester) -> Optional[str]
    """ Returns normalized variable name.
    Normalizing means that variable names get explicit visibility by
    visibility prefix such as: "g:", "s:", ...

    Returns None if the specified node is unanalyzable.
    A node is unanalyzable if:

    - the node is not identifier-like
    - the node is named dynamically
    """

    node_type = NodeType(node['type'])

    if not is_analyzable_identifier(node):
        return None

    if node_type is NodeType.IDENTIFIER:
        return _normalize_identifier_value(node, reachability_tester)

    # Nodes identifier-like without identifier is always normalized because
    # the nodes can not have a visibility prefix.
    if node_type in IdentifierLikeNodeTypes:
        return node['value']
Beispiel #13
0
    def _enter_identifier_terminate_node(self, id_term_node, is_on_lambda_body, is_on_lambda_str, is_declarative=None,
                                         is_function=None, is_declarative_parameter=None, is_lambda_argument=None):
        node_type = NodeType(id_term_node['type'])

        if node_type is NodeType.CURLYNAME:
            self._enter_curlyname_node(
                id_term_node,
                is_on_lambda_body=is_on_lambda_body,
                is_on_lambda_str=is_on_lambda_str,
                is_declarative=is_declarative,
                is_function=is_function,
                is_declarative_parameter=is_declarative_parameter,
            )
            return

        is_autoload = '#' in id_term_node['value']
        is_variadic = id_term_node['value'] == '...'
        _set_identifier_attribute(
            id_term_node,
            is_lambda_argument=is_lambda_argument,
            is_on_lambda_body=is_on_lambda_body,
            is_on_lambda_str=is_on_lambda_str,
            is_declarative=is_declarative,
            is_autoload=is_autoload,
            is_function=is_function,
            is_declarative_parameter=is_declarative_parameter,
            is_variadic=is_variadic,
        )
Beispiel #14
0
    def _handle_enter(self, node):
        node_type = NodeType(node['type'])

        if node_type not in self.node_type_to_on_enter_handler_map:
            return

        enter_handler = self.node_type_to_on_enter_handler_map[node_type]
        enter_handler(node)
Beispiel #15
0
    def _leave_handler(self, node):  # type: (Dict[str, Any]) -> None
        node_type = NodeType(node['type'])

        if node_type is NodeType.FUNCTION:
            self._scope_tree_builder.leave_current_scope()

        elif node_type is NodeType.LAMBDA:
            self._scope_tree_builder.leave_current_scope()
Beispiel #16
0
    def _handle_leave(self, node):
        node_type = NodeType(node['type'])

        if node_type not in self.node_type_to_on_leave_handler_map:
            return

        leave_handler = self.node_type_to_on_leave_handler_map[node_type]
        leave_handler(node)
Beispiel #17
0
    def _enter_handler(self, node):  # type: (Dict[str, Any]) -> None
        node_type = NodeType(node['type'])

        if node_type is NodeType.FUNCTION:
            return self._handle_function_node(node)
        elif node_type is NodeType.LAMBDA:
            return self._handle_lambda_node(node)

        self._find_variable_like_nodes(node)
Beispiel #18
0
        def enter_handler(node):
            node_type = NodeType(node['type'])
            if node_type is not NodeType.CALL:
                return

            called_function_identifier = node['left']

            # The name node type of "map" or "filter" or "call" are always IDENTIFIER.
            if NodeType(called_function_identifier['type']) is not NodeType.IDENTIFIER:
                return

            called_function_identifier_value = called_function_identifier.get('value')

            if called_function_identifier_value in ['map', 'filter']:
                # Analyze second argument of "map" or "filter" if the node type is STRING.
                self._attach_string_expr_content_to_map_or_func(node)
            elif called_function_identifier_value in ['call', 'function']:
                # Analyze first argument of "call" or "function" if the node type is STRING.
                self._attach_string_expr_content_to_call_or_function(node)
Beispiel #19
0
        def on_enter_handler(node):
            if IDENTIFIER_ATTRIBUTE not in node:
                return

            id_name = node['value']
            footstamps[id_name] = True

            self.assertEqual(
                expected_id_attr_map[id_name], node[IDENTIFIER_ATTRIBUTE],
                "Identifier Attribute of {1}({0}) have unexpected differences".
                format(NodeType(node['type']), id_name))
Beispiel #20
0
    def _pre_mark_member_node(self, member_node, is_on_lambda_body, is_on_lambda_str):
        member_node_type = NodeType(member_node['type'])

        if member_node_type in IdentifierTerminateNodeTypes or \
                member_node_type in AnalyzableSubScriptChildNodeTypes:
            _set_identifier_attribute(
                member_node,
                is_member=True,
                is_on_lambda_str=is_on_lambda_str,
                is_on_lambda_body=is_on_lambda_body,
            )
Beispiel #21
0
    def is_valid(self, node, lint_context):
        left_node = node['left']

        if NodeType(left_node['type']) != NodeType.IDENTIFIER:
            return True

        if left_node['value'] != 'map':
            return True

        args = node['rlist']
        return len(args) == 2
Beispiel #22
0
        def on_enter_handler(node):
            if IDENTIFIER_ATTRIBUTE not in node:
                return

            id_name = node['value']
            footstamps[id_name] = True

            # Print id_name for debugging
            pprint((NodeType(node['type']), id_name))
            self.assertEqual(expected_id_attr_map[id_name],
                             node[IDENTIFIER_ATTRIBUTE])
    def _check_scriptencoding(self, node):
        # TODO: Use BREAK when implemented
        if self.has_scriptencoding:
            return SKIP_CHILDREN

        node_type = NodeType(node['type'])

        if node_type is not NodeType.EXCMD:
            return

        self.has_scriptencoding = node['str'].startswith('scripte')
Beispiel #24
0
    def _attach_string_expr_content_to_call_or_function(self, call_call_node):
        args = call_call_node['rlist']

        if len(args) < 1:
            return

        # We can statically analyze only STRING node
        string_expr_node = args[0]

        if NodeType(string_expr_node['type']) is not NodeType.STRING:
            return

        parser = Parser()
        string_expr_content_nodes = parser.parse_string_expr(string_expr_node)

        func_ref_nodes = list(filter(
            lambda node: NodeType(node['type']) is NodeType.IDENTIFIER,
            string_expr_content_nodes
        ))

        string_expr_node[FUNCTION_REFERENCE_STRING_EXPR_CONTENT] = func_ref_nodes
Beispiel #25
0
def parse_config_comment_node_if_exists(node):
    # type: (Dict[str, Any]) -> Optional[ConfigComment]
    if NodeType(node['type']) is not NodeType.COMMENT:
        return None

    comment_node = node
    comment_content = comment_node['str']

    if not is_config_comment(comment_content):
        return None

    return parse_config_comment(comment_content)
Beispiel #26
0
    def _enter_handler(self, node, is_on_lambda_body, is_on_lambda_str):
        node_type = NodeType(node['type'])

        if node_type in IdentifierTerminateNodeTypes:
            # Attach identifier attributes to all IdentifierTerminateNodeTypes.
            self._enter_identifier_terminate_node(
                node,
                is_on_lambda_str=is_on_lambda_str,
                is_on_lambda_body=is_on_lambda_body,
            )

        if node_type in AccessorLikeNodeTypes:
            self._pre_mark_accessor_children(
                node,
                is_on_lambda_str=is_on_lambda_str,
                is_on_lambda_body=is_on_lambda_body,
            )

        if node_type in DeclarativeNodeTypes:
            self._enter_declarative_node(
                node,
                is_on_lambda_str=is_on_lambda_str,
                is_on_lambda_body=is_on_lambda_body,
            )

        if node_type is NodeType.CALL:
            self._enter_call_node(
                node,
                is_on_lambda_str=is_on_lambda_str,
                is_on_lambda_body=is_on_lambda_body
            )

        if node_type is NodeType.DELFUNCTION:
            self._enter_delfunction_node(
                node,
                is_on_lambda_str=is_on_lambda_str,
                is_on_lambda_body=is_on_lambda_body
            )

        if node_type is NodeType.STRING:
            self._enter_string_node(
                node,
                is_on_lambda_str=is_on_lambda_str,
                is_on_lambda_body=is_on_lambda_body
            )

        if node_type is NodeType.LAMBDA:
            return self._enter_lambda_node(
                node,
                is_on_lambda_str=is_on_lambda_str,
                is_on_lambda_body=is_on_lambda_body,
            )
Beispiel #27
0
    def _fire_listeners(self, node, lint_context):
        node_type = NodeType(node['type'])

        if node_type not in self._listeners_map:
            return

        listening_policies = self._listeners_map[node_type]

        for listening_policy in listening_policies:
            violation = listening_policy.get_violation_if_found(
                node, lint_context)

            if violation is not None:
                self._violations.append(violation)
Beispiel #28
0
    def _enter_declarative_node(self, node):
        node_type = NodeType(node['type'])

        if node_type is NodeType.FUNCTION:
            self._enter_function_node(node)
            return
        if node_type is NodeType.LET:
            self._enter_let_node(node)
            return
        if node_type is NodeType.FOR:
            self._enter_for_node(node)
            return
        if node_type is NodeType.EXCMD:
            self._enter_excmd_node(node)
            return
Beispiel #29
0
def detect_scope_visibility(node, context_scope):
    """ Returns a variable visibility hint by the specified node.
    The hint is a dict that has 2 attributes: "scope_visibility" and
    "is_implicit".
    """
    node_type = NodeType(node['type'])

    if not is_analyzable_identifier(node):
        return _create_identifier_visibility_hint(ScopeVisibility.UNANALYZABLE)

    if node_type is NodeType.IDENTIFIER:
        return _detect_identifier_scope_visibility(node, context_scope)

    if node_type in GlobalLikeScopeVisibilityNodeTypes:
        return _create_identifier_visibility_hint(ScopeVisibility.GLOBAL_LIKE)
Beispiel #30
0
        def enter_handler(node):
            node_type = NodeType(node['type'])
            if node_type is not NodeType.EXCMD:
                return

            is_redir_command = node['ea']['cmd'].get('name') == 'redir'
            if not is_redir_command:
                return

            redir_cmd_str = node['str']
            is_redir_assignment = '=>' in redir_cmd_str
            if not is_redir_assignment:
                return

            parser = Parser()
            redir_content_node = parser.parse_redir(node)
            node[REDIR_CONTENT] = redir_content_node