Repository: pylint-dev/astroid

Issue:
Code for supporting `with_metaclass` seems broken
So this code works as expected:
```python
node = astroid.extract_node('''
def foo():
    return 42
''')
print(list(node.infer_call_result(caller=node)))
```
```console
$ python a.py
[<Const.int l.3 at 0x105704070>]
```

But this breaks:
```python
node = astroid.extract_node('''
def with_metaclass(meta, *bases):
    return 42
''')
print(list(node.infer_call_result(caller=node)))
```

```console
$ python a.py
Traceback (most recent call last):
  File "/Users/tusharsadhwani/a.py", line 14, in <module>
    print(list(node.infer_call_result(node)))
  File "/Users/tusharsadhwani/venv/lib/python3.10/site-packages/astroid/nodes/scoped_nodes/scoped_nodes.py", line 1738, in infer_call_result
    metaclass = next(caller.args[0].infer(context), None)
TypeError: 'Arguments' object is not subscriptable
```
astroid seems to have special handling for functions called `with_metaclass`, which seems to be broken.

Am I using the method wrongly? I tried using it just as I saw it being used in the project itself.


Discussion / hints:
This seems relevant:

https://github.com/PyCQA/astroid/blob/1a698acd4ca746851e6a525bf7e012ac6e6eb877/astroid/nodes/scoped_nodes/scoped_nodes.py#L1702-L1712

I am not familiar with that code, but it seems like this is indeed very error-prone.
@DanielNoord 

https://github.com/PyCQA/astroid/blob/1a698acd4ca746851e6a525bf7e012ac6e6eb877/astroid/nodes/scoped_nodes/scoped_nodes.py#L1713

I think this line is the exact problem. Did `FunctionDef.args` ever return a list of nodes before? It seems to return an `Arguments` type now.
Not as far as I know. However, is `caller` always a `FunctionDef`? Might that be where this is going wrong?
@DanielNoord do you know of any node type which has an `args` field of type list?
`CallContext` has `list[NodeNG]` and `Arguments` has `list[AssignName]`.
It looks like this is happening whether or not `six` is involved, but yes, since #1622 we no longer inject a `Call` as a fake base. That fake `Call` would have had `.args`.



Fix (patch):
diff --git a/ChangeLog b/ChangeLog
index 460ef30507..f02a58516c 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -61,6 +61,9 @@ What's New in astroid 2.15.3?
 =============================
 Release date: TBA
 
+* Fix ``infer_call_result()`` crash on methods called ``with_metaclass()``.
+
+  Closes #1735
 
 
 What's New in astroid 2.15.2?
diff --git a/astroid/nodes/scoped_nodes/scoped_nodes.py b/astroid/nodes/scoped_nodes/scoped_nodes.py
index c75237729d..8c39129c28 100644
--- a/astroid/nodes/scoped_nodes/scoped_nodes.py
+++ b/astroid/nodes/scoped_nodes/scoped_nodes.py
@@ -1692,10 +1692,18 @@ def infer_call_result(self, caller=None, context: InferenceContext | None = None
         # generators, and filter it out later.
         if (
             self.name == "with_metaclass"
+            and caller is not None
             and len(self.args.args) == 1
             and self.args.vararg is not None
         ):
-            metaclass = next(caller.args[0].infer(context), None)
+            if isinstance(caller.args, Arguments):
+                metaclass = next(caller.args.args[0].infer(context), None)
+            elif isinstance(caller.args, list):
+                metaclass = next(caller.args[0].infer(context), None)
+            else:
+                raise TypeError(  # pragma: no cover
+                    f"caller.args was neither Arguments nor list; got {type(caller.args)}"
+                )
             if isinstance(metaclass, ClassDef):
                 try:
                     class_bases = [


Test changes:
diff --git a/tests/test_inference.py b/tests/test_inference.py
index 37a48f089d..7fcbb10cce 100644
--- a/tests/test_inference.py
+++ b/tests/test_inference.py
@@ -4055,6 +4055,11 @@ class C:
             inferred = next(node.infer())
             self.assertRaises(InferenceError, next, inferred.infer_call_result(node))
 
+    def test_infer_call_result_with_metaclass(self) -> None:
+        node = extract_node("def with_metaclass(meta, *bases): return 42")
+        inferred = next(node.infer_call_result(caller=node))
+        self.assertIsInstance(inferred, nodes.Const)
+
     def test_context_call_for_context_managers(self) -> None:
         ast_nodes = extract_node(
             """