Bug 244434 - Symlinks cause "Open Declaration" to open 2nd editor window for same source file
Summary: Symlinks cause "Open Declaration" to open 2nd editor window for same source file
Status: RESOLVED FIXED
Alias: None
Product: CDT
Classification: Tools
Component: cdt-core (show other bugs)
Version: 5.0   Edit
Hardware: PC Linux
: P3 normal with 1 vote (vote)
Target Milestone: 9.0.0   Edit
Assignee: Project Inbox CLA
QA Contact:
URL:
Whiteboard:
Keywords:
: 471990 (view as bug list)
Depends on: 233939
Blocks:
  Show dependency tree
 
Reported: 2008-08-18 11:14 EDT by Steve Kennedy CLA
Modified: 2016-01-07 13:46 EST (History)
5 users (show)

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Steve Kennedy CLA 2008-08-18 11:14:41 EDT
I precreate a directory under my eclipse workspace:

  /Workspace/
    Project/
      src@ -> /SomewhereElse/Files

where /SomewhereElse/Files contains a simple C/C++ source file:

  /SomewhereElse/Files/
    main.C

main.C:
  int x;
  int main() {
    x = 1;
  }

I create a C++ project "Project" with Project type "Executable".  This works as expected: I get a Project with a folder "src" containing "main.C".  However, if I open "main.C", highlight "x" on line 3 above, and hit F3 (Open Declaration), a 2nd "main.C" editor window is opened.  The tooltip for the 1st editor window shows "Project/src/main.C" and the tooltip for the 2nd window shows "/Workspace/Project/src/main.C".
Comment 1 Steve Kennedy CLA 2008-08-18 13:52:25 EDT
Of course this problem doesn't occur when src is a real directory and not a symlink.  I had done some digging into the source and I think located the piece of code where a difference in behavior occurs:

(cdt.core:cdt.internal.core.pdom.indexer)
ProjectIndexerInputAdapter.resolveASTPath
ProjectIndexerInputAdapter.doResolveASTPath
(cdt.core.index)
IndexLocationFactory.getIFLExpensive
first line calls ResourcesPlugin.getWorkspace().getRoot().findFilesForLocation(new Path(absolutePath));

findFilesForLocation for absolutePath="/Workspace/Project/src/main.C" returns a 0 length array if src is a symlink and a 1 element array if src is a directory.
Comment 2 Gregory Kramida CLA 2016-01-05 08:15:09 EST
*** Bug 471990 has been marked as a duplicate of this bug. ***
Comment 3 Nathan Ridge CLA 2016-01-06 23:31:55 EST
I'm not able to reproduce the problem described in comment 0 with current CDT.

I can, however, reproduce the issue described in bug 471990; I'll pursue a fix for that here.
Comment 4 Nathan Ridge CLA 2016-01-06 23:44:41 EST
I investigated the issue described in bug 471990, and found the following.

First, some notes about how the project structure described in that bug is represented in Eclipse/CDT.

  - Entries in the Project Explorer are modeled as "resources",
    using the interface IResource (specifically IFile for files).

  - In a situation where a single file is reachable through
    multiple entries in Project Explorer, each entry has its own
    IFile.

  - IFiles have a notion of a "path in the workspace", accessed
    via IFile.getFullPath(), and a "location in the filesystem",
    accessed via IResource.getLocation(). If multiple resources
    represent the same file, they will have different paths in
    the workspace (e.g. /Project/folder/file vs. 
    /Project/[Subprojects]/folder/file), but they have the same
    location in the filesystem.

  - CDT models the contents of a project as translation units,
    using the interface ITranslationUnit. An ITranslationUnit
    is tied to a particular IFile, so in the above case there
    can be multiple ITranslationUnits corresponding to the same
    file.

  - However, even if multiple ITranslationUnits correspond to 
    the same file, it appears that only one of them is indexed.
    (This is a good thing. If multiple copies of the translation
    unit were indexed, we'd have problems caused by multiple
    definitions of the same entity and similar problems.)
Comment 5 Nathan Ridge CLA 2016-01-07 00:02:44 EST
Now, when doing "Open Declaration" on a project structure like this, one of two things can happen:

  1) The target of the action is in the same file that the action
     was invoked in.

     In this case, the target of the action is represented as an
     IASTName found in the AST of the ITranslationUnit that the
     action was invoked in.

     To navigate to the target, "Open Declaration" needs an
     ITranslationUnit to open. It was getting this in a roundabout
     way that involved getting the path on the filesystem,
     searching for resources that resolve to that path, and then
     using some heuristics to choose a single resource. In the
     affected project setup, often a different resource (resolving
     to the same file) was chosen than the one from which the
     action originated.

     The solution for this is simple: choose the resource from which
     the action originated. This was fixed today in [1].

  2) The target of the action is in a different file than the one
     the action was invoked in.

     In this case, the target was found through an index lookup,
     and it's represented as an IIndexName.

     To navigate to a target like this, CDT asks the index "what
     was the workspace path of the translation unit that was
     indexed that contained this name" (this path is stored in
     the index).

     As I mentioned in comment 4, the file could have been
     indexed under any one of the workspace paths that resolve to
     it. Whichever it was, "Open Declaration" opens that file.
     So, for example, starting from "/Project/folder/file.cpp", we 
     can open "/Project/[Subprojects]/folder/file.hpp", if 
     "file.hpp" happened to be indexed under that path. Of course,
     we'd prefer to open "/Project/folder/file.hpp" instead.

     To fix this, I propose to take the following approach
     (kindly suggested by Gregory Kramida): 

     Instead of taking the workspace path under which the file was
     indexed, find all workspace paths that resolve to the same
     location in the filesystem, and select whichever of these 
     paths shares the greatest common prefix with the workspace 
     path of the file originating the action.

     For example, if the originating file is 
     "/Project/folder/file.cpp", then
     "/Project/folder/file.hpp" (which shares 2 paths segments with
     the originating path) would be preferred over
     "/Project/[Subprojects]/folder/file.hpp" (which shares 1 path
     segment with the originating path).


[1] http://git.eclipse.org/c/cdt/org.eclipse.cdt.git/commit/?id=d4c3e42e7eb920fe37f173f90d8e0936fcedfdb8
Comment 6 Eclipse Genie CLA 2016-01-07 01:06:09 EST
New Gerrit change created: https://git.eclipse.org/r/63690