Bug 66694 - PackageExplorer shows elements twice
Summary: PackageExplorer shows elements twice
Status: VERIFIED FIXED
Alias: None
Product: JDT
Classification: Eclipse Project
Component: UI (show other bugs)
Version: 3.0   Edit
Hardware: PC Windows XP
: P2 normal (vote)
Target Milestone: 3.0 RC3   Edit
Assignee: Markus Keller CLA
QA Contact:
URL:
Whiteboard:
Keywords:
Depends on:
Blocks:
 
Reported: 2004-06-11 10:57 EDT by Olivier Thomann CLA
Modified: 2004-06-21 05:01 EDT (History)
4 users (show)

See Also:


Attachments
Patch to StandardJavaElementContentProvider (1.71 KB, patch)
2004-06-16 06:10 EDT, Markus Keller CLA
no flags Details | Diff
Test case demonstrated shortcoming of intermediate suggestion (2.25 KB, application/octet-stream)
2004-06-16 20:07 EDT, Philipe Mulet CLA
no flags Details

Note You need to log in before you can comment on or make changes to this bug.
Description Olivier Thomann CLA 2004-06-11 10:57:27 EDT
Using 200406110010, see bug 65234 comment 7. The compilation unit A is shown twice.
Comment 1 Markus Keller CLA 2004-06-16 06:05:54 EDT
The observation is correct. However, I checked in 200406111814 and it shouldn't
lead to problems with refactorings.

Without inclusion filters, all container children of an IPackageFragmentRoot
were either IPackageFragments, or IFolders (if folder is excluded, or name is
illegal package name) with only IResource children.

But with inclusion filters, the picture changes. When we have an IFolder like
'org', its children could be matched by an inclusion filter (also deep-down).

Therefore, we have to check for each child IFolder whether it's in fact a valid
IPackageFragment. If it is, it should not be rendered as child of an IFolder,
since it is alrady rendered as IPackageFragment in an IPackageFragmentRoot.

The basic assumption is this split:
- All resources inside an IPackageFragment are shown as children of the
IPackageFragment, regardless whether they are on the classpath or not.
- An IFolder 'in' inside an IFolder 'out' is only shown if 'in' is not an
IPackageFragment.
Comment 2 Markus Keller CLA 2004-06-16 06:10:41 EDT
Created attachment 12224 [details]
Patch to StandardJavaElementContentProvider

The patch is IMO low-risk and local. I tested it with various setups of
inclusion and exlusion filters and with project as source folder as well as
with separate source folders (all with Package Explorer in flat mode, since
hierarchical mode is not supported with inclusion filters).
Comment 3 Erich Gamma CLA 2004-06-16 07:03:38 EDT
(updated title to point at the problem).
This can result in all kinds of inconsistencies

must fix

after discussions with Philippe we should filter out all resources which have 
a corresponding Java element.

Here is the patch we came up with Philippe. Markus can you please review

Index: StandardJavaElementContentProvider.java
===================================================================
RCS 
file: /home/eclipse/org.eclipse.jdt.ui/ui/org/eclipse/jdt/ui/StandardJavaElemen
tContentProvider.java,v
retrieving revision 1.22
diff -u -r1.22 StandardJavaElementContentProvider.java
--- StandardJavaElementContentProvider.java	19 Apr 2004 09:38:30 -0000
	1.22
+++ StandardJavaElementContentProvider.java	16 Jun 2004 10:58:53 -0000
@@ -281,25 +281,19 @@
 		
 	private Object[] getResources(IFolder folder) {
 		try {
-			// filter out folders that are package fragment roots
-			Object[] members= folder.members();
+			IResource[] members= folder.members();
+			IJavaProject javaProject= JavaCore.create
(folder.getProject());
+			if (javaProject == null || !javaProject.exists())
+				return members;
 			List nonJavaResources= new ArrayList();
 			for (int i= 0; i < members.length; i++) {
-				Object o= members[i];
-				// A folder can also be a package fragment 
root in the following case
-				// Project
-				//  + src <- source folder
-				//    + excluded <- excluded from class path
-				//      + included  <- a new source folder.
-				// Included is a member of excluded, but since 
it is rendered as a source
-				// folder we have to exclude it as a normal 
child.
-				if (o instanceof IFolder) {
-					IJavaElement element= JavaCore.create
((IFolder)o);
-					if (element instanceof 
IPackageFragmentRoot && element.exists()) {
-						continue;
-					}
-				}
-				nonJavaResources.add(o);
+				IResource o= members[i];
+				// A resource can also be a java element
+				// in the case of exclusion and inclusion 
filters.
+				// We therefore exclude Java elements from the 
list
+				// of non-Java resources.
+				if (!javaProject.isOnClasspath(o))
+					nonJavaResources.add(o);
 			}
 			return nonJavaResources.toArray();
 		} catch(CoreException e) {
Comment 4 Markus Keller CLA 2004-06-16 10:23:08 EDT
Erich & Dirk: Your patch from comment 3 breaks the second scenario from bug
35851 (with srcFolder).

The other case (without source folder) is already broken in RC2 because of bug
67184 
Comment 5 Markus Keller CLA 2004-06-16 11:58:40 EDT
Philippe could you please advise on which solution we should take?
The proposed "javaProject.isOnClasspath(o)" makes bug 35851 reappear:

Test
  + srcFolder
    + a-b
       + a
    + p
       file.txt
==> a is not visible. This happens because a-b is not a valid package name, but
javaProject.isOnClasspath('a') returns true (which is usually wanted for cases
such as file.txt above).

[Original summary was:
"Java resources should be filtered out from non-Java folders"]
Comment 6 Philipe Mulet CLA 2004-06-16 20:02:55 EDT
Looking at the code we were talking about earlier with Dirk and Erich, it 
appears to be invoked in 2 situations with a IFolder.
1) case where some folder has some children which are included in classpath, 
due to presence of inclusion filters (parent isn't on CP, but child is, and 
thus shouldn't be rendered as non java rsc. 
This is the scenario described in this PR, for which children need to check 
whether they have become on CP, in which case, there are not direct children 
of this folder, from the model standpoint (i.e. they appear elsewhere either 
as element or subsequent non-java rsc of some other element).

2) case where some folder is sitting inside a package fragment root, but as a 
non-java resource. In this latter case, the only explanations for this 
situation are:
 2a) it is sitting inside a folder with invalid package name (bug 35051)
 2b) it is excluded by an exclusion filter from its enclosing source folder

in both cases, the #isOnClasspath criteria for members is irrelevant, as non-
java resources can be answered to live on the classpath. It would be tempting 
to simply answer all members in these cases, as in code below:

private Object[] getResources(IFolder folder) {
  try {
    IResource[] members= folder.members();
    IJavaProject javaProject= JavaCore.create(folder.getProject());
    if (javaProject == null 
         || !javaProject.exists() 
         || javaProject.isOnClasspath(folder))
	return members;
    List nonJavaResources= new ArrayList();
    // Can be on classpath but as a member of non-java resource folder
    for (int i= 0; i < members.length; i++) {
      IResource o= members[i];
      // A resource can also be a java element
      // in the case of exclusion and inclusion filters.
      // We therefore exclude Java elements from the list
      // of non-Java resources.
      if (!javaProject.isOnClasspath(o)) {
	nonJavaResources.add(o);
      }
    }
    return nonJavaResources.toArray();
  } catch(CoreException e) {
    return NO_CHILDREN;
  }
}

the only problem is it would not eliminate nested source folders burried 
inside a parent folder which is on classpath. 
The only scenario where a child should be still excluded is the case where a 
child would be a package fragment root, in which case it should be filtered 
out.



Comment 7 Philipe Mulet CLA 2004-06-16 20:07:20 EDT
Created attachment 12350 [details]
Test case demonstrated shortcoming of intermediate suggestion
Comment 8 Philipe Mulet CLA 2004-06-16 20:19:49 EDT
Suggesting the following version to address issues mentionned above.

private Object[] getResources(IFolder folder) {
  try {
    IResource[] members= folder.members();
    IJavaProject javaProject= JavaCore.create(folder.getProject());
    if (javaProject == null || !javaProject.exists())
      return members;
    boolean isFolderOnClasspath = javaProject.isOnClasspath(folder);
    List nonJavaResources= new ArrayList();
    // Can be on classpath but as a member of non-java resource folder
    for (int i= 0; i < members.length; i++) {
      IResource o= members[i];
      // A resource can also be a java element
      // in the case of exclusion and inclusion filters.
      // We therefore exclude Java elements from the list
      // of non-Java resources.
      if (isFolderOnClasspath) {
        if (javaProject.findPackageFragmentRoot(o.getFullPath()) == null) {
          nonJavaResources.add(o);
	}
      } else if (!javaProject.isOnClasspath(o)) {
	nonJavaResources.add(o);
      }
    }
    return nonJavaResources.toArray();
  } catch(CoreException e) {
    return NO_CHILDREN;
  }
}
Comment 9 Markus Keller CLA 2004-06-17 05:58:35 EDT
I reviewed and tested Philippe's version from comment 8, and I think it's fine.
Comment 10 Markus Keller CLA 2004-06-17 12:52:45 EDT
Fix from comment 8 reviewed by Andre and released for I20040617-1600.
Comment 11 Dirk Baeumer CLA 2004-06-19 06:09:00 EDT
Verified in I200406181804 that

- scenario from bug 65234
- one scenario from bug 35851 is broken. Creating a Test project with no
  source folders and creating a folder a-b in it will not show this folder
  Test
  + a-b  <== not visible
    + a
  This is because of the fact that a-b lives in the output folder and
  isn't a Java resource. We decided to not show output folder content.
Comment 12 Dirk Baeumer CLA 2004-06-21 04:18:22 EDT
start verifying...
Comment 13 Dirk Baeumer CLA 2004-06-21 05:01:10 EDT
Verified on I200406192000 that

- scenario from bug 65234 is fixed
- scenario two from bug 35851 is fixed
Test
  + srcFolder
    + a-b
       + a

Sceanrio one from bug 35851 is broken. I opened bug 67944 for this since the 
sceanrio got broken by fixing bug 45062