Skip to content

Don't discard custom configurations whose uri is a vscode.Uri - #14624

Merged
sean-mcmanus merged 2 commits into
microsoft:mainfrom
owevertonguedes:fix/14621-uri-normalize-before-deepcopy
Jul 30, 2026
Merged

Don't discard custom configurations whose uri is a vscode.Uri#14624
sean-mcmanus merged 2 commits into
microsoft:mainfrom
owevertonguedes:fix/14621-uri-normalize-before-deepcopy

Conversation

@owevertonguedes

Copy link
Copy Markdown
Contributor

Fixes #14621

With C_Cpp.mergeConfigurations enabled, provideCustomConfigurationAsync deep copies the provider's configurations before merging in the entries from c_cpp_properties.json. deepCopy is JSON.parse(JSON.stringify(...)) and vscode.Uri declares toJSON(), so the round trip leaves a plain object behind. isSourceFileConfigurationItem accepts only a string or a real Uri, so every item a provider returned with a vscode.Uri was discarded, sanitized.length was 0, and nothing reached the language server.

SourceFileConfigurationItem.uri is declared string | vscode.Uri and sendCustomConfigurations already converts a Uri with toString(), so this normalizes the field to a string before the copy, which is the option you preferred on the issue.

Makefile Tools builds its items with a Uri object, in src/extension.ts:

let uri: vscode.Uri = vscode.Uri.file(filePath);
let sourceFileConfigurationItem: cpptools.SourceFileConfigurationItem = {
    uri,
    configuration,
    compileCommand: { ... }
};

CMake Tools passes vscode.Uri.file(absolutePath).toString(), a string.

Measured by driving provideCustomConfigurationAsync with a stub provider and recording what reaches sendCustomConfigurations:

uri mergeConfigurations before after
string off all all
string on all all
vscode.Uri off all all
vscode.Uri on none all

The string the item now carries is the result of the same Uri.toString() call the merge off path already made, and sendCustomConfigurations passes a string that starts with file:// through unchanged.

Two details are separable, if you would rather not have them:

  • The configs instanceof Array guard. sendCustomConfigurations gates on that same test, so a value that is array like but not an Array is discarded there today with merge off, which I measured. Removing the guard makes that value work with merge on while it still fails with merge off.
  • The index loop rather than configs.map, and building a new item rather than spreading the old one. Today this function calls no method on the array the provider returns, and the deep copy reads uri once. I measured three inputs against both: an array whose own map is shadowed, an item whose uri is a getter, and an array like object. With configs.map the first one stopped delivering an item that is delivered today; with the spread the second one read uri twice. The version in this PR leaves all three as they are today. sendCustomConfigurations reads only uri and configuration, so anything else a provider attaches to an item, such as the compileCommand field above, is dropped there either way.

One behavior difference worth naming: with merge on, an item whose uri is a Uri with a scheme other than file now arrives as file:///<the original uri>, because sendCustomConfigurations treats any string that does not start with file:// as an fsPath. I measured that this is already what a provider gets today when it passes that same value as a string, in both merge modes. The API documents the field as following the file URI scheme.

No test is included. Nothing in the unit suite loads the vscode module, so a test for this would go in the integration suite, which needs the native binaries, and I did not want to add a test I could not run. tsc --build, the full lint, the 193 unit tests and git diff --check are clean.

This touches the same lines as #14620. Whichever lands first, I will rebase the other.

@owevertonguedes
owevertonguedes requested a review from a team as a code owner July 30, 2026 21:29
@github-project-automation github-project-automation Bot moved this to Pull Request in cpptools Jul 30, 2026
@sean-mcmanus
sean-mcmanus requested a review from Copilot July 30, 2026 22:23

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Fixes a bug where enabling C_Cpp.mergeConfigurations caused custom configuration provider results to be discarded when SourceFileConfigurationItem.uri was a vscode.Uri, due to deepCopy using a JSON round-trip that strips Uri instances.

Changes:

  • Normalize SourceFileConfigurationItem.uri from vscode.Uri to string before deepCopy runs in the mergeConfigurations path.
  • Preserve existing tolerance for unusual provider return shapes by avoiding calling provider-array methods and only reading uri once per item.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread Extension/src/LanguageServer/client.ts
@sean-mcmanus
sean-mcmanus merged commit 35408d5 into microsoft:main Jul 30, 2026
6 checks passed
@github-project-automation github-project-automation Bot moved this from Pull Request to Done in cpptools Jul 30, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

mergeConfigurations discards custom configurations whose uri is a vscode.Uri

4 participants