### Eclipse Workspace Patch 1.0 #P org.eclipse.jdt.core Index: model/org/eclipse/jdt/internal/core/JavaProject.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaProject.java,v retrieving revision 1.388 diff -u -r1.388 JavaProject.java --- model/org/eclipse/jdt/internal/core/JavaProject.java 18 Apr 2007 14:30:40 -0000 1.388 +++ model/org/eclipse/jdt/internal/core/JavaProject.java 24 Apr 2007 09:51:20 -0000 @@ -66,6 +66,7 @@ import org.eclipse.jdt.internal.compiler.util.ObjectVector; import org.eclipse.jdt.internal.compiler.util.SuffixConstants; import org.eclipse.jdt.internal.core.JavaModelManager.PerProjectInfo; +import org.eclipse.jdt.internal.core.JavaProjectElementInfo.ProjectCache; import org.eclipse.jdt.internal.core.builder.JavaBuilder; import org.eclipse.jdt.internal.core.eval.EvaluationContextWrapper; import org.eclipse.jdt.internal.core.util.MementoTokenizer; @@ -1809,6 +1810,10 @@ public IProject getProject() { return this.project; } + + public ProjectCache getProjectCache() throws JavaModelException { + return ((JavaProjectElementInfo) getElementInfo()).getProjectCache(this); + } /** * @see IJavaProject Index: model/org/eclipse/jdt/internal/core/JavaProjectElementInfo.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaProjectElementInfo.java,v retrieving revision 1.46 diff -u -r1.46 JavaProjectElementInfo.java --- model/org/eclipse/jdt/internal/core/JavaProjectElementInfo.java 23 Apr 2007 10:52:16 -0000 1.46 +++ model/org/eclipse/jdt/internal/core/JavaProjectElementInfo.java 24 Apr 2007 09:51:20 -0000 @@ -18,6 +18,7 @@ import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IPath; import org.eclipse.jdt.core.*; +import org.eclipse.jdt.internal.core.util.HashSetOfArray; import org.eclipse.jdt.internal.core.util.Util; import org.eclipse.jdt.internal.core.util.HashtableOfArrayToObject; @@ -37,10 +38,10 @@ static final IPackageFragmentRoot[] NO_ROOTS = new IPackageFragmentRoot[0]; static class ProjectCache { - ProjectCache(IPackageFragmentRoot[] allPkgFragmentRootsCache, HashtableOfArrayToObject allPkgFragmentsCache, Map rootToResolvedEntries) { + ProjectCache(IPackageFragmentRoot[] allPkgFragmentRootsCache, Map rootToResolvedEntries, Map pkgFragmentsCaches) { this.allPkgFragmentRootsCache = allPkgFragmentRootsCache; - this.allPkgFragmentsCache = allPkgFragmentsCache; this.rootToResolvedEntries = rootToResolvedEntries; + this.pkgFragmentsCaches = pkgFragmentsCaches; } /* @@ -50,10 +51,16 @@ /* * A cache of all package fragments in this project. - * (a map from String[] (the package name) to IPackageFragmentRoot[] (the package fragment roots that contain a package fragment with this name) + * (a map from String[] (the package name) to IPackageFragmentRoot[] (the package fragment roots that contain a package fragment with this name)) */ public HashtableOfArrayToObject allPkgFragmentsCache; + /* + * A cache of package fragments for each package fragment root of this project + * (a map from IPackageFragmentRoot to a set of String[] (the package name)) + */ + public Map pkgFragmentsCaches; + public Map rootToResolvedEntries; } @@ -68,12 +75,12 @@ * Adds the given name and its super names to the given set * (e.g. for {"a", "b", "c"}, adds {"a", "b", "c"}, {"a", "b"}, and {"a"}) */ - public static void addSuperPackageNames(String[] pkgName, HashtableOfArrayToObject packageFragments) { - int length = pkgName.length; - for (int i = length-1; i > 0; i--) { - System.arraycopy(pkgName, 0, pkgName = new String[i], 0, i); - if (packageFragments.get(pkgName) == null) + static void addSuperPackageNames(String[] pkgName, HashtableOfArrayToObject packageFragments) { + for (int i = pkgName.length-1; i > 0; i--) { + if (packageFragments.getKey(pkgName, i) == null) { + System.arraycopy(pkgName, 0, pkgName = new String[i], 0, i); packageFragments.put(pkgName, NO_ROOTS); + } } } @@ -202,47 +209,21 @@ reverseMap.clear(); } - HashMap otherRoots = JavaModelManager.getJavaModelManager().deltaState.otherRoots; - HashtableOfArrayToObject fragmentsCache = new HashtableOfArrayToObject(); - for (int i = 0, length = roots.length; i < length; i++) { + HashMap rootInfos = JavaModelManager.getJavaModelManager().deltaState.roots; + HashMap pkgFragmentsCaches = new HashMap(); + int length = roots.length; + for (int i = 0; i < length; i++) { IPackageFragmentRoot root = roots[i]; - IJavaElement[] frags = null; - try { - if (root.isArchive() - && !root.isOpen() - && otherRoots.get(((JarPackageFragmentRoot) root).jarPath) == null/*only if jar belongs to 1 project (https://bugs.eclipse.org/bugs/show_bug.cgi?id=161175)*/) { - JarPackageFragmentRootInfo info = new JarPackageFragmentRootInfo(); - ((JarPackageFragmentRoot) root).computeChildren(info, new HashMap()); - frags = info.children; - } else - frags = root.getChildren(); - } catch (JavaModelException e) { - // root doesn't exist: ignore - continue; - } - for (int j = 0, length2 = frags.length; j < length2; j++) { - PackageFragment fragment= (PackageFragment) frags[j]; - String[] pkgName = fragment.names; - Object existing = fragmentsCache.get(pkgName); - if (existing == null || existing == NO_ROOTS) { - fragmentsCache.put(pkgName, root); - // ensure super packages (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=119161) - // are also in the map - addSuperPackageNames(pkgName, fragmentsCache); - } else { - if (existing instanceof PackageFragmentRoot) { - fragmentsCache.put(pkgName, new IPackageFragmentRoot[] {(PackageFragmentRoot) existing, root}); - } else { - IPackageFragmentRoot[] entry= (IPackageFragmentRoot[]) existing; - IPackageFragmentRoot[] copy= new IPackageFragmentRoot[entry.length + 1]; - System.arraycopy(entry, 0, copy, 0, entry.length); - copy[entry.length]= root; - fragmentsCache.put(pkgName, copy); - } - } + DeltaProcessor.RootInfo rootInfo = (DeltaProcessor.RootInfo) rootInfos.get(root.getPath()); + if (rootInfo == null || rootInfo.project.equals(project)) { + // compute fragment cache + HashSetOfArray fragmentsCache = new HashSetOfArray(); + initializePackageNames(root, fragmentsCache); + pkgFragmentsCaches.put(root, fragmentsCache); } } - cache = new ProjectCache(roots, fragmentsCache, reverseMap); + + cache = new ProjectCache(roots, reverseMap, pkgFragmentsCaches); this.projectCache = cache; } return cache; @@ -258,6 +239,24 @@ } return this.nonJavaResources; } + + private void initializePackageNames(IPackageFragmentRoot root, HashSetOfArray fragmentsCache) { + IJavaElement[] frags = null; + try { + if (!root.isOpen()) { + PackageFragmentRootInfo info = root.isArchive() ? new JarPackageFragmentRootInfo() : new PackageFragmentRootInfo(); + ((PackageFragmentRoot) root).computeChildren(info, new HashMap()); + frags = info.children; + } else + frags = root.getChildren(); + } catch (JavaModelException e) { + // root doesn't exist: ignore + return; + } + for (int j = 0, length2 = frags.length; j < length2; j++) { + fragmentsCache.add(((PackageFragment) frags[j]).names); + } + } /* * Returns whether the given path is a classpath entry or an output location. @@ -284,6 +283,57 @@ */ NameLookup newNameLookup(JavaProject project, ICompilationUnit[] workingCopies) { ProjectCache cache = getProjectCache(project); + HashtableOfArrayToObject allPkgFragmentsCache = cache.allPkgFragmentsCache; + if (allPkgFragmentsCache == null) { + HashMap rootInfos = JavaModelManager.getJavaModelManager().deltaState.roots; + IPackageFragmentRoot[] allRoots = cache.allPkgFragmentRootsCache; + int length = allRoots.length; + allPkgFragmentsCache = new HashtableOfArrayToObject(); + for (int i = 0; i < length; i++) { + IPackageFragmentRoot root = allRoots[i]; + DeltaProcessor.RootInfo rootInfo = (DeltaProcessor.RootInfo) rootInfos.get(root.getPath()); + JavaProject rootProject = rootInfo == null ? project : rootInfo.project; + HashSetOfArray fragmentsCache; + if (rootProject.equals(project)) { + // retrieve package fragments cache from this project + fragmentsCache = (HashSetOfArray) cache.pkgFragmentsCaches.get(root); + } else { + // retrieve package fragments cache from the root's project + ProjectCache rootProjectCache; + try { + rootProjectCache = rootProject.getProjectCache(); + } catch (JavaModelException e) { + // project doesn't exit + continue; + } + fragmentsCache = (HashSetOfArray) rootProjectCache.pkgFragmentsCaches.get(root); + } + Object[][] set = fragmentsCache.set; + for (int j = 0, length2 = set.length; j < length2; j++) { + String[] pkgName = (String[]) set[j]; + if (pkgName == null) + continue; + Object existing = allPkgFragmentsCache.get(pkgName); + if (existing == null || existing == NO_ROOTS) { + allPkgFragmentsCache.put(pkgName, root); + // ensure super packages (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=119161) + // are also in the map + addSuperPackageNames(pkgName, allPkgFragmentsCache); + } else { + if (existing instanceof PackageFragmentRoot) { + allPkgFragmentsCache.put(pkgName, new IPackageFragmentRoot[] {(PackageFragmentRoot) existing, root}); + } else { + IPackageFragmentRoot[] roots = (IPackageFragmentRoot[]) existing; + int rootLength = roots.length; + System.arraycopy(roots, 0, roots = new IPackageFragmentRoot[rootLength+1], 0, rootLength); + roots[rootLength] = root; + allPkgFragmentsCache.put(pkgName, roots); + } + } + } + } + cache.allPkgFragmentsCache = allPkgFragmentsCache; + } return new NameLookup(cache.allPkgFragmentRootsCache, cache.allPkgFragmentsCache, workingCopies, cache.rootToResolvedEntries); } Index: model/org/eclipse/jdt/internal/core/util/HashSetOfArray.java =================================================================== RCS file: model/org/eclipse/jdt/internal/core/util/HashSetOfArray.java diff -N model/org/eclipse/jdt/internal/core/util/HashSetOfArray.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ model/org/eclipse/jdt/internal/core/util/HashSetOfArray.java 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,149 @@ +/******************************************************************************* + * Copyright (c) 2000, 2007 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.core.util; + +/** + * HashSet of Object[] + */ +public final class HashSetOfArray implements Cloneable { + + // to avoid using Enumerations, walk the individual tables skipping nulls + public Object[][] set; + + public int elementSize; // number of elements in the table + int threshold; + + public HashSetOfArray() { + this(13); + } + + public HashSetOfArray(int size) { + + this.elementSize = 0; + this.threshold = size; // size represents the expected number of elements + int extraRoom = (int) (size * 1.75f); + if (this.threshold == extraRoom) + extraRoom++; + this.set = new Object[extraRoom][]; + } + + public Object clone() throws CloneNotSupportedException { + HashSetOfArray result = (HashSetOfArray) super.clone(); + result.elementSize = this.elementSize; + result.threshold = this.threshold; + + int length = this.set.length; + result.set = new Object[length][]; + System.arraycopy(this.set, 0, result.set, 0, length); + + return result; + } + + public boolean contains(Object[] array) { + int length = this.set.length; + int index = hashCode(array) % length; + int arrayLength = array.length; + Object[] currentArray; + while ((currentArray = this.set[index]) != null) { + if (currentArray.length == arrayLength && Util.equalArraysOrNull(currentArray, array)) + return true; + if (++index == length) { + index = 0; + } + } + return false; + } + + private int hashCode(Object[] element) { + return hashCode(element, element.length); + } + + private int hashCode(Object[] element, int length) { + int hash = 0; + for (int i = length-1; i >= 0; i--) + hash = Util.combineHashCodes(hash, element[i].hashCode()); + return hash & 0x7FFFFFFF; + } + + public Object add(Object[] array) { + int length = this.set.length; + int index = hashCode(array) % length; + int arrayLength = array.length; + Object[] currentArray; + while ((currentArray = this.set[index]) != null) { + if (currentArray.length == arrayLength && Util.equalArraysOrNull(currentArray, array)) + return this.set[index] = array; + if (++index == length) { + index = 0; + } + } + this.set[index] = array; + + // assumes the threshold is never equal to the size of the table + if (++this.elementSize > threshold) + rehash(); + return array; + } + + public Object remove(Object[] array) { + int length = this.set.length; + int index = hashCode(array) % length; + int arrayLength = array.length; + Object[] currentArray; + while ((currentArray = this.set[index]) != null) { + if (currentArray.length == arrayLength && Util.equalArraysOrNull(currentArray, array)) { + Object existing = this.set[index]; + this.elementSize--; + this.set[index] = null; + rehash(); + return existing; + } + if (++index == length) { + index = 0; + } + } + return null; + } + + private void rehash() { + + HashSetOfArray newHashSet = new HashSetOfArray(elementSize * 2); // double the number of expected elements + Object[] currentArray; + for (int i = this.set.length; --i >= 0;) + if ((currentArray = this.set[i]) != null) + newHashSet.add(currentArray); + + this.set = newHashSet.set; + this.threshold = newHashSet.threshold; + } + + public int size() { + return elementSize; + } + + public String toString() { + StringBuffer buffer = new StringBuffer(); + Object[] element; + for (int i = 0, length = this.set.length; i < length; i++) + if ((element = this.set[i]) != null) { + buffer.append('{'); + for (int j = 0, length2 = element.length; j < length2; j++) { + buffer.append(element[j]); + if (j != length2-1) + buffer.append(", "); //$NON-NLS-1$ + } + buffer.append("}"); //$NON-NLS-1$ + if (i != length-1) + buffer.append('\n'); + } + return buffer.toString(); + } +}