diff options
| author | Eli Zaretskii | 2015-05-25 18:02:21 +0300 |
|---|---|---|
| committer | Eli Zaretskii | 2015-05-25 18:02:21 +0300 |
| commit | 9c66c5a0cabc748ce50d844a0f1af8d1fc121436 (patch) | |
| tree | ee646dc097c061206e8da00fd976485e25bc7038 /lib-src | |
| parent | 9b995d55c566737ef7aa3432826e1b7b656ff1c7 (diff) | |
| download | emacs-9c66c5a0cabc748ce50d844a0f1af8d1fc121436.tar.gz emacs-9c66c5a0cabc748ce50d844a0f1af8d1fc121436.zip | |
Fix tagging of class members in C-like OO languages
* lib-src/etags.c (longopts): Add new option --class-qualify and
its shorthand -Q.
(print_help): Add help text for --class-qualify.
(main): Add handling of -Q.
(consider_token, C_entries) <omethodparm>: Append argument types
to Objective C methods only if --class-qualify was specified.
Qualify C++, Objective C, and Java class members with their class
names only if --class-qualify was specified.
(C_entries): If --class-qualify was not specified, remove the
namespace and class qualifiers from tag names of C++ methods.
This allows to use etags.el as xref back-end without the
tag-symbol-match-p method, which greatly increases the number of
potentially false positives. (Bug#20629)
* doc/man/etags.1: Update to document the new --class-qualify
option.
* test/etags/ETAGS.good_1:
* test/etags/ETAGS.good_2:
* test/etags/ETAGS.good_3:
* test/etags/ETAGS.good_4:
* test/etags/ETAGS.good_5:
* test/etags/CTAGS.good: Update due to changes in etags.c.
Diffstat (limited to 'lib-src')
| -rw-r--r-- | lib-src/etags.c | 98 |
1 files changed, 79 insertions, 19 deletions
diff --git a/lib-src/etags.c b/lib-src/etags.c index 4b99e392728..73dd5a8a405 100644 --- a/lib-src/etags.c +++ b/lib-src/etags.c | |||
| @@ -441,6 +441,7 @@ static bool cxref_style; /* -x: create cxref style output */ | |||
| 441 | static bool cplusplus; /* .[hc] means C++, not C (undocumented) */ | 441 | static bool cplusplus; /* .[hc] means C++, not C (undocumented) */ |
| 442 | static bool ignoreindent; /* -I: ignore indentation in C */ | 442 | static bool ignoreindent; /* -I: ignore indentation in C */ |
| 443 | static int packages_only; /* --packages-only: in Ada, only tag packages*/ | 443 | static int packages_only; /* --packages-only: in Ada, only tag packages*/ |
| 444 | static int class_qualify; /* -Q: produce class-qualified tags in C++/Java */ | ||
| 444 | 445 | ||
| 445 | /* STDIN is defined in LynxOS system headers */ | 446 | /* STDIN is defined in LynxOS system headers */ |
| 446 | #ifdef STDIN | 447 | #ifdef STDIN |
| @@ -468,6 +469,7 @@ static struct option longopts[] = | |||
| 468 | { "members", no_argument, &members, 1 }, | 469 | { "members", no_argument, &members, 1 }, |
| 469 | { "no-members", no_argument, &members, 0 }, | 470 | { "no-members", no_argument, &members, 0 }, |
| 470 | { "output", required_argument, NULL, 'o' }, | 471 | { "output", required_argument, NULL, 'o' }, |
| 472 | { "class-qualify", no_argument, &class_qualify, 'Q' }, | ||
| 471 | { "regex", required_argument, NULL, 'r' }, | 473 | { "regex", required_argument, NULL, 'r' }, |
| 472 | { "no-regex", no_argument, NULL, 'R' }, | 474 | { "no-regex", no_argument, NULL, 'R' }, |
| 473 | { "ignore-case-regex", required_argument, NULL, 'c' }, | 475 | { "ignore-case-regex", required_argument, NULL, 'c' }, |
| @@ -933,6 +935,12 @@ Relative ones are stored relative to the output file's directory.\n"); | |||
| 933 | Do not create tag entries for members of structures\n\ | 935 | Do not create tag entries for members of structures\n\ |
| 934 | in some languages."); | 936 | in some languages."); |
| 935 | 937 | ||
| 938 | puts ("-Q, --class-qualify\n\ | ||
| 939 | Qualify tag names with their class name in C++, ObjC, and Java.\n\ | ||
| 940 | This produces tag names of the form \"class::member\" for C++,\n\ | ||
| 941 | \"class(category)\" for Objective C, and \"class.member\" for Java.\n\ | ||
| 942 | For Objective C, this also produces class methods qualified with\n\ | ||
| 943 | their arguments, as in \"foo:bar:baz:more\"."); | ||
| 936 | puts ("-r REGEXP, --regex=REGEXP or --regex=@regexfile\n\ | 944 | puts ("-r REGEXP, --regex=REGEXP or --regex=@regexfile\n\ |
| 937 | Make a tag for each line matching a regular expression pattern\n\ | 945 | Make a tag for each line matching a regular expression pattern\n\ |
| 938 | in the following files. {LANGUAGE}REGEXP uses REGEXP for LANGUAGE\n\ | 946 | in the following files. {LANGUAGE}REGEXP uses REGEXP for LANGUAGE\n\ |
| @@ -1050,7 +1058,7 @@ main (int argc, char **argv) | |||
| 1050 | 1058 | ||
| 1051 | /* When the optstring begins with a '-' getopt_long does not rearrange the | 1059 | /* When the optstring begins with a '-' getopt_long does not rearrange the |
| 1052 | non-options arguments to be at the end, but leaves them alone. */ | 1060 | non-options arguments to be at the end, but leaves them alone. */ |
| 1053 | optstring = concat ("-ac:Cf:Il:o:r:RSVhH", | 1061 | optstring = concat ("-ac:Cf:Il:o:Qr:RSVhH", |
| 1054 | (CTAGS) ? "BxdtTuvw" : "Di:", | 1062 | (CTAGS) ? "BxdtTuvw" : "Di:", |
| 1055 | ""); | 1063 | ""); |
| 1056 | 1064 | ||
| @@ -1139,6 +1147,9 @@ main (int argc, char **argv) | |||
| 1139 | case 'H': | 1147 | case 'H': |
| 1140 | help_asked = true; | 1148 | help_asked = true; |
| 1141 | break; | 1149 | break; |
| 1150 | case 'Q': | ||
| 1151 | class_qualify = 1; | ||
| 1152 | break; | ||
| 1142 | 1153 | ||
| 1143 | /* Etags options */ | 1154 | /* Etags options */ |
| 1144 | case 'D': constantypedefs = false; break; | 1155 | case 'D': constantypedefs = false; break; |
| @@ -2852,12 +2863,15 @@ consider_token (char *str, int len, int c, int *c_extp, | |||
| 2852 | case omethodparm: | 2863 | case omethodparm: |
| 2853 | if (parlev == 0) | 2864 | if (parlev == 0) |
| 2854 | { | 2865 | { |
| 2855 | int oldlen = token_name.len; | ||
| 2856 | fvdef = fvnone; | ||
| 2857 | objdef = omethodtag; | 2866 | objdef = omethodtag; |
| 2858 | linebuffer_setlen (&token_name, oldlen + len); | 2867 | if (class_qualify) |
| 2859 | memcpy (token_name.buffer + oldlen, str, len); | 2868 | { |
| 2860 | token_name.buffer[oldlen + len] = '\0'; | 2869 | int oldlen = token_name.len; |
| 2870 | fvdef = fvnone; | ||
| 2871 | linebuffer_setlen (&token_name, oldlen + len); | ||
| 2872 | memcpy (token_name.buffer + oldlen, str, len); | ||
| 2873 | token_name.buffer[oldlen + len] = '\0'; | ||
| 2874 | } | ||
| 2861 | return true; | 2875 | return true; |
| 2862 | } | 2876 | } |
| 2863 | return false; | 2877 | return false; |
| @@ -3307,21 +3321,42 @@ C_entries (int c_ext, FILE *inf) | |||
| 3307 | && nestlev > 0 && definedef == dnone) | 3321 | && nestlev > 0 && definedef == dnone) |
| 3308 | /* in struct body */ | 3322 | /* in struct body */ |
| 3309 | { | 3323 | { |
| 3310 | int len; | 3324 | if (class_qualify) |
| 3311 | write_classname (&token_name, qualifier); | 3325 | { |
| 3312 | len = token_name.len; | 3326 | int len; |
| 3313 | linebuffer_setlen (&token_name, len+qlen+toklen); | 3327 | write_classname (&token_name, qualifier); |
| 3314 | sprintf (token_name.buffer + len, "%s%.*s", | 3328 | len = token_name.len; |
| 3315 | qualifier, toklen, newlb.buffer + tokoff); | 3329 | linebuffer_setlen (&token_name, |
| 3330 | len + qlen + toklen); | ||
| 3331 | sprintf (token_name.buffer + len, "%s%.*s", | ||
| 3332 | qualifier, toklen, | ||
| 3333 | newlb.buffer + tokoff); | ||
| 3334 | } | ||
| 3335 | else | ||
| 3336 | { | ||
| 3337 | linebuffer_setlen (&token_name, toklen); | ||
| 3338 | sprintf (token_name.buffer, "%.*s", | ||
| 3339 | toklen, newlb.buffer + tokoff); | ||
| 3340 | } | ||
| 3316 | token.named = true; | 3341 | token.named = true; |
| 3317 | } | 3342 | } |
| 3318 | else if (objdef == ocatseen) | 3343 | else if (objdef == ocatseen) |
| 3319 | /* Objective C category */ | 3344 | /* Objective C category */ |
| 3320 | { | 3345 | { |
| 3321 | int len = strlen (objtag) + 2 + toklen; | 3346 | if (class_qualify) |
| 3322 | linebuffer_setlen (&token_name, len); | 3347 | { |
| 3323 | sprintf (token_name.buffer, "%s(%.*s)", | 3348 | int len = strlen (objtag) + 2 + toklen; |
| 3324 | objtag, toklen, newlb.buffer + tokoff); | 3349 | linebuffer_setlen (&token_name, len); |
| 3350 | sprintf (token_name.buffer, "%s(%.*s)", | ||
| 3351 | objtag, toklen, | ||
| 3352 | newlb.buffer + tokoff); | ||
| 3353 | } | ||
| 3354 | else | ||
| 3355 | { | ||
| 3356 | linebuffer_setlen (&token_name, toklen); | ||
| 3357 | sprintf (token_name.buffer, "%.*s", | ||
| 3358 | newlb.buffer + tokoff); | ||
| 3359 | } | ||
| 3325 | token.named = true; | 3360 | token.named = true; |
| 3326 | } | 3361 | } |
| 3327 | else if (objdef == omethodtag | 3362 | else if (objdef == omethodtag |
| @@ -3479,9 +3514,12 @@ C_entries (int c_ext, FILE *inf) | |||
| 3479 | case omethodtag: | 3514 | case omethodtag: |
| 3480 | case omethodparm: | 3515 | case omethodparm: |
| 3481 | objdef = omethodcolon; | 3516 | objdef = omethodcolon; |
| 3482 | int toklen = token_name.len; | 3517 | if (class_qualify) |
| 3483 | linebuffer_setlen (&token_name, toklen + 1); | 3518 | { |
| 3484 | strcpy (token_name.buffer + toklen, ":"); | 3519 | int toklen = token_name.len; |
| 3520 | linebuffer_setlen (&token_name, toklen + 1); | ||
| 3521 | strcpy (token_name.buffer + toklen, ":"); | ||
| 3522 | } | ||
| 3485 | break; | 3523 | break; |
| 3486 | } | 3524 | } |
| 3487 | if (structdef == stagseen) | 3525 | if (structdef == stagseen) |
| @@ -3716,6 +3754,28 @@ C_entries (int c_ext, FILE *inf) | |||
| 3716 | switch (fvdef) | 3754 | switch (fvdef) |
| 3717 | { | 3755 | { |
| 3718 | case flistseen: | 3756 | case flistseen: |
| 3757 | if (cplpl && !class_qualify) | ||
| 3758 | { | ||
| 3759 | /* Remove class and namespace qualifiers from the token, | ||
| 3760 | leaving only the method/member name. */ | ||
| 3761 | char *cc, *uqname = token_name.buffer; | ||
| 3762 | char *tok_end = token_name.buffer + token_name.len; | ||
| 3763 | |||
| 3764 | for (cc = token_name.buffer; cc < tok_end; cc++) | ||
| 3765 | { | ||
| 3766 | if (*cc == ':' && cc[1] == ':') | ||
| 3767 | { | ||
| 3768 | uqname = cc + 2; | ||
| 3769 | cc++; | ||
| 3770 | } | ||
| 3771 | } | ||
| 3772 | if (uqname > token_name.buffer) | ||
| 3773 | { | ||
| 3774 | int uqlen = strlen (uqname); | ||
| 3775 | linebuffer_setlen (&token_name, uqlen); | ||
| 3776 | memmove (token_name.buffer, uqname, uqlen + 1); | ||
| 3777 | } | ||
| 3778 | } | ||
| 3719 | make_C_tag (true); /* a function */ | 3779 | make_C_tag (true); /* a function */ |
| 3720 | /* FALLTHRU */ | 3780 | /* FALLTHRU */ |
| 3721 | case fignore: | 3781 | case fignore: |