diff --git a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/internal/index/tests/IndexUpdateTests.java b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/internal/index/tests/IndexUpdateTests.java index a3c181ba329..30fbea48661 100644 --- a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/internal/index/tests/IndexUpdateTests.java +++ b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/internal/index/tests/IndexUpdateTests.java @@ -96,7 +96,7 @@ public class IndexUpdateTests extends IndexTestBase { fContentUsed= -1; } IProject project= cpp ? fCppProject.getProject() : fCProject.getProject(); - fFile= TestSourceReader.createFile(project, "header.h", fContents[++fContentUsed].toString()); + fHeader= TestSourceReader.createFile(project, "header.h", fContents[++fContentUsed].toString()); assertTrue(CCorePlugin.getIndexManager().joinIndexer(INDEXER_WAIT_TIME, NPM)); } @@ -711,4 +711,49 @@ public class IndexUpdateTests extends IndexTestBase { } } + // int globalVar; + + // #include "header.h" + // void test() { + // globalVar= 1; + // } + public void testChangingSourceBeforeHeader_Bug171834() throws Exception { + setupHeader(2, true); + setupFile(0, true); + IBinding binding; + ICompositeType ct; + fIndex.acquireReadLock(); + try { + binding = findBinding("globalVar"); + assertTrue(binding instanceof IVariable); + assertEquals(2, fIndex.findNames(binding, IIndex.FIND_ALL_OCCURENCES).length); + } finally { + fIndex.releaseReadLock(); + } + + fFile= TestSourceReader.createFile(fFile.getParent(), fFile.getName(), fContents[1].toString().replaceAll("globalVar", "newVar")); + TestSourceReader.waitUntilFileIsIndexed(fIndex, fFile, INDEXER_WAIT_TIME); + + fIndex.acquireReadLock(); + try { + binding = findBinding("globalVar"); + assertTrue(binding instanceof IVariable); + assertEquals(1, fIndex.findNames(binding, IIndex.FIND_ALL_OCCURENCES).length); + } finally { + fIndex.releaseReadLock(); + } + + fHeader= TestSourceReader.createFile(fHeader.getParent(), fHeader.getName(), fContents[0].toString().replaceAll("globalVar", "newVar")); + TestSourceReader.waitUntilFileIsIndexed(fIndex, fHeader, INDEXER_WAIT_TIME); + assertTrue(CCorePlugin.getIndexManager().joinIndexer(INDEXER_WAIT_TIME, NPM)); + + fIndex.acquireReadLock(); + try { + binding = findBinding("newVar"); + assertTrue(binding instanceof IVariable); + assertEquals(2, fIndex.findNames(binding, IIndex.FIND_ALL_OCCURENCES).length); + } finally { + fIndex.releaseReadLock(); + } + } } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/CModelListener.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/CModelListener.java index c1bfe1cef94..9ffa2eea084 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/CModelListener.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/CModelListener.java @@ -11,12 +11,22 @@ package org.eclipse.cdt.internal.core.pdom; +import java.util.HashMap; +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + import org.eclipse.cdt.core.CCorePlugin; +import org.eclipse.cdt.core.dom.IPDOMIndexer; +import org.eclipse.cdt.core.dom.IPDOMManager; import org.eclipse.cdt.core.model.ElementChangedEvent; import org.eclipse.cdt.core.model.ICElement; import org.eclipse.cdt.core.model.ICElementDelta; import org.eclipse.cdt.core.model.ICProject; import org.eclipse.cdt.core.model.IElementChangedListener; +import org.eclipse.cdt.core.model.ITranslationUnit; +import org.eclipse.cdt.internal.core.pdom.indexer.DeltaAnalyzer; import org.eclipse.core.resources.IResourceChangeEvent; import org.eclipse.core.resources.IResourceChangeListener; import org.eclipse.core.runtime.CoreException; @@ -26,8 +36,14 @@ import org.eclipse.core.runtime.CoreException; * @since 4.0 */ public class CModelListener implements IElementChangedListener, IResourceChangeListener { + private static final int UPDATE_LR_CHANGED_FILES_COUNT = 5; private PDOMManager fManager; + private LinkedHashMap fLRUs= new LinkedHashMap(UPDATE_LR_CHANGED_FILES_COUNT, 0.75f, true) { + protected boolean removeEldestEntry(Map.Entry eldest) { + return size() > UPDATE_LR_CHANGED_FILES_COUNT; + } + }; public CModelListener(PDOMManager manager) { fManager= manager; @@ -38,22 +54,30 @@ public class CModelListener implements IElementChangedListener, IResourceChangeL if (event.getType() != ElementChangedEvent.POST_CHANGE) return; - // Walk the delta sending the subtrees to the appropriate indexers - try { - processDelta(event.getDelta()); - } catch (CoreException e) { - CCorePlugin.log(e); + // Walk the delta collecting tu's per project + HashMap changeMap= new HashMap(); + processDelta(event.getDelta(), changeMap); + + // bug 171834 update last recently changed sources + addLastRecentlyUsed(changeMap); + + for (Iterator it = changeMap.entrySet().iterator(); it.hasNext();) { + Map.Entry entry = (Map.Entry) it.next(); + ICProject cproject = (ICProject) entry.getKey(); + DeltaAnalyzer analyzer= (DeltaAnalyzer) entry.getValue(); + fManager.changeProject(cproject, analyzer.getAddedTUs(), analyzer.getChangedTUs(), analyzer.getRemovedTUs()); } } - private void processDelta(ICElementDelta delta) throws CoreException { + private void processDelta(ICElementDelta delta, HashMap changeMap) { int type = delta.getElement().getElementType(); switch (type) { case ICElement.C_MODEL: // Loop through the children ICElementDelta[] children = delta.getAffectedChildren(); - for (int i = 0; i < children.length; ++i) - processDelta(children[i]); + for (int i = 0; i < children.length; ++i) { + processDelta(children[i], changeMap); + } break; case ICElement.C_PROJECT: // Find the appropriate indexer and pass the delta on @@ -62,12 +86,77 @@ public class CModelListener implements IElementChangedListener, IResourceChangeL case ICElementDelta.ADDED: fManager.addProject(project); break; + case ICElementDelta.CHANGED: - fManager.changeProject(project, delta); + processProjectDelta(project, delta, changeMap); break; + case ICElementDelta.REMOVED: fManager.removeProject(project, delta); - break; + break; + } + } + } + + private void processProjectDelta(ICProject project, ICElementDelta delta, HashMap changeMap) { + IPDOMIndexer indexer = fManager.getIndexer(project); + if (indexer != null && indexer.getID().equals(IPDOMManager.ID_NO_INDEXER)) { + return; + } + + DeltaAnalyzer deltaAnalyzer = new DeltaAnalyzer(); + try { + deltaAnalyzer.analyzeDelta(delta); + } catch (CoreException e) { + CCorePlugin.log(e); + } + changeMap.put(project, deltaAnalyzer); + } + + private void addLastRecentlyUsed(HashMap changeMap) { + boolean addLRUs= false; + int count= 0; + ITranslationUnit[] newLRUs= new ITranslationUnit[UPDATE_LR_CHANGED_FILES_COUNT]; + + for (Iterator iterator = changeMap.values().iterator(); iterator.hasNext();) { + DeltaAnalyzer analyzer = (DeltaAnalyzer) iterator.next(); + List l= analyzer.getAddedList(); + for (Iterator it = l.iterator(); it.hasNext();) { + ITranslationUnit tu= (ITranslationUnit) it.next(); + newLRUs[count++ % UPDATE_LR_CHANGED_FILES_COUNT]= tu; + if (!addLRUs && tu.isHeaderUnit()) { + addLRUs= true; + } + } + l= analyzer.getChangedList(); + for (Iterator it = l.iterator(); it.hasNext();) { + ITranslationUnit tu= (ITranslationUnit) it.next(); + newLRUs[count++ % UPDATE_LR_CHANGED_FILES_COUNT]= tu; + if (!addLRUs && tu.isHeaderUnit()) { + addLRUs= true; + } + } + } + + if (count > 0) { + if (addLRUs) { + for (Iterator it = fLRUs.keySet().iterator(); it.hasNext();) { + final ITranslationUnit tu = (ITranslationUnit) it.next(); + if (tu.getResource().exists()) { + final ICProject cproject= tu.getCProject(); + DeltaAnalyzer analyzer= (DeltaAnalyzer) changeMap.get(cproject); + if (analyzer == null) { + analyzer= new DeltaAnalyzer(); + changeMap.put(cproject, analyzer); + } + analyzer.getChangedList().add(tu); + } + } + } + count= Math.min(count, newLRUs.length); + for (int i = 0; i < count; i++) { + final ITranslationUnit tu = newLRUs[i]; + fLRUs.put(tu, tu); } } } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/PDOMManager.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/PDOMManager.java index aec982e1071..f40d73101bd 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/PDOMManager.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/PDOMManager.java @@ -63,7 +63,6 @@ import org.eclipse.cdt.internal.core.index.provider.IndexProviderManager; import org.eclipse.cdt.internal.core.pdom.PDOM.IListener; import org.eclipse.cdt.internal.core.pdom.db.ChunkCache; import org.eclipse.cdt.internal.core.pdom.dom.PDOMProjectIndexLocationConverter; -import org.eclipse.cdt.internal.core.pdom.indexer.DeltaAnalyzer; import org.eclipse.cdt.internal.core.pdom.indexer.IndexerPreferences; import org.eclipse.cdt.internal.core.pdom.indexer.PDOMRebuildTask; import org.eclipse.cdt.internal.core.pdom.indexer.PDOMUpdateTask; @@ -471,7 +470,7 @@ public class PDOMManager implements IWritableIndexManager, IListener { createPolicy(project).setIndexer(indexer); } - private IPDOMIndexer getIndexer(ICProject project) { + IPDOMIndexer getIndexer(ICProject project) { assert !Thread.holdsLock(fProjectToPDOM); synchronized (fUpdatePolicies) { IndexUpdatePolicy policy= getPolicy(project); @@ -724,18 +723,13 @@ public class PDOMManager implements IWritableIndexManager, IListener { } } - void changeProject(ICProject project, ICElementDelta delta) throws CoreException { + void changeProject(ICProject project, ITranslationUnit[] added, ITranslationUnit[] changed, ITranslationUnit[] removed) { assert !Thread.holdsLock(fProjectToPDOM); IPDOMIndexer indexer = getIndexer(project); if (indexer != null && indexer.getID().equals(IPDOMManager.ID_NO_INDEXER)) { return; } - DeltaAnalyzer deltaAnalyzer = new DeltaAnalyzer(); - deltaAnalyzer.analyzeDelta(delta); - ITranslationUnit[] added= deltaAnalyzer.getAddedTUs(); - ITranslationUnit[] changed= deltaAnalyzer.getChangedTUs(); - ITranslationUnit[] removed= deltaAnalyzer.getRemovedTUs(); if (added.length > 0 || changed.length > 0 || removed.length > 0) { synchronized (fUpdatePolicies) { IndexUpdatePolicy policy= createPolicy(project); diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/indexer/DeltaAnalyzer.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/indexer/DeltaAnalyzer.java index 9e6601df389..812f23fd43d 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/indexer/DeltaAnalyzer.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/indexer/DeltaAnalyzer.java @@ -88,4 +88,12 @@ public class DeltaAnalyzer { public ITranslationUnit[] getRemovedTUs() { return (ITranslationUnit[]) fRemoved.toArray(new ITranslationUnit[fRemoved.size()]); } + + public List getAddedList() { + return fAdded; + } + + public List getChangedList() { + return fChanged; + } }