diff --git a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/internal/index/tests/IndexCompositeTests.java b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/internal/index/tests/IndexCompositeTests.java index 4ce0d077f0a..c24b1647480 100644 --- a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/internal/index/tests/IndexCompositeTests.java +++ b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/internal/index/tests/IndexCompositeTests.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2007, 2013 Symbian Software Systems and others. + * Copyright (c) 2007, 2017 Symbian Software Systems 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 @@ -13,15 +13,12 @@ package org.eclipse.cdt.internal.index.tests; import java.io.IOException; import java.util.ArrayList; -import java.util.HashMap; import java.util.HashSet; import java.util.List; -import java.util.Map; import java.util.Set; import java.util.regex.Pattern; import org.eclipse.cdt.core.CCorePlugin; -import org.eclipse.cdt.core.dom.IPDOMManager; import org.eclipse.cdt.core.dom.ast.DOMException; import org.eclipse.cdt.core.dom.ast.IBinding; import org.eclipse.cdt.core.dom.ast.ICompositeType; @@ -31,16 +28,12 @@ import org.eclipse.cdt.core.index.IIndex; import org.eclipse.cdt.core.index.IIndexManager; import org.eclipse.cdt.core.index.IndexFilter; import org.eclipse.cdt.core.model.ICProject; -import org.eclipse.cdt.core.testplugin.CProjectHelper; import org.eclipse.cdt.core.testplugin.CTestPlugin; import org.eclipse.cdt.core.testplugin.util.BaseTestCase; import org.eclipse.cdt.core.testplugin.util.TestSourceReader; -import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IProject; -import org.eclipse.core.resources.IProjectDescription; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.NullProgressMonitor; -import org.eclipse.core.runtime.Path; import junit.framework.Test; @@ -50,58 +43,6 @@ import junit.framework.Test; public class IndexCompositeTests extends BaseTestCase { Set createdProjects = new HashSet<>(); - /* - * Convenience class for setting up projects. - */ - private class ProjectBuilder { - private final String name; - private final boolean cpp; - private List dependencies = new ArrayList<>(); - private Map path2content = new HashMap<>(); - - ProjectBuilder(String name, boolean cpp) { - this.name = name; - this.cpp = cpp; - } - - ProjectBuilder addDependency(IProject project) { - dependencies.add(project); - return this; - } - - ProjectBuilder addFile(String relativePath, CharSequence content) { - path2content.put(relativePath, content.toString()); - return this; - } - - ICProject create() throws Exception { - ICProject result = cpp ? - CProjectHelper.createCCProject(name, "bin", IPDOMManager.ID_NO_INDEXER) : - CProjectHelper.createCProject(name, "bin", IPDOMManager.ID_NO_INDEXER); - createdProjects.add(result.getProject()); - - IFile lastFile= null; - for (Map.Entry entry : path2content.entrySet()) { - lastFile= TestSourceReader.createFile(result.getProject(), new Path(entry.getKey()), entry.getValue()); - } - - IProjectDescription desc = result.getProject().getDescription(); - desc.setReferencedProjects(dependencies.toArray(new IProject[dependencies.size()])); - result.getProject().setDescription(desc, new NullProgressMonitor()); - - IIndexManager indexManager = CCorePlugin.getIndexManager(); - indexManager.setIndexerId(result, IPDOMManager.ID_FAST_INDEXER); - if (lastFile != null) { - // Call reindex explicitly since setting indexer ID doesn't trigger reindexing. - indexManager.reindex(result); - IIndex index= indexManager.getIndex(result); - TestSourceReader.waitUntilFileIsIndexed(index, lastFile, INDEXER_TIMEOUT_SEC * 1000); - } - BaseTestCase.waitForIndexer(result); - return result; - } - } - public static Test suite() { return suite(IndexCompositeTests.class); } @@ -128,6 +69,12 @@ public class IndexCompositeTests extends BaseTestCase { CTestPlugin.getDefault().getBundle(), "parser", getClass(), getName(), blocks); } + protected ICProject createAndAddProject(ProjectBuilder builder) throws Exception { + ICProject project = builder.create(); + createdProjects.add(project.getProject()); + return project; + } + // class A {}; // class B {}; @@ -138,12 +85,12 @@ public class IndexCompositeTests extends BaseTestCase { try { ProjectBuilder pb = new ProjectBuilder("projB_" + getName(), true); pb.addFile("h1.h", contents[0]); - ICProject cprojB = pb.create(); + ICProject cprojB = createAndAddProject(pb); projects.add(cprojB); pb = new ProjectBuilder("projA_" + getName(), true); pb.addFile("h2.h", contents[1]).addDependency(cprojB.getProject()); - ICProject cprojA = pb.create(); + ICProject cprojA = createAndAddProject(pb); projects.add(cprojA); setIndex(cprojB, NONE); assertBCount(1, 1); @@ -186,17 +133,17 @@ public class IndexCompositeTests extends BaseTestCase { try { ProjectBuilder pb = new ProjectBuilder("projC_" + getName(), true); pb.addFile("h3.h", contents[0]); - ICProject cprojC = pb.create(); + ICProject cprojC = createAndAddProject(pb); projects.add(cprojC); pb = new ProjectBuilder("projB_" + getName(), true); pb.addFile("h2.h", contents[1]).addDependency(cprojC.getProject()); - ICProject cprojB = pb.create(); + ICProject cprojB = createAndAddProject(pb); projects.add(cprojB); pb = new ProjectBuilder("projA_" + getName(), true); pb.addFile("h1.h", contents[2]).addDependency(cprojB.getProject()); - ICProject cprojA = pb.create(); + ICProject cprojA = createAndAddProject(pb); projects.add(cprojA); /* Defines Global, Defines Namespace, References Global, References Namespace @@ -301,17 +248,17 @@ public class IndexCompositeTests extends BaseTestCase { try { ProjectBuilder pb = new ProjectBuilder("projB_" + getName(), true); pb.addFile("h2.h", contents[0]); - ICProject cprojB = pb.create(); + ICProject cprojB = createAndAddProject(pb); projects.add(cprojB); pb = new ProjectBuilder("projA_" + getName(), true); pb.addFile("h1.h", contents[1]).addDependency(cprojB.getProject()); - ICProject cprojA = pb.create(); + ICProject cprojA = createAndAddProject(pb); projects.add(cprojA); pb = new ProjectBuilder("projC_" + getName(), true); pb.addFile("h3.h", contents[2]).addDependency(cprojB.getProject()); - ICProject cprojC = pb.create(); + ICProject cprojC = createAndAddProject(pb); projects.add(cprojC); /* A C | @@ -399,17 +346,17 @@ public class IndexCompositeTests extends BaseTestCase { try { ProjectBuilder pb = new ProjectBuilder("projC_" + getName(), true); pb.addFile("h3.h", contents[0]); - ICProject cprojC = pb.create(); + ICProject cprojC = createAndAddProject(pb); projects.add(cprojC); pb = new ProjectBuilder("projA_" + getName(), true); pb.addFile("h1.h", contents[2]); - ICProject cprojA = pb.create(); + ICProject cprojA = createAndAddProject(pb); projects.add(cprojA); pb = new ProjectBuilder("projB_" + getName(), true); pb.addFile("h2.h", contents[1]).addDependency(cprojC.getProject()).addDependency(cprojA.getProject()); - ICProject cprojB = pb.create(); + ICProject cprojB = createAndAddProject(pb); projects.add(cprojB); /* B | 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 b6ab96a2fd8..0b6b429431c 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 @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2007, 2015 Wind River Systems, Inc. and others. + * Copyright (c) 2007, 2017 Wind River Systems, Inc. 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 @@ -10,7 +10,9 @@ *******************************************************************************/ package org.eclipse.cdt.internal.index.tests; +import java.util.ArrayList; import java.util.Arrays; +import java.util.List; import org.eclipse.cdt.core.CCorePlugin; import org.eclipse.cdt.core.dom.IPDOMManager; @@ -47,6 +49,7 @@ import org.eclipse.cdt.core.index.IIndex; import org.eclipse.cdt.core.index.IIndexBinding; import org.eclipse.cdt.core.index.IndexFilter; import org.eclipse.cdt.core.model.ICProject; +import org.eclipse.cdt.core.model.ITranslationUnit; import org.eclipse.cdt.core.testplugin.CProjectHelper; import org.eclipse.cdt.core.testplugin.util.TestSourceReader; import org.eclipse.cdt.internal.core.pdom.CModelListener; @@ -56,6 +59,7 @@ import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IProject; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IAdaptable; +import org.eclipse.core.runtime.Path; import junit.framework.TestSuite; @@ -1495,4 +1499,48 @@ public class IndexUpdateTests extends IndexTestBase { fIndex.releaseReadLock(); } } + + + // int dummy; + + //#include "A.h" + //void foo() { + // bar(); + //} + public void testDependentProjectGetsUpdated_Bug310837() throws Exception { + CharSequence[] contents = getContentsForTest(2); + List projects = new ArrayList(); + + try { + ProjectBuilder projectABuilder = new ProjectBuilder("projA_" + getName(), true); + projectABuilder.addFile("A.h", contents[0]); + ICProject projectA = projectABuilder.create(); + projects.add(projectA); + + ProjectBuilder projectBBuilder = new ProjectBuilder("projB_" + getName(), true); + projectBBuilder.addFile("B.h", contents[1]).addDependency(projectA.getProject()); + ICProject projectB = projectBBuilder.create(); + projects.add(projectB); + + IIndex aIndex = CCorePlugin.getIndexManager().getIndex(projectA); + IIndex bIndex = CCorePlugin.getIndexManager().getIndex(projectB); + bIndex.acquireReadLock(); + IIndexBinding[] barBinding = bIndex.findBindings("bar".toCharArray(), IndexFilter.ALL, null); + assertEquals(0, barBinding.length); + bIndex.releaseReadLock(); + + IFile fileAh = (IFile) ((ITranslationUnit)projectA.findElement(Path.fromOSString("A.h"))).getResource(); + fileAh = TestSourceReader.createFile(projectA.getSourceRoots()[0].getResource(), Path.fromOSString("A.h"), "void bar(){}\n"); + TestSourceReader.waitUntilFileIsIndexed(aIndex, fileAh, INDEXER_TIMEOUT_SEC * 1000); + TestSourceReader.waitUntilFileIsIndexed(bIndex, fileAh, INDEXER_TIMEOUT_SEC * 1000); + bIndex.acquireReadLock(); + IIndexBinding[] barBinding2 = bIndex.findBindings("bar".toCharArray(), IndexFilter.ALL, null); + assertEquals(1, barBinding2.length); + bIndex.releaseReadLock(); + } finally { + for (ICProject project : projects) { + CProjectHelper.delete(project); + } + } + } } diff --git a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/internal/index/tests/ProjectBuilder.java b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/internal/index/tests/ProjectBuilder.java new file mode 100644 index 00000000000..f609bedc5b5 --- /dev/null +++ b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/internal/index/tests/ProjectBuilder.java @@ -0,0 +1,78 @@ +/******************************************************************************* + * Copyright (c) 2007, 2017 Symbian Software Systems 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 + *******************************************************************************/ +package org.eclipse.cdt.internal.index.tests; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.eclipse.cdt.core.CCorePlugin; +import org.eclipse.cdt.core.dom.IPDOMManager; +import org.eclipse.cdt.core.index.IIndex; +import org.eclipse.cdt.core.index.IIndexManager; +import org.eclipse.cdt.core.model.ICProject; +import org.eclipse.cdt.core.testplugin.CProjectHelper; +import org.eclipse.cdt.core.testplugin.util.BaseTestCase; +import org.eclipse.cdt.core.testplugin.util.TestSourceReader; +import org.eclipse.core.resources.IFile; +import org.eclipse.core.resources.IProject; +import org.eclipse.core.resources.IProjectDescription; +import org.eclipse.core.runtime.NullProgressMonitor; +import org.eclipse.core.runtime.Path; + +/* + * Convenience class for setting up projects. + */ +class ProjectBuilder { + private final String name; + private final boolean cpp; + private List dependencies = new ArrayList<>(); + private Map path2content = new HashMap<>(); + + ProjectBuilder(String name, boolean cpp) { + this.name = name; + this.cpp = cpp; + } + + ProjectBuilder addDependency(IProject project) { + dependencies.add(project); + return this; + } + + ProjectBuilder addFile(String relativePath, CharSequence content) { + path2content.put(relativePath, content.toString()); + return this; + } + + ICProject create() throws Exception { + ICProject result = cpp ? + CProjectHelper.createCCProject(name, "bin", IPDOMManager.ID_NO_INDEXER) : + CProjectHelper.createCProject(name, "bin", IPDOMManager.ID_NO_INDEXER); + + IFile lastFile= null; + for (Map.Entry entry : path2content.entrySet()) { + lastFile= TestSourceReader.createFile(result.getProject(), new Path(entry.getKey()), entry.getValue()); + } + + IProjectDescription desc = result.getProject().getDescription(); + desc.setReferencedProjects(dependencies.toArray(new IProject[dependencies.size()])); + result.getProject().setDescription(desc, new NullProgressMonitor()); + + IIndexManager indexManager = CCorePlugin.getIndexManager(); + indexManager.setIndexerId(result, IPDOMManager.ID_FAST_INDEXER); + if (lastFile != null) { + // Call reindex explicitly since setting indexer ID doesn't trigger reindexing. + indexManager.reindex(result); + IIndex index= indexManager.getIndex(result); + BaseTestCase.waitUntilFileIsIndexed(index, lastFile); + } + BaseTestCase.waitForIndexer(result); + return result; + } +} \ No newline at end of file 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 77ef13a9d92..044376b61ea 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 @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2005, 2016 QNX Software Systems and others. + * Copyright (c) 2005, 2017 QNX Software Systems 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 @@ -25,6 +25,7 @@ import java.io.InputStream; import java.io.OutputStream; import java.util.ArrayDeque; import java.util.ArrayList; +import java.util.Arrays; import java.util.Date; import java.util.HashMap; import java.util.HashSet; @@ -797,24 +798,54 @@ public class PDOMManager implements IWritableIndexManager, IListener { } } - void changeProject(ICProject project, ITranslationUnit[] added, ITranslationUnit[] changed, ITranslationUnit[] removed) { - assert !Thread.holdsLock(fProjectToPDOM); + private void updateProject(ICProject project, ITranslationUnit[] added, ITranslationUnit[] changed, + ITranslationUnit[] removed) { + IPDOMIndexer indexer = getIndexer(project); if (indexer != null && indexer.getID().equals(IPDOMManager.ID_NO_INDEXER)) { return; } + synchronized (fUpdatePolicies) { + IndexUpdatePolicy policy = createPolicy(project); + IPDOMIndexerTask task = policy.handleDelta(added, changed, removed); + if (task != null) { + enqueue(task); + } + } + } + + void changeProject(ICProject project, ITranslationUnit[] added, ITranslationUnit[] changed, + ITranslationUnit[] removed) { + assert !Thread.holdsLock(fProjectToPDOM); if (added.length > 0 || changed.length > 0 || removed.length > 0) { - synchronized (fUpdatePolicies) { - IndexUpdatePolicy policy= createPolicy(project); - IPDOMIndexerTask task= policy.handleDelta(added, changed, removed); - if (task != null) { - enqueue(task); + updateProject(project, added, changed, removed); + if (shouldUpdateReferencingProjects(added, changed, removed)) { + ITranslationUnit[] addedHeaders = filterHeaderTU(added); + ITranslationUnit[] changedHeaders = filterHeaderTU(changed); + ITranslationUnit[] removedHeaders = filterHeaderTU(removed); + IProject[] referencingProjects = project.getProject().getReferencingProjects(); + for (IProject referencingProject : referencingProjects) { + ICProject projectToIndex = CoreModel.getDefault().create(referencingProject); + updateProject(projectToIndex, addedHeaders, changedHeaders, removedHeaders); } } } } + private ITranslationUnit[] filterHeaderTU(ITranslationUnit[] units) { + return Arrays.stream(units).filter(ITranslationUnit::isHeaderUnit).toArray(ITranslationUnit[]::new); + } + + private boolean shouldUpdateReferencingProjects(ITranslationUnit[] added, ITranslationUnit[] changed, + ITranslationUnit[] removed) { + return hasHeaderTU(added) || hasHeaderTU(changed) || hasHeaderTU(removed); + } + + private boolean hasHeaderTU(ITranslationUnit[] units) { + return Arrays.stream(units).anyMatch(ITranslationUnit::isHeaderUnit); + } + private IndexUpdatePolicy createPolicy(final ICProject project) { assert !Thread.holdsLock(fProjectToPDOM); synchronized (fUpdatePolicies) {