Skip to content

Functions nested in different methods of a class all get the symbol Class#name(). #231

Open

Description

@Chaptyziok

Version: scip-python 0.6.6

class Graph:
    def order(self) -> None:
        def visit(name: str) -> None:
            pass

        visit("a")

    def check(self) -> None:
        def visit(value: int) -> None:
            pass

        visit(1)

scip-python snapshot-dir output:

        def visit(name: str) -> None:
#           ^^^^^ definition  demo 0.1.0 `demo.nested`/Graph#visit().
        visit("a")
#       ^^^^^ reference  demo 0.1.0 `demo.nested`/Graph#visit().
        def visit(value: int) -> None:
#           ^^^^^ definition  demo 0.1.0 `demo.nested`/Graph#visit().
        visit(1)
#       ^^^^^ reference  demo 0.1.0 `demo.nested`/Graph#visit().

The two different functions share one symbol, which is also the symbol a real method Graph.visit would have. The index ends up with two definitions of one symbol that have different parameters, and each call references both.

Expected: Graph#order().visit(). and Graph#check().visit().. That is what scip-python already emits for functions nested in module-level functions: def first(): def inner() gives first().inner(). for both the definition and the call.

Cause: makeScipSymbol (the Function case) and getFunctionSymbol call ParseTreeUtils.getEnclosingClass(node) with stopAtFunction = false, so a function nested in a method finds the method's class and skips the method.

Possible fix (packages/pyright-scip/src/treeVisitor.ts):

             case ParseNodeType.Function: {
-                let cls = ParseTreeUtils.getEnclosingClass(node, false);
+                let cls = ParseTreeUtils.getEnclosingClass(node, /* stopAtFunction */ true);
-        const enclosingClass = ParseTreeUtils.getEnclosingClass(decl.node);
+        if (ParseTreeUtils.getEnclosingFunction(decl.node)) {
+            // A nested function: use the same symbol as its definition.
+            return this.getScipSymbol(decl.node);
+        }
+
+        const enclosingClass = ParseTreeUtils.getEnclosingClass(decl.node, /* stopAtFunction */ true);

With this change, the example gives Graph#order().visit(). and Graph#check().visit(). for each definition and its call, and the existing snapshot outputs are unchanged. Related, but a different case: #160. I can open a PR with a snapshot test.

Activity

  1. linear commented on Oct 21, 2026

    @linear
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions