Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

go to definition of function within current class #1960

Open
baiwfg2 opened this issue Dec 19, 2018 · 2 comments
Open

go to definition of function within current class #1960

baiwfg2 opened this issue Dec 19, 2018 · 2 comments
Labels
client tools/libctags/ctags api multipass issues which can be fixed with multi-pass parsing feature

Comments

@baiwfg2
Copy link

baiwfg2 commented Dec 19, 2018

Hi. I have a C++ member function foo in class A, void A::foo();. And I call it in a function bar.

void bar() {
  a.foo();
}

When I put cursor under foo and press g + ], I expect to jump exactly to the foo definition of class A, not the function of same name in other classes. This will greatly reduce the number of entries in the selection list when there're many same function name across the project classes. Would ctags be able to do that ? Or I may need to find other plugin for vim to do that ?

(
Thank you for contacting us.

If you are reporting an issue with the parsing output, please fill
the following template. As your custom CTags configuration can
affect results, please always use --options=NONE as the first
option when running ctags.

Otherwise, delete the template and write your issue from scratch.
Examples may help developers understanding your issue better.

Use GitHub web interface and markdown notation.
Using mail results broken text rendering that makes
the developers go crazy.
)


The name of the parser:

The command line you used to run ctags:

$ ctags --options=NONE ...

The content of input file:

/* THIS IS AN EXAMPLE */
int
main(void)
{
	...

The tags output you are not satisfied with:

!_THIS_IS_AN_EXAMPLE
mainVoid	foo.c	/^main(void)$/;"	kind:function	line:2	language:C	typeref:typename:int	signature:(void)	roles:def
...

The tags output you expect:

!_THIS_IS_AN_EXAMPLE
main	foo.c	/^main(void)$/;"	kind:function	line:2	language:C	typeref:typename:int	signature:(void)	roles:def
...

The version of ctags:

$ ctags --version
Universal Ctags 0.0.0(EXAMPLE), Copyright (C) 2015 Universal Ctags Team
Universal Ctags is derived from Exuberant Ctags.
Exuberant Ctags 5.8, Copyright (C) 1996-2009 Darren Hiebert
  Compiled: May 11 1018, 23:16:36
  URL: https://ctags.io/
  Optional compiled features: +wildcards, +regex, +iconv, +option-directory, +xpath, +json, +interactive, +sandbox, +yaml, +aspell

How do you get ctags binary:

(
Building it locally, via GNU/Linux distribution, as BSD's package,
win32 binary taken from Universal-ctags/ctags-win32 project, macosx
binary taken from Universal-ctags/homebrew-universal-ctags project,
etc.
)

@masatake masatake changed the title go to definition of function within current class C++: go to definition of function within current class Dec 19, 2018
@masatake
Copy link
Member

ctags provides hints to implement such feature in a client tool like vim.

[yamato@slave]~/var/ctags-github% cat -n /tmp/foo.cpp
cat -n /tmp/foo.cpp
     1	class A {
     2	public:
     3	  int foo (void);
     4	};
     5	
     6	int A::foo (void)
     7	{
     8	  return 0;
     9	}
    10	
    11	class B {
    12	public:
    13	  int foo (void);
    14	};
    15	
    16	int B::foo (void)
    17	{
    18	  return 0;
    19	}
    20	
    21	A a;
    22	B b;
    23	
    24	int
    25	main(void)
    26	{
    27	  return a.foo();
    28	}
[yamato@slave]~/var/ctags-github% u-ctags --fields=+enlK -o - /tmp/foo.cpp 
u-ctags --fields=+enlK -o - /tmp/foo.cpp 
A	/tmp/foo.cpp	/^class A {$/;"	class	line:1	language:C++	file:	end:4
B	/tmp/foo.cpp	/^class B {$/;"	class	line:11	language:C++	file:	end:14
a	/tmp/foo.cpp	/^A a;$/;"	variable	line:21	language:C++	typeref:typename:A
b	/tmp/foo.cpp	/^B b;$/;"	variable	line:22	language:C++	typeref:typename:B
foo	/tmp/foo.cpp	/^int A::foo (void)$/;"	function	line:6	language:C++	class:A	typeref:typename:int	end:9
foo	/tmp/foo.cpp	/^int B::foo (void)$/;"	function	line:16	language:C++	class:B	typeref:typename:int	end:19
main	/tmp/foo.cpp	/^main(void)$/;"	function	line:25	language:C++	typeref:typename:int	end:28

Consider you press "JUMP" key at foo of line 27 of foo.cpp.
The client tool scans backwards to find a as a object where the method foo affects.
The client tool memorizes a and foo.
The client tool searches a in tags file. The client tool finds:

a	/tmp/foo.cpp	/^A a;$/;"	variable	line:21	language:C++	typeref:typename:A

From the found line, the client tool knows a is an instance of A.
What is A? The client tool searches A in the tags file.
The client tool finds:

A	/tmp/foo.cpp	/^class A {$/;"	class	line:1	language:C++	file:	end:4

The client tool knows the kind of A is class.

Now the client tool searchs foo. It will finds two lines:

foo	/tmp/foo.cpp	/^int A::foo (void)$/;"	function	line:6	language:C++	class:A	typeref:typename:int	end:9
foo	/tmp/foo.cpp	/^int B::foo (void)$/;"	function	line:16	language:C++	class:B	typeref:typename:int	end:19

From the field class:A, the client tool knows the definition of foo for foo.a is at line 6 of /tmp/foo.cpp.

What you have to do is find a plug-in implementing above algorithm or write your own one.
I don't know well about vim. So I cannot do any more for you.

  • The client tool scans backwards to find a as a object where the method foo affects.

This is the most difficult step in the algorithm. How to do is is not so obvious.
One said it is nice that ctags does this scanning in https://github.com/universal-ctags/ctags/issues/1600.

@masatake masatake changed the title C++: go to definition of function within current class go to definition of function within current class Dec 19, 2018
@pragmaware
Copy link
Contributor

This was exactly my goal when writing the C++ parser: add intelligent symbol lookups and smart completion. With the current state of ctags this can be done in 95% of the cases but it requires a fair amount of additional external code. The process is roughly the following:

  • Run ctags once on the whole source tree and possibly some of the include paths
  • Parse the ctags output (without really generating a tags file) and build auxiliary structures:
    • a symbol tree: functions linked to classes, variables linked to classes or functions they belong to etc..
    • a global symbol list ordered by name
    • a source map with line ranges for each file (by using the start/end line numbers) linked to symbols in the tree

When the user wants to jump to a symbol (say CTRL+Clicks on a text line):

  • Figure out the logical location of the line by performing a reverse lookup in the source map. In most cases the location will be the body of a function.
  • Parse the line the user clicked in to figure out the symbol context. This is hard in the general case because the line can contain arbitrary code. However most cases are "common" and can be worked on.
  • Start from the leftmost symbol in the context and try to resolve it by looking in the right scopes: the function we're in, the class the function belongs to, the containing namespace and so on.
  • Resolve each symbol on the right by looking it up in the scope resolved on the left until the symbol clicked by the user is found.

The details are quite complicated because

  • The symbol tree may be incomplete
  • There are ambiguities in symbol resolution (see overloading)
  • The language is hard: think of templates
  • The preprocessor is in the way
  • And so on....

Additionally one usually wants the symbol maps to be updated on-the-fly as files are being edited. Making this non invasive (non blocking) is an interesting challenge.

I have a (scary) implementation of all this in my editor. So yes, it can be done... but it requires quite some code. Maybe one day I'll find time to publish it.

@masatake masatake added the multipass issues which can be fixed with multi-pass parsing feature label Feb 13, 2021
@masatake masatake changed the title go to definition of function within current class main: go to definition of function within current class Feb 13, 2021
@masatake masatake changed the title main: go to definition of function within current class go to definition of function within current class Feb 13, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
client tools/libctags/ctags api multipass issues which can be fixed with multi-pass parsing feature
Projects
None yet
Development

No branches or pull requests

3 participants