Skip to content

Commit af9ed5d

Browse files
stale IntelliSense behavior after preset/configuration switches. (#4874)
Co-authored-by: Hannia Valera <[email protected]>
1 parent 681cd20 commit af9ed5d

3 files changed

Lines changed: 89 additions & 0 deletions

File tree

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ Improvements:
4949
- Updated IntelliSense tooltips with changes from CMake 4.3.1. [#4872](https://github.com/microsoft/vscode-cmake-tools/pull/4872)
5050

5151
Bug Fixes:
52+
- 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)
5253
- Fix `tasks.json` schema validation rejecting valid CMake task commands `package` and `workflow`. [#4167](https://github.com/microsoft/vscode-cmake-tools/issues/4167)
5354
- 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)
5455
- 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)

src/cpptools.ts

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -430,6 +430,12 @@ export class CppConfigurationProvider implements cpptools.CustomConfigurationPro
430430
*/
431431
private readonly fileIndex = new Map<string, Map<string, cpptools.SourceFileConfigurationItem>>();
432432

433+
/**
434+
* Track indexed files per workspace folder so stale entries can be evicted
435+
* when a folder is reconfigured (e.g. switching presets).
436+
*/
437+
private readonly fileIndexByFolder = new Map<string, Set<string>>();
438+
433439
/**
434440
* If a source file configuration exists for the active target, we will prefer that one when asked.
435441
*/
@@ -438,6 +444,18 @@ export class CppConfigurationProvider implements cpptools.CustomConfigurationPro
438444
private activeBuildType: string | null = null;
439445
private buildTypesSeen = new Set<string>();
440446

447+
private clearConfigurationDataForFolder(folder: string) {
448+
const normalizedFolder = util.platformNormalizePath(folder);
449+
const indexedFiles = this.fileIndexByFolder.get(normalizedFolder);
450+
if (indexedFiles) {
451+
for (const filePath of indexedFiles) {
452+
this.fileIndex.delete(filePath);
453+
}
454+
this.fileIndexByFolder.delete(normalizedFolder);
455+
}
456+
this.workspaceBrowseConfigurations.delete(normalizedFolder);
457+
}
458+
441459
/**
442460
* Create a source file configuration for the given file group.
443461
* @param fileGroup The file group from the code model to create config data for
@@ -552,9 +570,12 @@ export class CppConfigurationProvider implements cpptools.CustomConfigurationPro
552570
*/
553571
private updateFileGroup(sourceDir: string, fileGroup: CodeModelFileGroup, options: CodeModelParams, target: TargetDefaults, sysroot?: string) {
554572
const configuration = this.buildConfigurationData(fileGroup, options, target, sysroot);
573+
const normalizedFolder = util.platformNormalizePath(options.folder);
574+
const indexedFiles = this.fileIndexByFolder.get(normalizedFolder);
555575
for (const src of fileGroup.sources) {
556576
const absolutePath = path.isAbsolute(src) ? src : path.join(sourceDir, src);
557577
const normalizedAbsolutePath = util.platformNormalizePath(absolutePath);
578+
indexedFiles?.add(normalizedAbsolutePath);
558579
if (this.fileIndex.has(normalizedAbsolutePath)) {
559580
this.fileIndex.get(normalizedAbsolutePath)!.set(target.name, {
560581
uri: vscode.Uri.file(absolutePath).toString(),
@@ -593,6 +614,10 @@ export class CppConfigurationProvider implements cpptools.CustomConfigurationPro
593614
this.buildTypesSeen.clear();
594615
this.targets = [];
595616

617+
const normalizedFolder = util.platformNormalizePath(opts.folder);
618+
this.clearConfigurationDataForFolder(normalizedFolder);
619+
this.fileIndexByFolder.set(normalizedFolder, new Set<string>());
620+
596621
let hadMissingCompilers = false;
597622
this.workspaceBrowseConfiguration = { browsePath: [] };
598623
this.activeTarget = opts.activeTarget;

test/unit-tests/cpptools.test.ts

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -406,4 +406,67 @@ suite('CppTools tests', () => {
406406
expect(browseConfig2?.browsePath.length).to.eq(1);
407407
expect(browseConfig2?.browsePath[0]).to.eq(util.platformNormalizePath(smokeFolder));
408408
});
409+
410+
test('Evicts stale file configurations after folder refresh', async () => {
411+
const provider = new CppConfigurationProvider();
412+
const cache = await CMakeCache.fromPath(getTestResourceFilePath('TestCMakeCache.txt'));
413+
const folder = here;
414+
const oldSourceFile = path.join(folder, 'stale_old.cpp');
415+
const newSourceFile = path.join(folder, 'stale_new.cpp');
416+
417+
const oldCodeModel: codeModel.CodeModelContent = {
418+
configurations: [{
419+
name: 'Release',
420+
projects: [{
421+
name: 'stale-config-test',
422+
sourceDirectory: folder,
423+
targets: [{
424+
name: 'oldTarget',
425+
type: 'EXECUTABLE',
426+
fileGroups: [{
427+
sources: [oldSourceFile],
428+
isGenerated: false,
429+
defines: ['OLD'],
430+
compileCommandFragments: ['-DOLD'],
431+
language: 'CXX'
432+
}]
433+
}]
434+
}]
435+
}],
436+
toolchains: new Map<string, codeModel.CodeModelToolchain>()
437+
};
438+
439+
provider.updateConfigurationData({ cache, codeModelContent: oldCodeModel, activeTarget: 'oldTarget', activeBuildTypeVariant: 'Release', folder });
440+
441+
const newCodeModel: codeModel.CodeModelContent = {
442+
configurations: [{
443+
name: 'Release',
444+
projects: [{
445+
name: 'stale-config-test',
446+
sourceDirectory: folder,
447+
targets: [{
448+
name: 'newTarget',
449+
type: 'EXECUTABLE',
450+
fileGroups: [{
451+
sources: [newSourceFile],
452+
isGenerated: false,
453+
defines: ['NEW'],
454+
compileCommandFragments: ['-DNEW'],
455+
language: 'CXX'
456+
}]
457+
}]
458+
}]
459+
}],
460+
toolchains: new Map<string, codeModel.CodeModelToolchain>()
461+
};
462+
463+
provider.updateConfigurationData({ cache, codeModelContent: newCodeModel, activeTarget: 'newTarget', activeBuildTypeVariant: 'Release', folder });
464+
465+
const staleConfigurations = await provider.provideConfigurations([vscode.Uri.file(oldSourceFile)]);
466+
expect(staleConfigurations.length).to.eq(0);
467+
468+
const activeConfigurations = await provider.provideConfigurations([vscode.Uri.file(newSourceFile)]);
469+
expect(activeConfigurations.length).to.eq(1);
470+
expect(activeConfigurations[0].configuration.defines).to.contain('NEW');
471+
});
409472
});

0 commit comments

Comments
 (0)