Skip to content

Commit 81989fa

Browse files
[cdt_11_6] On createBuildConfiguration, reset project's ScannerInfoProvider (#817) (#854)
When the project's active IBuildConfiguration has the default name and the chosen ICBuildConfigurationProvider.getCBuildConfiguration does not support the IBuildConfiguration.DEFAULT_CONFIG_NAME and returns null, this can cause the project's ScannerInfoProvider to become "stuck" (https://bugs.eclipse.org/bugs/show_bug.cgi?id=413357) on the wrong setting (eg LanguageSettingsScannerInfoProvider instead of ICBuildConfiguration) until Eclipse is restarted or the project is closed and reopened. When this happens, the indexer does not function. This problem may arise if an ISV contributes a ICBuildConfigurationProvider which has very specific naming conventions for it's build configurations. The solution uses the API (resetCachedScannerInfoProvider(project)), introduced by 413357, to reset the project's ScannerInfoProvider when a new ICBuildConfiguration is created. (cherry picked from commit 0f36d5d) Co-authored-by: betamax <[email protected]>
1 parent f40c481 commit 81989fa

File tree

4 files changed

+149
-4
lines changed

4 files changed

+149
-4
lines changed

core/org.eclipse.cdt.core.tests/META-INF/MANIFEST.MF

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,12 +45,17 @@ Require-Bundle: org.eclipse.core.resources,
4545
org.eclipse.ltk.core.refactoring;bundle-version="3.4.0",
4646
org.hamcrest.core,
4747
org.hamcrest.library,
48-
com.google.gson;bundle-version="[2.8.6,3.0.0)"
48+
com.google.gson;bundle-version="[2.8.6,3.0.0)",
49+
org.eclipse.cdt.debug.core,
50+
org.eclipse.cdt.cmake.core,
51+
org.eclipse.debug.core
4952
Bundle-ActivationPolicy: lazy
5053
Bundle-Vendor: %providerName
5154
Bundle-RequiredExecutionEnvironment: JavaSE-17
5255
Automatic-Module-Name: org.eclipse.cdt.core.tests
5356
Bundle-Localization: plugin
5457
Import-Package: org.junit.jupiter.api;version="5.9.0",
5558
org.junit.jupiter.params;version="5.9.0",
56-
org.junit.jupiter.params.provider;version="5.9.0"
59+
org.junit.jupiter.params.provider;version="5.9.0",
60+
org.mockito;version="[5.12.0,6.0.0]",
61+
org.mockito.stubbing;version="[5.12.0,6.0.0]"
Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
/*******************************************************************************
2+
* Copyright (c) 2024 Renesas Electronics Europe.
3+
*
4+
* This program and the accompanying materials
5+
* are made available under the terms of the Eclipse Public License 2.0
6+
* which accompanies this distribution, and is available at
7+
* https://www.eclipse.org/legal/epl-2.0/
8+
*
9+
* SPDX-License-Identifier: EPL-2.0
10+
*******************************************************************************/
11+
package org.eclipse.cdt.core.build;
12+
13+
import static org.hamcrest.MatcherAssert.assertThat;
14+
import static org.mockito.Mockito.mock;
15+
import static org.mockito.Mockito.when;
16+
17+
import org.eclipse.cdt.cmake.core.CMakeNature;
18+
import org.eclipse.cdt.cmake.core.internal.CMakeBuildConfigurationProvider;
19+
import org.eclipse.cdt.core.CCProjectNature;
20+
import org.eclipse.cdt.core.CCorePlugin;
21+
import org.eclipse.cdt.core.CProjectNature;
22+
import org.eclipse.cdt.core.parser.IScannerInfoProvider;
23+
import org.eclipse.cdt.core.testplugin.ResourceHelper;
24+
import org.eclipse.cdt.core.testplugin.util.BaseTestCase5;
25+
import org.eclipse.cdt.debug.core.CDebugCorePlugin;
26+
import org.eclipse.cdt.internal.core.language.settings.providers.LanguageSettingsScannerInfoProvider;
27+
import org.eclipse.core.resources.IBuildConfiguration;
28+
import org.eclipse.core.resources.IProject;
29+
import org.eclipse.core.resources.IProjectDescription;
30+
import org.eclipse.core.runtime.NullProgressMonitor;
31+
import org.eclipse.debug.core.ILaunchManager;
32+
import org.junit.jupiter.api.Test;
33+
34+
public class CBuildConfigurationManagerTests extends BaseTestCase5 {
35+
protected ICBuildConfigurationManager configManager = CDebugCorePlugin
36+
.getService(ICBuildConfigurationManager.class);
37+
38+
/**
39+
* Tests that CBuildConfigurationManager.getBuildConfiguration(IProject, IToolChain, String, IProgressMonitor)
40+
* calls CCorePlugin.resetCachedScannerInfoProvider(IProject) after creating a new ICBuildConfiguration.
41+
*
42+
* Tests the following failure mode.
43+
* When the project's active IBuildConfiguration has the default name and the chosen ICBuildConfigurationProvider.
44+
* getCBuildConfiguration does not support the IBuildConfiguration.DEFAULT_CONFIG_NAME and returns null, this can
45+
* cause the project's ScannerInfoProvider to become "stuck"
46+
* (https://bugs.eclipse.org/bugs/show_bug.cgi?id=413357) on the wrong setting (eg
47+
* LanguageSettingsScannerInfoProvider instead of ICBuildConfiguration) until Eclipse is restarted or the project
48+
* is closed and reopened. When this happens, the indexer does not function.
49+
*
50+
* This problem may arise if an ISV contributes a ICBuildConfigurationProvider which has very specific naming
51+
* conventions for it's build configurations.
52+
*
53+
* Test approach:
54+
* The test requires that a faulty build configuration is setup for the project to trick the getScannerInfoProvider
55+
* into thinking it's not a core build project. Typically ContainerGCCToolChainProvider may find a valid gcc toolchain
56+
* and then the provider's getCBuildConfiguration will return a valid ICBuildConfiguration. So need to set the active
57+
* build configuration to one which does not use the default name.
58+
*
59+
* (1)
60+
* In a CMake project, add a new build configuration which doesn't use the default name and add this to the project
61+
* using an invalid ICBuildConfiguration and set this as the active build configuration.
62+
*
63+
* (2)
64+
* Later, when the indexer gets the project's active build configuration it is null and so the project's
65+
* IScannerInfoProvider is set to the wrong type and is cached.
66+
*
67+
* (3)
68+
* Later still, a new build configuration is created, this time with a valid ICBuildConfiguration, which is set as the
69+
* project's active build configuration.
70+
*
71+
* (4)
72+
* With the fix in place (resetCachedScannerInfoProvider), the next time the indexer gets the project's
73+
* IScannerInfoProvider it will be recomputed and return the project's expected IScannerInfoProvider
74+
* (ie: ICBuildConfiguration).
75+
*/
76+
@Test
77+
public void testResetCachedScannerInfoProvider() throws Exception {
78+
// (1) create a CMake project
79+
IProject project = createCMakeProject();
80+
81+
CMakeBuildConfigurationProvider provider = new CMakeBuildConfigurationProvider();
82+
String buildConfigBaseName = "notDefaultName";
83+
// Create a new IBuildConfiguration with a name that is not the default name.
84+
IBuildConfiguration buildConfiguration = configManager.createBuildConfiguration(provider, project,
85+
buildConfigBaseName, new NullProgressMonitor());
86+
// Add the IBuildConfiguration/ICBuildConfiguration combo using an invalid ICBuildConfiguration
87+
configManager.addBuildConfiguration(buildConfiguration, null);
88+
// Set the IBuildConfiguration, with this name, as the active build config
89+
IProjectDescription description = project.getDescription();
90+
String buildConfigName = provider.getId() + "/" + buildConfigBaseName;
91+
description.setActiveBuildConfig(buildConfigName);
92+
project.setDescription(description, new NullProgressMonitor());
93+
94+
// (2) The project's scannerInfoProvider is expected to be the wrong type here
95+
IScannerInfoProvider scannerInfoProvider = CCorePlugin.getDefault().getScannerInfoProvider(project);
96+
assertThat("scannerInfoProvider expected to be LanguageSettingsScannerInfoProvider",
97+
scannerInfoProvider instanceof LanguageSettingsScannerInfoProvider);
98+
99+
// (3) Setup a toolchain ready to use for creating the valid ICBuildConfiguration
100+
IToolChain mockToolchain = mock(IToolChain.class);
101+
when(mockToolchain.getProperty(IToolChain.ATTR_OS)).thenReturn("osDummy");
102+
when(mockToolchain.getProperty(IToolChain.ATTR_ARCH)).thenReturn("archDummy");
103+
when(mockToolchain.getTypeId()).thenReturn("tc_typeId");
104+
when(mockToolchain.getId()).thenReturn("tcId");
105+
when(mockToolchain.getBuildConfigNameFragment()).thenReturn("buildConfigName");
106+
107+
ICBuildConfiguration cBuildConfiguration = configManager.getBuildConfiguration(project, mockToolchain,
108+
ILaunchManager.RUN_MODE, new NullProgressMonitor());
109+
assertThat("The cBuildConfiguration should of type CBuildConfiguration",
110+
cBuildConfiguration instanceof CBuildConfiguration);
111+
CBuildConfiguration cbc = (CBuildConfiguration) cBuildConfiguration;
112+
// Set this ICBuildConfiguration as the active build configuration
113+
cbc.setActive(new NullProgressMonitor());
114+
115+
// (4) The project's scannerInfoProvider is expected to be the correct type here
116+
scannerInfoProvider = CCorePlugin.getDefault().getScannerInfoProvider(project);
117+
assertThat("scannerInfoProvider expected to be ICBuildConfiguration",
118+
scannerInfoProvider instanceof ICBuildConfiguration);
119+
}
120+
121+
private IProject createCMakeProject() throws Exception {
122+
// Create a plain Eclipse project
123+
IProject project = ResourceHelper.createProject(this.getName());
124+
// Add C/C++ and CMake natures to make it a CMake project
125+
IProjectDescription description = project.getDescription();
126+
description.setNatureIds(
127+
new String[] { CProjectNature.C_NATURE_ID, CCProjectNature.CC_NATURE_ID, CMakeNature.ID });
128+
project.setDescription(description, null);
129+
return project;
130+
}
131+
}

core/org.eclipse.cdt.core/META-INF/MANIFEST.MF

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ Manifest-Version: 1.0
22
Bundle-ManifestVersion: 2
33
Bundle-Name: %pluginName
44
Bundle-SymbolicName: org.eclipse.cdt.core; singleton:=true
5-
Bundle-Version: 8.4.200.qualifier
5+
Bundle-Version: 8.4.201.qualifier
66
Bundle-Activator: org.eclipse.cdt.core.CCorePlugin
77
Bundle-Vendor: %providerName
88
Bundle-Localization: plugin

core/org.eclipse.cdt.core/src/org/eclipse/cdt/internal/core/build/CBuildConfigurationManager.java

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -320,7 +320,16 @@ public ICBuildConfiguration getBuildConfiguration(IProject project, IToolChain t
320320
ICBuildConfigurationProvider provider = getProvider(project);
321321
if (provider != null) {
322322
// The provider will call us back to add in the new one
323-
return provider.createBuildConfiguration(project, toolChain, launchMode, monitor);
323+
ICBuildConfiguration cconfig = provider.createBuildConfiguration(project, toolChain, launchMode, monitor);
324+
if (cconfig != null) {
325+
/*
326+
* The IScannerInfoProvider may be cached with an incorrect value if the ICBuildConfiguration is not
327+
* available at the time it is checked. Now that one has been created, the previous value should be
328+
* forgotten so the new cconfig can be used.
329+
*/
330+
CCorePlugin.getDefault().resetCachedScannerInfoProvider(project);
331+
}
332+
return cconfig;
324333
} else {
325334
return null;
326335
}

0 commit comments

Comments
 (0)