Esempio n. 1
0
    def visit_functiondef(self, func: nodes.FunctionDef) -> None:
        self._current_block.add_statement(func)

        previous_cfg = self._current_cfg
        previous_block = self._current_block

        self.cfgs[func] = ControlFlowGraph()
        self._current_cfg = self.cfgs[func]

        self._control_boundaries.append((func, {
            nodes.Return.__name__:
            self._current_cfg.end
        }))

        self._current_cfg.start.add_statement(func.args)
        func.cfg_block = self._current_cfg.start

        self._current_block = self._current_cfg.create_block(
            self._current_cfg.start)

        for child in func.body:
            child.accept(self)

        self._control_boundaries.pop()

        self._current_cfg.link_or_merge(self._current_block,
                                        self._current_cfg.end)
        self._current_cfg.update_block_reachability()

        self._current_block = previous_block
        self._current_cfg = previous_cfg
Esempio n. 2
0
def _determine_function_name_type(node: nodes.FunctionDef,
                                  config: argparse.Namespace) -> str:
    """Determine the name type whose regex the function's name should match.

    :param node: A function node.
    :param config: Configuration from which to pull additional property classes.

    :returns: One of ('function', 'method', 'attr')
    """
    property_classes, property_names = _get_properties(config)
    if not node.is_method():
        return "function"

    if is_property_setter(node) or is_property_deleter(node):
        # If the function is decorated using the prop_method.{setter,getter}
        # form, treat it like an attribute as well.
        return "attr"

    decorators = node.decorators.nodes if node.decorators else []
    for decorator in decorators:
        # If the function is a property (decorated with @property
        # or @abc.abstractproperty), the name type is 'attr'.
        if isinstance(
                decorator,
                nodes.Name) or (isinstance(decorator, nodes.Attribute)
                                and decorator.attrname in property_names):
            inferred = utils.safe_infer(decorator)
            if (inferred and hasattr(inferred, "qname")
                    and inferred.qname() in property_classes):
                return "attr"
    return "method"
Esempio n. 3
0
 def visit_functiondef(self, node: nodes.FunctionDef) -> None:
     """Check function name, docstring, arguments, redefinition,
     variable names, max locals.
     """
     if node.is_method():
         self.linter.stats.node_count["method"] += 1
     else:
         self.linter.stats.node_count["function"] += 1
     self._check_dangerous_default(node)
Esempio n. 4
0
    def _check_nonlocal_and_global(self, node: nodes.FunctionDef) -> None:
        """Check that a name is both nonlocal and global."""
        def same_scope(current: nodes.Global | nodes.Nonlocal) -> bool:
            return current.scope() is node

        from_iter = itertools.chain.from_iterable
        nonlocals = set(
            from_iter(child.names
                      for child in node.nodes_of_class(nodes.Nonlocal)
                      if same_scope(child)))

        if not nonlocals:
            return

        global_vars = set(
            from_iter(child.names
                      for child in node.nodes_of_class(nodes.Global)
                      if same_scope(child)))
        for name in nonlocals.intersection(global_vars):
            self.add_message("nonlocal-and-global", args=(name, ), node=node)
Esempio n. 5
0
    def visit_functiondef(self, node: nodes.FunctionDef) -> None:
        if not node.is_method():
            return

        inferred = _safe_infer_call_result(node, node)
        # Only want to check types that we are able to infer
        if (inferred and node.name in self._protocol_map
                and not is_function_body_ellipsis(node)):
            self._protocol_map[node.name](node, inferred)

        if node.name in PYMETHODS:
            self._check_unexpected_method_signature(node)
Esempio n. 6
0
def infer_typedDict(  # pylint: disable=invalid-name
    node: nodes.FunctionDef, ctx: context.InferenceContext = None
) -> None:
    """Replace TypedDict FunctionDef with ClassDef."""
    class_def = nodes.ClassDef(
        name="TypedDict",
        doc=node.doc,
        lineno=node.lineno,
        col_offset=node.col_offset,
        parent=node.parent,
    )
    class_def.postinit(bases=[], body=[], decorators=None)
    node.root().locals["TypedDict"] = [class_def]
Esempio n. 7
0
 def _check_first_arg_for_type(self, node: nodes.FunctionDef) -> None:
     """Check the name of first argument."""
     # pylint: disable=duplicate-code
     if node.args.posonlyargs:
         first_arg = node.args.posonlyargs[0].name
     elif node.args.args:
         first_arg = node.argnames()[0]
     else:
         first_arg = None
     self._first_attrs.append(first_arg)
     # static method
     if node.type == "staticmethod":
         self._first_attrs[-1] = None
Esempio n. 8
0
def _looks_like_signal(node: nodes.FunctionDef,
                       signal_name: str = "pyqtSignal") -> bool:
    """Detect a Signal node."""
    klasses = node.instance_attrs.get("__class__", [])
    # On PySide2 or PySide6 (since  Qt 5.15.2) the Signal class changed locations
    if node.qname().partition(".")[0] in {"PySide2", "PySide6"}:
        return any(cls.qname() == "Signal"
                   for cls in klasses)  # pragma: no cover
    if klasses:
        try:
            return klasses[0].name == signal_name
        except AttributeError:  # pragma: no cover
            # return False if the cls does not have a name attribute
            pass
    return False
Esempio n. 9
0
    def _add_raise_message(self, missing_excs: set[str],
                           node: nodes.FunctionDef) -> None:
        """Adds a message on :param:`node` for the missing exception type.

        :param missing_excs: A list of missing exception types.

        :param node: The node show the message on.
        """
        if node.is_abstract():
            try:
                missing_excs.remove("NotImplementedError")
            except KeyError:
                pass

        if not missing_excs:
            return

        self.add_message("missing-raises-doc",
                         args=(", ".join(sorted(missing_excs)), ),
                         node=node)
Esempio n. 10
0
    def visit_functiondef(self, node: nodes.FunctionDef) -> None:
        """Called when a FunctionDef node is visited."""
        if not node.is_method() or node.name != "__init__":
            return

        # Check that all arguments are annotated.
        # The first argument is "self".
        args = node.args
        annotations = (args.posonlyargs_annotations + args.annotations +
                       args.kwonlyargs_annotations)[1:]
        if args.vararg is not None:
            annotations.append(args.varargannotation)
        if args.kwarg is not None:
            annotations.append(args.kwargannotation)
        if not annotations or None in annotations:
            return

        # Check that return type is specified and it is "None".
        if not isinstance(node.returns,
                          nodes.Const) or node.returns.value is not None:
            self.add_message("hass-constructor-return", node=node)
Esempio n. 11
0
    def visit_functiondef(self, node: nodes.FunctionDef) -> None:
        # Do not emit any warnings if the method is just an implementation
        # of a base class method.
        confidence = interfaces.HIGH
        if node.is_method():
            if utils.overrides_a_method(node.parent.frame(future=True),
                                        node.name):
                return
            confidence = (interfaces.INFERENCE if utils.has_known_bases(
                node.parent.frame(
                    future=True)) else interfaces.INFERENCE_FAILURE)

        self._check_name(
            _determine_function_name_type(node, config=self.linter.config),
            node.name,
            node,
            confidence,
        )
        # Check argument names
        args = node.args.args
        if args is not None:
            self._recursive_check_names(args)
Esempio n. 12
0
    def visit_functiondef(self, node: nodes.FunctionDef) -> None:
        """check use of super"""
        # ignore actual functions or method within a new style class
        if not node.is_method():
            return
        klass = node.parent.frame()
        for stmt in node.nodes_of_class(nodes.Call):
            if node_frame_class(stmt) != node_frame_class(node):
                # Don't look down in other scopes.
                continue

            expr = stmt.func
            if not isinstance(expr, nodes.Attribute):
                continue

            call = expr.expr
            # skip the test if using super
            if not (isinstance(call, nodes.Call) and isinstance(
                    call.func, nodes.Name) and call.func.name == "super"):
                continue

            # super should not be used on an old style class
            if klass.newstyle or not has_known_bases(klass):
                # super first arg should not be the class
                if not call.args:
                    continue

                # calling super(type(self), self) can lead to recursion loop
                # in derived classes
                arg0 = call.args[0]
                if (isinstance(arg0, nodes.Call)
                        and isinstance(arg0.func, nodes.Name)
                        and arg0.func.name == "type"):
                    self.add_message("bad-super-call",
                                     node=call,
                                     args=("type", ))
                    continue

                # calling super(self.__class__, self) can lead to recursion loop
                # in derived classes
                if (len(call.args) >= 2
                        and isinstance(call.args[1], nodes.Name)
                        and call.args[1].name == "self"
                        and isinstance(arg0, nodes.Attribute)
                        and arg0.attrname == "__class__"):
                    self.add_message("bad-super-call",
                                     node=call,
                                     args=("self.__class__", ))
                    continue

                try:
                    supcls = call.args and next(call.args[0].infer(), None)
                except astroid.InferenceError:
                    continue

                if klass is not supcls:
                    name = None
                    # if supcls is not Uninferable, then supcls was inferred
                    # and use its name. Otherwise, try to look
                    # for call.args[0].name
                    if supcls:
                        name = supcls.name
                    elif call.args and hasattr(call.args[0], "name"):
                        name = call.args[0].name
                    if name:
                        self.add_message("bad-super-call",
                                         node=call,
                                         args=(name, ))
Esempio n. 13
0
 def visit_functiondef(self, node: nodes.FunctionDef) -> None:
     ftype = "method" if node.is_method() else "function"
     self._check_docstring(ftype, node)
Esempio n. 14
0
 def visit_functiondef(self, node: nodes.FunctionDef) -> None:
     if not node.is_method():
         return
     self._meth_could_be_func = True
     self._check_first_arg_for_type(node)
Esempio n. 15
0
def _has_bare_super_call(fundef_node: nodes.FunctionDef) -> bool:
    for call in fundef_node.nodes_of_class(nodes.Call):
        func = call.func
        if isinstance(func, nodes.Name) and func.name == "super" and not call.args:
            return True
    return False
Esempio n. 16
0
 def visit_functiondef(self, node: nodes.FunctionDef) -> None:
     """Called when a FunctionDef node is visited."""
     for match in self._function_matchers:
         if node.name != match.function_name or node.is_method():
             continue
         self._check_function(node, match)