View | Details | Raw Unified | Return to bug 182930 | Differences between
and this patch

Collapse All | Expand All

(-)model/org/eclipse/jdt/internal/core/JavaProject.java (+5 lines)
Lines 63-68 Link Here
63
import org.eclipse.jdt.core.eval.IEvaluationContext;
63
import org.eclipse.jdt.core.eval.IEvaluationContext;
64
import org.eclipse.jdt.internal.compiler.util.ObjectVector;
64
import org.eclipse.jdt.internal.compiler.util.ObjectVector;
65
import org.eclipse.jdt.internal.compiler.util.SuffixConstants;
65
import org.eclipse.jdt.internal.compiler.util.SuffixConstants;
66
import org.eclipse.jdt.internal.core.JavaProjectElementInfo.ProjectCache;
66
import org.eclipse.jdt.internal.core.eval.EvaluationContextWrapper;
67
import org.eclipse.jdt.internal.core.eval.EvaluationContextWrapper;
67
import org.eclipse.jdt.internal.core.util.MementoTokenizer;
68
import org.eclipse.jdt.internal.core.util.MementoTokenizer;
68
import org.eclipse.jdt.internal.core.util.Messages;
69
import org.eclipse.jdt.internal.core.util.Messages;
Lines 1945-1950 Link Here
1945
	public IProject getProject() {
1946
	public IProject getProject() {
1946
		return this.project;
1947
		return this.project;
1947
	}
1948
	}
1949
	
1950
	public ProjectCache getProjectCache() throws JavaModelException {
1951
		return ((JavaProjectElementInfo) getElementInfo()).getProjectCache(this);
1952
	}
1948
1953
1949
	/**
1954
	/**
1950
	 * @see IJavaProject
1955
	 * @see IJavaProject
(-)model/org/eclipse/jdt/internal/core/JavaProjectElementInfo.java (-51 / +103 lines)
Lines 18-23 Link Here
18
import org.eclipse.core.runtime.CoreException;
18
import org.eclipse.core.runtime.CoreException;
19
import org.eclipse.core.runtime.IPath;
19
import org.eclipse.core.runtime.IPath;
20
import org.eclipse.jdt.core.*;
20
import org.eclipse.jdt.core.*;
21
import org.eclipse.jdt.internal.core.util.HashSetOfArray;
21
import org.eclipse.jdt.internal.core.util.Util;
22
import org.eclipse.jdt.internal.core.util.Util;
22
import org.eclipse.jdt.internal.core.util.HashtableOfArrayToObject;
23
import org.eclipse.jdt.internal.core.util.HashtableOfArrayToObject;
23
24
Lines 33-45 Link Here
33
34
34
/* package */
35
/* package */
35
class JavaProjectElementInfo extends OpenableElementInfo {
36
class JavaProjectElementInfo extends OpenableElementInfo {
37
	
38
	static final IPackageFragmentRoot[] NO_ROOTS = new IPackageFragmentRoot[0];
36
39
37
	static class ProjectCache {
40
	static class ProjectCache {
38
		ProjectCache(IPackageFragmentRoot[] allPkgFragmentRootsCache, HashtableOfArrayToObject allPkgFragmentsCache, HashtableOfArrayToObject isPackageCache, Map rootToResolvedEntries) {
41
		ProjectCache(IPackageFragmentRoot[] allPkgFragmentRootsCache, Map rootToResolvedEntries, Map pkgFragmentsCaches) {
39
			this.allPkgFragmentRootsCache = allPkgFragmentRootsCache;
42
			this.allPkgFragmentRootsCache = allPkgFragmentRootsCache;
40
			this.allPkgFragmentsCache = allPkgFragmentsCache;
41
			this.isPackageCache = isPackageCache;
42
			this.rootToResolvedEntries = rootToResolvedEntries;
43
			this.rootToResolvedEntries = rootToResolvedEntries;
44
			this.pkgFragmentsCaches = pkgFragmentsCaches;
43
		}
45
		}
44
		
46
		
45
		/*
47
		/*
Lines 49-63 Link Here
49
		
51
		
50
		/*
52
		/*
51
		 * A cache of all package fragments in this project.
53
		 * A cache of all package fragments in this project.
52
		 * (a map from String[] (the package name) to IPackageFragmentRoot[] (the package fragment roots that contain a package fragment with this name)
54
		 * (a map from String[] (the package name) to IPackageFragmentRoot[] (the package fragment roots that contain a package fragment with this name))
53
		 */
55
		 */
54
		public HashtableOfArrayToObject allPkgFragmentsCache;
56
		public HashtableOfArrayToObject allPkgFragmentsCache;
55
		
57
		
56
		/*
58
		/*
57
		 * A set of package names (String[]) that are known to be packages.
59
		 * A cache of package fragments for each package fragment root of this project
60
		 * (a map from IPackageFragmentRoot to a set of String[] (the package name))
58
		 */
61
		 */
59
		public HashtableOfArrayToObject isPackageCache;
62
		public Map pkgFragmentsCaches;
60
	
63
		
61
		public Map rootToResolvedEntries;		
64
		public Map rootToResolvedEntries;		
62
	}
65
	}
63
	
66
	
Lines 72-84 Link Here
72
	 * Adds the given name and its super names to the given set
75
	 * Adds the given name and its super names to the given set
73
	 * (e.g. for {"a", "b", "c"}, adds {"a", "b", "c"}, {"a", "b"}, and {"a"})
76
	 * (e.g. for {"a", "b", "c"}, adds {"a", "b", "c"}, {"a", "b"}, and {"a"})
74
	 */
77
	 */
75
	public static void addNames(String[] name, HashtableOfArrayToObject set) {
78
	static void addSuperPackageNames(String[] pkgName, HashtableOfArrayToObject packageFragments) {
76
		set.put(name, name);
79
		for (int i = pkgName.length-1; i > 0; i--) {
77
		int length = name.length;
80
			if (packageFragments.getKey(pkgName, i) == null) {
78
		for (int i = length-1; i > 0; i--) {
81
				System.arraycopy(pkgName, 0, pkgName = new String[i], 0, i);
79
			String[] superName = new String[i];
82
				packageFragments.put(pkgName, NO_ROOTS);
80
			System.arraycopy(name, 0, superName, 0, i);
83
			}
81
			set.put(superName, superName);
82
		}
84
		}
83
	}
85
	}
84
	
86
	
Lines 204-248 Link Here
204
				roots = new IPackageFragmentRoot[0];
206
				roots = new IPackageFragmentRoot[0];
205
				reverseMap.clear();
207
				reverseMap.clear();
206
			}
208
			}
207
			HashtableOfArrayToObject fragmentsCache = new HashtableOfArrayToObject();
209
			
208
			HashtableOfArrayToObject isPackageCache = new HashtableOfArrayToObject();
210
			HashMap rootInfos = JavaModelManager.getJavaModelManager().deltaState.roots;
209
			for (int i = 0, length = roots.length; i < length; i++) {
211
			HashMap pkgFragmentsCaches = new HashMap();
212
			int length = roots.length;
213
			for (int i = 0; i < length; i++) {
210
				IPackageFragmentRoot root = roots[i];
214
				IPackageFragmentRoot root = roots[i];
211
				IJavaElement[] frags = null;
215
				DeltaProcessor.RootInfo rootInfo = (DeltaProcessor.RootInfo) rootInfos.get(root.getPath());
212
				try {
216
				if (rootInfo == null || rootInfo.project.equals(project)) {
213
					if (root.isArchive() && !root.isOpen()) {
217
					// compute fragment cache
214
						JarPackageFragmentRootInfo info = new JarPackageFragmentRootInfo();
218
					HashSetOfArray fragmentsCache = new HashSetOfArray();
215
						((JarPackageFragmentRoot) root).computeChildren(info, new HashMap());
219
					initializePackageNames(root, fragmentsCache);
216
						frags = info.children;
220
					pkgFragmentsCaches.put(root, fragmentsCache);
217
					} else 
218
						frags = root.getChildren();
219
				} catch (JavaModelException e) {
220
					// root doesn't exist: ignore
221
					continue;
222
				}
223
				for (int j = 0, length2 = frags.length; j < length2; j++) {
224
					PackageFragment fragment= (PackageFragment) frags[j];
225
					String[] pkgName = fragment.names;
226
					Object existing = fragmentsCache.get(pkgName);
227
					if (existing == null) {
228
						fragmentsCache.put(pkgName, root);
229
						// cache whether each package and its including packages (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=119161)
230
						// are actual packages
231
						addNames(pkgName, isPackageCache);
232
					} else {
233
						if (existing instanceof PackageFragmentRoot) {
234
							fragmentsCache.put(pkgName, new IPackageFragmentRoot[] {(PackageFragmentRoot) existing, root});
235
						} else {
236
							IPackageFragmentRoot[] entry= (IPackageFragmentRoot[]) existing;
237
							IPackageFragmentRoot[] copy= new IPackageFragmentRoot[entry.length + 1];
238
							System.arraycopy(entry, 0, copy, 0, entry.length);
239
							copy[entry.length]= root;
240
							fragmentsCache.put(pkgName, copy);
241
						}
242
					}
243
				}
221
				}
244
			}
222
			}
245
			cache = new ProjectCache(roots, fragmentsCache, isPackageCache, reverseMap);
223
			
224
			cache = new ProjectCache(roots, reverseMap, pkgFragmentsCaches);
246
			this.projectCache = cache;
225
			this.projectCache = cache;
247
		}
226
		}
248
		return cache;
227
		return cache;
Lines 258-263 Link Here
258
		}
237
		}
259
		return this.nonJavaResources;
238
		return this.nonJavaResources;
260
	}
239
	}
240
	
241
	private void initializePackageNames(IPackageFragmentRoot root, HashSetOfArray fragmentsCache) {
242
		IJavaElement[] frags = null;
243
		try {
244
			if (!root.isOpen()) {
245
				PackageFragmentRootInfo info = root.isArchive() ? new JarPackageFragmentRootInfo() : new PackageFragmentRootInfo();
246
				((PackageFragmentRoot) root).computeChildren(info, new HashMap());
247
				frags = info.children;
248
			} else 
249
				frags = root.getChildren();
250
		} catch (JavaModelException e) {
251
			// root doesn't exist: ignore
252
			return;
253
		}
254
		for (int j = 0, length2 = frags.length; j < length2; j++) {
255
			fragmentsCache.add(((PackageFragment) frags[j]).names);
256
		}
257
	}
261
258
262
	/*
259
	/*
263
	 * Returns whether the given path is a classpath entry or an output location.
260
	 * Returns whether the given path is a classpath entry or an output location.
Lines 284-290 Link Here
284
	 */
281
	 */
285
	NameLookup newNameLookup(JavaProject project, ICompilationUnit[] workingCopies) {
282
	NameLookup newNameLookup(JavaProject project, ICompilationUnit[] workingCopies) {
286
		ProjectCache cache = getProjectCache(project);
283
		ProjectCache cache = getProjectCache(project);
287
		return new NameLookup(cache.allPkgFragmentRootsCache, cache.allPkgFragmentsCache, cache.isPackageCache, workingCopies, cache.rootToResolvedEntries);
284
		HashtableOfArrayToObject allPkgFragmentsCache = cache.allPkgFragmentsCache;
285
		if (allPkgFragmentsCache == null) {
286
			HashMap rootInfos = JavaModelManager.getJavaModelManager().deltaState.roots;
287
			IPackageFragmentRoot[] allRoots = cache.allPkgFragmentRootsCache;
288
			int length = allRoots.length;
289
			allPkgFragmentsCache = new HashtableOfArrayToObject();
290
			for (int i = 0; i < length; i++) {
291
				IPackageFragmentRoot root = allRoots[i];
292
				DeltaProcessor.RootInfo rootInfo = (DeltaProcessor.RootInfo) rootInfos.get(root.getPath());
293
				JavaProject rootProject = rootInfo == null ? project : rootInfo.project;
294
				HashSetOfArray fragmentsCache;
295
				if (rootProject.equals(project)) {
296
					// retrieve package fragments cache from this project
297
					fragmentsCache = (HashSetOfArray) cache.pkgFragmentsCaches.get(root);
298
				} else {
299
					// retrieve package fragments  cache from the root's project
300
					ProjectCache rootProjectCache;
301
					try {
302
						rootProjectCache = rootProject.getProjectCache();
303
					} catch (JavaModelException e) {
304
						// project doesn't exit
305
						continue;
306
					}
307
					fragmentsCache = (HashSetOfArray) rootProjectCache.pkgFragmentsCaches.get(root);
308
				}
309
				if (fragmentsCache == null) { // see https://bugs.eclipse.org/bugs/show_bug.cgi?id=183833
310
					fragmentsCache = new HashSetOfArray();
311
					initializePackageNames(root, fragmentsCache);
312
				}
313
				Object[][] set = fragmentsCache.set;
314
				for (int j = 0, length2 = set.length; j < length2; j++) {
315
					String[] pkgName = (String[]) set[j];
316
					if (pkgName == null)
317
						continue;
318
					Object existing = allPkgFragmentsCache.get(pkgName);
319
					if (existing == null || existing == NO_ROOTS) {
320
						allPkgFragmentsCache.put(pkgName, root);
321
						// ensure super packages (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=119161)
322
						// are also in the map
323
						addSuperPackageNames(pkgName, allPkgFragmentsCache);
324
					} else {
325
						if (existing instanceof PackageFragmentRoot) {
326
							allPkgFragmentsCache.put(pkgName, new IPackageFragmentRoot[] {(PackageFragmentRoot) existing, root});
327
						} else {
328
							IPackageFragmentRoot[] roots = (IPackageFragmentRoot[]) existing;
329
							int rootLength = roots.length;
330
							System.arraycopy(roots, 0, roots = new IPackageFragmentRoot[rootLength+1], 0, rootLength);
331
							roots[rootLength] = root;
332
							allPkgFragmentsCache.put(pkgName, roots);
333
						}
334
					}
335
				}
336
			}
337
			cache.allPkgFragmentsCache = allPkgFragmentsCache;
338
		}
339
		return new NameLookup(cache.allPkgFragmentRootsCache, cache.allPkgFragmentsCache, workingCopies, cache.rootToResolvedEntries);
288
	}
340
	}
289
	
341
	
290
	/*
342
	/*
(-)model/org/eclipse/jdt/internal/core/NameLookup.java (-14 / +5 lines)
Lines 125-136 Link Here
125
	 */
125
	 */
126
	protected HashtableOfArrayToObject packageFragments;
126
	protected HashtableOfArrayToObject packageFragments;
127
	
127
	
128
	/*
129
	 * A set of names (String[]) that are known to be package names.
130
	 * Value is not null for known package.
131
	 */
132
	protected HashtableOfArrayToObject isPackageCache;
133
134
	/**
128
	/**
135
	 * Reverse map from root path to corresponding resolved CP entry
129
	 * Reverse map from root path to corresponding resolved CP entry
136
	 * (so as to be able to figure inclusion/exclusion rules)
130
	 * (so as to be able to figure inclusion/exclusion rules)
Lines 149-155 Link Here
149
	public NameLookup(
143
	public NameLookup(
150
			IPackageFragmentRoot[] packageFragmentRoots, 
144
			IPackageFragmentRoot[] packageFragmentRoots, 
151
			HashtableOfArrayToObject packageFragments, 
145
			HashtableOfArrayToObject packageFragments, 
152
			HashtableOfArrayToObject isPackage, 
153
			ICompilationUnit[] workingCopies, 
146
			ICompilationUnit[] workingCopies, 
154
			Map rootToResolvedEntries) {
147
			Map rootToResolvedEntries) {
155
		long start = -1;
148
		long start = -1;
Lines 163-174 Link Here
163
		this.packageFragmentRoots = packageFragmentRoots;
156
		this.packageFragmentRoots = packageFragmentRoots;
164
		if (workingCopies == null) {
157
		if (workingCopies == null) {
165
			this.packageFragments = packageFragments;
158
			this.packageFragments = packageFragments;
166
			this.isPackageCache = isPackage;
167
		} else {
159
		} else {
168
			// clone tables as we're adding packages from working copies
160
			// clone tables as we're adding packages from working copies
169
			try {
161
			try {
170
				this.packageFragments = (HashtableOfArrayToObject) packageFragments.clone();
162
				this.packageFragments = (HashtableOfArrayToObject) packageFragments.clone();
171
				this.isPackageCache = (HashtableOfArrayToObject) isPackage.clone();
172
			} catch (CloneNotSupportedException e1) {
163
			} catch (CloneNotSupportedException e1) {
173
				// ignore (implementation of HashtableOfArrayToObject supports cloning)
164
				// ignore (implementation of HashtableOfArrayToObject supports cloning)
174
			}
165
			}
Lines 213-223 Link Here
213
				IPackageFragmentRoot root = (IPackageFragmentRoot) pkg.getParent();
204
				IPackageFragmentRoot root = (IPackageFragmentRoot) pkg.getParent();
214
				String[] pkgName = pkg.names;
205
				String[] pkgName = pkg.names;
215
				Object existing = this.packageFragments.get(pkgName);
206
				Object existing = this.packageFragments.get(pkgName);
216
				if (existing == null) {
207
				if (existing == null || existing == JavaProjectElementInfo.NO_ROOTS) {
217
					this.packageFragments.put(pkgName, root);
208
					this.packageFragments.put(pkgName, root);
218
					// cache whether each package and its including packages (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=119161)
209
					// ensure super packages (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=119161)
219
					// are actual packages
210
					// are also in the map
220
					JavaProjectElementInfo.addNames(pkgName, this.isPackageCache);
211
					JavaProjectElementInfo.addSuperPackageNames(pkgName, this.packageFragments);
221
				} else {
212
				} else {
222
					if (existing instanceof PackageFragmentRoot) {
213
					if (existing instanceof PackageFragmentRoot) {
223
						if (!existing.equals(root))
214
						if (!existing.equals(root))
Lines 778-784 Link Here
778
	}
769
	}
779
	
770
	
780
	public boolean isPackage(String[] pkgName) {
771
	public boolean isPackage(String[] pkgName) {
781
		return this.isPackageCache.get(pkgName) != null;
772
		return this.packageFragments.get(pkgName) != null;
782
	}
773
	}
783
774
784
	/**
775
	/**
(-)model/org/eclipse/jdt/internal/core/util/HashSetOfArray.java (+149 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2000, 2007 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
10
 *******************************************************************************/
11
package org.eclipse.jdt.internal.core.util;
12
13
/**
14
 * HashSet of Object[]
15
 */
16
public final class HashSetOfArray implements Cloneable {
17
	
18
	// to avoid using Enumerations, walk the individual tables skipping nulls
19
	public Object[][] set;
20
21
	public int elementSize; // number of elements in the table
22
	int threshold;
23
24
	public HashSetOfArray() {
25
		this(13);
26
	}
27
28
	public HashSetOfArray(int size) {
29
30
		this.elementSize = 0;
31
		this.threshold = size; // size represents the expected number of elements
32
		int extraRoom = (int) (size * 1.75f);
33
		if (this.threshold == extraRoom)
34
			extraRoom++;
35
		this.set = new Object[extraRoom][];
36
	}
37
38
	public Object clone() throws CloneNotSupportedException {
39
		HashSetOfArray result = (HashSetOfArray) super.clone();
40
		result.elementSize = this.elementSize;
41
		result.threshold = this.threshold;
42
43
		int length = this.set.length;
44
		result.set = new Object[length][];
45
		System.arraycopy(this.set, 0, result.set, 0, length);
46
47
		return result;
48
	}
49
50
	public boolean contains(Object[] array) {
51
		int length = this.set.length;
52
		int index = hashCode(array) % length;
53
		int arrayLength = array.length;
54
		Object[] currentArray;
55
		while ((currentArray = this.set[index]) != null) {
56
			if (currentArray.length == arrayLength && Util.equalArraysOrNull(currentArray, array))
57
				return true;
58
			if (++index == length) {
59
				index = 0;
60
			}
61
		}
62
		return false;
63
	}
64
65
	private int hashCode(Object[] element) {
66
		return hashCode(element, element.length);
67
	}
68
	
69
	private int hashCode(Object[] element, int length) {
70
		int hash = 0;
71
		for (int i = length-1; i >= 0; i--)
72
			hash = Util.combineHashCodes(hash, element[i].hashCode());
73
		return hash & 0x7FFFFFFF;
74
	}
75
	
76
	public Object add(Object[] array) {
77
		int length = this.set.length;
78
		int index = hashCode(array) % length;
79
		int arrayLength = array.length;
80
		Object[] currentArray;
81
		while ((currentArray = this.set[index]) != null) {
82
			if (currentArray.length == arrayLength && Util.equalArraysOrNull(currentArray, array))
83
				return this.set[index] = array;
84
			if (++index == length) {
85
				index = 0;
86
			}
87
		}
88
		this.set[index] = array;
89
90
		// assumes the threshold is never equal to the size of the table
91
		if (++this.elementSize > threshold)
92
			rehash();
93
		return array;
94
	}
95
96
	public Object remove(Object[] array) {
97
		int length = this.set.length;
98
		int index = hashCode(array) % length;
99
		int arrayLength = array.length;
100
		Object[] currentArray;
101
		while ((currentArray = this.set[index]) != null) {
102
			if (currentArray.length == arrayLength && Util.equalArraysOrNull(currentArray, array)) {
103
				Object existing = this.set[index];
104
				this.elementSize--;
105
				this.set[index] = null;
106
				rehash();
107
				return existing;
108
			}
109
			if (++index == length) {
110
				index = 0;
111
			}
112
		}
113
		return null;
114
	}
115
116
	private void rehash() {
117
118
		HashSetOfArray newHashSet = new HashSetOfArray(elementSize * 2);		// double the number of expected elements
119
		Object[] currentArray;
120
		for (int i = this.set.length; --i >= 0;)
121
			if ((currentArray = this.set[i]) != null)
122
				newHashSet.add(currentArray);
123
124
		this.set = newHashSet.set;
125
		this.threshold = newHashSet.threshold;
126
	}
127
128
	public int size() {
129
		return elementSize;
130
	}
131
132
	public String toString() {
133
		StringBuffer buffer = new StringBuffer();
134
		Object[] element;
135
		for (int i = 0, length = this.set.length; i < length; i++)
136
			if ((element = this.set[i]) != null) {
137
				buffer.append('{');
138
				for (int j = 0, length2 = element.length; j < length2; j++) {
139
					buffer.append(element[j]);
140
					if (j != length2-1) 
141
						buffer.append(", "); //$NON-NLS-1$
142
				}
143
				buffer.append("}");  //$NON-NLS-1$
144
				if (i != length-1)
145
					buffer.append('\n');
146
			}
147
		return buffer.toString();
148
	}
149
}

Return to bug 182930