### Eclipse Workspace Patch 1.0 #P org.eclipse.jdt.core Index: search/org/eclipse/jdt/internal/core/search/indexing/InternalSearchDocument.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/search/org/eclipse/jdt/internal/core/search/indexing/InternalSearchDocument.java,v retrieving revision 1.5 diff -u -r1.5 InternalSearchDocument.java --- search/org/eclipse/jdt/internal/core/search/indexing/InternalSearchDocument.java 5 Dec 2005 15:52:20 -0000 1.5 +++ search/org/eclipse/jdt/internal/core/search/indexing/InternalSearchDocument.java 7 Dec 2005 11:03:56 -0000 @@ -30,8 +30,8 @@ if (length > 1 && key[length-2] == IIndexConstants.SEPARATOR && key[length-1] == IIndexConstants.SECONDARY_SUFFIX ) { // This is a key of a secondary type => reset java model manager secondary types cache for document path project JavaModelManager manager = JavaModelManager.getJavaModelManager(); - manager.resetSecondaryTypesCache(getPath()); -// manager.addSecondaryType(getPath(), key); +// manager.resetSecondaryTypesCache(getPath()); + manager.addSecondaryType(getPath(), key); } } } Index: model/org/eclipse/jdt/internal/core/JavaModelManager.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/JavaModelManager.java,v retrieving revision 1.310 diff -u -r1.310 JavaModelManager.java --- model/org/eclipse/jdt/internal/core/JavaModelManager.java 6 Dec 2005 10:00:18 -0000 1.310 +++ model/org/eclipse/jdt/internal/core/JavaModelManager.java 7 Dec 2005 11:03:56 -0000 @@ -169,7 +169,7 @@ private static final String ENABLE_NEW_FORMATTER = JavaCore.PLUGIN_ID + "/formatter/enable_new" ; //$NON-NLS-1$ - private final static String DIRTY_CACHE = "***dirty***"; //$NON-NLS-1$ + private final static String INDEXING_CACHE = "#@*indexing*@#"; //$NON-NLS-1$ private final static HashMap NO_SECONDARY_TYPES = new HashMap(0); public static boolean PERF_VARIABLE_INITIALIZER = false; @@ -1463,8 +1463,8 @@ } } - // Return cache if not empty and not dirty - if (projectInfo.secondaryTypes != null && projectInfo.secondaryTypes.get(DIRTY_CACHE) == null) { + // Return cache if not empty and there's indexing cache + if (projectInfo.secondaryTypes != null && projectInfo.secondaryTypes.get(INDEXING_CACHE) == null) { return projectInfo.secondaryTypes; } @@ -1473,7 +1473,12 @@ if (projectInfo.secondaryTypes == null) { return NO_SECONDARY_TYPES; // cache is not initialized return empty one } - return projectInfo.secondaryTypes; // cache is dirty => return current one... + return projectInfo.secondaryTypes; // there's an indexing cache => return current one... + } + + // If cache not null, then return it merged with indexing cache + if (projectInfo.secondaryTypes != null) { + return getSecondaryTypesMerged(projectInfo.secondaryTypes); } // Init variables for search @@ -1503,15 +1508,6 @@ // Search all secondary types on scope new BasicSearchEngine().searchAllSecondaryTypeNames(allSourceFolders, nameRequestor, monitor); - if (VERBOSE) { - System.out.print(Thread.currentThread() + " -> secondary paths: "); //$NON-NLS-1$ - System.out.println(); - Iterator keys = secondaryTypes.keySet().iterator(); - while (keys.hasNext()) { - String qualifiedName = (String) keys.next(); - Util.verbose(" - "+qualifiedName+'-'+secondaryTypes.get(qualifiedName) ); //$NON-NLS-1$ - } - } // Build types from paths Iterator packages = secondaryTypes.keySet().iterator(); @@ -1531,12 +1527,79 @@ } } - // Store result in per project info cache if still null or dirty (may have been set by another thread...) - if (projectInfo.secondaryTypes == null || projectInfo.secondaryTypes.get(DIRTY_CACHE) != null) { + // Store result in per project info cache if still null or there's still an indexing cache (may have been set by another thread...) + if (projectInfo.secondaryTypes == null || projectInfo.secondaryTypes.get(INDEXING_CACHE) != null) { projectInfo.secondaryTypes = secondaryTypes; + if (VERBOSE) { + System.out.print(Thread.currentThread() + " -> secondary paths stored in cache: "); //$NON-NLS-1$ + System.out.println(); + Iterator keys = secondaryTypes.keySet().iterator(); + while (keys.hasNext()) { + String qualifiedName = (String) keys.next(); + Util.verbose(" - "+qualifiedName+'-'+secondaryTypes.get(qualifiedName) ); //$NON-NLS-1$ + } + } } return projectInfo.secondaryTypes; } + + /* + * Return secondary types cache merged with cached done while indexing was runnning. + * Note that result of merged is directly stored in given parameter map. + */ + private HashMap getSecondaryTypesMerged(HashMap secondaryTypes) { + if (VERBOSE) { + Util.verbose("JavaModelManager.getSecondaryTypesMerged()"); //$NON-NLS-1$ + Util.verbose(" - current cache to merge:"); //$NON-NLS-1$ + Iterator keys = secondaryTypes.keySet().iterator(); + while (keys.hasNext()) { + String packName = (String) keys.next(); + Util.verbose(" + "+packName+':'+secondaryTypes.get(packName) ); //$NON-NLS-1$ + } + } + + // Return current cache if there's no indexing cache + HashMap indexingCache = (HashMap) secondaryTypes.remove(INDEXING_CACHE); + if (indexingCache == null) { + return secondaryTypes; + } + + // Merge indexing cache in secondary types one + Iterator indexedFiles = indexingCache.keySet().iterator(); + while (indexedFiles.hasNext()) { + IFile indexedFile = (IFile) indexedFiles.next(); + + // Remove all secondary types of indexed file from cache + removeFromSecondaryTypesMap(secondaryTypes, indexedFile); + + // Add all indexing file secondary types in given secondary types cache + HashMap allIndexedTypes = (HashMap) indexingCache.get(indexedFile); + Iterator indexedPackages = allIndexedTypes.keySet().iterator(); + while (indexedPackages.hasNext()) { + String indexedPackage = (String) indexedPackages.next(); + HashMap types = (HashMap) secondaryTypes.get(indexedPackage); + if (types == null) { + secondaryTypes.put(indexedPackage, allIndexedTypes.get(indexedPackage)); + } else { + HashMap indexedTypes = (HashMap) allIndexedTypes.get(indexedPackage); + Iterator indexedTypeNames = indexedTypes.keySet().iterator(); + while (indexedTypeNames.hasNext()) { + String indexedTypeName = (String) indexedTypeNames.next(); + types.put(indexedTypeName, indexedTypes.get(indexedTypeName)); + } + } + } + } + if (VERBOSE) { + Util.verbose(" - secondary types cache merged:"); //$NON-NLS-1$ + Iterator keys = secondaryTypes.keySet().iterator(); + while (keys.hasNext()) { + String packName = (String) keys.next(); + Util.verbose(" + "+packName+':'+secondaryTypes.get(packName) ); //$NON-NLS-1$ + } + } + return secondaryTypes; + } /** * Returns the temporary cache for newly opened elements for the current thread. @@ -2401,9 +2464,9 @@ * * @param file File to remove */ - public void removeFromSecondaryTypesCache(IFile file) { + public void removeFromSecondaryTypesCache(IFile file, boolean cleanIndexCache) { if (VERBOSE) { - StringBuffer buffer = new StringBuffer("JavaModelManager.removeSecondaryTypePaths("); //$NON-NLS-1$ + StringBuffer buffer = new StringBuffer("JavaModelManager.removeFromSecondaryTypesCache("); //$NON-NLS-1$ buffer.append(file.getName()); buffer.append(')'); Util.verbose(buffer.toString()); @@ -2414,43 +2477,110 @@ if (VERBOSE) { Util.verbose("-> remove file from cache of project: "+file.getProject().getName()); //$NON-NLS-1$ } - Iterator packages = projectInfo.secondaryTypes.keySet().iterator(); - while (packages.hasNext()) { - String packName = (String) packages.next(); - Object object = projectInfo.secondaryTypes.get(packName); - if (object instanceof HashMap) { - HashMap types = (HashMap) object; - Iterator names = types.keySet().iterator(); - while (names.hasNext()) { - String typeName = (String) names.next(); - IType type = (IType) types.get(typeName); - if (file.equals(type.getResource())) { - types.remove(typeName); - if (types.size() == 0) { - projectInfo.secondaryTypes.remove(packName); - } - return; - } + + // Clean current cache + removeFromSecondaryTypesMap(projectInfo.secondaryTypes, file); + + // Clean indexing cache if necessary + if (!cleanIndexCache) return; + HashMap indexingCache = (HashMap) projectInfo.secondaryTypes.get(INDEXING_CACHE); + if (indexingCache != null) { + Set keys = indexingCache.keySet(); + int filesSize = keys.size(), filesCount = 0; + IFile[] removed = null; + Iterator cachedFiles = keys.iterator(); + while (cachedFiles.hasNext()) { + IFile cachedFile = (IFile) cachedFiles.next(); + if (file.equals(cachedFile)) { + if (removed == null) removed = new IFile[filesSize]; + filesSize--; + removed[filesCount++] = cachedFile; } } + for (int i=0; i reset cache for project: "+resource.getProject().getName()); //$NON-NLS-1$ + // Get or create map for indexing cache + HashMap indexingCache = null; + if (projectInfo.secondaryTypes == null) { + projectInfo.secondaryTypes = new HashMap(3); + indexingCache = new HashMap(3); + projectInfo.secondaryTypes.put(INDEXING_CACHE, indexingCache); + } else { + indexingCache = (HashMap) projectInfo.secondaryTypes.get(INDEXING_CACHE); + if (indexingCache == null) { + indexingCache = new HashMap(3); + projectInfo.secondaryTypes.put(INDEXING_CACHE, indexingCache); + } + } + // Store secondary type in indexing cache + if (org.eclipse.jdt.internal.core.util.Util.isJavaLikeFileName(path) && resource.getType() == IResource.FILE) { + HashMap allTypes = (HashMap) indexingCache.get(resource); + if (allTypes == null) { + allTypes = new HashMap(3); + indexingCache.put(resource, allTypes); + } + ICompilationUnit unit = JavaModelManager.createCompilationUnitFrom((IFile)resource, null); + if (unit != null) { + char[][] names = CharOperation.splitOn('/', key); + String typeName = new String(names[0]); + String packName = new String(names[1]); + HashMap packageTypes = (HashMap) allTypes.get(packName); + if (packageTypes == null) { + packageTypes = new HashMap(3); + allTypes.put(packName, packageTypes); + } + packageTypes.put(typeName, unit.getType(typeName)); + } } - if (projectInfo.secondaryTypes != null) { - Object dirty = projectInfo.secondaryTypes.get(DIRTY_CACHE); - if (dirty == null) { - projectInfo.secondaryTypes.put(DIRTY_CACHE, resource); - } else { - HashSet resources = (dirty instanceof HashSet) ? (HashSet) dirty : new HashSet(3); - resources.add(resource); - projectInfo.secondaryTypes.put(DIRTY_CACHE, resource); + if (VERBOSE) { + Util.verbose(" - indexing cache:"); //$NON-NLS-1$ + Iterator keys = indexingCache.keySet().iterator(); + while (keys.hasNext()) { + IFile file = (IFile) keys.next(); + Util.verbose(" + "+file.getFullPath()+':'+indexingCache.get(file) ); //$NON-NLS-1$ } } } Index: model/org/eclipse/jdt/internal/core/DeltaProcessor.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/DeltaProcessor.java,v retrieving revision 1.271 diff -u -r1.271 DeltaProcessor.java --- model/org/eclipse/jdt/internal/core/DeltaProcessor.java 25 Nov 2005 16:44:45 -0000 1.271 +++ model/org/eclipse/jdt/internal/core/DeltaProcessor.java 7 Dec 2005 11:03:54 -0000 @@ -2398,10 +2398,11 @@ break; case IResourceDelta.ADDED : indexManager.addSource(file, file.getProject().getFullPath()); + this.manager.removeFromSecondaryTypesCache(file, false); break; case IResourceDelta.REMOVED : indexManager.remove(Util.relativePath(file.getFullPath(), 1/*remove project segment*/), file.getProject().getFullPath()); - this.manager.removeFromSecondaryTypesCache(file); + this.manager.removeFromSecondaryTypesCache(file, true); break; } } #P org.eclipse.jdt.core.tests.model Index: src/org/eclipse/jdt/core/tests/model/ReconcilerTests.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/ReconcilerTests.java,v retrieving revision 1.75 diff -u -r1.75 ReconcilerTests.java --- src/org/eclipse/jdt/core/tests/model/ReconcilerTests.java 5 Dec 2005 15:52:04 -0000 1.75 +++ src/org/eclipse/jdt/core/tests/model/ReconcilerTests.java 7 Dec 2005 11:04:05 -0000 @@ -104,7 +104,7 @@ assertProblems(message, expected, this.problemRequestor); } // Expect no error as soon as indexing is finished -protected void assertNoProblem(char[] source) throws InterruptedException, JavaModelException { +protected void assertNoProblem(char[] source, ICompilationUnit unit) throws InterruptedException, JavaModelException { IndexManager indexManager = JavaModelManager.getJavaModelManager().getIndexManager(); if (this.problemRequestor.problemCount > 0) { // If errors then wait for indexes to finish @@ -113,7 +113,7 @@ } // Reconcile again to see if error goes away this.problemRequestor.initialize(source); - this.workingCopy.reconcile(AST.JLS3, true, null, null); + unit.reconcile(AST.JLS3, true, null, null); if (this.problemRequestor.problemCount > 0) { assertEquals("Working copy should NOT have any problem!", "", this.problemRequestor.problems.toString()); } @@ -2499,7 +2499,6 @@ /** * Bug 36032:[plan] JavaProject.findType() fails to find second type in source file * @see "https://bugs.eclipse.org/bugs/show_bug.cgi?id=36032" - * */ public void testBug36032a() throws CoreException, InterruptedException { try { @@ -2526,7 +2525,7 @@ this.workingCopy = getCompilationUnit("/P/Test.java").getWorkingCopy(new WorkingCopyOwner() {}, problemRequestor, null); this.workingCopy.getBuffer().setContents(source); this.workingCopy.reconcile(AST.JLS3, true, null, null); - assertNoProblem(sourceChars); + assertNoProblem(sourceChars, this.workingCopy); // Add new secondary type this.createFile( @@ -2546,7 +2545,7 @@ this.problemRequestor.initialize(sourceChars); this.workingCopy.getBuffer().setContents(source); this.workingCopy.reconcile(AST.JLS3, true, null, null); - assertNoProblem(sourceChars); + assertNoProblem(sourceChars, this.workingCopy); } finally { deleteProject("P"); } @@ -2581,7 +2580,7 @@ this.workingCopy = getCompilationUnit("/P/Test.java").getWorkingCopy(new WorkingCopyOwner() {}, this.problemRequestor, null); this.workingCopy.getBuffer().setContents(source); this.workingCopy.reconcile(AST.JLS3, true, null, null); - assertNoProblem(sourceChars); + assertNoProblem(sourceChars, this.workingCopy); // Delete secondary type => should get a problem waitUntilIndexesReady(); @@ -2609,7 +2608,7 @@ this.problemRequestor.initialize(sourceChars); this.workingCopy.getBuffer().setContents(source); this.workingCopy.reconcile(AST.JLS3, true, null, null); - assertNoProblem(sourceChars); + assertNoProblem(sourceChars, this.workingCopy); } finally { deleteProject("P"); } @@ -2656,10 +2655,77 @@ this.workingCopy = getCompilationUnit("/P2/test/Test2.java").getWorkingCopy(new WorkingCopyOwner() {}, this.problemRequestor, null); this.workingCopy.getBuffer().setContents(source); this.workingCopy.reconcile(AST.JLS3, true, null, null); - assertNoProblem(sourceChars); + assertNoProblem(sourceChars, this.workingCopy); } finally { deleteProject("P1"); deleteProject("P2"); } } +/** + * Bug 118823: [model] Secondary types cache not reset while removing _all_ secondary types from CU + * @see "https://bugs.eclipse.org/bugs/show_bug.cgi?id=118823" + */ +public void testBug118823a() throws CoreException, InterruptedException { + try { + // Resources creation + createJavaProject("P", new String[] {""}, new String[] {"JCL_LIB"}, "bin"); + String[] sources = { + "/P/Test.java", + "public class Test {}\n" + + "class Secondary{}\n", + "/P/A.java", + "class X {\n" + + " Secondary s;\n" + + "}\n" + }; + int length = sources.length / 2; + this.workingCopies = new ICompilationUnit[length]; + this.wcOwner = new WorkingCopyOwner() {}; + for (int i=0; i should get a problem + String source = "public class Test {}\n"; + char[] sourceChars = source.toCharArray(); + this.problemRequestor.initialize(sourceChars); + this.workingCopies[0].getBuffer().setContents(source); + this.workingCopies[0].reconcile(AST.JLS3, true, null, null); + assertNoProblem(sourceChars, this.workingCopies[0]); + sourceChars = sources[3].toCharArray(); + this.problemRequestor.initialize(sourceChars); + this.workingCopies[1].getBuffer().setContents(sources[3]); + this.workingCopies[1].reconcile(AST.JLS3, true, null, null); + assertEquals("Working copy should not find secondary type 'Secondary'!", 1, this.problemRequestor.problemCount); + assertProblems("Working copy should have problem!", + "----------\n" + + "1. ERROR in /P/A.java (at line 2)\n" + + " Secondary s;\n" + + " ^^^^^^^^^\n" + + "Secondary cannot be resolved to a type\n" + + "----------\n" + ); + + // Put back secondary type declaration from cu => problem should go away + for (int i=0; i [in [in P]]]]", + type.toString() + ); + + // Delete file and recreate it without secondary + deleteFile("/P/Test.java"); + createFile( + "/P/Test.java", + "public class X {}\n" + ); + + // Verify that secondary is NOT found + type = javaProject.findType("", "Secondary", new NullProgressMonitor()); + assertTrue("type 'Secondary' should NOT exist!", type == null); + } finally { + deleteProject("P"); + } +} }