1import pprint
2import sys
3import typing
4import warnings
5from functools import singledispatch as _singledispatch
6from typing import (
7    TYPE_CHECKING,
8    ClassVar,
9    Iterator,
10    List,
11    Optional,
12    Tuple,
13    Type,
14    TypeVar,
15    Union,
16    cast,
17    overload,
18)
19
20from astroid import decorators, util
21from astroid.exceptions import (
22    AstroidError,
23    InferenceError,
24    ParentMissingError,
25    StatementMissing,
26    UseInferenceDefault,
27)
28from astroid.manager import AstroidManager
29from astroid.nodes.as_string import AsStringVisitor
30from astroid.nodes.const import OP_PRECEDENCE
31
32if TYPE_CHECKING:
33    from astroid import nodes
34
35    if sys.version_info >= (3, 6, 2):
36        # To be fixed with https://github.com/PyCQA/pylint/pull/5316
37        from typing import NoReturn  # pylint: disable=unused-import
38    else:
39        from typing_extensions import NoReturn
40
41if sys.version_info >= (3, 8):
42    from typing import Literal
43else:
44    from typing_extensions import Literal
45
46
47# Types for 'NodeNG.nodes_of_class()'
48T_Nodes = TypeVar("T_Nodes", bound="NodeNG")
49T_Nodes2 = TypeVar("T_Nodes2", bound="NodeNG")
50T_Nodes3 = TypeVar("T_Nodes3", bound="NodeNG")
51SkipKlassT = Union[None, Type["NodeNG"], Tuple[Type["NodeNG"], ...]]
52
53
54class NodeNG:
55    """A node of the new Abstract Syntax Tree (AST).
56
57    This is the base class for all Astroid node classes.
58    """
59
60    is_statement: ClassVar[bool] = False
61    """Whether this node indicates a statement."""
62    optional_assign: ClassVar[
63        bool
64    ] = False  # True for For (and for Comprehension if py <3.0)
65    """Whether this node optionally assigns a variable.
66
67    This is for loop assignments because loop won't necessarily perform an
68    assignment if the loop has no iterations.
69    This is also the case from comprehensions in Python 2.
70    """
71    is_function: ClassVar[bool] = False  # True for FunctionDef nodes
72    """Whether this node indicates a function."""
73    is_lambda: ClassVar[bool] = False
74
75    # Attributes below are set by the builder module or by raw factories
76    _astroid_fields: ClassVar[typing.Tuple[str, ...]] = ()
77    """Node attributes that contain child nodes.
78
79    This is redefined in most concrete classes.
80    """
81    _other_fields: ClassVar[typing.Tuple[str, ...]] = ()
82    """Node attributes that do not contain child nodes."""
83    _other_other_fields: ClassVar[typing.Tuple[str, ...]] = ()
84    """Attributes that contain AST-dependent fields."""
85    # instance specific inference function infer(node, context)
86    _explicit_inference = None
87
88    def __init__(
89        self,
90        lineno: Optional[int] = None,
91        col_offset: Optional[int] = None,
92        parent: Optional["NodeNG"] = None,
93        *,
94        end_lineno: Optional[int] = None,
95        end_col_offset: Optional[int] = None,
96    ) -> None:
97        """
98        :param lineno: The line that this node appears on in the source code.
99
100        :param col_offset: The column that this node appears on in the
101            source code.
102
103        :param parent: The parent node in the syntax tree.
104
105        :param end_lineno: The last line this node appears on in the source code.
106
107        :param end_col_offset: The end column this node appears on in the
108            source code. Note: This is after the last symbol.
109        """
110        self.lineno: Optional[int] = lineno
111        """The line that this node appears on in the source code."""
112
113        self.col_offset: Optional[int] = col_offset
114        """The column that this node appears on in the source code."""
115
116        self.parent: Optional["NodeNG"] = parent
117        """The parent node in the syntax tree."""
118
119        self.end_lineno: Optional[int] = end_lineno
120        """The last line this node appears on in the source code."""
121
122        self.end_col_offset: Optional[int] = end_col_offset
123        """The end column this node appears on in the source code.
124        Note: This is after the last symbol.
125        """
126
127    def infer(self, context=None, **kwargs):
128        """Get a generator of the inferred values.
129
130        This is the main entry point to the inference system.
131
132        .. seealso:: :ref:`inference`
133
134        If the instance has some explicit inference function set, it will be
135        called instead of the default interface.
136
137        :returns: The inferred values.
138        :rtype: iterable
139        """
140        if context is not None:
141            context = context.extra_context.get(self, context)
142        if self._explicit_inference is not None:
143            # explicit_inference is not bound, give it self explicitly
144            try:
145                # pylint: disable=not-callable
146                results = list(self._explicit_inference(self, context, **kwargs))
147                if context is not None:
148                    context.nodes_inferred += len(results)
149                yield from results
150                return
151            except UseInferenceDefault:
152                pass
153
154        if not context:
155            # nodes_inferred?
156            yield from self._infer(context, **kwargs)
157            return
158
159        key = (self, context.lookupname, context.callcontext, context.boundnode)
160        if key in context.inferred:
161            yield from context.inferred[key]
162            return
163
164        generator = self._infer(context, **kwargs)
165        results = []
166
167        # Limit inference amount to help with performance issues with
168        # exponentially exploding possible results.
169        limit = AstroidManager().max_inferable_values
170        for i, result in enumerate(generator):
171            if i >= limit or (context.nodes_inferred > context.max_inferred):
172                yield util.Uninferable
173                break
174            results.append(result)
175            yield result
176            context.nodes_inferred += 1
177
178        # Cache generated results for subsequent inferences of the
179        # same node using the same context
180        context.inferred[key] = tuple(results)
181        return
182
183    def _repr_name(self):
184        """Get a name for nice representation.
185
186        This is either :attr:`name`, :attr:`attrname`, or the empty string.
187
188        :returns: The nice name.
189        :rtype: str
190        """
191        if all(name not in self._astroid_fields for name in ("name", "attrname")):
192            return getattr(self, "name", "") or getattr(self, "attrname", "")
193        return ""
194
195    def __str__(self):
196        rname = self._repr_name()
197        cname = type(self).__name__
198        if rname:
199            string = "%(cname)s.%(rname)s(%(fields)s)"
200            alignment = len(cname) + len(rname) + 2
201        else:
202            string = "%(cname)s(%(fields)s)"
203            alignment = len(cname) + 1
204        result = []
205        for field in self._other_fields + self._astroid_fields:
206            value = getattr(self, field)
207            width = 80 - len(field) - alignment
208            lines = pprint.pformat(value, indent=2, width=width).splitlines(True)
209
210            inner = [lines[0]]
211            for line in lines[1:]:
212                inner.append(" " * alignment + line)
213            result.append(f"{field}={''.join(inner)}")
214
215        return string % {
216            "cname": cname,
217            "rname": rname,
218            "fields": (",\n" + " " * alignment).join(result),
219        }
220
221    def __repr__(self):
222        rname = self._repr_name()
223        if rname:
224            string = "<%(cname)s.%(rname)s l.%(lineno)s at 0x%(id)x>"
225        else:
226            string = "<%(cname)s l.%(lineno)s at 0x%(id)x>"
227        return string % {
228            "cname": type(self).__name__,
229            "rname": rname,
230            "lineno": self.fromlineno,
231            "id": id(self),
232        }
233
234    def accept(self, visitor):
235        """Visit this node using the given visitor."""
236        func = getattr(visitor, "visit_" + self.__class__.__name__.lower())
237        return func(self)
238
239    def get_children(self) -> Iterator["NodeNG"]:
240        """Get the child nodes below this node."""
241        for field in self._astroid_fields:
242            attr = getattr(self, field)
243            if attr is None:
244                continue
245            if isinstance(attr, (list, tuple)):
246                yield from attr
247            else:
248                yield attr
249        yield from ()
250
251    def last_child(self) -> Optional["NodeNG"]:
252        """An optimized version of list(get_children())[-1]"""
253        for field in self._astroid_fields[::-1]:
254            attr = getattr(self, field)
255            if not attr:  # None or empty listy / tuple
256                continue
257            if isinstance(attr, (list, tuple)):
258                return attr[-1]
259            return attr
260        return None
261
262    def node_ancestors(self) -> Iterator["NodeNG"]:
263        """Yield parent, grandparent, etc until there are no more."""
264        parent = self.parent
265        while parent is not None:
266            yield parent
267            parent = parent.parent
268
269    def parent_of(self, node):
270        """Check if this node is the parent of the given node.
271
272        :param node: The node to check if it is the child.
273        :type node: NodeNG
274
275        :returns: True if this node is the parent of the given node,
276            False otherwise.
277        :rtype: bool
278        """
279        for parent in node.node_ancestors():
280            if self is parent:
281                return True
282        return False
283
284    @overload
285    def statement(
286        self, *, future: Literal[None] = ...
287    ) -> Union["nodes.Statement", "nodes.Module"]:
288        ...
289
290    @overload
291    def statement(self, *, future: Literal[True]) -> "nodes.Statement":
292        ...
293
294    def statement(
295        self, *, future: Literal[None, True] = None
296    ) -> Union["nodes.Statement", "nodes.Module", "NoReturn"]:
297        """The first parent node, including self, marked as statement node.
298
299        TODO: Deprecate the future parameter and only raise StatementMissing and return
300        nodes.Statement
301
302        :raises AttributeError: If self has no parent attribute
303        :raises StatementMissing: If self has no parent attribute and future is True
304        """
305        if self.is_statement:
306            return cast("nodes.Statement", self)
307        if not self.parent:
308            if future:
309                raise StatementMissing(target=self)
310            warnings.warn(
311                "In astroid 3.0.0 NodeNG.statement() will return either a nodes.Statement "
312                "or raise a StatementMissing exception. AttributeError will no longer be raised. "
313                "This behaviour can already be triggered "
314                "by passing 'future=True' to a statement() call.",
315                DeprecationWarning,
316            )
317            raise AttributeError(f"{self} object has no attribute 'parent'")
318        return self.parent.statement(future=future)
319
320    def frame(
321        self,
322    ) -> Union["nodes.FunctionDef", "nodes.Module", "nodes.ClassDef", "nodes.Lambda"]:
323        """The first parent frame node.
324
325        A frame node is a :class:`Module`, :class:`FunctionDef`,
326        :class:`ClassDef` or :class:`Lambda`.
327
328        :returns: The first parent frame node.
329        """
330        return self.parent.frame()
331
332    def scope(self) -> "nodes.LocalsDictNodeNG":
333        """The first parent node defining a new scope.
334        These can be Module, FunctionDef, ClassDef, Lambda, or GeneratorExp nodes.
335
336        :returns: The first parent scope node.
337        """
338        if not self.parent:
339            raise ParentMissingError(target=self)
340        return self.parent.scope()
341
342    def root(self):
343        """Return the root node of the syntax tree.
344
345        :returns: The root node.
346        :rtype: Module
347        """
348        if self.parent:
349            return self.parent.root()
350        return self
351
352    def child_sequence(self, child):
353        """Search for the sequence that contains this child.
354
355        :param child: The child node to search sequences for.
356        :type child: NodeNG
357
358        :returns: The sequence containing the given child node.
359        :rtype: iterable(NodeNG)
360
361        :raises AstroidError: If no sequence could be found that contains
362            the given child.
363        """
364        for field in self._astroid_fields:
365            node_or_sequence = getattr(self, field)
366            if node_or_sequence is child:
367                return [node_or_sequence]
368            # /!\ compiler.ast Nodes have an __iter__ walking over child nodes
369            if (
370                isinstance(node_or_sequence, (tuple, list))
371                and child in node_or_sequence
372            ):
373                return node_or_sequence
374
375        msg = "Could not find %s in %s's children"
376        raise AstroidError(msg % (repr(child), repr(self)))
377
378    def locate_child(self, child):
379        """Find the field of this node that contains the given child.
380
381        :param child: The child node to search fields for.
382        :type child: NodeNG
383
384        :returns: A tuple of the name of the field that contains the child,
385            and the sequence or node that contains the child node.
386        :rtype: tuple(str, iterable(NodeNG) or NodeNG)
387
388        :raises AstroidError: If no field could be found that contains
389            the given child.
390        """
391        for field in self._astroid_fields:
392            node_or_sequence = getattr(self, field)
393            # /!\ compiler.ast Nodes have an __iter__ walking over child nodes
394            if child is node_or_sequence:
395                return field, child
396            if (
397                isinstance(node_or_sequence, (tuple, list))
398                and child in node_or_sequence
399            ):
400                return field, node_or_sequence
401        msg = "Could not find %s in %s's children"
402        raise AstroidError(msg % (repr(child), repr(self)))
403
404    # FIXME : should we merge child_sequence and locate_child ? locate_child
405    # is only used in are_exclusive, child_sequence one time in pylint.
406
407    def next_sibling(self):
408        """The next sibling statement node.
409
410        :returns: The next sibling statement node.
411        :rtype: NodeNG or None
412        """
413        return self.parent.next_sibling()
414
415    def previous_sibling(self):
416        """The previous sibling statement.
417
418        :returns: The previous sibling statement node.
419        :rtype: NodeNG or None
420        """
421        return self.parent.previous_sibling()
422
423    # these are lazy because they're relatively expensive to compute for every
424    # single node, and they rarely get looked at
425
426    @decorators.cachedproperty
427    def fromlineno(self) -> Optional[int]:
428        """The first line that this node appears on in the source code."""
429        if self.lineno is None:
430            return self._fixed_source_line()
431        return self.lineno
432
433    @decorators.cachedproperty
434    def tolineno(self) -> Optional[int]:
435        """The last line that this node appears on in the source code."""
436        if not self._astroid_fields:
437            # can't have children
438            last_child = None
439        else:
440            last_child = self.last_child()
441        if last_child is None:
442            return self.fromlineno
443        return last_child.tolineno
444
445    def _fixed_source_line(self) -> Optional[int]:
446        """Attempt to find the line that this node appears on.
447
448        We need this method since not all nodes have :attr:`lineno` set.
449        """
450        line = self.lineno
451        _node: Optional[NodeNG] = self
452        try:
453            while line is None:
454                _node = next(_node.get_children())
455                line = _node.lineno
456        except StopIteration:
457            _node = self.parent
458            while _node and line is None:
459                line = _node.lineno
460                _node = _node.parent
461        return line
462
463    def block_range(self, lineno):
464        """Get a range from the given line number to where this node ends.
465
466        :param lineno: The line number to start the range at.
467        :type lineno: int
468
469        :returns: The range of line numbers that this node belongs to,
470            starting at the given line number.
471        :rtype: tuple(int, int or None)
472        """
473        return lineno, self.tolineno
474
475    def set_local(self, name, stmt):
476        """Define that the given name is declared in the given statement node.
477
478        This definition is stored on the parent scope node.
479
480        .. seealso:: :meth:`scope`
481
482        :param name: The name that is being defined.
483        :type name: str
484
485        :param stmt: The statement that defines the given name.
486        :type stmt: NodeNG
487        """
488        self.parent.set_local(name, stmt)
489
490    @overload
491    def nodes_of_class(
492        self,
493        klass: Type[T_Nodes],
494        skip_klass: SkipKlassT = None,
495    ) -> Iterator[T_Nodes]:
496        ...
497
498    @overload
499    def nodes_of_class(
500        self,
501        klass: Tuple[Type[T_Nodes], Type[T_Nodes2]],
502        skip_klass: SkipKlassT = None,
503    ) -> Union[Iterator[T_Nodes], Iterator[T_Nodes2]]:
504        ...
505
506    @overload
507    def nodes_of_class(
508        self,
509        klass: Tuple[Type[T_Nodes], Type[T_Nodes2], Type[T_Nodes3]],
510        skip_klass: SkipKlassT = None,
511    ) -> Union[Iterator[T_Nodes], Iterator[T_Nodes2], Iterator[T_Nodes3]]:
512        ...
513
514    @overload
515    def nodes_of_class(
516        self,
517        klass: Tuple[Type[T_Nodes], ...],
518        skip_klass: SkipKlassT = None,
519    ) -> Iterator[T_Nodes]:
520        ...
521
522    def nodes_of_class(  # type: ignore[misc] # mypy doesn't correctly recognize the overloads
523        self,
524        klass: Union[
525            Type[T_Nodes],
526            Tuple[Type[T_Nodes], Type[T_Nodes2]],
527            Tuple[Type[T_Nodes], Type[T_Nodes2], Type[T_Nodes3]],
528            Tuple[Type[T_Nodes], ...],
529        ],
530        skip_klass: SkipKlassT = None,
531    ) -> Union[Iterator[T_Nodes], Iterator[T_Nodes2], Iterator[T_Nodes3]]:
532        """Get the nodes (including this one or below) of the given types.
533
534        :param klass: The types of node to search for.
535
536        :param skip_klass: The types of node to ignore. This is useful to ignore
537            subclasses of :attr:`klass`.
538
539        :returns: The node of the given types.
540        """
541        if isinstance(self, klass):
542            yield self
543
544        if skip_klass is None:
545            for child_node in self.get_children():
546                yield from child_node.nodes_of_class(klass, skip_klass)
547
548            return
549
550        for child_node in self.get_children():
551            if isinstance(child_node, skip_klass):
552                continue
553            yield from child_node.nodes_of_class(klass, skip_klass)
554
555    @decorators.cached
556    def _get_assign_nodes(self):
557        return []
558
559    def _get_name_nodes(self):
560        for child_node in self.get_children():
561            yield from child_node._get_name_nodes()
562
563    def _get_return_nodes_skip_functions(self):
564        yield from ()
565
566    def _get_yield_nodes_skip_lambdas(self):
567        yield from ()
568
569    def _infer_name(self, frame, name):
570        # overridden for ImportFrom, Import, Global, TryExcept and Arguments
571        pass
572
573    def _infer(self, context=None):
574        """we don't know how to resolve a statement by default"""
575        # this method is overridden by most concrete classes
576        raise InferenceError(
577            "No inference function for {node!r}.", node=self, context=context
578        )
579
580    def inferred(self):
581        """Get a list of the inferred values.
582
583        .. seealso:: :ref:`inference`
584
585        :returns: The inferred values.
586        :rtype: list
587        """
588        return list(self.infer())
589
590    def instantiate_class(self):
591        """Instantiate an instance of the defined class.
592
593        .. note::
594
595            On anything other than a :class:`ClassDef` this will return self.
596
597        :returns: An instance of the defined class.
598        :rtype: object
599        """
600        return self
601
602    def has_base(self, node):
603        """Check if this node inherits from the given type.
604
605        :param node: The node defining the base to look for.
606            Usually this is a :class:`Name` node.
607        :type node: NodeNG
608        """
609        return False
610
611    def callable(self):
612        """Whether this node defines something that is callable.
613
614        :returns: True if this defines something that is callable,
615            False otherwise.
616        :rtype: bool
617        """
618        return False
619
620    def eq(self, value):
621        return False
622
623    def as_string(self) -> str:
624        """Get the source code that this node represents."""
625        return AsStringVisitor()(self)
626
627    def repr_tree(
628        self,
629        ids=False,
630        include_linenos=False,
631        ast_state=False,
632        indent="   ",
633        max_depth=0,
634        max_width=80,
635    ) -> str:
636        """Get a string representation of the AST from this node.
637
638        :param ids: If true, includes the ids with the node type names.
639        :type ids: bool
640
641        :param include_linenos: If true, includes the line numbers and
642            column offsets.
643        :type include_linenos: bool
644
645        :param ast_state: If true, includes information derived from
646            the whole AST like local and global variables.
647        :type ast_state: bool
648
649        :param indent: A string to use to indent the output string.
650        :type indent: str
651
652        :param max_depth: If set to a positive integer, won't return
653            nodes deeper than max_depth in the string.
654        :type max_depth: int
655
656        :param max_width: Attempt to format the output string to stay
657            within this number of characters, but can exceed it under some
658            circumstances. Only positive integer values are valid, the default is 80.
659        :type max_width: int
660
661        :returns: The string representation of the AST.
662        :rtype: str
663        """
664
665        @_singledispatch
666        def _repr_tree(node, result, done, cur_indent="", depth=1):
667            """Outputs a representation of a non-tuple/list, non-node that's
668            contained within an AST, including strings.
669            """
670            lines = pprint.pformat(
671                node, width=max(max_width - len(cur_indent), 1)
672            ).splitlines(True)
673            result.append(lines[0])
674            result.extend([cur_indent + line for line in lines[1:]])
675            return len(lines) != 1
676
677        # pylint: disable=unused-variable,useless-suppression; doesn't understand singledispatch
678        @_repr_tree.register(tuple)
679        @_repr_tree.register(list)
680        def _repr_seq(node, result, done, cur_indent="", depth=1):
681            """Outputs a representation of a sequence that's contained within an AST."""
682            cur_indent += indent
683            result.append("[")
684            if not node:
685                broken = False
686            elif len(node) == 1:
687                broken = _repr_tree(node[0], result, done, cur_indent, depth)
688            elif len(node) == 2:
689                broken = _repr_tree(node[0], result, done, cur_indent, depth)
690                if not broken:
691                    result.append(", ")
692                else:
693                    result.append(",\n")
694                    result.append(cur_indent)
695                broken = _repr_tree(node[1], result, done, cur_indent, depth) or broken
696            else:
697                result.append("\n")
698                result.append(cur_indent)
699                for child in node[:-1]:
700                    _repr_tree(child, result, done, cur_indent, depth)
701                    result.append(",\n")
702                    result.append(cur_indent)
703                _repr_tree(node[-1], result, done, cur_indent, depth)
704                broken = True
705            result.append("]")
706            return broken
707
708        # pylint: disable=unused-variable,useless-suppression; doesn't understand singledispatch
709        @_repr_tree.register(NodeNG)
710        def _repr_node(node, result, done, cur_indent="", depth=1):
711            """Outputs a strings representation of an astroid node."""
712            if node in done:
713                result.append(
714                    indent + f"<Recursion on {type(node).__name__} with id={id(node)}"
715                )
716                return False
717            done.add(node)
718
719            if max_depth and depth > max_depth:
720                result.append("...")
721                return False
722            depth += 1
723            cur_indent += indent
724            if ids:
725                result.append(f"{type(node).__name__}<0x{id(node):x}>(\n")
726            else:
727                result.append(f"{type(node).__name__}(")
728            fields = []
729            if include_linenos:
730                fields.extend(("lineno", "col_offset"))
731            fields.extend(node._other_fields)
732            fields.extend(node._astroid_fields)
733            if ast_state:
734                fields.extend(node._other_other_fields)
735            if not fields:
736                broken = False
737            elif len(fields) == 1:
738                result.append(f"{fields[0]}=")
739                broken = _repr_tree(
740                    getattr(node, fields[0]), result, done, cur_indent, depth
741                )
742            else:
743                result.append("\n")
744                result.append(cur_indent)
745                for field in fields[:-1]:
746                    result.append(f"{field}=")
747                    _repr_tree(getattr(node, field), result, done, cur_indent, depth)
748                    result.append(",\n")
749                    result.append(cur_indent)
750                result.append(f"{fields[-1]}=")
751                _repr_tree(getattr(node, fields[-1]), result, done, cur_indent, depth)
752                broken = True
753            result.append(")")
754            return broken
755
756        result: List[str] = []
757        _repr_tree(self, result, set())
758        return "".join(result)
759
760    def bool_value(self, context=None):
761        """Determine the boolean value of this node.
762
763        The boolean value of a node can have three
764        possible values:
765
766            * False: For instance, empty data structures,
767              False, empty strings, instances which return
768              explicitly False from the __nonzero__ / __bool__
769              method.
770            * True: Most of constructs are True by default:
771              classes, functions, modules etc
772            * Uninferable: The inference engine is uncertain of the
773              node's value.
774
775        :returns: The boolean value of this node.
776        :rtype: bool or Uninferable
777        """
778        return util.Uninferable
779
780    def op_precedence(self):
781        # Look up by class name or default to highest precedence
782        return OP_PRECEDENCE.get(self.__class__.__name__, len(OP_PRECEDENCE))
783
784    def op_left_associative(self):
785        # Everything is left associative except `**` and IfExp
786        return True
787