From a266b9a6d178285181427169e1060b748f499013 Mon Sep 17 00:00:00 2001 From: Engin Polat <118744+polatengin@users.noreply.github.com> Date: Thu, 23 Jul 2026 21:10:16 +0000 Subject: [PATCH 1/5] test: add diagnostics for invalid inherited user-defined type in extends path --- .../ParametersTests.cs | 43 +++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/src/Bicep.Core.IntegrationTests/ParametersTests.cs b/src/Bicep.Core.IntegrationTests/ParametersTests.cs index 991d991937f..d2180a1fe4a 100644 --- a/src/Bicep.Core.IntegrationTests/ParametersTests.cs +++ b/src/Bicep.Core.IntegrationTests/ParametersTests.cs @@ -419,6 +419,49 @@ public void Valid_extends_should_not_fail() result.ExcludingLinterDiagnostics().Should().NotHaveAnyDiagnostics(); } + [TestMethod] + public void Invalid_inherited_user_defined_type_should_report_diagnostics_on_extends_path() + { + var result = CompilationHelper.CompileParams( + ("parameters.bicepparam", """ + using 'main.bicep' + extends 'shared.bicepparam' + """), + ("shared.bicepparam", """ + using none + + param person = { + test: 'testing' + } + """), + ("main.bicep", """ + param person personType + + type personType = { + name: string + age: int + address: string + } + """)); + + var extendsPath = result.Compilation.GetEntrypointSemanticModel().SourceFile.ProgramSyntax.Declarations + .OfType() + .Single() + .Path; + var diagnostics = result.ExcludingLinterDiagnostics().Diagnostics.ToArray(); + + diagnostics.Should().HaveDiagnostics([ + ("BCP035", DiagnosticLevel.Error, "The specified \"param\" declaration is missing the following required properties: \"address\", \"age\", \"name\"."), + ("BCP037", DiagnosticLevel.Warning, "The property \"test\" is not allowed on objects of type \"{ name: string, age: int, address: string }\". Permissible properties include \"address\", \"age\", \"name\"."), + ]); + diagnostics.Should().AllSatisfy(diagnostic => + { + diagnostic.Span.Should().Be(extendsPath.Span); + diagnostic.Should().BeOfType().Which.Fixes.Should().BeEmpty(); + }); + } + + [TestMethod] public void Invalid_extends_reference_does_not_exist_should_fail() { From 0cfa4baf7c18ce99ab94989633dfdad0b6b9360c Mon Sep 17 00:00:00 2001 From: Engin Polat <118744+polatengin@users.noreply.github.com> Date: Thu, 23 Jul 2026 21:10:27 +0000 Subject: [PATCH 2/5] test: add validation for inherited user-defined type compilation --- .../ParametersTests.cs | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/src/Bicep.Core.IntegrationTests/ParametersTests.cs b/src/Bicep.Core.IntegrationTests/ParametersTests.cs index d2180a1fe4a..c90bd15a9cf 100644 --- a/src/Bicep.Core.IntegrationTests/ParametersTests.cs +++ b/src/Bicep.Core.IntegrationTests/ParametersTests.cs @@ -461,6 +461,43 @@ param person personType }); } + [TestMethod] + public void Valid_inherited_user_defined_type_should_compile() + { + var result = CompilationHelper.CompileParams( + ("parameters.bicepparam", """ + using 'main.bicep' + extends 'shared.bicepparam' + """), + ("shared.bicepparam", """ + using none + + param person = { + name: 'Ada' + age: 36 + address: 'London' + } + """), + ("main.bicep", """ + param person personType + + type personType = { + name: string + age: int + address: string + } + """)); + + result.ExcludingLinterDiagnostics().Should().NotHaveAnyDiagnostics(); + result.Parameters.Should().HaveJsonAtPath("parameters.person.value", """ + { + "name": "Ada", + "age": 36, + "address": "London" + } + """); + } + [TestMethod] public void Invalid_extends_reference_does_not_exist_should_fail() From 0418b7cff6b812f5f165640d6821e1682eca770e Mon Sep 17 00:00:00 2001 From: Engin Polat <118744+polatengin@users.noreply.github.com> Date: Thu, 23 Jul 2026 21:10:46 +0000 Subject: [PATCH 3/5] test: add validation for error severity in invalid inherited user-defined type --- .../ParametersTests.cs | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/src/Bicep.Core.IntegrationTests/ParametersTests.cs b/src/Bicep.Core.IntegrationTests/ParametersTests.cs index c90bd15a9cf..140020f7a09 100644 --- a/src/Bicep.Core.IntegrationTests/ParametersTests.cs +++ b/src/Bicep.Core.IntegrationTests/ParametersTests.cs @@ -498,6 +498,42 @@ param person personType """); } + [TestMethod] + public void Sealed_invalid_inherited_user_defined_type_should_preserve_error_severity() + { + var result = CompilationHelper.CompileParams( + ("parameters.bicepparam", """ + using 'main.bicep' + extends 'shared.bicepparam' + """), + ("shared.bicepparam", """ + using none + + param person = { + test: 'testing' + } + """), + ("main.bicep", """ + param person personType + + @sealed() + type personType = { + name: string + } + """)); + + var extendsPath = result.Compilation.GetEntrypointSemanticModel().SourceFile.ProgramSyntax.Declarations + .OfType() + .Single() + .Path; + var diagnostics = result.ExcludingLinterDiagnostics().Diagnostics.ToArray(); + + diagnostics.Should().HaveDiagnostics([ + ("BCP035", DiagnosticLevel.Error, "The specified \"param\" declaration is missing the following required properties: \"name\"."), + ("BCP037", DiagnosticLevel.Error, "The property \"test\" is not allowed on objects of type \"{ name: string }\". Permissible properties include \"name\"."), + ]); + diagnostics.Should().AllSatisfy(diagnostic => diagnostic.Span.Should().Be(extendsPath.Span)); + } [TestMethod] public void Invalid_extends_reference_does_not_exist_should_fail() From b224aa67c541fc1272629ac40bc1f21c5c2773bf Mon Sep 17 00:00:00 2001 From: Engin Polat <118744+polatengin@users.noreply.github.com> Date: Thu, 23 Jul 2026 21:10:55 +0000 Subject: [PATCH 4/5] test: add diagnostic for nested invalid inherited user-defined type on direct extends path --- .../ParametersTests.cs | 38 +++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/src/Bicep.Core.IntegrationTests/ParametersTests.cs b/src/Bicep.Core.IntegrationTests/ParametersTests.cs index 140020f7a09..23a22ef123e 100644 --- a/src/Bicep.Core.IntegrationTests/ParametersTests.cs +++ b/src/Bicep.Core.IntegrationTests/ParametersTests.cs @@ -535,6 +535,44 @@ param person personType diagnostics.Should().AllSatisfy(diagnostic => diagnostic.Span.Should().Be(extendsPath.Span)); } + [TestMethod] + public void Nested_invalid_inherited_user_defined_type_should_report_diagnostic_on_direct_extends_path() + { + var result = CompilationHelper.CompileParams( + ("parameters.bicepparam", """ + using 'main.bicep' + extends 'middle.bicepparam' + """), + ("middle.bicepparam", """ + using none + extends 'base.bicepparam' + """), + ("base.bicepparam", """ + using none + + param person = { + name: 42 + } + """), + ("main.bicep", """ + param person personType + + type personType = { + name: string + } + """)); + + var extendsPath = result.Compilation.GetEntrypointSemanticModel().SourceFile.ProgramSyntax.Declarations + .OfType() + .Single() + .Path; + var diagnostic = result.ExcludingLinterDiagnostics().Diagnostics.Should().ContainSingle().Subject; + + diagnostic.Should().HaveCodeAndSeverity("BCP036", DiagnosticLevel.Error) + .And.HaveMessage("The property \"name\" expected a value of type \"string\" but the provided value is of type \"42\"."); + diagnostic.Span.Should().Be(extendsPath.Span); + } + [TestMethod] public void Invalid_extends_reference_does_not_exist_should_fail() { From 147b40eedae0553fa411abec89d426ab702327b0 Mon Sep 17 00:00:00 2001 From: Engin Polat <118744+polatengin@users.noreply.github.com> Date: Thu, 23 Jul 2026 21:11:07 +0000 Subject: [PATCH 5/5] fix: correct severity and message for invalid UDT parameter in extended Bicep parameter file --- src/Bicep.Core/Semantics/SemanticModel.cs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/Bicep.Core/Semantics/SemanticModel.cs b/src/Bicep.Core/Semantics/SemanticModel.cs index cb80aa4f58b..607829177ab 100644 --- a/src/Bicep.Core/Semantics/SemanticModel.cs +++ b/src/Bicep.Core/Semantics/SemanticModel.cs @@ -706,6 +706,8 @@ private IEnumerable GatherMissingRequiredExtensionConfigAssignmentD private IEnumerable GatherTypeMismatchDiagnostics() { + var extendsPath = SourceFile.ProgramSyntax.Declarations.OfType().FirstOrDefault()?.Path; + foreach (var assignmentSymbol in Root.ParameterAssignments) { var isFromSameFile = assignmentSymbol.Context.SourceFile == Root.Context.SourceFile; @@ -733,7 +735,9 @@ private IEnumerable GatherTypeMismatchDiagnostics() foreach (var diagnostic in diagnostics.GetDiagnostics()) { - yield return diagnostic; + yield return !isFromSameFile && extendsPath is not null && diagnostic is Diagnostic concreteDiagnostic + ? concreteDiagnostic with { Span = extendsPath.Span, Fixes = [] } + : diagnostic; } } }