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
|