ruby: Fix parsing qualified identifiers

The implementation is a bit hacky, but avoids the need for complex
logic to pop several scopes at once.

Closes universal-ctags/ctags#452.
This commit is contained in:
Colomban Wendling 2015-07-23 22:50:24 +02:00
parent eaf6c82af8
commit 1ed29f1d7b
4 changed files with 49 additions and 4 deletions

View File

@ -43,6 +43,8 @@ static kindOption RubyKinds [] = {
static stringList* nesting = NULL;
#define SCOPE_SEPARATOR '.'
/*
* FUNCTION DEFINITIONS
*/
@ -66,7 +68,8 @@ static vString* stringListToScope (const stringList* list)
vString* chunk = stringListItem (list, i);
if (vStringLength (chunk) > 0)
{
vStringCatS (result, (chunks_output++ > 0) ? "." : "");
if (chunks_output++ > 0)
vStringPut (result, SCOPE_SEPARATOR);
vStringCatS (result, vStringValue (chunk));
}
}
@ -165,6 +168,8 @@ static void emitRubyTag (vString* name, rubyKind kind)
{
tagEntryInfo tag;
vString* scope;
const char *unqualified_name;
const char *qualified_name;
if (!RubyKinds[kind].enabled) {
return;
@ -173,7 +178,23 @@ static void emitRubyTag (vString* name, rubyKind kind)
vStringTerminate (name);
scope = stringListToScope (nesting);
initTagEntry (&tag, vStringValue (name));
qualified_name = vStringValue (name);
unqualified_name = strrchr (qualified_name, SCOPE_SEPARATOR);
if (unqualified_name && unqualified_name[1])
{
if (unqualified_name > qualified_name)
{
if (vStringLength (scope) > 0)
vStringPut (scope, SCOPE_SEPARATOR);
vStringNCatS (scope, qualified_name,
unqualified_name - qualified_name);
}
unqualified_name++;
}
else
unqualified_name = qualified_name;
initTagEntry (&tag, unqualified_name);
if (vStringLength (scope) > 0) {
tag.extensionFields.scope [0] = "class";
tag.extensionFields.scope [1] = vStringValue (scope);
@ -215,6 +236,7 @@ static rubyKind parseIdentifier (
* point or equals sign. These are all part of the name.
* A method name may also contain a period if it's a singleton method.
*/
boolean had_sep = FALSE;
const char* also_ok;
if (kind == K_METHOD)
{
@ -251,11 +273,21 @@ static rubyKind parseIdentifier (
}
/* Copy the identifier into 'name'. */
while (**cp != 0 && (isalnum (**cp) || charIsIn (**cp, also_ok)))
while (**cp != 0 && (**cp == ':' || isalnum (**cp) || charIsIn (**cp, also_ok)))
{
char last_char = **cp;
vStringPut (name, last_char);
if (last_char == ':')
had_sep = TRUE;
else
{
if (had_sep)
{
vStringPut (name, SCOPE_SEPARATOR);
had_sep = FALSE;
}
vStringPut (name, last_char);
}
++*cp;
if (kind == K_METHOD)

View File

@ -257,6 +257,7 @@ test_sources = \
return-types.go \
ruby-block-call.rb \
ruby-doc.rb \
ruby-namespaced-class.rb \
ruby-sf-bug-364.rb \
rules.t2t \
sample.t2t \

View File

@ -0,0 +1,8 @@
module A
module B
end
end
class A::B::C; end
puts A::B::C

View File

@ -0,0 +1,4 @@
# format=tagmanager
AÌ256Ö0
BÌ256ÎAÖ0
CÌ1ÎA.BÖ0