Repository: pylint-dev/astroid

Issue:
IndexError when _alias() has no arguments 
### Bug description

```python
_alias()
```

This bug was discovered by OSS-Fuzz:
https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=57984 (report not public yet)


### Configuration

```ini
N/A
```


### Command used

```shell
pylint a.py
```


### Pylint output

<details open>
    <summary>Stacktrace</summary>

```
Traceback (most recent call last):
  File "/home/s/code/pylint/pylint/lint/pylinter.py", line 974, in get_ast
    return MANAGER.ast_from_file(filepath, modname, source=True)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/s/code/astroid/astroid/manager.py", line 167, in ast_from_file
    return AstroidBuilder(self).file_build(filepath, modname)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/s/code/astroid/astroid/builder.py", line 145, in file_build
    return self._post_build(module, builder, encoding)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/s/code/astroid/astroid/builder.py", line 173, in _post_build
    module = self._manager.visit_transforms(module)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/s/code/astroid/astroid/manager.py", line 128, in visit_transforms
    return self._transform.visit(node)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/s/code/astroid/astroid/transforms.py", line 162, in visit
    return self._visit(node)
           ^^^^^^^^^^^^^^^^^
  File "/home/s/code/astroid/astroid/transforms.py", line 84, in _visit
    visited = self._visit_generic(value)
              ^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/s/code/astroid/astroid/transforms.py", line 112, in _visit_generic
    return [self._visit_generic(child) for child in node]
            ^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/s/code/astroid/astroid/transforms.py", line 119, in _visit_generic
    return self._visit(node)
           ^^^^^^^^^^^^^^^^^
  File "/home/s/code/astroid/astroid/transforms.py", line 84, in _visit
    visited = self._visit_generic(value)
              ^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/s/code/astroid/astroid/transforms.py", line 119, in _visit_generic
    return self._visit(node)
           ^^^^^^^^^^^^^^^^^
  File "/home/s/code/astroid/astroid/transforms.py", line 87, in _visit
    return self._transform(node)
           ^^^^^^^^^^^^^^^^^^^^^
  File "/home/s/code/astroid/astroid/transforms.py", line 66, in _transform
    if predicate is None or predicate(node):
                            ^^^^^^^^^^^^^^^
  File "/home/s/code/astroid/astroid/brain/brain_typing.py", line 262, in _looks_like_typing_alias
    isinstance(node.args[0], (Attribute, Name))
               ~~~~~~~~~^^^
IndexError: list index out of range

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "/home/s/code/pylint/pylint/lint/pylinter.py", line 714, in _get_asts
    ast_per_fileitem[fileitem] = self.get_ast(
                                 ^^^^^^^^^^^^^
  File "/home/s/code/pylint/pylint/lint/pylinter.py", line 996, in get_ast
    raise astroid.AstroidBuildingError(
astroid.exceptions.AstroidBuildingError: Building error when trying to create ast representation of module 'input'
```

</details>


### Expected behavior

No crash

### Pylint version

pylint 6bb335f5ca2c52a994d5836eee63dc2c140fc5f3
pylint-dev/astroid@f924ba2299328dc4d138ac9117edbfd0581f880b

### OS / Environment

Arch Linux

### Additional dependencies

_No response_


Discussion / hints:
OSS-Fuzz discovered another `IndexError` when there's only one argument to `_alias` ([OSS-Fuzz bug report](https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=64639)):

```python
a = _alias(int)
```

```
Traceback (most recent call last):
  File "pylint/pylint/checkers/utils.py", line 1365, in safe_infer
    value = next(infer_gen)
            ^^^^^^^^^^^^^^^
  File "astroid/astroid/nodes/node_ng.py", line 147, in infer
    for result in self._explicit_inference(
                  ^^^^^^^^^^^^^^^^^^^^^^^^^
  File "astroid/astroid/inference_tip.py", line 70, in inner
    raise e from None
  File "astroid/astroid/inference_tip.py", line 66, in inner
    func(node, context, **kwargs)
  File "astroid/astroid/brain/brain_typing.py", line 330, in infer_typing_alias
    maybe_type_var = node.args[1]
                     ~~~~~~~~~^^^
IndexError: list index out of range
```

It seems like a comprehensive fix can handle both crashes.  If not, I will file this issue separately.



Fix (patch):
diff --git a/ChangeLog b/ChangeLog
index 036f888e08..8ab5375b4f 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -17,6 +17,10 @@ Release date: TBA
   Closes #2521
   Closes #2523
 
+* Fix crash when typing._alias() call is missing arguments.
+
+  Closes #2513
+
 
 What's New in astroid 3.3.6?
 ============================
diff --git a/astroid/brain/brain_typing.py b/astroid/brain/brain_typing.py
index 239e63af24..c44687bf89 100644
--- a/astroid/brain/brain_typing.py
+++ b/astroid/brain/brain_typing.py
@@ -258,6 +258,7 @@ def _looks_like_typing_alias(node: Call) -> bool:
         isinstance(node.func, Name)
         # TODO: remove _DeprecatedGenericAlias when Py3.14 min
         and node.func.name in {"_alias", "_DeprecatedGenericAlias"}
+        and len(node.args) == 2
         and (
             # _alias function works also for builtins object such as list and dict
             isinstance(node.args[0], (Attribute, Name))


Test changes:
diff --git a/tests/brain/test_typing.py b/tests/brain/test_typing.py
index 1e8e3eaf88..11b77b7f9e 100644
--- a/tests/brain/test_typing.py
+++ b/tests/brain/test_typing.py
@@ -4,7 +4,7 @@
 
 import pytest
 
-from astroid import builder
+from astroid import bases, builder, nodes
 from astroid.exceptions import InferenceError
 
 
@@ -23,3 +23,50 @@ def test_infer_typevar() -> None:
     )
     with pytest.raises(InferenceError):
         call_node.inferred()
+
+
+class TestTypingAlias:
+    def test_infer_typing_alias(self) -> None:
+        """
+        Test that _alias() calls can be inferred.
+        """
+        node = builder.extract_node(
+            """
+            from typing import _alias
+            x = _alias(int, float)
+            """
+        )
+        assert isinstance(node, nodes.Assign)
+        assert isinstance(node.value, nodes.Call)
+        inferred = next(node.value.infer())
+        assert isinstance(inferred, nodes.ClassDef)
+        assert len(inferred.bases) == 1
+        assert inferred.bases[0].name == "int"
+
+    @pytest.mark.parametrize(
+        "alias_args",
+        [
+            "",  # two missing arguments
+            "int",  # one missing argument
+            "int, float, tuple",  # one additional argument
+        ],
+    )
+    def test_infer_typing_alias_incorrect_number_of_arguments(
+        self, alias_args: str
+    ) -> None:
+        """
+        Regression test for: https://github.com/pylint-dev/astroid/issues/2513
+
+        Test that _alias() calls with the incorrect number of arguments can be inferred.
+        """
+        node = builder.extract_node(
+            f"""
+            from typing import _alias
+            x = _alias({alias_args})
+            """
+        )
+        assert isinstance(node, nodes.Assign)
+        assert isinstance(node.value, nodes.Call)
+        inferred = next(node.value.infer())
+        assert isinstance(inferred, bases.Instance)
+        assert inferred.name == "_SpecialGenericAlias"