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
define operators whose names include '='. */
while (!notinname (*cp) || *cp == '=')
cp++;
{
cp++;
if (*(cp - 1) == ':') name = cp;
}
/* Remove "self." from the method name. */
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 /^ C(int i) {x = i;}$/
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),/
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)$/
@ -483,6 +484,7 @@ Cstar_suffixes c-src/etags.c 562
Cube.data.getFoo lua-src/test.lua /^function Cube.data.getFoo ()$/
D cp-src/fail.C 41
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 4262
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_help c-src/etags.c 600
Lua_suffixes c-src/etags.c 598
M ruby-src/test1.ru /^module A::M; end$/
MAGENTA cp-src/screen.hpp 17
MAGICBYTE c-src/emacs/src/gmalloc.c 1861
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 ModuleExample.module_class_methodmodule_class_method49,1131
ruby-src/test1.ru,935
ruby-src/test1.ru,998
class A1,0
def a(2,8
def b(5,38
@ -3133,6 +3133,9 @@ module A9,57
:qux1)qux136,563
alias_method ( :foo2,foo237,586
A::Constant Constant42,655
class A::C;C47,700
module A::M;M48,716
class ::D;D49,733
rs-src/test.rs,52
enum IpAddrKind 3,11

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -3085,7 +3085,7 @@ module ModuleExample1,0
def module_instance_method46,1051
def ModuleExample.module_class_methodmodule_class_method49,1131
ruby-src/test1.ru,935
ruby-src/test1.ru,998
class A1,0
def a(2,8
def b(5,38
@ -3115,6 +3115,9 @@ module A9,57
:qux1)qux136,563
alias_method ( :foo2,foo237,586
A::Constant Constant42,655
class A::C;C47,700
module A::M;M48,716
class ::D;D49,733
rs-src/test.rs,52
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
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
(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
@ -48,9 +48,13 @@ corresponding "good" files, one by one. Like this:
$ cp ETAGS ETAGS.good_3
...
$ make check
$ cp ETAGS ETAGS.good_6
$ cp ETAGS ETAGS.good_7
$ make check
$ 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
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
# end
class A::C; end
module A::M; end
class ::D; end