pappasam / jedi-language-server

A Python language server exclusively for Jedi. If Jedi supports it well, this language server should too.
MIT License
572 stars 44 forks source link

Properties should be children of classes not the methods where they are defined #240

Closed pyscripter closed 1 year ago

pyscripter commented 1 year ago

Consider the following python code:

class A:
    def __init__(self):
        self.prop = "A property"

The response to a docSymbols request is:

    {
      "name": "A",
      "kind": 5,
      "range": {
        "start": { "line": 0, "character": 0 },
        "end": { "line": 2, "character": 32 }
      },
      "selectionRange": {
        "start": { "line": 0, "character": 6 },
        "end": { "line": 0, "character": 7 }
      },
      "detail": "class A",
      "children": [
        {
          "name": "__init__",
          "kind": 6,
          "range": {
            "start": { "line": 1, "character": 4 },
            "end": { "line": 2, "character": 32 }
          },
          "selectionRange": {
            "start": { "line": 1, "character": 8 },
            "end": { "line": 1, "character": 16 }
          },
          "detail": "def __init__",
          "children": [
            {
              "name": "prop",
              "kind": 7,
              "range": {
                "start": { "line": 2, "character": 8 },
                "end": { "line": 2, "character": 32 }
              },
              "selectionRange": {
                "start": { "line": 2, "character": 13 },
                "end": { "line": 2, "character": 17 }
              },
              "detail": "self.prop = \"A property\"",
              "children": []
            }
          ]
        }
      ]
    }

You can see that 'prop' is a child of __init__, but I think that it should be a child of the class A.

The problem is the following code in jedi_utils.py.lsp_document_symbols:

        elif name.is_side_effect() and name.get_line_code().strip().startswith(
            "self."
        ):
            # handle attribute creation on __init__ method
            symbol.kind = SymbolKind.Property
            parent_symbol = _name_lookup[parent]
            assert parent_symbol.children is not None
            parent_symbol.children.append(symbol)

I think this should be replaced with:


        elif (
              name.is_side_effect() and 
              parent.name == "__init__" and
              name.get_line_code().strip().startswith("self.")
        ):
            # handle attribute creation on __init__ method
            symbol.kind = SymbolKind.Property
            grandparent_symbol = _name_lookup.get(parent.parent())
            if grandparent_symbol and (grandparent_symbol.kind == SymbolKind.Class):
                grandparent_symbol.children.append(symbol)```
pyscripter commented 1 year ago

Thanks!