Community
Participate
Working Groups
I am reporting this bug for a WSAD customer. I have a simple scenario that will crash the Eclipse workbench. The key to making the crash happen seems to be that I need to have two projects whose classpath is dependent on each other with each dependency exported. I will attach two .zip files- each containing a Java Project that exhibit this behavior. Here are the steps to follow: - Unzip each of these projects into your workspace. - Start Eclipse - verify that IafConfigurationEJB is dependentent on IafConfigurationJAVA and vice versa inthe Java Build Paths page. Also notice that each dependendency is exported. - Open the com.deere.u90.iaf.configuration.ConfigurationPropertiesHelper class. In the Outline view, select the GetDefaultDirectory() method and select Refactor->Rename. Rename the method to GetDefaultDirectoryXX() and select the Next button. The JVM will crash and the Eclipse will come down. Note that if you remove the exports or the circular dependency, the crash does not occur.
Created attachment 2289 [details] IafConfigurationEJB
Created attachment 2290 [details] IafConfigurationJAVA
Do you have any information printed in the console when the VM exits ?
Moreover, do you have any evidence that JDT/Core is guilty ?
I am not sure if it is the JDT Core that is at fault, but the problem is somewhere in the JDT. Its hard for me to distinguish the source of problem. There is nothing of consequence written to the .log file and nothing that I can see written to the console when I run with the -consolelog option. If there are other options you want me to run with or futher debugging you would like me to do, please let me know. I will be happy to try anything.
Thanks for checking, we will have to try reproducing it.
Cannot reproduce. I grabbed wsa-base-20021030_0100-WB202-AD-V50S-GA.zip+wsa-jdk-20021030_0100- WB202-AD-V50S-GA.zip. I unzipped the 2 zip files, and created one EJP project on top of IafConfigurationEJB, one Java project on top of IafConfigurationJAVA. The JAVA project did not prereq the EJB one, I added it on the classpath (note that it does not seem to need it anyway). Refactor worked fine, proposed me two matches (one in each project). Am I missing something ? Which VM were you using (could just be a VM bug as symptoms seem to indicate). I was using the default wsad/eclipse/jre one which came with the install.
Was able to reproduce the crash with following steps: Unzip the project zips, and then create "simple" projects on top of them.
By disabling the JIT (-Djava.compiler=none), a stack overflow gets dumped into the .log. Refactoring is looping: java.fullversion=J2RE 1.3.1 IBM Windows 32 build cn131-20020710 (JIT disabled) BootLoader constants: OS=win32, ARCH=x86, WS=win32, NL=en_US Command-line arguments: -os win32 -ws win32 -arch x86 -data d:\eclipse\wsad\workspace -install file:D:/eclipse/wsad/eclipse/ !ENTRY org.eclipse.jdt.ui 4 1 Oct 31, 2002 12:24:50.304 !MESSAGE Internal Error !STACK 0 java.lang.reflect.InvocationTargetException: java.lang.StackOverflowError at java.lang.String.compareTo(String.java:1313) at org.eclipse.core.internal.dtree.AbstractDataTreeNode.childAtOrNull (AbstractDataTreeNode.java:208) at org.eclipse.core.internal.dtree.DeltaDataTree.lookup (DeltaDataTree.java:702) at org.eclipse.core.internal.watson.ElementTree.includes (ElementTree.java:706) at org.eclipse.core.internal.resources.Workspace.getResourceInfo (Workspace.java:976) at org.eclipse.core.internal.resources.Resource.getResourceInfo (Resource.java:686) at org.eclipse.core.internal.resources.Resource.exists (Resource.java:538) at org.eclipse.jdt.internal.core.JavaProject.getSharedProperty (JavaProject.java:1468) at org.eclipse.jdt.internal.core.JavaProject.loadClasspath (JavaProject.java:1604) at org.eclipse.jdt.internal.core.JavaProject.getRawClasspath (JavaProject.java:1247) at org.eclipse.jdt.internal.corext.refactoring.rename.RefactoringScopeFactory.addRe ferencingProjects(RefactoringScopeFactory.java:61) at org.eclipse.jdt.internal.corext.refactoring.rename.RefactoringScopeFactory.addRe ferencingProjects(RefactoringScopeFactory.java:67) at org.eclipse.jdt.internal.corext.refactoring.rename.RefactoringScopeFactory.addRe ferencingProjects(RefactoringScopeFactory.java:67) .... at org.eclipse.jdt.internal.corext.refactoring.rename.RefactoringScopeFactory.addRe ferencingProjects(RefactoringScopeFactory.java:67) at org.eclipse.jdt.internal.corext.refactoring.rename.RefactoringScopeFactory.addRe ferencingProjects(RefactoringScopeFactory.java:67) at org.eclipse.jdt.internal.corext.refactoring.rename.RefactoringScopeFactory.addRe ferencingProjects(RefactoringScopeFactory.java:67) at org.eclipse.jdt.internal.corext.refactoring.rename.RefactoringScopeFactory.addRe ferencingProjects(RefactoringScopeFactory.java:67) at org.eclipse.jdt.internal.corext.refactoring.rename.RefactoringScopeFactory.creat e(RefactoringScopeFactory.java:33) at org.eclipse.jdt.internal.corext.refactoring.rename.RefactoringScopeFactory.creat e(RefactoringScopeFactory.java:52) at org.eclipse.jdt.internal.corext.refactoring.rename.RenameMethodRefactoring.creat eRefactoringScope(RenameMethodRefactoring.java:244) at org.eclipse.jdt.internal.corext.refactoring.rename.RenameMethodRefactoring.getOc currences(RenameMethodRefactoring.java:285) at org.eclipse.jdt.internal.corext.refactoring.rename.RenameMethodRefactoring.check Input(RenameMethodRefactoring.java:214) at org.eclipse.jdt.internal.corext.refactoring.rename.RenameStaticMethodRefactoring .checkInput(RenameStaticMethodRefactoring.java:51) at org.eclipse.jdt.internal.ui.refactoring.CheckConditionsOperation.run (CheckConditionsOperation.java:58) at org.eclipse.jdt.internal.ui.refactoring.CreateChangeOperation.run (CreateChangeOperation.java:93) at org.eclipse.jface.operation.ModalContext$ModalContextThread.run (ModalContext.java:98) Moving to JDT/UI
George, you should open a defect against your VM provider (is it Husrley?) The VM should not crash like that because of a StackOverflowError. Adam, this can be reproduced in Eclipse 2.0.1
Glancing through the offending code, the method incorrectly rebuilds the list of prerequisite projects. It iterates over raw classpaths, but projects could be made available through variables/containers (JDT/Core API supports it). Suggested fix: private static void addReferencingProjects(IProject focus, List list) throws JavaModelException { IPath path= focus.getProject().getFullPath(); IProject[] projects= focus.getProject().getReferencingProjects (); for (int i= 0, length= projects.length; i < length; i++) { IProject project= projects[i]; if (list.contains(project)) continue; // break cycle IJavaProject javaProject= JavaCore.create(project); IClasspathEntry[] classpath= javaProject.getResolvedClasspath(true); for (int j= 0, length2= classpath.length; j < length2; j++) { IClasspathEntry entry= classpath[j]; if (entry.getEntryKind() == IClasspathEntry.CPE_PROJECT && path.equals(entry.getPath())) { list.addAll(getSourceRoots (javaProject)); if (entry.isExported()) addReferencingProjects (javaProject.getProject(), list); break; } } } }
Actually, in 2.0.1 branch, the fix should rather look like: private static void addReferencingProjects(IProject focus, List list) throws JavaModelException { IPath path= focus.getProject().getFullPath(); IProject[] projects= focus.getProject().getReferencingProjects (); for (int i= 0, length= projects.length; i < length; i++) { IProject project= projects[i]; if (list.contains(project)) continue; // break cycle IJavaProject javaProject= JavaCore.create(project); IClasspathEntry[] classpath= javaProject.getResolvedClasspath(true); for (int j= 0, length2= classpath.length; j < length2; j++) { IClasspathEntry entry= classpath[j]; if (entry.getEntryKind() == IClasspathEntry.CPE_PROJECT && path.equals(entry.getPath())) { list.add(javaProject); if (entry.isExported()) addReferencingProjects (javaProject.getProject(), list); break; } } } }
I guess I should have tried the fix before posting it... <g> The fix should rather read: private static void addReferencingProjects(IProject focus, List list) throws JavaModelException { IPath path= focus.getProject().getFullPath(); IProject[] projects= focus.getProject().getReferencingProjects (); for (int i= 0, length= projects.length; i < length; i++) { IProject project= projects[i]; IJavaProject javaProject= JavaCore.create(project); if (list.contains(javaProject)) continue; // break cycle IClasspathEntry[] classpath= javaProject.getResolvedClasspath(true); for (int j= 0, length2= classpath.length; j < length2; j++) { IClasspathEntry entry= classpath[j]; if (entry.getEntryKind() == IClasspathEntry.CPE_PROJECT && path.equals(entry.getPath())) { list.add(javaProject); if (entry.isExported()) addReferencingProjects (javaProject.getProject(), list); break; } } } }
Here's the proposed fix. We now have a method addReferencingProjectSourceRoots, which finds source roots in referencing projects other than focus. This method is implemented in terms of another method, addReferencingProjects, which is recursive; the recursive method adds IJavaProjects to a list. ---8<--- /******************************************************************************* * Copyright (c) 2000, 2001 International Business Machines Corp. and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Common Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/cpl-v10.html * * Contributors: * IBM Corporation - initial API and implementation ******************************************************************************/ package org.eclipse.jdt.internal.corext.refactoring.rename; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import org.eclipse.core.resources.IProject; import org.eclipse.core.runtime.IPath; import org.eclipse.jdt.core.IClasspathEntry; import org.eclipse.jdt.core.IJavaElement; import org.eclipse.jdt.core.IJavaProject; import org.eclipse.jdt.core.IMember; import org.eclipse.jdt.core.IPackageFragment; import org.eclipse.jdt.core.IPackageFragmentRoot; import org.eclipse.jdt.core.JavaCore; import org.eclipse.jdt.core.JavaModelException; import org.eclipse.jdt.core.search.IJavaSearchScope; import org.eclipse.jdt.core.search.SearchEngine; import org.eclipse.jdt.internal.corext.util.JdtFlags; public class RefactoringScopeFactory { private RefactoringScopeFactory(){ } private static IJavaSearchScope create(IJavaProject javaProject) throws JavaModelException { List elements= getSourceRoots(javaProject); addReferencingProjectSourceRoots(javaProject.getProject(), elements); return SearchEngine.createJavaSearchScope((IJavaElement[]) elements.toArray(new IJavaElement[elements.size()]), false); } public static IJavaSearchScope create(IJavaElement javaElement) throws JavaModelException { if (javaElement instanceof IMember) { IMember member= (IMember)javaElement; if (JdtFlags.isPrivate(member)) { if (member.getCompilationUnit() != null) return SearchEngine.createJavaSearchScope(new IJavaElement[]{member.getCompilationUnit ()}); else return SearchEngine.createJavaSearchScope(new IJavaElement[]{member}); } if (! JdtFlags.isPublic(member) && !JdtFlags.isProtected (member) && member.getCompilationUnit() != null) { IPackageFragment pack= (IPackageFragment) member.getCompilationUnit().getParent(); return SearchEngine.createJavaSearchScope(new IJavaElement[]{pack}); } } return create(javaElement.getJavaProject()); } /** * Adds to sourceRoots all source roots in projects referencing focus * (excluding focus itself) * * @param focus * @param sourceRoots Source roots (IPackageFragmentRoot) will be * added to this list */ private static void addReferencingProjectSourceRoots(IProject focus, List sourceRoots) throws JavaModelException { List projects= new ArrayList(); addReferencingProjects(focus, projects); // remove focus project in case it has been added because it // references itself indirectly projects.remove(JavaCore.create(focus)); sourceRoots.addAll(getAllSourceRootsInProjects(projects)); } /** * Adds to <code>projects</code> IJavaProject objects for all projects * referenced by focus * * @param focus * @param list IJavaProjects will be added to this list * @throws JavaModelException */ private static void addReferencingProjects(IProject focus, List list) throws JavaModelException { IPath path= focus.getProject().getFullPath(); IProject[] projects= focus.getProject().getReferencingProjects (); for (int i= 0, length= projects.length; i < length; i++) { IProject project= projects[i]; IJavaProject javaProject= JavaCore.create(project); if (list.contains(javaProject)) continue; // break cycle IClasspathEntry[] classpath= javaProject.getResolvedClasspath(true); for (int j= 0, length2= classpath.length; j < length2; j++) { IClasspathEntry entry= classpath[j]; if (entry.getEntryKind() == IClasspathEntry.CPE_PROJECT && path.equals(entry.getPath())) { list.add(javaProject); if (entry.isExported()) addReferencingProjects (javaProject.getProject(), list); break; } } } } /** * @param projects a list of IJavaProject * @return List a list of IPackageFragmentRoot */ private static List getAllSourceRootsInProjects(List projects) throws JavaModelException { List result= new ArrayList(); for(Iterator it= projects.iterator(); it.hasNext();) result.addAll(getSourceRoots((IJavaProject)it.next())); return result; } private static List getSourceRoots(IJavaProject javaProject) throws JavaModelException { List elements= new ArrayList(); IPackageFragmentRoot[] roots= javaProject.getPackageFragmentRoots(); // Add all package fragment roots except archives for (int i= 0; i < roots.length; i++) { IPackageFragmentRoot root= roots[i]; if (!root.isArchive()) elements.add(root); } return elements; } }
Rory's assessment is related to 2.1 stream while Philippe's fix is the good one for 2.0.2. Rory and Claude are currently testing the Philippe's fix on 2.0.2 stream.
We tested and released Philippe's patch. -- Claude and Rory.
Must still be fixed against HEAD.
Fix for HEAD will be provided next Monday when Dirk is back. He is one of the refactoring guys.
Reminder: the milestone for this defect should probably be 2.0.2
There are two issues here 1) the target milestone: this should be either 2.0.2 or 2.1 M3 - but not 2.1 M4. I think we don't have a clear rule what we do with PRs that we fix in two or more streams but as far as I can remember we set the milestone to the first occurrence of the fix - in this case 2.0.2. 2) the version. This bug was reported against 2.0.2 and Claude now changed it to be 2.1. Given the bugzilla restrictions I think the best solution would be to have two PRs: one for version 2.0.2 whit target milestone 2.0.2 and the other for 2.1 with target milestone 2.1. This will allow us to find the fixed PRs for a given release (e.g. 2.0.2 or 2.1).
Dirk, please see with Rory for proposed patch for HEAD.
Here is my proposed fix for HEAD. The methods compose better with these method choices. /******************************************************************************* * Copyright (c) 2000, 2001 International Business Machines Corp. and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Common Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/cpl-v10.html * * Contributors: * IBM Corporation - initial API and implementation ******************************************************************************/ package org.eclipse.jdt.internal.corext.refactoring.rename; import java.util.ArrayList; import java.util.Collection; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Set; import org.eclipse.core.resources.IProject; import org.eclipse.core.runtime.IPath; import org.eclipse.jdt.core.IClasspathEntry; import org.eclipse.jdt.core.IJavaElement; import org.eclipse.jdt.core.IJavaProject; import org.eclipse.jdt.core.IMember; import org.eclipse.jdt.core.IPackageFragment; import org.eclipse.jdt.core.IPackageFragmentRoot; import org.eclipse.jdt.core.JavaCore; import org.eclipse.jdt.core.JavaModelException; import org.eclipse.jdt.core.search.IJavaSearchScope; import org.eclipse.jdt.core.search.SearchEngine; import org.eclipse.jdt.internal.corext.util.JdtFlags; public class RefactoringScopeFactory { public static IJavaSearchScope create(IJavaElement javaElement) throws JavaModelException { if (javaElement instanceof IMember) { IMember member= (IMember)javaElement; if (JdtFlags.isPrivate(member)) { if (member.getCompilationUnit() != null) return SearchEngine.createJavaSearchScope(new IJavaElement[]{member.getCompilationUnit ()}); else return SearchEngine.createJavaSearchScope(new IJavaElement[]{member}); } if (! JdtFlags.isPublic(member) && !JdtFlags.isProtected (member) && member.getCompilationUnit() != null) { IPackageFragment pack= (IPackageFragment) member.getCompilationUnit().getParent(); return SearchEngine.createJavaSearchScope(new IJavaElement[]{pack}); } } return create(javaElement.getJavaProject()); } private RefactoringScopeFactory(){ } private static IJavaSearchScope create(IJavaProject javaProject) throws JavaModelException { return SearchEngine.createJavaSearchScope(getAllScopeElements (javaProject), false); } private static IJavaElement[] getAllScopeElements(IJavaProject project) throws JavaModelException { Collection sourceRoots= getAllSourceRootsInProjects (getProjectsInScopeFor(project)); return (IPackageFragmentRoot[]) sourceRoots.toArray(new IPackageFragmentRoot[sourceRoots.size()]); } /** * @param focus * @return Collection containing IJavaProject objects * @throws JavaModelException */ private static Collection getProjectsInScopeFor(IJavaProject focus) throws JavaModelException { Set projects= new HashSet(); addReferencingProjects(focus, projects); projects.add(focus); return projects; } /** * Adds to <code>projects</code> IJavaProject objects for all projects * directly or indirectly referencing focus. * * @param focus * @param projects IJavaProjects will be added to this set * @throws JavaModelException */ private static void addReferencingProjects(IJavaProject focus, Set projects) throws JavaModelException { IProject[] referencingProjects= focus.getProject ().getReferencingProjects(); for (int i= 0; i < referencingProjects.length; i++) { IJavaProject candidate= JavaCore.create (referencingProjects[i]); if(projects.contains(candidate)) continue; // break cycle IClasspathEntry entry= getReferencingClassPathEntry (candidate, focus); if(entry != null) { projects.add(candidate); if(entry.isExported()) addReferencingProjects(candidate, projects); } } } /** * Finds, if possible, a classpathEntry in one given project such that this * classpath entry references another given project. If more than one entry * exists for the referenced project and at least one is exported, then an * exported entry will be returned. * * @param referencingProject * @param referencedProject * @return IClasspathEntry * @throws JavaModelException */ private static IClasspathEntry getReferencingClassPathEntry (IJavaProject referencingProject, IJavaProject referencedProject) throws JavaModelException { IClasspathEntry result= null; IPath path= referencedProject.getProject().getFullPath(); IClasspathEntry[] classpath= referencingProject.getResolvedClasspath(true); for (int i= 0; i < classpath.length; i++) { IClasspathEntry entry= classpath[i]; if (entry.getEntryKind() == IClasspathEntry.CPE_PROJECT && path.equals(entry.getPath())) { if(result == null || !result.isExported()) result= entry; } } return result; } /** * @param projects a collection of IJavaProject * @return Collection a collection of IPackageFragmentRoot, one element * for each packageFragmentRoot which lies within a project in * <code>projects</code>. */ private static Collection getAllSourceRootsInProjects(Collection projects) throws JavaModelException { List result= new ArrayList(); for(Iterator it= projects.iterator(); it.hasNext();) result.addAll(getSourceRoots((IJavaProject)it.next())); return result; } private static List getSourceRoots(IJavaProject javaProject) throws JavaModelException { List elements= new ArrayList(); IPackageFragmentRoot[] roots= javaProject.getPackageFragmentRoots(); // Add all package fragment roots except archives for (int i= 0; i < roots.length; i++) { IPackageFragmentRoot root= roots[i]; if (!root.isArchive()) elements.add(root); } return elements; } }
Clarification: In the 2.0.2 stream, and presumably in the common ancestor of this stream and the 2.1 stream, the RefactoringScopeFactory.create(IJavaProject javaProject) method constructed a search scope consisting of javaProject and all the projects indirectly or directly referencing it. In the 2.1 stream, the method currently constructs a search scope consisting of the Package Fragment Roots of these projects.
PR fixed on 2.0.2 and 2.1 stream.