diff --git a/src/MSBuild.UnitTests/XMake_Tests.cs b/src/MSBuild.UnitTests/XMake_Tests.cs index 4173c747739..43976f7e022 100644 --- a/src/MSBuild.UnitTests/XMake_Tests.cs +++ b/src/MSBuild.UnitTests/XMake_Tests.cs @@ -888,6 +888,38 @@ public void GetStarOutputsToFileIfRequested(string extraSwitch, string result) result.ShouldContain("MSB1068"); } + /// + /// Regression test for issue where getTargetResult/getItem would throw an unhandled exception + /// when the item spec contained illegal path characters (e.g. compiler command line flags). + /// + [Theory] + [InlineData("-getTargetResult:GetCompileCommands", "\"Result\": \"Success\"")] + [InlineData("-getItem:CompileCommands", "\"Identity\":")] + public void GetTargetResultWithIllegalPathCharacters(string extraSwitch, string expectedContent) + { + using TestEnvironment env = TestEnvironment.Create(); + // Create a project that mimics the ClangTidy target - it outputs items with illegal path characters + // (compiler command line flags) as the item spec. + TransientTestFile project = env.CreateFile("testProject.csproj", @" + + + + + + + + + + + +"); + string results = RunnerUtilities.ExecMSBuild($" {project.Path} /t:GetCompileCommands {extraSwitch}", out bool success); + // The build should succeed instead of throwing an unhandled exception + success.ShouldBeTrue(results); + // The output should contain the expected content + results.ShouldContain(expectedContent); + } + [Theory] [InlineData(true)] [InlineData(false)] diff --git a/src/MSBuild/JsonOutputFormatter.cs b/src/MSBuild/JsonOutputFormatter.cs index cdc166849ca..a3c2f0afc9d 100644 --- a/src/MSBuild/JsonOutputFormatter.cs +++ b/src/MSBuild/JsonOutputFormatter.cs @@ -67,7 +67,7 @@ internal void AddItemInstancesInJsonFormat(string[] itemNames, ProjectInstance p continue; } - jsonItem[metadatumName] = item.GetMetadataValue(metadatumName); + jsonItem[metadatumName] = TryGetMetadataValue(item, metadatumName); } itemArray.Add(jsonItem); @@ -108,7 +108,7 @@ internal void AddItemsInJsonFormat(string[] itemNames, Project project) continue; } - jsonItem[metadatumName] = item.GetMetadataValue(metadatumName); + jsonItem[metadatumName] = TryGetMetadataValue(item, metadatumName); } itemArray.Add(jsonItem); @@ -147,7 +147,7 @@ internal void AddTargetResultsInJsonFormat(string[] targetNames, BuildResult res continue; } - jsonItem[metadatumName] = item.GetMetadata(metadatumName); + jsonItem[metadatumName] = TryGetMetadata(item, metadatumName); } outputArray.Add(jsonItem); @@ -159,5 +159,62 @@ internal void AddTargetResultsInJsonFormat(string[] targetNames, BuildResult res _topLevelNode["TargetResults"] = targetResultsNode; } + + /// + /// Attempts to get metadata from an ITaskItem. If the metadata is a built-in metadata + /// (like FullPath, Directory, etc.) and the item spec contains illegal path characters, + /// this will catch the InvalidOperationException and return an empty string. + /// + private static string TryGetMetadata(ITaskItem item, string metadataName) + { + try + { + return item.GetMetadata(metadataName); + } + catch (InvalidOperationException) + { + // Built-in metadata like FullPath, Directory, etc. require path computation. + // If the item spec contains illegal path characters, return empty string. + return string.Empty; + } + } + + /// + /// Attempts to get metadata value from a ProjectItemInstance. If the metadata is a built-in metadata + /// (like FullPath, Directory, etc.) and the item spec contains illegal path characters, + /// this will catch the InvalidOperationException and return an empty string. + /// + private static string TryGetMetadataValue(ProjectItemInstance item, string metadataName) + { + try + { + return item.GetMetadataValue(metadataName); + } + catch (InvalidOperationException) + { + // Built-in metadata like FullPath, Directory, etc. require path computation. + // If the item spec contains illegal path characters, return empty string. + return string.Empty; + } + } + + /// + /// Attempts to get metadata value from a ProjectItem. If the metadata is a built-in metadata + /// (like FullPath, Directory, etc.) and the item spec contains illegal path characters, + /// this will catch the InvalidOperationException and return an empty string. + /// + private static string TryGetMetadataValue(ProjectItem item, string metadataName) + { + try + { + return item.GetMetadataValue(metadataName); + } + catch (InvalidOperationException) + { + // Built-in metadata like FullPath, Directory, etc. require path computation. + // If the item spec contains illegal path characters, return empty string. + return string.Empty; + } + } } }