Fix etags for Ruby module definitions with ::

Problem: In Ruby we can define a nested module/class the safe
way (in the sense, if the parent module does not exist, it will
define it:

  module M
    module N
    end
  end

If M already exists, we can also write:

  module M::N; end

With the later notation, the tag generated by etags will be M::N.
When browsing the code, using xref-find-definitions when the point
is on N, will not be able to find the definition of N because the
implicit tag name is M::N.

This is the same problem with nested classes or even some rare
allowed definitions like explicitely defining a module/class from
the global namespace:

  class ::A; end

Solution: We need to give an explicit tag name.  To achieve this,
on module/class definition we truncate the name to the last found
column.
* lib-src/etags.c (Ruby_functions): Support "::" in module
definitions.
* test/manual/etags/README: Update instructions.
* test/manual/etags/ruby-src/test1.ru: Add identifiers with "::".
* test/manual/etags/CTAGS.good:
* test/manual/etags/CTAGS.good_crlf:
* test/manual/etags/CTAGS.good_update:
* test/manual/etags/ETAGS.good_1:
* test/manual/etags/ETAGS.good_2:
* test/manual/etags/ETAGS.good_3:
* test/manual/etags/ETAGS.good_4:
* test/manual/etags/ETAGS.good_5:
* test/manual/etags/ETAGS.good_6:
* test/manual/etags/ETAGS.good_7: Adapt expected results to the
change.  (Bug#77421)

Copyright-paperwork-exempt: yes
This commit is contained in:
Laurent Stacul 2025-03-31 20:30:27 +02:00 committed by Eli Zaretskii
parent 5039ad24a3
commit 8db310ce8b
13 changed files with 5072 additions and 5034 deletions

View file

@ -5069,7 +5069,10 @@ Ruby_functions (FILE *inf)
/* Ruby method names can end in a '='. Also, operator overloading can /* Ruby method names can end in a '='. Also, operator overloading can
define operators whose names include '='. */ define operators whose names include '='. */
while (!notinname (*cp) || *cp == '=') while (!notinname (*cp) || *cp == '=')
cp++; {
cp++;
if (*(cp - 1) == ':') name = cp;
}
/* Remove "self." from the method name. */ /* Remove "self." from the method name. */
if (cp - name > self_size1 if (cp - name > self_size1

View file

@ -327,6 +327,7 @@ ButtonBar pyt-src/server.py /^def ButtonBar(frame, legend, ref, alternatives, co
C cp-src/fail.C 9 C cp-src/fail.C 9
C cp-src/fail.C /^ C(int i) {x = i;}$/ C cp-src/fail.C /^ C(int i) {x = i;}$/
C cp-src/fail.C 25 C cp-src/fail.C 25
C ruby-src/test1.ru /^class A::C; end$/
CALLMANY c-src/emacs/src/lisp.h /^#define CALLMANY(f, array) (f) (ARRAYELTS (array),/ CALLMANY c-src/emacs/src/lisp.h /^#define CALLMANY(f, array) (f) (ARRAYELTS (array),/
CALLN c-src/emacs/src/lisp.h /^#define CALLN(f, ...) CALLMANY (f, ((Lisp_Object [/ CALLN c-src/emacs/src/lisp.h /^#define CALLN(f, ...) CALLMANY (f, ((Lisp_Object [/
CAR c-src/emacs/src/lisp.h /^CAR (Lisp_Object c)$/ CAR c-src/emacs/src/lisp.h /^CAR (Lisp_Object c)$/
@ -483,6 +484,7 @@ Cstar_suffixes c-src/etags.c 562
Cube.data.getFoo lua-src/test.lua /^function Cube.data.getFoo ()$/ Cube.data.getFoo lua-src/test.lua /^function Cube.data.getFoo ()$/
D cp-src/fail.C 41 D cp-src/fail.C 41
D cp-src/fail.C /^ D() : ::A::T2::T(97), x(1066) {}$/ D cp-src/fail.C /^ D() : ::A::T2::T(97), x(1066) {}$/
D ruby-src/test1.ru /^class ::D; end$/
DAEMON_RUNNING c-src/emacs/src/lisp.h 4258 DAEMON_RUNNING c-src/emacs/src/lisp.h 4258
DAEMON_RUNNING c-src/emacs/src/lisp.h 4262 DAEMON_RUNNING c-src/emacs/src/lisp.h 4262
DARKGRAY cp-src/screen.hpp 20 DARKGRAY cp-src/screen.hpp 20
@ -964,6 +966,7 @@ LowerCaseNmStr pas-src/common.pas /^function LowerCaseNmStr; (*($/
Lua_functions c-src/etags.c /^Lua_functions (FILE *inf)$/ Lua_functions c-src/etags.c /^Lua_functions (FILE *inf)$/
Lua_help c-src/etags.c 600 Lua_help c-src/etags.c 600
Lua_suffixes c-src/etags.c 598 Lua_suffixes c-src/etags.c 598
M ruby-src/test1.ru /^module A::M; end$/
MAGENTA cp-src/screen.hpp 17 MAGENTA cp-src/screen.hpp 17
MAGICBYTE c-src/emacs/src/gmalloc.c 1861 MAGICBYTE c-src/emacs/src/gmalloc.c 1861
MAGICFREE c-src/emacs/src/gmalloc.c 1860 MAGICFREE c-src/emacs/src/gmalloc.c 1860

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -3103,7 +3103,7 @@ module ModuleExample1,0
def module_instance_method46,1051 def module_instance_method46,1051
def ModuleExample.module_class_methodmodule_class_method49,1131 def ModuleExample.module_class_methodmodule_class_method49,1131
ruby-src/test1.ru,935 ruby-src/test1.ru,998
class A1,0 class A1,0
def a(2,8 def a(2,8
def b(5,38 def b(5,38
@ -3133,6 +3133,9 @@ module A9,57
:qux1)qux136,563 :qux1)qux136,563
alias_method ( :foo2,foo237,586 alias_method ( :foo2,foo237,586
A::Constant Constant42,655 A::Constant Constant42,655
class A::C;C47,700
module A::M;M48,716
class ::D;D49,733
rs-src/test.rs,52 rs-src/test.rs,52
enum IpAddrKind 3,11 enum IpAddrKind 3,11

View file

@ -3676,7 +3676,7 @@ module ModuleExample1,0
def module_instance_method46,1051 def module_instance_method46,1051
def ModuleExample.module_class_methodmodule_class_method49,1131 def ModuleExample.module_class_methodmodule_class_method49,1131
ruby-src/test1.ru,935 ruby-src/test1.ru,998
class A1,0 class A1,0
def a(2,8 def a(2,8
def b(5,38 def b(5,38
@ -3706,6 +3706,9 @@ module A9,57
:qux1)qux136,563 :qux1)qux136,563
alias_method ( :foo2,foo237,586 alias_method ( :foo2,foo237,586
A::Constant Constant42,655 A::Constant Constant42,655
class A::C;C47,700
module A::M;M48,716
class ::D;D49,733
rs-src/test.rs,52 rs-src/test.rs,52
enum IpAddrKind 3,11 enum IpAddrKind 3,11

View file

@ -3510,7 +3510,7 @@ module ModuleExample1,0
def module_instance_method46,1051 def module_instance_method46,1051
def ModuleExample.module_class_methodmodule_class_method49,1131 def ModuleExample.module_class_methodmodule_class_method49,1131
ruby-src/test1.ru,935 ruby-src/test1.ru,998
class A1,0 class A1,0
def a(2,8 def a(2,8
def b(5,38 def b(5,38
@ -3540,6 +3540,9 @@ module A9,57
:qux1)qux136,563 :qux1)qux136,563
alias_method ( :foo2,foo237,586 alias_method ( :foo2,foo237,586
A::Constant Constant42,655 A::Constant Constant42,655
class A::C;C47,700
module A::M;M48,716
class ::D;D49,733
rs-src/test.rs,52 rs-src/test.rs,52
enum IpAddrKind 3,11 enum IpAddrKind 3,11

View file

@ -3265,7 +3265,7 @@ module ModuleExample1,0
def module_instance_method46,1051 def module_instance_method46,1051
def ModuleExample.module_class_methodmodule_class_method49,1131 def ModuleExample.module_class_methodmodule_class_method49,1131
ruby-src/test1.ru,935 ruby-src/test1.ru,998
class A1,0 class A1,0
def a(2,8 def a(2,8
def b(5,38 def b(5,38
@ -3295,6 +3295,9 @@ module A9,57
:qux1)qux136,563 :qux1)qux136,563
alias_method ( :foo2,foo237,586 alias_method ( :foo2,foo237,586
A::Constant Constant42,655 A::Constant Constant42,655
class A::C;C47,700
module A::M;M48,716
class ::D;D49,733
rs-src/test.rs,52 rs-src/test.rs,52
enum IpAddrKind 3,11 enum IpAddrKind 3,11

View file

@ -4245,7 +4245,7 @@ module ModuleExample1,0
def module_instance_method46,1051 def module_instance_method46,1051
def ModuleExample.module_class_methodmodule_class_method49,1131 def ModuleExample.module_class_methodmodule_class_method49,1131
ruby-src/test1.ru,935 ruby-src/test1.ru,998
class A1,0 class A1,0
def a(2,8 def a(2,8
def b(5,38 def b(5,38
@ -4275,6 +4275,9 @@ module A9,57
:qux1)qux136,563 :qux1)qux136,563
alias_method ( :foo2,foo237,586 alias_method ( :foo2,foo237,586
A::Constant Constant42,655 A::Constant Constant42,655
class A::C;C47,700
module A::M;M48,716
class ::D;D49,733
rs-src/test.rs,52 rs-src/test.rs,52
enum IpAddrKind 3,11 enum IpAddrKind 3,11

View file

@ -4245,7 +4245,7 @@ module ModuleExample1,0
def module_instance_method46,1051 def module_instance_method46,1051
def ModuleExample.module_class_methodmodule_class_method49,1131 def ModuleExample.module_class_methodmodule_class_method49,1131
ruby-src/test1.ru,935 ruby-src/test1.ru,998
class A1,0 class A1,0
def a(2,8 def a(2,8
def b(5,38 def b(5,38
@ -4275,6 +4275,9 @@ module A9,57
:qux1)qux136,563 :qux1)qux136,563
alias_method ( :foo2,foo237,586 alias_method ( :foo2,foo237,586
A::Constant Constant42,655 A::Constant Constant42,655
class A::C;C47,700
module A::M;M48,716
class ::D;D49,733
rs-src/test.rs,52 rs-src/test.rs,52
enum IpAddrKind 3,11 enum IpAddrKind 3,11

View file

@ -3085,7 +3085,7 @@ module ModuleExample1,0
def module_instance_method46,1051 def module_instance_method46,1051
def ModuleExample.module_class_methodmodule_class_method49,1131 def ModuleExample.module_class_methodmodule_class_method49,1131
ruby-src/test1.ru,935 ruby-src/test1.ru,998
class A1,0 class A1,0
def a(2,8 def a(2,8
def b(5,38 def b(5,38
@ -3115,6 +3115,9 @@ module A9,57
:qux1)qux136,563 :qux1)qux136,563
alias_method ( :foo2,foo237,586 alias_method ( :foo2,foo237,586
A::Constant Constant42,655 A::Constant Constant42,655
class A::C;C47,700
module A::M;M48,716
class ::D;D49,733
rs-src/test.rs,52 rs-src/test.rs,52
enum IpAddrKind 3,11 enum IpAddrKind 3,11

View file

@ -5,9 +5,9 @@ The input files, which include source files in various languages
supported by the programs, are in the *-src/ directories (e.g., c-src supported by the programs, are in the *-src/ directories (e.g., c-src
for C sources, ada-src for Ada, tex-src for TeX, etc.). for C sources, ada-src for Ada, tex-src for TeX, etc.).
The expected results are slightly different for each of the 7 commands The expected results are slightly different for each of the 8 commands
(see below) run by the test suite, and are on files ETAGS.good_N (see below) run by the test suite, and are on files ETAGS.good_N
(where N is between 1 and 6) and CTAGS.good. (where N is between 1 and 7) and CTAGS.good.
To run the tests, say To run the tests, say
@ -48,9 +48,13 @@ corresponding "good" files, one by one. Like this:
$ cp ETAGS ETAGS.good_3 $ cp ETAGS ETAGS.good_3
... ...
$ make check $ make check
$ cp ETAGS ETAGS.good_6 $ cp ETAGS ETAGS.good_7
$ make check $ make check
$ cp CTAGS CTAGS.good $ cp CTAGS CTAGS.good
$ make check
$ cp CTAGS CTAGS.good_update
$ make check
$ cp CTAGS CTAGS.good_crlf
This uses the fact that "make check" will stop after the first This uses the fact that "make check" will stop after the first
failure, i.e. after the first time 'diff' reports any diffs, and then failure, i.e. after the first time 'diff' reports any diffs, and then

View file

@ -43,3 +43,7 @@ A::Constant = 5
# def foo_in_comment # def foo_in_comment
# end # end
class A::C; end
module A::M; end
class ::D; end