@@ -165,9 +165,13 @@ def find_in_scope(
165
165
obj_tree : dict ,
166
166
interface : bool = False ,
167
167
local_only : bool = False ,
168
+ var_line_number : int = None ,
168
169
):
169
170
def check_scope (
170
- local_scope : fortran_scope , var_name_lower : str , filter_public : bool = False
171
+ local_scope : fortran_scope ,
172
+ var_name_lower : str ,
173
+ filter_public : bool = False ,
174
+ var_line_number : int = None ,
171
175
):
172
176
for child in local_scope .get_children ():
173
177
if child .name .startswith ("#GEN_INT" ):
@@ -178,6 +182,19 @@ def check_scope(
178
182
if (child .vis < 0 ) or ((local_scope .def_vis < 0 ) and (child .vis <= 0 )):
179
183
continue
180
184
if child .name .lower () == var_name_lower :
185
+ # For functions with an implicit result() variable the name
186
+ # of the function is used. If we are hovering over the function
187
+ # definition, we do not want the implicit result() to be returned.
188
+ # If scope is from a function and child's name is same as functions name
189
+ # and start of scope i.e. function definition is equal to the request ln
190
+ # then we are need to skip this child
191
+ if (
192
+ isinstance (local_scope , fortran_function )
193
+ and local_scope .name .lower () == child .name .lower ()
194
+ and var_line_number in (local_scope .sline , local_scope .eline )
195
+ ):
196
+ return None
197
+
181
198
return child
182
199
return None
183
200
@@ -186,7 +203,7 @@ def check_scope(
186
203
# Check local scope
187
204
if scope is None :
188
205
return None
189
- tmp_var = check_scope (scope , var_name_lower )
206
+ tmp_var = check_scope (scope , var_name_lower , var_line_number = var_line_number )
190
207
if local_only or (tmp_var is not None ):
191
208
return tmp_var
192
209
# Check INCLUDE statements
@@ -959,7 +976,7 @@ def get_hover(self, long=False, include_doc=True, drop_arg=-1):
959
976
keyword_list = get_keywords (self .keywords )
960
977
keyword_list .append (f"{ self .get_desc ()} " )
961
978
hover_array = [" " .join (keyword_list ) + sub_sig ]
962
- self .get_docs_full (hover_array , long , include_doc , drop_arg )
979
+ hover_array = self .get_docs_full (hover_array , long , include_doc , drop_arg )
963
980
return "\n " .join (hover_array ), long
964
981
965
982
def get_docs_full (
@@ -977,6 +994,7 @@ def get_docs_full(
977
994
doc_str = arg_obj .get_documentation ()
978
995
if include_doc and (doc_str is not None ):
979
996
hover_array += doc_str .splitlines ()
997
+ return hover_array
980
998
981
999
def get_signature (self , drop_arg = - 1 ):
982
1000
arg_sigs = []
@@ -1070,8 +1088,8 @@ def __init__(
1070
1088
args : str = "" ,
1071
1089
mod_flag : bool = False ,
1072
1090
keywords : list = None ,
1073
- return_type = None ,
1074
- result_var = None ,
1091
+ result_type : str = None ,
1092
+ result_name : str = None ,
1075
1093
):
1076
1094
super ().__init__ (file_ast , line_number , name , args , mod_flag , keywords )
1077
1095
self .args : str = args .replace (" " , "" ).lower ()
@@ -1080,65 +1098,108 @@ def __init__(
1080
1098
self .in_children : list = []
1081
1099
self .missing_args : list = []
1082
1100
self .mod_scope : bool = mod_flag
1083
- self .result_var = result_var
1084
- self .result_obj = None
1085
- self .return_type = None
1086
- if return_type is not None :
1087
- self .return_type = return_type [0 ]
1101
+ self .result_name : str = result_name
1102
+ self .result_type : str = result_type
1103
+ self .result_obj : fortran_var = None
1104
+ # Set the implicit result() name to be the function name
1105
+ if self .result_name is None :
1106
+ self .result_name = self .name
1088
1107
1089
1108
def copy_interface (self , copy_source : fortran_function ):
1090
1109
# Call the parent class method
1091
1110
child_names = super ().copy_interface (copy_source )
1092
1111
# Return specific options
1093
- self .result_var = copy_source .result_var
1112
+ self .result_name = copy_source .result_name
1113
+ self .result_type = copy_source .result_type
1094
1114
self .result_obj = copy_source .result_obj
1095
1115
if copy_source .result_obj is not None :
1096
1116
if copy_source .result_obj .name .lower () not in child_names :
1097
1117
self .in_children .append (copy_source .result_obj )
1098
1118
1099
1119
def resolve_link (self , obj_tree ):
1100
1120
self .resolve_arg_link (obj_tree )
1101
- if self .result_var is not None :
1102
- result_var_lower = self .result_var .lower ()
1103
- for child in self .children :
1104
- if child .name .lower () == result_var_lower :
1105
- self .result_obj = child
1121
+ result_var_lower = self .result_name .lower ()
1122
+ for child in self .children :
1123
+ if child .name .lower () == result_var_lower :
1124
+ self .result_obj = child
1125
+ # Update result value and type
1126
+ self .result_name = child .name
1127
+ self .result_type = child .get_desc ()
1106
1128
1107
1129
def get_type (self , no_link = False ):
1108
1130
return FUNCTION_TYPE_ID
1109
1131
1110
1132
def get_desc (self ):
1111
- if self .result_obj is not None :
1112
- return self .result_obj .get_desc () + " FUNCTION"
1113
- if self .return_type is not None :
1114
- return self .return_type + " FUNCTION"
1133
+ if self .result_type :
1134
+ return self .result_type + " FUNCTION"
1115
1135
return "FUNCTION"
1116
1136
1117
1137
def is_callable (self ):
1118
1138
return False
1119
1139
1120
- def get_hover (self , long = False , include_doc = True , drop_arg = - 1 ):
1140
+ def get_hover (
1141
+ self , long : bool = False , include_doc : bool = True , drop_arg : int = - 1
1142
+ ) -> tuple [str , bool ]:
1143
+ """Construct the hover message for a FUNCTION.
1144
+ Two forms are produced here the `long` i.e. the normal for hover requests
1145
+
1146
+ ```
1147
+ [MODIFIERS] FUNCTION NAME([ARGS]) RESULT(RESULT_VAR)
1148
+ TYPE, [ARG_MODIFIERS] :: [ARGS]
1149
+ TYPE, [RESULT_MODIFIERS] :: RESULT_VAR
1150
+ ```
1151
+
1152
+ note: intrinsic functions will display slightly different,
1153
+ `RESULT_VAR` and its `TYPE` might not always be present
1154
+
1155
+ short form, used when functions are arguments in functions and subroutines:
1156
+
1157
+ ```
1158
+ FUNCTION NAME([ARGS]) :: ARG_LIST_NAME
1159
+ ```
1160
+
1161
+ Parameters
1162
+ ----------
1163
+ long : bool, optional
1164
+ toggle between long and short hover results, by default False
1165
+ include_doc : bool, optional
1166
+ if to include any documentation, by default True
1167
+ drop_arg : int, optional
1168
+ Ignore argument at position `drop_arg` in the argument list, by default -1
1169
+
1170
+ Returns
1171
+ -------
1172
+ tuple[str, bool]
1173
+ String representative of the hover message and the `long` flag used
1174
+ """
1121
1175
fun_sig , _ = self .get_snippet (drop_arg = drop_arg )
1122
- fun_return = ""
1123
- if self .result_obj is not None :
1124
- fun_return , _ = self .result_obj .get_hover (include_doc = False )
1125
- if self .return_type is not None :
1126
- fun_return = self .return_type
1176
+ # short hover messages do not include the result()
1177
+ fun_sig += f" RESULT({ self .result_name } )" if long else ""
1127
1178
keyword_list = get_keywords (self .keywords )
1128
1179
keyword_list .append ("FUNCTION" )
1129
- hover_array = [f"{ fun_return } { ' ' .join (keyword_list )} { fun_sig } " ]
1130
- self .get_docs_full (hover_array , long , include_doc , drop_arg )
1180
+
1181
+ hover_array = [f"{ ' ' .join (keyword_list )} { fun_sig } " ]
1182
+ hover_array = self .get_docs_full (hover_array , long , include_doc , drop_arg )
1183
+ # Only append the return value if using long form
1184
+ if self .result_obj and long :
1185
+ arg_doc , _ = self .result_obj .get_hover (include_doc = False )
1186
+ hover_array .append (f"{ arg_doc } :: { self .result_obj .name } " )
1187
+ # intrinsic functions, where the return type is missing but can be inferred
1188
+ elif self .result_type and long :
1189
+ # prepend type to function signature
1190
+ hover_array [0 ] = f"{ self .result_type } { hover_array [0 ]} "
1131
1191
return "\n " .join (hover_array ), long
1132
1192
1133
1193
def get_interface (self , name_replace = None , change_arg = - 1 , change_strings = None ):
1134
1194
fun_sig , _ = self .get_snippet (name_replace = name_replace )
1195
+ fun_sig += f" RESULT({ self .result_name } )"
1196
+ # XXX:
1135
1197
keyword_list = []
1136
- if self .return_type is not None :
1137
- keyword_list .append (self .return_type )
1138
- if self .result_obj is not None :
1139
- fun_sig += f" RESULT({ self .result_obj .name } )"
1198
+ if self .result_type :
1199
+ keyword_list .append (self .result_type )
1140
1200
keyword_list += get_keywords (self .keywords )
1141
1201
keyword_list .append ("FUNCTION " )
1202
+
1142
1203
interface_array = self .get_interface_array (
1143
1204
keyword_list , fun_sig , change_arg , change_strings
1144
1205
)
@@ -1628,6 +1689,7 @@ def get_hover(self, long=False, include_doc=True, drop_arg=-1):
1628
1689
hover_str = ", " .join (
1629
1690
[self .desc ] + get_keywords (self .keywords , self .keyword_info )
1630
1691
)
1692
+ # TODO: at this stage we can mae this lowercase
1631
1693
# Add parameter value in the output
1632
1694
if self .is_parameter () and self .param_val :
1633
1695
hover_str += f" :: { self .name } = { self .param_val } "
0 commit comments