Bug 20158 - Close and reopen a project does not remove errors
Summary: Close and reopen a project does not remove errors
Status: VERIFIED FIXED
Alias: None
Product: JDT
Classification: Eclipse Project
Component: Core (show other bugs)
Version: 2.0   Edit
Hardware: PC Windows 2000
: P2 normal (vote)
Target Milestone: 2.0 F4   Edit
Assignee: Kent Johnson CLA
QA Contact:
URL:
Whiteboard:
Keywords:
Depends on:
Blocks:
 
Reported: 2002-06-13 09:39 EDT by David Audel CLA
Modified: 2002-06-17 08:25 EDT (History)
0 users

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description David Audel CLA 2002-06-13 09:39:51 EDT
1. Create simple project SP1
2. Add x.jar in SP1
3. Create Java project JP2
3. Add SP1/x.jar on JP2's classpath
4. Close SP1
5. Do ctrl+B (errors appears)
6. Open SP1
x.jar is present in package view but there is errors in task view and ctrl+B 
does not remove these errors.
Comment 1 Kent Johnson CLA 2002-06-13 14:58:57 EDT
Instead of deleting SP1's build state when its closed... its being saved 
instead. So when SP1 is reopened, no build is 'needed'... no deltas are 
generated/propagated to its dependent projects.

We should either stop saving a project's build state when its closed or delete 
the state when its reopened.

PM: comments?
Comment 2 Philipe Mulet CLA 2002-06-14 06:20:56 EDT
This wouldn't make a difference if the closed project is a non-java project 
(like in this scenario).

There must be a delta for the prereq project which isn't a Java one which is 
ignored.
Comment 3 Philipe Mulet CLA 2002-06-14 06:34:20 EDT
Indeed, when SP1 is closed, the builder can no longer find SP1/x.jar, which is 
thus removed from the binary resources. Therefore, SP1 is no longer claimed to 
be an interesting prereq project. So when reopening it later, its delta won't 
even be considered.
Comment 4 Philipe Mulet CLA 2002-06-14 06:45:00 EDT
Proposed fix is: NameEnvironment#computeLocations
-----

public static ClasspathLocation[] computeLocations(
	IWorkspaceRoot workspaceRoot,
	IJavaProject javaProject,
	String outputFolderLocation,
	ArrayList sourceFolders,
	SimpleLookupTable binaryResources) throws JavaModelException {

	IClasspathEntry[] classpathEntries = ((JavaProject) 
javaProject).getExpandedClasspath(true, true);
	int cpCount = 0;
	int max = classpathEntries.length;
	ClasspathLocation[] classpathLocations = new ClasspathLocation[max];

	boolean firstSourceFolder = true;
	nextEntry : for (int i = 0; i < max; i++) {
		IClasspathEntry entry = classpathEntries[i];
		IPath path = entry.getPath();
		Object target = JavaModel.getTarget(workspaceRoot, path, true);
		if (target == null){
			if (entry.getEntryKind() == 
IClasspathEntry.CPE_LIBRARY) {
				if (path.segmentCount() > 1) {
					IResource rsc = workspaceRoot.findMember
(path.segment(0));
					if (rsc instanceof IProject && 
rsc.exists()) {
						binaryResources.put((IProject)
rsc, new IResource[0]);
					}
				}
			}
			continue nextEntry;
		}

		if (target instanceof IResource) {
			IResource resource = (IResource) target;
			switch(entry.getEntryKind()) {
				case IClasspathEntry.CPE_SOURCE :
					if (outputFolderLocation == null || !
(resource instanceof IContainer)) continue nextEntry;
					if (sourceFolders != null) { // normal 
builder mode
						sourceFolders.add(resource);
						classpathLocations[cpCount++] =
						
	ClasspathLocation.forSourceFolder(resource.getLocation().toString(), 
outputFolderLocation);
					} else if (firstSourceFolder) { // add 
the output folder only once
						firstSourceFolder = false;
						classpathLocations[cpCount++] = 
ClasspathLocation.forBinaryFolder(outputFolderLocation);
					}
					continue nextEntry;

				case IClasspathEntry.CPE_PROJECT :
					if (!(resource instanceof IProject)) 
continue nextEntry;
					IProject prereqProject = (IProject) 
resource;
					if (!prereqProject.isAccessible()) 
continue nextEntry;
					IPath outputLocation = JavaCore.create
(prereqProject).getOutputLocation();
					IResource prereqOutputFolder;
					if (prereqProject.getFullPath().equals
(outputLocation)) {
						prereqOutputFolder = 
prereqProject;
					} else {
						prereqOutputFolder = 
workspaceRoot.findMember(outputLocation);
						if (prereqOutputFolder == null 
|| !prereqOutputFolder.exists() || !(prereqOutputFolder instanceof IFolder))
							continue nextEntry;
					}
					if (prereqOutputFolder.getLocation() == 
null) // sanity check
						continue nextEntry;
					if (binaryResources != null) { // 
normal builder mode
						IResource[] existingResources = 
(IResource[]) binaryResources.get(prereqProject);
						if (existingResources == null)
							binaryResources.put
(prereqProject, new IResource[] {prereqOutputFolder});
						else
							existingResources[0] = 
prereqOutputFolder; // project's output folder is always first
					}
					classpathLocations[cpCount++] = 
ClasspathLocation.forBinaryFolder(prereqOutputFolder.getLocation().toString());
					continue nextEntry;

				case IClasspathEntry.CPE_LIBRARY :
					if (resource.getLocation() == null) // 
sanity check
						continue nextEntry;
					if (resource instanceof IFile) {
						String extension = 
path.getFileExtension();
						if (!
(JavaBuilder.JAR_EXTENSION.equalsIgnoreCase(extension) || 
JavaBuilder.ZIP_EXTENSION.equalsIgnoreCase(extension)))
							continue nextEntry;
						classpathLocations[cpCount++] = 
ClasspathLocation.forLibrary(resource.getLocation().toString());
					} else if (resource instanceof IFolder) 
{
						classpathLocations[cpCount++] = 
ClasspathLocation.forBinaryFolder(resource.getLocation().toString());
					}
					if (binaryResources != null) { // 
normal builder mode
						IProject p = resource.getProject
(); // can be the project being built
						IResource[] existingResources = 
(IResource[]) binaryResources.get(p);
						if (existingResources == null) {
							existingResources = new 
IResource[] {null, resource}; // project's output folder is always first, null 
if not included
						} else {
							int size = 
existingResources.length;
							System.arraycopy
(existingResources, 0, existingResources = new IResource[size + 1], 0, size);
							existingResources[size] 
= resource;
						}
						binaryResources.put(p, 
existingResources);
					}
					continue nextEntry;
			}
		} else if (target instanceof File) {
			String extension = path.getFileExtension();
			if (!(JavaBuilder.JAR_EXTENSION.equalsIgnoreCase
(extension) || JavaBuilder.ZIP_EXTENSION.equalsIgnoreCase(extension)))
				continue nextEntry;
			classpathLocations[cpCount++] = 
ClasspathLocation.forLibrary(path.toString());
		}
	}
	if (cpCount < max)
		System.arraycopy(classpathLocations, 0, (classpathLocations = 
new ClasspathLocation[cpCount]), 0, cpCount);
	return classpathLocations;
}
Comment 5 Philipe Mulet CLA 2002-06-14 07:52:34 EDT
Actually, my fix shouldn't be necessary, since it should rather be detected as 
a classpath change.
Comment 6 Philipe Mulet CLA 2002-06-14 08:21:04 EDT
I take my previous comment back, the proposed fix is necessary for the Java 
builder do get invoked at all. From thereon, it can react to the change as it 
wants (in this case it will have discarded the original build state when 
aborting the build due to classpath error).
Comment 7 Philipe Mulet CLA 2002-06-14 08:32:36 EDT
Better fix below. Found some suspicious code near management of binaryResources 
for output folder (did not grow existing list if any).

NameEnvironment#computeLocations

[public static ClasspathLocation[] computeLocations(
	IWorkspaceRoot workspaceRoot,
	IJavaProject javaProject,
	String outputFolderLocation,
	ArrayList sourceFolders,
	SimpleLookupTable binaryResources) throws JavaModelException {

	IClasspathEntry[] classpathEntries = ((JavaProject) 
javaProject).getExpandedClasspath(true, true);
	int cpCount = 0;
	int max = classpathEntries.length;
	ClasspathLocation[] classpathLocations = new ClasspathLocation[max];

	boolean firstSourceFolder = true;
	nextEntry : for (int i = 0; i < max; i++) {
		IClasspathEntry entry = classpathEntries[i];
		IPath path = entry.getPath();
		Object target = JavaModel.getTarget(workspaceRoot, path, true);
		if (target == null){
			// still remember a dependency onto the container 
project (20158)
			if (entry.getEntryKind() == 
IClasspathEntry.CPE_LIBRARY) {
				if (path.segmentCount() > 1) {
					IResource rsc = workspaceRoot.findMember
(path.segment(0));
					if (rsc instanceof IProject) {
						binaryResources.put((IProject)
rsc, new IResource[0]);
					}
				}
			}
			continue nextEntry;
		}

		if (target instanceof IResource) {
			IResource resource = (IResource) target;
			switch(entry.getEntryKind()) {
				case IClasspathEntry.CPE_SOURCE :
					if (outputFolderLocation == null || !
(resource instanceof IContainer)) continue nextEntry;
					if (sourceFolders != null) { // normal 
builder mode
						sourceFolders.add(resource);
						classpathLocations[cpCount++] =
						
	ClasspathLocation.forSourceFolder(resource.getLocation().toString(), 
outputFolderLocation);
					} else if (firstSourceFolder) { // add 
the output folder only once
						firstSourceFolder = false;
						classpathLocations[cpCount++] = 
ClasspathLocation.forBinaryFolder(outputFolderLocation);
					}
					continue nextEntry;

				case IClasspathEntry.CPE_PROJECT :
					if (!(resource instanceof IProject)) 
continue nextEntry;
					IProject prereqProject = (IProject) 
resource;
					if (!prereqProject.isAccessible()) 
continue nextEntry;
					IPath outputLocation = JavaCore.create
(prereqProject).getOutputLocation();
					IResource prereqOutputFolder;
					if (prereqProject.getFullPath().equals
(outputLocation)) {
						prereqOutputFolder = 
prereqProject;
					} else {
						prereqOutputFolder = 
workspaceRoot.findMember(outputLocation);
						if (prereqOutputFolder == null 
|| !prereqOutputFolder.exists() || !(prereqOutputFolder instanceof IFolder))
							continue nextEntry;
					}
					if (prereqOutputFolder.getLocation() == 
null) // sanity check
						continue nextEntry;
					if (binaryResources != null) { // 
normal builder mode
						IResource[] existingResources = 
(IResource[]) binaryResources.get(prereqProject);
						if (existingResources == null)
							existingResources = new 
IResource[] {prereqOutputFolder};
						else {
							int size = 
existingResources.length;
							System.arraycopy
(existingResources, 0, existingResources = new IResource[size + 1], 1, size);
							existingResources[0] = 
prereqOutputFolder; // project's output folder is always first
						}
						binaryResources.put
(prereqProject, existingResources);
					}
					classpathLocations[cpCount++] = 
ClasspathLocation.forBinaryFolder(prereqOutputFolder.getLocation().toString());
					continue nextEntry;

				case IClasspathEntry.CPE_LIBRARY :
					if (resource.getLocation() == null) // 
sanity check
						continue nextEntry;
					if (resource instanceof IFile) {
						String extension = 
path.getFileExtension();
						if (!
(JavaBuilder.JAR_EXTENSION.equalsIgnoreCase(extension) || 
JavaBuilder.ZIP_EXTENSION.equalsIgnoreCase(extension)))
							continue nextEntry;
						classpathLocations[cpCount++] = 
ClasspathLocation.forLibrary(resource.getLocation().toString());
					} else if (resource instanceof IFolder) 
{
						classpathLocations[cpCount++] = 
ClasspathLocation.forBinaryFolder(resource.getLocation().toString());
					}
					if (binaryResources != null) { // 
normal builder mode
						IProject p = resource.getProject
(); // can be the project being built
						IResource[] existingResources = 
(IResource[]) binaryResources.get(p);
						if (existingResources == null) {
							existingResources = new 
IResource[] {null, resource}; // project's output folder is always first, null 
if not included
						} else {
							int size = 
existingResources.length;
							System.arraycopy
(existingResources, 0, existingResources = new IResource[size + 1], 0, size);
							existingResources[size] 
= resource;
						}
						binaryResources.put(p, 
existingResources);
					}
					continue nextEntry;
			}
		} else if (target instanceof File) {
			String extension = path.getFileExtension();
			if (!(JavaBuilder.JAR_EXTENSION.equalsIgnoreCase
(extension) || JavaBuilder.ZIP_EXTENSION.equalsIgnoreCase(extension)))
				continue nextEntry;
			classpathLocations[cpCount++] = 
ClasspathLocation.forLibrary(path.toString());
		}
	}
	if (cpCount < max)
		System.arraycopy(classpathLocations, 0, (classpathLocations = 
new ClasspathLocation[cpCount]), 0, cpCount);
	return classpathLocations;
}
]
Comment 8 Philipe Mulet CLA 2002-06-14 08:34:32 EDT
Fixed
Comment 9 Kent Johnson CLA 2002-06-14 11:38:53 EDT
Replaced fix with one on JavaBuilder.getRequiredProjects().

It now searches for Library entries as well as Project entries.
Comment 10 Philipe Mulet CLA 2002-06-14 11:55:16 EDT
Last fix is indeed the most safe. It doesn't interact with the binary resources 
collection, which did work but wasn't as clean as new fix which only changes 
the method for computing prereq project names (which used to use the binary 
resources collection) by simply walking the classpath.

Did both (KJ and PM) write the new fix separately and it was the same 
implementation.

Removing 'FIXED' status, until it gets approved for F4
Comment 11 Philipe Mulet CLA 2002-06-14 11:57:13 EDT
If we don't fix it, then the Java builder wouldn't notice additions/removals of 
internal JARs contained in distinct projects onto which it has no other 
explicit references (as a project prereq on its classpath).

Fix is fairly simple in the end.
Comment 12 Olivier Thomann CLA 2002-06-14 13:11:23 EDT
Verified. It works great.
Comment 13 Jerome Lanneluc CLA 2002-06-17 08:21:42 EDT
No veto. Marking as fixed.
Comment 14 Jerome Lanneluc CLA 2002-06-17 08:25:05 EDT
Verified.