universal-ctags / ctags

A maintained ctags implementation
https://ctags.io
GNU General Public License v2.0
6.48k stars 620 forks source link

Objective-C/C++ parser not generating "signature:" field for C functions #907

Open siegel opened 8 years ago

siegel commented 8 years ago

See the attached "foo.mm", which contains a static C function as well as an interface and implementation section for an Objective-C class. foo.mm.zip

cd to where the file is, and then run this command:

ctags --excmd=number --tag-relative=no --fields=+a+m+n+S foo.mm

Then examine the resulting tags file. (Attached here: tags.zip.)

The entry for foo has the following form:

foo foo.mm 2;" f line:2 interface:

Note that the signature field is missing for foo().

Now, rename foo.mm to foo.cp and run the above command again:

ctags --excmd=number --tag-relative=no --fields=+a+m+n+S foo.cp

Examine the generated tags again, and you'll see the expected entry for foo():

foo foo.cp 2;" f line:2 typeref:typename:void file: signature:(int a, int b, int c)

I have a hack on the old Exuberant Ctags source, which "supports" Objective-C/C++ by routing through the C parser, and then following up with some lightweight parsing to find Objective-C structures. It's different enough from the current code that it's probably impractical to integrate, but the overall strategy (layering Objective-C/C++ support on top of the C/C++ parser) might be feasible anyway.

siegel commented 8 years ago

Here's the original "objc.c" from our hack on the old exuberant ctags source, in case that helps. objc.c.zip

masatake commented 8 years ago

(About foo.mm.zip and tags.zip we want you to put them inline. I don't want to open zip.)

C++/C parsers completely rewritten by @pragmaware. As far as I can remember he started this work to sp;lit them from Java/C#/D/Vala parsers. All of them are implemented in a source file and it was too complicated for maintaining.

Implementing ObjC parser based on the current C++/C parser looks natural for me because they really share their syntax. However, I'm not sure how @pragmaware will say about this.

If I am @pragmaware, I will say that I will accept reimplementing ObjC parser based on C++/C with following conditions: (0) the copyright of code is clarified, (1) you will maintaine the code, (2) compatiblity with old ObjC parser is considered well (breaking the compatibility is acceptable if there are enough reason, (3) you will provide enough test cases.

siegel commented 8 years ago

Here are the referenced files inline:

foo.mm/foo.cp:

static
void    foo(int a, int b, int c)
{

}

@interface XYZ : NSObject

-(instancetype)initWithMumble: (NSObject*)mumble;

@end

@implementation XYZ

-(instancetype)initWithMumble: (NSObject*)mumble;

@end

Tags output for foo.mm:

!_TAG_FILE_FORMAT       2       /extended format; --format=1 will not append ;" to lines/
!_TAG_FILE_SORTED       1       /0=unsorted, 1=sorted, 2=foldcase/
!_TAG_PROGRAM_AUTHOR    Universal Ctags Team    //
!_TAG_PROGRAM_NAME      Universal Ctags /Derived from Exuberant Ctags/
!_TAG_PROGRAM_URL       https://ctags.io/       /official site/
!_TAG_PROGRAM_VERSION   0.0.0   /9434eb3/
XYZ     foo.mm  13;"    I       line:13 interface:
XYZ     foo.mm  7;"     i       line:7  interface:
foo     foo.mm  2;"     f       line:2  interface:
initWithMumble: foo.mm  16;"    m       line:16 implementation:XYZ
initWithMumble: foo.mm  9;"     m       line:9  interface:XYZ

Tags output for foo.cp:

!_TAG_FILE_FORMAT       2       /extended format; --format=1 will not append ;" to lines/
!_TAG_FILE_SORTED       1       /0=unsorted, 1=sorted, 2=foldcase/
!_TAG_PROGRAM_AUTHOR    Universal Ctags Team    //
!_TAG_PROGRAM_NAME      Universal Ctags /Derived from Exuberant Ctags/
!_TAG_PROGRAM_URL       https://ctags.io/       /official site/
!_TAG_PROGRAM_VERSION   0.0.0   /9434eb3/
foo     foo.cp  2;"     f       line:2  typeref:typename:void   file:   signature:(int a, int b, int c)
masatake commented 8 years ago

BTW, inteface: field of foo, XYZ (implementation)and XYZ(interface) are broken.

static void prepareTag (tagEntryInfo * tag, vString const *name, objcKind kind)
{
    initTagEntry (tag, vStringValue (name), &(ObjcKinds[kind]));

    if (parentName != NULL)
    {

This condition is not enough. vStringLength (parentName) > 0 is needed as additional condition.

pragmaware commented 8 years ago

I've been thinking a bit about this.

It's probably better to hack-in Objective-C support right into the new parser than doing a two pass analysis. Local variables, for instance, may appear both in C and Objective-C scopes. With two passes scoping will be just wrong.

I have done a couple of tests and it's rather feasible. However the C parser needs some refactoring before work on Objective-C can begin. The tag kinds are currently shared between C and C++ and I think they need to be split so, say, C enums are different from C++ enums and later Objective-C enums... (#977)

siegel commented 8 years ago

I think the approach you describe sounds reasonable.

As to enums, I'm not clear on what the issues are there. I know there's an "NS_ENUM" macro and a related "CF_ENUM" macro, which both do the same thing, and which both subtly alter the structure and discovery of enum detection. If that's what you meant by "Objective-C enums", then yeah, I agree there might be some additional work needed there.

It occurred to me that libclang might be useful for writing a tags generator, but there are some real risks there; for one thing, it drags in an awful lot of external code; and for another, in my own experimentation I've seen some very strange (unexpected) results from parsing files with libclang. (Digging into that is on my to-do list, but I'm also trying to find someone who knows how libclang works to find some relevant expertise.)

k-takata commented 7 years ago

From #1486:

This doesn't close #907.

So, reopen.

masatake commented 7 years ago

@k-takata, thank you.