Branch: refs/heads/master Author: Jiří Techet techet@gmail.com Committer: GitHub noreply@github.com Date: Wed, 21 Sep 2022 21:32:25 UTC Commit: 3952182724b84c465f680e0a82e1333fefc94f64 https://github.com/geany/geany/commit/3952182724b84c465f680e0a82e1333fefc94f...
Log Message: ----------- Merge pull request #3275 from techee/local_python
Enable local variable and parameter tag reporting for various languages
Modified Paths: -------------- ctags/parsers/python.c src/tagmanager/tm_parser.c tests/ctags/cython_sample.pyx.tags tests/ctags/gdscript-inner-class.gd.tags tests/ctags/gdscript-modifiers.gd.tags tests/ctags/gdscript-no-implicit-class.gd.tags tests/ctags/simple.py.tags
Modified: ctags/parsers/python.c 258 lines changed, 206 insertions(+), 52 deletions(-) =================================================================== @@ -23,6 +23,7 @@ #include "debug.h" #include "xtag.h" #include "objpool.h" +#include "ptrarray.h"
#define isIdentifierChar(c) \ (isalnum (c) || (c) == '_' || (c) >= 0x80) @@ -935,15 +936,204 @@ static vString *parseReturnTypeAnnotation (tokenInfo *const token) return NULL; }
+struct typedParam { + tokenInfo *token; + vString *type; +}; + +static struct typedParam *makeTypedParam (tokenInfo *token, vString *type) +{ + struct typedParam *p = xMalloc (1, struct typedParam); + p->token = token; + p->type = type; + return p; +} + +static struct typedParam *makeTypedParamWithCopy (const tokenInfo *token, const vString *type) +{ + tokenInfo *token_copied = newToken (); + copyToken (token_copied, token); + + + vString *type_copied = type? vStringNewCopy (type): NULL; + return makeTypedParam (token_copied, type_copied); +} + +static void deleteTypedParam (struct typedParam *p) +{ + deleteToken (p->token); + vStringDelete (p->type); /* NULL is acceptable. */ + eFree (p); +} + +static void parseArglist (tokenInfo *const token, const int kind, + vString *const arglist, ptrArray *const parameters) +{ + int prevTokenType = token->type; + int depth = 1; + + if (kind != K_CLASS) + reprCat (arglist, token); + + do + { + if (token->type != TOKEN_WHITESPACE && + /* for easy `*args` and `**kwargs` support, we also ignore + * `*`, which anyway can't otherwise screw us up */ + token->type != '*') + { + prevTokenType = token->type; + } + + readTokenFull (token, true); + if (kind != K_CLASS || token->type != ')' || depth > 1) + reprCat (arglist, token); + + if (token->type == '(' || + token->type == '[' || + token->type == '{') + depth ++; + else if (token->type == ')' || + token->type == ']' || + token->type == '}') + depth --; + else if (kind != K_CLASS && depth == 1 && + token->type == TOKEN_IDENTIFIER && + (prevTokenType == '(' || prevTokenType == ',') && + PythonKinds[K_PARAMETER].enabled) + { + tokenInfo *parameterName; + vString *parameterType; + struct typedParam *parameter; + + parameterName = newToken (); + copyToken (parameterName, token); + parameterType = parseParamTypeAnnotation (token, arglist); + + parameter = makeTypedParam (parameterName, parameterType); + ptrArrayAdd (parameters, parameter); + } + } + while (token->type != TOKEN_EOF && depth > 0); +} + +static void parseCArglist (tokenInfo *const token, const int kind, + vString *const arglist, ptrArray *const parameters) +{ + int depth = 1; + tokenInfo *pname = newToken (); + vString *ptype = vStringNew (); + vStringCat (arglist, token->string); /* '(' */ + + while (true) + { + readToken (token); + if (token->type == TOKEN_EOF) + { + /* Unexpected input. */ + vStringClear (arglist); + ptrArrayClear (parameters); + break; + } + + if (depth == 1 && (token->type == ',' || token->type == ')')) + { + if (pname->type == TOKEN_IDENTIFIER) + { + struct typedParam *p; + + /* + * Clean up the type string. + * The type string includes the parameter name at the end. + * 1. Trim the parameter name at the end. + * 2. Then, trim the white space at the end of the type string. + * 3. If the type string is not empty, + * 3.a append (the type stirng + ' ' + the parameter name) to arglist. + * 3.b else just append the parameter name to arglist. + * + * FIXME: + * This doesn't work well with an array and a function pointer. + * + * f(..., int seq [dim], ...) + * in this case, dim is extacted as a parameter. + * + * f(..., int (*fn)(int), ...) + * in this case , int is extacted as a parameter. + */ + Assert (vStringLength (ptype) >= vStringLength (pname->string)); + size_t ptype_len = vStringLength (ptype) - vStringLength (pname->string); + vStringTruncate (ptype, ptype_len); + + if (vStringLength (ptype) > 0) + { + vStringStripTrailing (ptype); + if (vStringLength (ptype) > 0) + { + vStringCat (arglist, ptype); + vStringPut (arglist, ' '); + } + } + vStringCat (arglist, pname->string); + + p = makeTypedParamWithCopy (pname, vStringIsEmpty(ptype)? NULL: ptype); + ptrArrayAdd (parameters, p); + } + if (token->type == ')') + { + vStringPut (arglist, ')'); + break; + } + vStringCatS (arglist, ", "); + vStringClear (ptype); + pname->type = TOKEN_UNDEFINED; + continue; + } + + if (token->type == '(' || + token->type == '[' || + token->type == '{') + { + vStringPut (ptype, token->type); + depth ++; + continue; + } + + if (token->type == ')' || + token->type == ']' || + token->type == '}') + { + vStringPut (ptype, token->type); + depth --; + continue; + } + + if (token->type == TOKEN_IDENTIFIER || token->type == TOKEN_KEYWORD) + { + if (vStringLength (ptype) > 0 + && (isalnum ((unsigned char)vStringLast (ptype)) + || vStringLast (ptype) == ',')) + vStringPut (ptype, ' '); + vStringCat (ptype, token->string); + + if (!isdigit ((unsigned char)vStringLast (token->string))) + copyToken (pname, token); + continue; + } + + vStringCat (ptype, token->string); + } + + vStringDelete (ptype); + deleteToken (pname); +} + static bool parseClassOrDef (tokenInfo *const token, const vString *const decorators, pythonKind kind, bool isCDef) { vString *arglist = NULL; tokenInfo *name = NULL; - tokenInfo *parameterTokens[16] = { NULL }; - vString *parameterTypes [ARRAY_SIZE(parameterTokens)] = { NULL }; - unsigned int parameterCount = 0; + ptrArray *parameters = NULL; NestingLevel *lv; int corkIndex;
@@ -966,49 +1156,13 @@ static bool parseClassOrDef (tokenInfo *const token, /* collect parameters or inheritance */ if (token->type == '(') { - int prevTokenType = token->type; - int depth = 1; - arglist = vStringNew (); - if (kind != K_CLASS) - reprCat (arglist, token); - - do - { - if (token->type != TOKEN_WHITESPACE && - /* for easy `*args` and `**kwargs` support, we also ignore - * `*`, which anyway can't otherwise screw us up */ - token->type != '*') - { - prevTokenType = token->type; - } + parameters = ptrArrayNew ((ptrArrayDeleteFunc)deleteTypedParam);
- readTokenFull (token, true); - if (kind != K_CLASS || token->type != ')' || depth > 1) - reprCat (arglist, token); - - if (token->type == '(' || - token->type == '[' || - token->type == '{') - depth ++; - else if (token->type == ')' || - token->type == ']' || - token->type == '}') - depth --; - else if (kind != K_CLASS && depth == 1 && - token->type == TOKEN_IDENTIFIER && - (prevTokenType == '(' || prevTokenType == ',') && - parameterCount < ARRAY_SIZE (parameterTokens) && - PythonKinds[K_PARAMETER].enabled) - { - tokenInfo *parameterName = newToken (); - - copyToken (parameterName, token); - parameterTokens[parameterCount] = parameterName; - parameterTypes [parameterCount++] = parseParamTypeAnnotation (token, arglist); - } - } - while (token->type != TOKEN_EOF && depth > 0); + if (isCDef && kind != K_CLASS) + parseCArglist (token, kind, arglist, parameters); + else + parseArglist (token, kind, arglist, parameters); }
if (kind == K_CLASS) @@ -1022,24 +1176,24 @@ static bool parseClassOrDef (tokenInfo *const token, deleteToken (name); vStringDelete (arglist);
- if (parameterCount > 0) + if (parameters && !ptrArrayIsEmpty (parameters)) { unsigned int i;
- for (i = 0; i < parameterCount; i++) + for (i = 0; i < ptrArrayCount (parameters); i++) { - int paramCorkIndex = makeSimplePythonTag (parameterTokens[i], K_PARAMETER); - deleteToken (parameterTokens[i]); + struct typedParam *parameter = ptrArrayItem (parameters, i); + int paramCorkIndex = makeSimplePythonTag (parameter->token, K_PARAMETER); tagEntryInfo *e = getEntryInCorkQueue (paramCorkIndex); - if (e && parameterTypes[i]) + if (e && parameter->type) { e->extensionFields.typeRef [0] = eStrdup ("typename"); - e->extensionFields.typeRef [1] = vStringDeleteUnwrap (parameterTypes[i]); - parameterTypes[i] = NULL; + e->extensionFields.typeRef [1] = vStringDeleteUnwrap (parameter->type); + parameter->type = NULL; } - vStringDelete (parameterTypes[i]); /* NULL is acceptable. */ } } + ptrArrayDelete (parameters); /* NULL is acceptable. */
tagEntryInfo *e; vString *t;
Modified: src/tagmanager/tm_parser.c 23 lines changed, 11 insertions(+), 12 deletions(-) =================================================================== @@ -166,7 +166,7 @@ static TMParserMapEntry map_PHP[] = { {'d', tm_tag_macro_t}, // define {'f', tm_tag_function_t}, // function {'i', tm_tag_interface_t}, // interface - {'l', tm_tag_undef_t}, // local + {'l', tm_tag_local_var_t}, // local {'n', tm_tag_namespace_t}, // namespace {'t', tm_tag_struct_t}, // trait {'v', tm_tag_variable_t}, // variable @@ -178,7 +178,7 @@ static TMParserMapGroup group_PHP[] = { {_("Classes"), TM_ICON_CLASS, tm_tag_class_t}, {_("Functions"), TM_ICON_METHOD, tm_tag_function_t}, {_("Constants"), TM_ICON_MACRO, tm_tag_macro_t}, - {_("Variables"), TM_ICON_VAR, tm_tag_variable_t}, + {_("Variables"), TM_ICON_VAR, tm_tag_variable_t | tm_tag_local_var_t}, {_("Traits"), TM_ICON_STRUCT, tm_tag_struct_t}, };
@@ -192,14 +192,14 @@ static TMParserMapEntry map_PYTHON[] = { /* defined as externvar to get those excluded as forward type in symbols.c:goto_tag() * so we can jump to the real implementation (if known) instead of to the import statement */ {'x', tm_tag_externvar_t}, // unknown - {'z', tm_tag_undef_t}, // parameter - {'l', tm_tag_undef_t}, // local + {'z', tm_tag_local_var_t}, // parameter + {'l', tm_tag_local_var_t}, // local }; static TMParserMapGroup group_PYTHON[] = { {_("Classes"), TM_ICON_CLASS, tm_tag_class_t}, {_("Methods"), TM_ICON_MACRO, tm_tag_method_t}, {_("Functions"), TM_ICON_METHOD, tm_tag_function_t}, - {_("Variables"), TM_ICON_VAR, tm_tag_variable_t}, + {_("Variables"), TM_ICON_VAR, tm_tag_variable_t | tm_tag_local_var_t}, {_("Imports"), TM_ICON_NAMESPACE, tm_tag_externvar_t}, };
@@ -969,16 +969,15 @@ static TMParserMapEntry map_GDSCRIPT[] = { {'C', tm_tag_variable_t}, // const {'g', tm_tag_enum_t}, // enum {'e', tm_tag_variable_t}, // enumerator - {'z', tm_tag_other_t}, // parameter - {'l', tm_tag_other_t}, // local + {'z', tm_tag_local_var_t}, // parameter + {'l', tm_tag_local_var_t}, // local {'s', tm_tag_variable_t}, // signal }; static TMParserMapGroup group_GDSCRIPT[] = { {_("Classes"), TM_ICON_CLASS, tm_tag_class_t}, {_("Methods"), TM_ICON_MACRO, tm_tag_method_t}, - {_("Variables"), TM_ICON_VAR, tm_tag_variable_t}, + {_("Variables"), TM_ICON_VAR, tm_tag_variable_t | tm_tag_local_var_t}, {_("Enums"), TM_ICON_STRUCT, tm_tag_enum_t}, - {_("Other"), TM_ICON_OTHER, tm_tag_other_t}, };
static TMParserMapEntry map_CLOJURE[] = { @@ -1012,10 +1011,10 @@ static TMParserMapEntry map_TYPESCRIPT[] = { {'e', tm_tag_enumerator_t}, // enumerator {'m', tm_tag_method_t}, // method {'n', tm_tag_namespace_t}, // namespace - {'z', tm_tag_undef_t}, // parameter + {'z', tm_tag_local_var_t}, // parameter {'p', tm_tag_member_t}, // property {'v', tm_tag_variable_t}, // variable - {'l', tm_tag_undef_t}, // local + {'l', tm_tag_local_var_t}, // local {'C', tm_tag_macro_t}, // constant {'G', tm_tag_undef_t}, // generator {'a', tm_tag_undef_t}, // alias @@ -1026,7 +1025,7 @@ static TMParserMapGroup group_TYPESCRIPT[] = { {_("Interfaces"), TM_ICON_STRUCT, tm_tag_interface_t}, {_("Functions"), TM_ICON_METHOD, tm_tag_function_t | tm_tag_method_t}, {_("Enums"), TM_ICON_STRUCT, tm_tag_enum_t}, - {_("Variables"), TM_ICON_VAR, tm_tag_variable_t}, + {_("Variables"), TM_ICON_VAR, tm_tag_variable_t | tm_tag_local_var_t}, {_("Constants"), TM_ICON_MACRO, tm_tag_macro_t}, {_("Other"), TM_ICON_MEMBER, tm_tag_member_t | tm_tag_enumerator_t}, };
Modified: tests/ctags/cython_sample.pyx.tags 4 lines changed, 2 insertions(+), 2 deletions(-) =================================================================== @@ -4,8 +4,8 @@ StdClass class: StdClass __init__�128�(self)�CDefClass�0 method: CDefClass :: __init__(self) -c_method�128�(self,int i)�CDefClass�0 -method: CDefClass :: c_method(self,int i) +c_method�128�(self, int i)�CDefClass�0 +method: CDefClass :: c_method(self, int i) identity�16�(x)�0 function: identity(x) int2string�16�(int i)�0
Modified: tests/ctags/gdscript-inner-class.gd.tags 20 lines changed, 0 insertions(+), 20 deletions(-) =================================================================== @@ -22,14 +22,10 @@ _init method: Peer :: _init(peer_id) center�16384�Circle2D�0 variable: Circle2D :: center -close�524288�Lobby.leave�0 -other: Lobby.leave :: close color�16384�Circle2D�0 variable: Circle2D :: color host�16384�Lobby�0�int variable: int Lobby :: host -host_id�524288�Lobby._init�0�int -other: int Lobby._init :: host_id id�16384�Peer�0 variable: Peer :: id join�128�(peer_id, server)�Lobby�0�bool @@ -40,16 +36,6 @@ lobbies variable: Dictionary lobbies lobby�16384�Peer�0 variable: Peer :: lobby -new_peer�524288�Lobby.join�0�WebSocketPeer -other: WebSocketPeer Lobby.join :: new_peer -peer_id�524288�Lobby.join�0 -other: Lobby.join :: peer_id -peer_id�524288�Lobby.leave�0 -other: Lobby.leave :: peer_id -peer_id�524288�Lobby.seal�0 -other: Lobby.seal :: peer_id -peer_id�524288�Peer._init�0 -other: Peer._init :: peer_id peers�16384�0�Dictionary variable: Dictionary peers peers�16384�Lobby�0�Array @@ -64,12 +50,6 @@ sealed variable: bool Lobby :: sealed server�16384�0�WebSocketServer variable: WebSocketServer server -server�524288�Lobby.join�0 -other: Lobby.join :: server -server�524288�Lobby.leave�0 -other: Lobby.leave :: server -server�524288�Lobby.seal�0 -other: Lobby.seal :: server time�16384�Lobby�0 variable: Lobby :: time time�16384�Peer�0
Modified: tests/ctags/gdscript-modifiers.gd.tags 16 lines changed, 0 insertions(+), 16 deletions(-) =================================================================== @@ -1,26 +1,10 @@ _create_block_collider�128�(block_sub_position)�0 method: _create_block_collider(block_sub_position) -a�524288�id�0 -other: id :: a -b�524288�r�0 -other: r :: b -block_id�524288�calculate_block_uvs�0 -other: calculate_block_uvs :: block_id -block_sub_position�524288�_create_block_collider�0 -other: _create_block_collider :: block_sub_position -c�524288�x�0 -other: x :: c calculate_block_uvs�128�(block_id)�0 method: calculate_block_uvs(block_id) -col�524288�calculate_block_uvs�0 -other: calculate_block_uvs :: col -collider�524288�_create_block_collider�0 -other: _create_block_collider :: collider id�128�(a)�0 method: id(a) r�128�(b)�0 method: r(b) -row�524288�calculate_block_uvs�0 -other: calculate_block_uvs :: row x�128�(c)�0 method: x(c)
Modified: tests/ctags/gdscript-no-implicit-class.gd.tags 14 lines changed, 0 insertions(+), 14 deletions(-) =================================================================== @@ -38,20 +38,6 @@ foooooooo method: String Something :: foooooooo() inferred_type�16384�0 variable: inferred_type -local_var�524288�some_function�0 -other: some_function :: local_var -local_var2�524288�some_function�0 -other: some_function :: local_var2 -lv�524288�_init�0 -other: _init :: lv -p1�524288�something�0 -other: something :: p1 -p2�524288�something�0 -other: something :: p2 -param1�524288�some_function�0�Vector3 -other: Vector3 some_function :: param1 -param2�524288�some_function�0�int -other: int some_function :: param2 s�16384�0 variable: s sig�16384�0
Modified: tests/ctags/simple.py.tags 4 lines changed, 2 insertions(+), 2 deletions(-) =================================================================== @@ -26,8 +26,8 @@ deeply_nested class: _test.ignored_function.more_nesting :: deeply_nested even_more�128�()�_test.ignored_function.more_nesting.deeply_nested�0 method: _test.ignored_function.more_nesting.deeply_nested :: even_more() -foo�16�( x , y, z)�0 -function: foo( x , y, z) +foo�16�( x, y, z)�0 +function: foo( x, y, z) ignored_function�16�()�_test�0 function: _test :: ignored_function() more_nesting�16�()�_test.ignored_function�0
-------------- This E-Mail was brought to you by github_commit_mail.py (Source: https://github.com/geany/infrastructure).