Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ Improvements:
- Updated IntelliSense tooltips with changes from CMake 4.3.1. [#4872](https://github.com/microsoft/vscode-cmake-tools/pull/4872)

Bug Fixes:
- Fix stale C/C++ custom-configuration entries persisting after reconfigure/preset switches, which could cause Go to Definition/IntelliSense to surface symbols from inactive sources in the same folder. [#4472](https://github.com/microsoft/vscode-cmake-tools/issues/4472)
- Fix `tasks.json` schema validation rejecting valid CMake task commands `package` and `workflow`. [#4167](https://github.com/microsoft/vscode-cmake-tools/issues/4167)
- Import the `EXTERNAL_INCLUDE` environment variable from the VS developer environment so that MSVC's external-header diagnostic suppression works correctly. [#4217](https://github.com/microsoft/vscode-cmake-tools/issues/4217)
- Fix test presets not automatically switching when the build preset changes in multi-config generator setups (e.g., Ninja Multi-Config). The extension now auto-selects a compatible test preset after a build preset change, and properly considers build type when guessing the test preset. [#4395](https://github.com/microsoft/vscode-cmake-tools/issues/4395)
Expand Down
25 changes: 25 additions & 0 deletions src/cpptools.ts
Original file line number Diff line number Diff line change
Expand Up @@ -430,6 +430,12 @@ export class CppConfigurationProvider implements cpptools.CustomConfigurationPro
*/
private readonly fileIndex = new Map<string, Map<string, cpptools.SourceFileConfigurationItem>>();

/**
* Track indexed files per workspace folder so stale entries can be evicted
* when a folder is reconfigured (e.g. switching presets).
*/
private readonly fileIndexByFolder = new Map<string, Set<string>>();

/**
* If a source file configuration exists for the active target, we will prefer that one when asked.
*/
Expand All @@ -438,6 +444,18 @@ export class CppConfigurationProvider implements cpptools.CustomConfigurationPro
private activeBuildType: string | null = null;
private buildTypesSeen = new Set<string>();

private clearConfigurationDataForFolder(folder: string) {
const normalizedFolder = util.platformNormalizePath(folder);
const indexedFiles = this.fileIndexByFolder.get(normalizedFolder);
if (indexedFiles) {
for (const filePath of indexedFiles) {
this.fileIndex.delete(filePath);
}
this.fileIndexByFolder.delete(normalizedFolder);
}
this.workspaceBrowseConfigurations.delete(normalizedFolder);
}

/**
* Create a source file configuration for the given file group.
* @param fileGroup The file group from the code model to create config data for
Expand Down Expand Up @@ -552,9 +570,12 @@ export class CppConfigurationProvider implements cpptools.CustomConfigurationPro
*/
private updateFileGroup(sourceDir: string, fileGroup: CodeModelFileGroup, options: CodeModelParams, target: TargetDefaults, sysroot?: string) {
const configuration = this.buildConfigurationData(fileGroup, options, target, sysroot);
const normalizedFolder = util.platformNormalizePath(options.folder);
const indexedFiles = this.fileIndexByFolder.get(normalizedFolder);
for (const src of fileGroup.sources) {
const absolutePath = path.isAbsolute(src) ? src : path.join(sourceDir, src);
const normalizedAbsolutePath = util.platformNormalizePath(absolutePath);
indexedFiles?.add(normalizedAbsolutePath);
if (this.fileIndex.has(normalizedAbsolutePath)) {
this.fileIndex.get(normalizedAbsolutePath)!.set(target.name, {
uri: vscode.Uri.file(absolutePath).toString(),
Expand Down Expand Up @@ -593,6 +614,10 @@ export class CppConfigurationProvider implements cpptools.CustomConfigurationPro
this.buildTypesSeen.clear();
this.targets = [];

const normalizedFolder = util.platformNormalizePath(opts.folder);
this.clearConfigurationDataForFolder(normalizedFolder);
this.fileIndexByFolder.set(normalizedFolder, new Set<string>());

let hadMissingCompilers = false;
this.workspaceBrowseConfiguration = { browsePath: [] };
this.activeTarget = opts.activeTarget;
Expand Down
63 changes: 63 additions & 0 deletions test/unit-tests/cpptools.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -406,4 +406,67 @@ suite('CppTools tests', () => {
expect(browseConfig2?.browsePath.length).to.eq(1);
expect(browseConfig2?.browsePath[0]).to.eq(util.platformNormalizePath(smokeFolder));
});

test('Evicts stale file configurations after folder refresh', async () => {
const provider = new CppConfigurationProvider();
const cache = await CMakeCache.fromPath(getTestResourceFilePath('TestCMakeCache.txt'));
const folder = here;
const oldSourceFile = path.join(folder, 'stale_old.cpp');
const newSourceFile = path.join(folder, 'stale_new.cpp');

const oldCodeModel: codeModel.CodeModelContent = {
configurations: [{
name: 'Release',
projects: [{
name: 'stale-config-test',
sourceDirectory: folder,
targets: [{
name: 'oldTarget',
type: 'EXECUTABLE',
fileGroups: [{
sources: [oldSourceFile],
isGenerated: false,
defines: ['OLD'],
compileCommandFragments: ['-DOLD'],
language: 'CXX'
}]
}]
}]
}],
toolchains: new Map<string, codeModel.CodeModelToolchain>()
};

provider.updateConfigurationData({ cache, codeModelContent: oldCodeModel, activeTarget: 'oldTarget', activeBuildTypeVariant: 'Release', folder });

const newCodeModel: codeModel.CodeModelContent = {
configurations: [{
name: 'Release',
projects: [{
name: 'stale-config-test',
sourceDirectory: folder,
targets: [{
name: 'newTarget',
type: 'EXECUTABLE',
fileGroups: [{
sources: [newSourceFile],
isGenerated: false,
defines: ['NEW'],
compileCommandFragments: ['-DNEW'],
language: 'CXX'
}]
}]
}]
}],
toolchains: new Map<string, codeModel.CodeModelToolchain>()
};

provider.updateConfigurationData({ cache, codeModelContent: newCodeModel, activeTarget: 'newTarget', activeBuildTypeVariant: 'Release', folder });

const staleConfigurations = await provider.provideConfigurations([vscode.Uri.file(oldSourceFile)]);
expect(staleConfigurations.length).to.eq(0);

const activeConfigurations = await provider.provideConfigurations([vscode.Uri.file(newSourceFile)]);
expect(activeConfigurations.length).to.eq(1);
expect(activeConfigurations[0].configuration.defines).to.contain('NEW');
});
});
Loading