File: method.py

package info (click to toggle)
fortran-language-server 3.2.2%2Bdfsg-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 2,268 kB
  • sloc: python: 9,688; f90: 1,195; fortran: 30; makefile: 28; ansic: 20
file content (136 lines) | stat: -rw-r--r-- 5,134 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
from __future__ import annotations

from typing import TYPE_CHECKING

from fortls.constants import CLASS_TYPE_ID, KEYWORD_ID_DICT, METH_TYPE_ID
from fortls.helper_functions import get_paren_substring

from .utilities import find_in_scope
from .variable import Variable

if TYPE_CHECKING:
    from .ast import FortranAST


class Method(Variable):  # i.e. TypeBound procedure
    def __init__(
        self,
        file_ast: FortranAST,
        line_number: int,
        name: str,
        var_desc: str,
        keywords: list,
        keyword_info: dict,
        proc_ptr: str = "",  # procedure pointer e.g. `foo` in `procedure(foo)`
        link_obj=None,
    ):
        super().__init__(
            file_ast,
            line_number,
            name,
            var_desc,
            keywords,
            keyword_info,
            kind=proc_ptr,
            link_obj=link_obj,
        )
        self.drop_arg: int = -1
        self.pass_name: str = keyword_info.get("pass")
        if link_obj is None:
            self.link_name = get_paren_substring(self.get_desc(True).lower())

    def set_parent(self, parent_obj):
        self.parent = parent_obj
        if self.parent.get_type() == CLASS_TYPE_ID:
            if self.keywords.count(KEYWORD_ID_DICT["nopass"]) == 0:
                self.drop_arg = 0
            if (
                (self.parent.contains_start is not None)
                and (self.sline > self.parent.contains_start)
                and (self.link_name is None)
            ):
                self.link_name = self.name.lower()

    def get_snippet(self, name_replace=None, drop_arg=-1):
        if self.link_obj is not None:
            name = self.name if name_replace is None else name_replace
            return self.link_obj.get_snippet(name, self.drop_arg)
        return None, None

    def get_type(self, no_link=False):
        if (not no_link) and (self.link_obj is not None):
            return self.link_obj.get_type()
        # Generic
        return METH_TYPE_ID

    def get_documentation(self):
        if (self.link_obj is not None) and (self.doc_str is None):
            return self.link_obj.get_documentation()
        return self.doc_str

    def get_hover(self, long=False, drop_arg=-1) -> tuple[str, str]:
        docs = self.get_documentation()
        # Long hover message
        if self.link_obj is None:
            sub_sig, _ = self.get_snippet()
            hover_str = f"{self.get_desc()} {sub_sig}"
        else:
            link_msg, link_docs = self.link_obj.get_hover(
                long=True, drop_arg=self.drop_arg
            )
            # Replace the name of the linked object with the name of this object
            hover_str = link_msg.replace(self.link_obj.name, self.name, 1)
            if isinstance(link_docs, str):
                # Get just the docstring of the link, if any, no args
                link_doc_top = self.link_obj.get_documentation()
                # Replace the linked objects topmost documentation with the
                # documentation of the procedure pointer if one is present
                if link_doc_top is not None:
                    docs = link_docs.replace(link_doc_top, docs, 1)
                # If no top docstring is present at the linked object but there
                # are docstrings for the arguments, add them to the end of the
                # documentation for this object
                elif link_docs:
                    if docs is None:
                        docs = ""
                    docs += "  \n" + link_docs
        return hover_str, docs

    def get_signature(self, drop_arg=-1):
        if self.link_obj is not None:
            call_sig, _ = self.get_snippet()
            _, _, arg_sigs = self.link_obj.get_signature(self.drop_arg)
            return call_sig, self.get_documentation(), arg_sigs
        return None, None, None

    def get_interface(self, name_replace=None, drop_arg=-1, change_strings=None):
        if self.link_obj is not None:
            return self.link_obj.get_interface(
                name_replace, self.drop_arg, change_strings
            )
        return None

    def resolve_link(self, obj_tree):
        if self.link_name is None:
            return
        if self.parent is not None:
            if self.parent.get_type() == CLASS_TYPE_ID:
                link_obj = find_in_scope(self.parent.parent, self.link_name, obj_tree)
            else:
                link_obj = find_in_scope(self.parent, self.link_name, obj_tree)
            if link_obj is not None:
                self.link_obj = link_obj
                if self.pass_name is not None:
                    self.pass_name = self.pass_name.lower()
                    for i, arg in enumerate(link_obj.args_snip.split(",")):
                        if arg.lower() == self.pass_name:
                            self.drop_arg = i
                            break

    def is_callable(self):
        return True

    def check_definition(self, obj_tree, known_types=None, interface=False):
        if known_types is None:
            known_types = {}
        return None, known_types