leoliu / ggtags

Emacs frontend to GNU Global source code tagging system.

Home Page:http://elpa.gnu.org

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

'xref-find-definitions' problem in symbolic link directory

tttuuu888 opened this issue · comments

Hello.

First of all, thanks a lot for this great package.

This issue is very similar to #9 except this has to do only with xref-find-definitions.
xref-find-definitions with ggtags backend works fine in most case. It correctly find definition even if the definition exists in symlink directory. However, if I execute xref-find-definitions in a symbolic link directory, it fails.

For example, when I have a project folder as below:

.
├── a
│   ├── GPATH
│   ├── GRTAGS
│   ├── GTAGS
│   ├── b -> ../b
│   └── main.c
└── b
    ├── test1.h
    └── test2.h

If I execute xref-find-definitions in main.c to find a definition which exists in b/test1.h, it works.
However, If I execute xref-find-definitions in test1.h to find a definition which exists in b/test2.h, it fails.

Below is the result of (ggtags--xref-find-tags "DEF_TEST2" 'definition) in test1.h:

(#s(xref-item #("#define DEF_TEST2 2" 8 17 (font-lock-face ...)) #s(ggtags-xref-location "/tmp/test/a/a/b/test2.h" 1 16 "/tmp/test/a/")))

ggtags-find-definition works fine for this case.

Thank you.

Hi @leoliu .
I'm sorry for lack of enough test before the commit but I found recent commit cause another problem.

Now xref-find-definitions doesn't find definition correctly if project root, which has GTAGS file is upper directory.

Simply, if the project structure is as follows, the definition of the function in test1.c cannot be found correctly within test2.c.

.
├── GPATH
├── GRTAGS
├── GTAGS
└── a
    ├── test1.c
    └── test2.c
// test1.c
int test1(void) {
    return 1;
}

// test2.c
extern int test1(void);

int test2(void) {
    return test1();    // Can't find test1 correctly.
}

I tested file-truename fix and it worked fine for this case.

Thanks.

@tttuuu888,

I was the one who suggested it :( Will take a thorough look later today. BTW, file-truename may move outside the project so it has some downside.

Leo

@tttuuu888,

Sorry for the delay.

The issue is ggtags-make-xref-location tries to construct location using project root plus relative filename. So it is critical to make default-directory agree with the project root. Could you test this patch? Thanks.

diff --git a/ggtags.el b/ggtags.el
index caba1a3c..ba14d883 100644
--- a/ggtags.el
+++ b/ggtags.el
@@ -2417,7 +2417,7 @@ (defun ggtags--xref-collect-tags (tag root colored)
    with re = (cadr (assq 'grep ggtags-global-error-regexp-alist-alist))
    while (re-search-forward re nil t)
    for summary = (buffer-substring (1+ (match-end 2)) (line-end-position))
-   for file = (expand-file-name (match-string 1) root)
+   for file = (expand-file-name (match-string 1))
    for line = (string-to-number (match-string 2))
    for column = (string-match-p tag summary)
    if colored do (setq summary (ansi-color-apply summary)) end
@@ -2450,12 +2450,13 @@ (defun ggtags--xref-find-tags (tag cmd)
                               (ggtags-project-has-color project))))
             (kill-buffer (current-buffer)))))
     (ggtags-with-current-project
-      (ggtags-global-output
-       (get-buffer-create " *ggtags-xref*")
-       (append
-        (split-string (ggtags-global-build-command cmd))
-        (list "--" (shell-quote-argument tag)))
-       collect ggtags--xref-limit 'sync)
+      (let ((default-directory (ggtags-current-project-root)))
+        (ggtags-global-output
+         (get-buffer-create " *ggtags-xref*")
+         (append
+          (split-string (ggtags-global-build-command cmd))
+          (list "--" (shell-quote-argument tag)))
+         collect ggtags--xref-limit 'sync))
       xrefs)))
 
 (cl-defmethod xref-backend-definitions ((_backend (eql ggtags)) tag)

@leoliu Thank you a lot for your patch. I tested in various way and the patch worked as good as file-truename fix. However I found another problem from both 'file-truename' fix and your patch.

From the main.c of the first example project structure (#218 (comment)), if I find DEF_TEST2 which is defined in test1.h, ggtags-find-definition jump to a/b/test1.h, but both file-truename fix and your patch makes jump to b/test1.h. And it makes further searching unavailable(ex. finding DEF_TEST3 in test2.h)
So I think it would be much better if the fix would work as ggtags-find-definition.
Thanks.

@leoliu I think I confused test result of your patch and the result of file-truename fix. Now I tested again and found your patch works as same as ggtags-find-definition. I think it works good for all cases I mentioned above. Thank you so much!

@tttuuu888, pushed. Thanks a lot for the thorough tests.