From f49338fed1edc59fd58456165f135d19d0779ea4 Mon Sep 17 00:00:00 2001 From: Andrew Gvozdev Date: Sat, 21 Sep 2013 05:15:58 -0400 Subject: [PATCH] bug 416628: Handle case when projects reference each other recursively --- ...ttingsProviderReferencedProjectsTests.java | 96 ++++++++++++++++++- ...encedProjectsLanguageSettingsProvider.java | 43 ++++++--- 2 files changed, 125 insertions(+), 14 deletions(-) diff --git a/core/org.eclipse.cdt.core.tests/model/org/eclipse/cdt/core/language/settings/providers/LanguageSettingsProviderReferencedProjectsTests.java b/core/org.eclipse.cdt.core.tests/model/org/eclipse/cdt/core/language/settings/providers/LanguageSettingsProviderReferencedProjectsTests.java index 35fdc7a1eae..7613f726fdb 100644 --- a/core/org.eclipse.cdt.core.tests/model/org/eclipse/cdt/core/language/settings/providers/LanguageSettingsProviderReferencedProjectsTests.java +++ b/core/org.eclipse.cdt.core.tests/model/org/eclipse/cdt/core/language/settings/providers/LanguageSettingsProviderReferencedProjectsTests.java @@ -141,12 +141,12 @@ public class LanguageSettingsProviderReferencedProjectsTests extends BaseTestCas IProject referencedProject = ResourceHelper.createCDTProjectWithConfig(projectName+"-referenced"); setReference(project, referencedProject); - // get cfgDescription and language to work with + // get cfgDescription ICConfigurationDescription[] cfgDescriptions = getConfigurationDescriptions(project); ICConfigurationDescription cfgDescription = cfgDescriptions[0]; { - // doublecheck that provider for referenced projects is set in the configuration + // double-check that provider for referenced projects is set in the configuration ILanguageSettingsProvider refProjectsProvider = LanguageSettingsManager.getWorkspaceProvider(ReferencedProjectsLanguageSettingsProvider.ID); assertNotNull(refProjectsProvider); List providers = ((ILanguageSettingsProvidersKeeper) cfgDescription).getLanguageSettingProviders(); @@ -207,4 +207,96 @@ public class LanguageSettingsProviderReferencedProjectsTests extends BaseTestCas } } + /** + * Test case when projects reference each other recursively. + */ + public void testRecursiveReferences() throws Exception { + // Create model projects that reference each other + String projectName = getName(); + IProject projectA = ResourceHelper.createCDTProjectWithConfig(projectName + "-A"); + IProject projectB = ResourceHelper.createCDTProjectWithConfig(projectName + "-B"); + setReference(projectA, projectB); + setReference(projectB, projectA); + + { + // get cfgDescriptions to work with + ICConfigurationDescription[] cfgDescriptionsA = getConfigurationDescriptions(projectA); + ICConfigurationDescription cfgDescriptionA = cfgDescriptionsA[0]; + ICConfigurationDescription[] cfgDescriptionsB = getConfigurationDescriptions(projectB); + ICConfigurationDescription cfgDescriptionB = cfgDescriptionsB[0]; + // double-check that provider for referenced projects is set in the configurations + ILanguageSettingsProvider refProjectsProvider = LanguageSettingsManager.getWorkspaceProvider(ReferencedProjectsLanguageSettingsProvider.ID); + assertNotNull(refProjectsProvider); + List providersA = ((ILanguageSettingsProvidersKeeper) cfgDescriptionA).getLanguageSettingProviders(); + assertTrue(providersA.contains(refProjectsProvider)); + List providersB = ((ILanguageSettingsProvidersKeeper) cfgDescriptionB).getLanguageSettingProviders(); + assertTrue(providersB.contains(refProjectsProvider)); + + // Check that no setting entries are set initially + List entriesA = LanguageSettingsManager.getSettingEntriesByKind(cfgDescriptionA, projectA, null, ICSettingEntry.ALL); + assertEquals(0, entriesA.size()); + List entriesB = LanguageSettingsManager.getSettingEntriesByKind(cfgDescriptionA, projectB, null, ICSettingEntry.ALL); + assertEquals(0, entriesB.size()); + } + + CIncludePathEntry entryExportedA = CDataUtil.createCIncludePathEntry("referenced-exported-A", ICSettingEntry.EXPORTED); + CIncludePathEntry entryNotExportedA = CDataUtil.createCIncludePathEntry("referenced-not-exported-A", 0); + // Add entries into a project A + { + ICConfigurationDescription[] refCfgDescriptions = getConfigurationDescriptions(projectA); + ICConfigurationDescription refCfgDescription = refCfgDescriptions[0]; + List providersRef = ((ILanguageSettingsProvidersKeeper) refCfgDescription).getLanguageSettingProviders(); + // get user provider which is the first one + ILanguageSettingsProvider userProviderRef = providersRef.get(0); + assertEquals(ScannerDiscoveryLegacySupport.USER_LANGUAGE_SETTINGS_PROVIDER_ID, userProviderRef.getId()); + assertTrue(userProviderRef instanceof LanguageSettingsGenericProvider); + // add sample entries + ArrayList entries = new ArrayList(); + entries.add(entryExportedA); + entries.add(entryNotExportedA); + ((LanguageSettingsGenericProvider) userProviderRef).setSettingEntries(null, null, null, entries); + } + + CIncludePathEntry entryExportedB = CDataUtil.createCIncludePathEntry("referenced-exported-B", ICSettingEntry.EXPORTED); + CIncludePathEntry entryNotExportedB = CDataUtil.createCIncludePathEntry("referenced-not-exported-B", 0); + // Add entries into a project B + { + ICConfigurationDescription[] refCfgDescriptions = getConfigurationDescriptions(projectB); + ICConfigurationDescription refCfgDescription = refCfgDescriptions[0]; + List providersRef = ((ILanguageSettingsProvidersKeeper) refCfgDescription).getLanguageSettingProviders(); + // get user provider which is the first one + ILanguageSettingsProvider userProviderRef = providersRef.get(0); + assertEquals(ScannerDiscoveryLegacySupport.USER_LANGUAGE_SETTINGS_PROVIDER_ID, userProviderRef.getId()); + assertTrue(userProviderRef instanceof LanguageSettingsGenericProvider); + // add sample entries + ArrayList entries = new ArrayList(); + entries.add(entryExportedB); + entries.add(entryNotExportedB); + ((LanguageSettingsGenericProvider) userProviderRef).setSettingEntries(null, null, null, entries); + } + + // Check that the new entries from projectB made it to projectA + { + ICConfigurationDescription[] cfgDescriptionsA = getConfigurationDescriptions(projectA); + ICConfigurationDescription cfgDescriptionA = cfgDescriptionsA[0]; + List entries = LanguageSettingsManager.getSettingEntriesByKind(cfgDescriptionA, projectA, null, ICSettingEntry.ALL); + assertEquals(entryExportedA, entries.get(0)); + assertEquals(entryNotExportedA, entries.get(1)); + assertEquals(CDataUtil.createCIncludePathEntry(entryExportedB.getName(), 0), entries.get(2)); + assertEquals(3, entries.size()); + } + // Check that the new entries from projectA made it to projectB + { + ICConfigurationDescription[] cfgDescriptionsB = getConfigurationDescriptions(projectB); + ICConfigurationDescription cfgDescriptionB = cfgDescriptionsB[0]; + List entries = LanguageSettingsManager.getSettingEntriesByKind(cfgDescriptionB, projectB, null, ICSettingEntry.ALL); + assertEquals(entryExportedB, entries.get(0)); + assertEquals(entryNotExportedB, entries.get(1)); + assertEquals(CDataUtil.createCIncludePathEntry(entryExportedA.getName(), 0), entries.get(2)); + assertEquals(3, entries.size()); + } + + // Hopefully it gets here without stack overflow + } + } diff --git a/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/language/settings/providers/ReferencedProjectsLanguageSettingsProvider.java b/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/language/settings/providers/ReferencedProjectsLanguageSettingsProvider.java index 5c333332350..68dc700d0be 100644 --- a/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/language/settings/providers/ReferencedProjectsLanguageSettingsProvider.java +++ b/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/language/settings/providers/ReferencedProjectsLanguageSettingsProvider.java @@ -31,8 +31,22 @@ public class ReferencedProjectsLanguageSettingsProvider extends LanguageSettings /** ID of the provider used in extension point from plugin.xml */ public static final String ID = "org.eclipse.cdt.core.ReferencedProjectsLanguageSettingsProvider"; //$NON-NLS-1$ + final private ThreadLocal recursiveCallIndicator = new ThreadLocal() { + @Override + protected Boolean initialValue() { + return false; + } + }; + @Override public List getSettingEntries(ICConfigurationDescription cfgDescription, IResource rc, String languageId) { + if (recursiveCallIndicator.get()) { + // Recursive call indicates that the provider of a referenced project is called. + // Only exported entries of the original configuration should be considered, + // entries of referenced projects are not re-exported. + return null; + } + if (cfgDescription == null) { return null; } @@ -41,20 +55,25 @@ public class ReferencedProjectsLanguageSettingsProvider extends LanguageSettings return null; } - List entries = new ArrayList(); - ICConfigurationDescription[] refCfgDescriptions = CoreModelUtil.getReferencedConfigurationDescriptions(cfgDescription, false); - for (ICConfigurationDescription refCfgDescription : refCfgDescriptions) { - List refEntries = LanguageSettingsManager.getSettingEntriesByKind(refCfgDescription, rc, languageId, ICSettingEntry.ALL); - for (ICLanguageSettingEntry refEntry : refEntries) { - int flags = refEntry.getFlags(); - if ((flags & ICSettingEntry.EXPORTED) == ICSettingEntry.EXPORTED) { - // create a new entry with EXPORTED flag cleared - ICLanguageSettingEntry entry = CDataUtil.createEntry(refEntry, flags & ~ICSettingEntry.EXPORTED); - entries.add(entry); + try { + recursiveCallIndicator.set(true); + List entries = new ArrayList(); + ICConfigurationDescription[] refCfgDescriptions = CoreModelUtil.getReferencedConfigurationDescriptions(cfgDescription, false); + for (ICConfigurationDescription refCfgDescription : refCfgDescriptions) { + List refEntries = LanguageSettingsManager.getSettingEntriesByKind(refCfgDescription, rc, languageId, ICSettingEntry.ALL); + for (ICLanguageSettingEntry refEntry : refEntries) { + int flags = refEntry.getFlags(); + if ((flags & ICSettingEntry.EXPORTED) == ICSettingEntry.EXPORTED) { + // create a new entry with EXPORTED flag cleared + ICLanguageSettingEntry entry = CDataUtil.createEntry(refEntry, flags & ~ICSettingEntry.EXPORTED); + entries.add(entry); + } } } - } - return LanguageSettingsStorage.getPooledList(new ArrayList(entries)); + return LanguageSettingsStorage.getPooledList(new ArrayList(entries)); + } finally { + recursiveCallIndicator.set(false); + } } }