diff --git a/src/Bicep.Cli/Commands/FormatCommand.cs b/src/Bicep.Cli/Commands/FormatCommand.cs index a1750c72cce..0e0f344eb2e 100644 --- a/src/Bicep.Cli/Commands/FormatCommand.cs +++ b/src/Bicep.Cli/Commands/FormatCommand.cs @@ -44,7 +44,7 @@ public int Run(FormatArguments args) if (!this.fileResolver.TryRead(inputUri).IsSuccess(out var fileContents, out var failureBuilder)) { var diagnostic = failureBuilder(DiagnosticBuilder.ForPosition(new TextSpan(0, 0))); - throw new ErrorDiagnosticException(diagnostic); + throw new DiagnosticException(diagnostic); } BaseParser parser = PathHelper.HasBicepExtension(inputUri) ? new Parser(fileContents) : new ParamsParser(fileContents); diff --git a/src/Bicep.Core.IntegrationTests/ModuleTests.cs b/src/Bicep.Core.IntegrationTests/ModuleTests.cs index 0cefc21923e..effd4abddc7 100644 --- a/src/Bicep.Core.IntegrationTests/ModuleTests.cs +++ b/src/Bicep.Core.IntegrationTests/ModuleTests.cs @@ -179,9 +179,9 @@ param inputb string success.Should().BeFalse(); } - private delegate bool TryReadDelegate(Uri fileUri, out string? fileContents, out DiagnosticBuilder.ErrorBuilderDelegate? failureBuilder); + private delegate bool TryReadDelegate(Uri fileUri, out string? fileContents, out DiagnosticBuilder.DiagnosticBuilderDelegate? failureBuilder); - private static void SetupFileReaderMock(Mock mockFileResolver, Uri fileUri, string? fileContents, DiagnosticBuilder.ErrorBuilderDelegate? failureBuilder) + private static void SetupFileReaderMock(Mock mockFileResolver, Uri fileUri, string? fileContents, DiagnosticBuilder.DiagnosticBuilderDelegate? failureBuilder) { mockFileResolver.Setup(x => x.TryRead(fileUri)).Returns(ResultHelper.Create(fileContents, failureBuilder)); } @@ -197,7 +197,7 @@ public void SourceFileGroupingBuilder_build_should_throw_diagnostic_exception_if SetupFileReaderMock(mockFileResolver, fileUri, null, x => x.ErrorOccurredReadingFile("Mock read failure!")); Action buildAction = () => SourceFileGroupingBuilder.Build(mockFileResolver.Object, mockDispatcher, mockConfigurationManager, new Workspace(), fileUri, BicepTestConstants.FeatureProviderFactory); - buildAction.Should().Throw() + buildAction.Should().Throw() .And.Diagnostic.Should().HaveCodeAndSeverity("BCP091", DiagnosticLevel.Error).And.HaveMessage("An error occurred reading file. Mock read failure!"); } diff --git a/src/Bicep.Core.UnitTests/Assertions/DiagnosticBuilderAssertions.cs b/src/Bicep.Core.UnitTests/Assertions/DiagnosticBuilderAssertions.cs index 0e320e48d45..b6666af67b2 100644 --- a/src/Bicep.Core.UnitTests/Assertions/DiagnosticBuilderAssertions.cs +++ b/src/Bicep.Core.UnitTests/Assertions/DiagnosticBuilderAssertions.cs @@ -22,9 +22,21 @@ public DiagnosticBuilderAssertions(DiagnosticBuilder.DiagnosticBuilderDelegate d protected override string Identifier => "DiagnosticBuilderDelegate"; + public AndConstraint HaveCode(string code, string because = "", params object[] becauseArgs) + { + var diagnostic = GetDiagnosticFromSubject(); + + using (new AssertionScope()) + { + diagnostic.Should().HaveCodeAndSeverity(code, DiagnosticLevel.Error, because, becauseArgs); + } + + return new(this); + } + public AndConstraint HaveCodeAndSeverity(string code, DiagnosticLevel level, string because = "", params object[] becauseArgs) { - Diagnostic diagnostic = GetDiagnosticFromSubject(); + var diagnostic = GetDiagnosticFromSubject(); using (new AssertionScope()) { @@ -36,7 +48,7 @@ public AndConstraint HaveCodeAndSeverity(string cod public AndConstraint HaveMessage(string message, string because = "", params object[] becauseArgs) { - Diagnostic diagnostic = GetDiagnosticFromSubject(); + var diagnostic = GetDiagnosticFromSubject(); using (new AssertionScope()) { @@ -46,6 +58,18 @@ public AndConstraint HaveMessage(string message, st return new(this); } + public AndConstraint HaveMessageStartWith(string prefix, string because = "", params object[] becauseArgs) + { + var diagnostic = GetDiagnosticFromSubject(); + + using (new AssertionScope()) + { + diagnostic.Should().HaveMessageStartWith(prefix, because, becauseArgs); + } + + return new(this); + } + private Diagnostic GetDiagnosticFromSubject() => this.Subject(DiagnosticBuilder.ForDocumentStart()); } } diff --git a/src/Bicep.Core.UnitTests/Assertions/ErrorBuilderAssertions.cs b/src/Bicep.Core.UnitTests/Assertions/ErrorBuilderAssertions.cs deleted file mode 100644 index 900494ffcc1..00000000000 --- a/src/Bicep.Core.UnitTests/Assertions/ErrorBuilderAssertions.cs +++ /dev/null @@ -1,63 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. - -using Bicep.Core.Diagnostics; -using FluentAssertions; -using FluentAssertions.Execution; -using FluentAssertions.Primitives; - -namespace Bicep.Core.UnitTests.Assertions -{ - public static class ErrorBuilderExtensions - { - public static ErrorBuilderAssertions Should(this DiagnosticBuilder.ErrorBuilderDelegate errorBuilder) => new(errorBuilder); - } - - public class ErrorBuilderAssertions : ReferenceTypeAssertions - { - public ErrorBuilderAssertions(DiagnosticBuilder.ErrorBuilderDelegate errorBuilder) - : base(errorBuilder) - { - } - - protected override string Identifier => "ErrorBuilderDelegate"; - - public AndConstraint HaveCode(string code, string because = "", params object[] becauseArgs) - { - ErrorDiagnostic error = GetErrorFromSubject(); - - using (new AssertionScope()) - { - error.Should().HaveCodeAndSeverity(code, DiagnosticLevel.Error, because, becauseArgs); - } - - return new(this); - } - - public AndConstraint HaveMessage(string message, string because = "", params object[] becauseArgs) - { - ErrorDiagnostic error = GetErrorFromSubject(); - - using (new AssertionScope()) - { - error.Should().HaveMessage(message, because, becauseArgs); - } - - return new(this); - } - - public AndConstraint HaveMessageStartWith(string prefix, string because = "", params object[] becauseArgs) - { - ErrorDiagnostic error = GetErrorFromSubject(); - - using (new AssertionScope()) - { - error.Should().HaveMessageStartWith(prefix, because, becauseArgs); - } - - return new(this); - } - - private ErrorDiagnostic GetErrorFromSubject() => this.Subject(DiagnosticBuilder.ForDocumentStart()); - } -} diff --git a/src/Bicep.Core.UnitTests/Registry/ArtifactDispatcherTests.cs b/src/Bicep.Core.UnitTests/Registry/ArtifactDispatcherTests.cs index 4dac745a42e..f9447f49341 100644 --- a/src/Bicep.Core.UnitTests/Registry/ArtifactDispatcherTests.cs +++ b/src/Bicep.Core.UnitTests/Registry/ArtifactDispatcherTests.cs @@ -83,7 +83,7 @@ public async Task MockRegistries_ModuleLifecycle() mock.Setup(x => x.OnRestoreArtifacts(It.IsAny())) .Returns(Task.CompletedTask); - ErrorBuilderDelegate? @null = null; + DiagnosticBuilderDelegate? @null = null; var configuration = BicepTestConstants.BuiltInConfiguration; var validRefUri = RandomFileUri(); @@ -100,7 +100,7 @@ public async Task MockRegistries_ModuleLifecycle() var badRefUri = RandomFileUri(); ArtifactReference? nullRef = null; - ErrorBuilderDelegate? badRefError = x => new ErrorDiagnostic(x.TextSpan, "BCPMock", "Bad ref error"); + DiagnosticBuilderDelegate? badRefError = x => new Diagnostic(x.TextSpan, DiagnosticLevel.Error, "BCPMock", "Bad ref error"); mock.Setup(m => m.TryParseArtifactReference(ArtifactType.Module, null, "badRef")).Returns(ResultHelper.Create(nullRef, badRefError)); mock.Setup(m => m.IsArtifactRestoreRequired(validRef)).Returns(true); @@ -113,9 +113,9 @@ public async Task MockRegistries_ModuleLifecycle() mock.Setup(m => m.TryGetLocalArtifactEntryPointUri(validRef3)).Returns(ResultHelper.Create(validRef3LocalUri, @null)); mock.Setup(m => m.RestoreArtifacts(It.IsAny>())) - .ReturnsAsync(new Dictionary + .ReturnsAsync(new Dictionary { - [validRef3] = x => new ErrorDiagnostic(x.TextSpan, "RegFail", "Failed to restore module") + [validRef3] = x => new Diagnostic(x.TextSpan, DiagnosticLevel.Error, "RegFail", "Failed to restore module") }); var dispatcher = CreateDispatcher(BicepTestConstants.ConfigurationManager, fail.Object, mock.Object); @@ -172,9 +172,9 @@ public async Task GetModuleRestoreStatus_ConfigurationChanges_ReturnsCachedStatu var registryMock = StrictMock.Of(); registryMock.SetupGet(x => x.Scheme).Returns("mock"); registryMock.Setup(x => x.RestoreArtifacts(It.IsAny>())) - .ReturnsAsync(new Dictionary + .ReturnsAsync(new Dictionary { - [badReference] = x => new ErrorDiagnostic(x.TextSpan, "RestoreFailure", "Failed to restore module.") + [badReference] = x => new Diagnostic(x.TextSpan, DiagnosticLevel.Error, "RestoreFailure", "Failed to restore module.") }); registryMock.Setup(x => x.IsArtifactRestoreRequired(badReference)) .Returns(true); diff --git a/src/Bicep.Core.UnitTests/Semantics/AuxiliaryFileCacheTests.cs b/src/Bicep.Core.UnitTests/Semantics/AuxiliaryFileCacheTests.cs index 24419523bd9..7dd7cf7e83c 100644 --- a/src/Bicep.Core.UnitTests/Semantics/AuxiliaryFileCacheTests.cs +++ b/src/Bicep.Core.UnitTests/Semantics/AuxiliaryFileCacheTests.cs @@ -22,7 +22,7 @@ public void TryReadAsBinaryData_should_return_the_same_cached_result() var fileResolverMock = StrictMock.Of(); fileResolverMock.Setup(x => x.TryReadAsBinaryData(fileUri, null)) - .Returns(new ResultWithDiagnostic(binaryData)); + .Returns(new ResultWithDiagnosticBuilder(binaryData)); var sut = new AuxiliaryFileCache(fileResolverMock.Object); @@ -47,7 +47,7 @@ public void TryReadAsBinaryData_caches_negative_results() var fileResolverMock = StrictMock.Of(); fileResolverMock.Setup(x => x.TryReadAsBinaryData(fileUri, null)) - .Returns(new ResultWithDiagnostic(x => x.FilePathInterpolationUnsupported())); + .Returns(new ResultWithDiagnosticBuilder(x => x.FilePathInterpolationUnsupported())); var sut = new AuxiliaryFileCache(fileResolverMock.Object); @@ -71,7 +71,7 @@ public void ClearEntries_should_clear_cached_results() var fileResolverMock = StrictMock.Of(); fileResolverMock.Setup(x => x.TryReadAsBinaryData(fileUri, null)) - .Returns(new ResultWithDiagnostic(binaryData)); + .Returns(new ResultWithDiagnosticBuilder(binaryData)); var sut = new AuxiliaryFileCache(fileResolverMock.Object); @@ -94,7 +94,7 @@ public void PruneInactiveEntries_should_clear_inactive_entries() var fileResolverMock = StrictMock.Of(); fileResolverMock.Setup(x => x.TryReadAsBinaryData(fileUri, null)) - .Returns(new ResultWithDiagnostic(binaryData)); + .Returns(new ResultWithDiagnosticBuilder(binaryData)); var sut = new AuxiliaryFileCache(fileResolverMock.Object); diff --git a/src/Bicep.Core.UnitTests/Utils/ResultHelper.cs b/src/Bicep.Core.UnitTests/Utils/ResultHelper.cs index 8a996867ce6..a6a04ccf764 100644 --- a/src/Bicep.Core.UnitTests/Utils/ResultHelper.cs +++ b/src/Bicep.Core.UnitTests/Utils/ResultHelper.cs @@ -20,7 +20,7 @@ public static Result Create(TSuccess? succes _ => throw new InvalidOperationException($"{nameof(success)} and {nameof(error)} cannot both be non-null"), }; - public static ResultWithDiagnostic Create(TSuccess? success, DiagnosticBuilder.ErrorBuilderDelegate? error) + public static ResultWithDiagnosticBuilder Create(TSuccess? success, DiagnosticBuilder.DiagnosticBuilderDelegate? error) where TSuccess : class => (success, error) switch { diff --git a/src/Bicep.Core.UnitTests/Utils/TestTypeHelper.cs b/src/Bicep.Core.UnitTests/Utils/TestTypeHelper.cs index 3b59fbc214a..34519ce38d6 100644 --- a/src/Bicep.Core.UnitTests/Utils/TestTypeHelper.cs +++ b/src/Bicep.Core.UnitTests/Utils/TestTypeHelper.cs @@ -48,7 +48,7 @@ public static IResourceTypeLoader CreateResourceTypeLoaderWithTypes(IEnumerable< public static IResourceTypeProviderFactory CreateResourceTypeLoaderFactory(IResourceTypeProvider provider) { var factory = StrictMock.Of(); - factory.Setup(m => m.GetResourceTypeProvider(It.IsAny(), It.IsAny(), It.IsAny())).Returns(new ResultWithDiagnostic(provider)); + factory.Setup(m => m.GetResourceTypeProvider(It.IsAny(), It.IsAny(), It.IsAny())).Returns(new ResultWithDiagnosticBuilder(provider)); factory.Setup(m => m.GetBuiltInAzResourceTypesProvider()).Returns(provider); return factory.Object; } diff --git a/src/Bicep.Core/Configuration/ExtensionAliasesConfiguration.cs b/src/Bicep.Core/Configuration/ExtensionAliasesConfiguration.cs index 8fb9e61d727..8096cb5c96e 100644 --- a/src/Bicep.Core/Configuration/ExtensionAliasesConfiguration.cs +++ b/src/Bicep.Core/Configuration/ExtensionAliasesConfiguration.cs @@ -42,7 +42,7 @@ private ExtensionAliasesConfiguration(ExtensionAliases data, Uri? configFileUri) public ImmutableSortedDictionary OciArtifactExtensionAliases => this.Data.OciArtifactExtensionAliases; - public ResultWithDiagnostic TryGetOciArtifactExtensionAlias(string aliasName) + public ResultWithDiagnosticBuilder TryGetOciArtifactExtensionAlias(string aliasName) { if (!ValidateAliasName(aliasName, out var errorBuilder)) { @@ -62,7 +62,7 @@ public ResultWithDiagnostic TryGetOciArtifactExtensio return new(alias); } - private static bool ValidateAliasName(string aliasName, [NotNullWhen(false)] out ErrorBuilderDelegate? errorBuilder) + private static bool ValidateAliasName(string aliasName, [NotNullWhen(false)] out DiagnosticBuilderDelegate? errorBuilder) { if (!ExtensionAliasNameRegex().IsMatch(aliasName)) { diff --git a/src/Bicep.Core/Configuration/ProvidersConfiguration.cs b/src/Bicep.Core/Configuration/ExtensionsConfiguration.cs similarity index 94% rename from src/Bicep.Core/Configuration/ProvidersConfiguration.cs rename to src/Bicep.Core/Configuration/ExtensionsConfiguration.cs index b6e1a84990c..ab3da127f70 100644 --- a/src/Bicep.Core/Configuration/ProvidersConfiguration.cs +++ b/src/Bicep.Core/Configuration/ExtensionsConfiguration.cs @@ -36,7 +36,7 @@ public static ExtensionsConfiguration Bind(JsonElement element) pair => new ExtensionConfigEntry(pair.Value)) ); - public ResultWithDiagnostic TryGetExtensionSource(string extensionName) + public ResultWithDiagnosticBuilder TryGetExtensionSource(string extensionName) { if (!this.Data.TryGetValue(extensionName, out var extensionConfigEntry)) { diff --git a/src/Bicep.Core/Configuration/ModuleAliasesConfiguration.cs b/src/Bicep.Core/Configuration/ModuleAliasesConfiguration.cs index ef5da0ab7fd..5bec6197323 100644 --- a/src/Bicep.Core/Configuration/ModuleAliasesConfiguration.cs +++ b/src/Bicep.Core/Configuration/ModuleAliasesConfiguration.cs @@ -63,7 +63,7 @@ public ImmutableSortedDictionary GetTemplateSpe return this.Data.TemplateSpecModuleAliases; } - public ResultWithDiagnostic TryGetTemplateSpecModuleAlias(string aliasName) + public ResultWithDiagnosticBuilder TryGetTemplateSpecModuleAlias(string aliasName) { if (!ValidateAliasName(aliasName, out var errorBuilder)) { @@ -88,7 +88,7 @@ public ResultWithDiagnostic TryGetTemplateSpecModuleAli return new(alias); } - public ResultWithDiagnostic TryGetOciArtifactModuleAlias(string aliasName) + public ResultWithDiagnosticBuilder TryGetOciArtifactModuleAlias(string aliasName) { if (!ValidateAliasName(aliasName, out var errorBuilder)) { @@ -108,7 +108,7 @@ public ResultWithDiagnostic TryGetOciArtifactModuleAlias return new(alias); } - private static bool ValidateAliasName(string aliasName, [NotNullWhen(false)] out ErrorBuilderDelegate? errorBuilder) + private static bool ValidateAliasName(string aliasName, [NotNullWhen(false)] out DiagnosticBuilderDelegate? errorBuilder) { if (!ModuleAliasNameRegex().IsMatch(aliasName)) { diff --git a/src/Bicep.Core/Diagnostics/Diagnostic.cs b/src/Bicep.Core/Diagnostics/Diagnostic.cs index a370d61cccf..4a0122f9d80 100644 --- a/src/Bicep.Core/Diagnostics/Diagnostic.cs +++ b/src/Bicep.Core/Diagnostics/Diagnostic.cs @@ -40,6 +40,5 @@ public Diagnostic( public string Message { get; } public Uri? Uri { get; } - } } diff --git a/src/Bicep.Core/Diagnostics/DiagnosticBuilder.cs b/src/Bicep.Core/Diagnostics/DiagnosticBuilder.cs index 3dec2548503..3e6ea194083 100644 --- a/src/Bicep.Core/Diagnostics/DiagnosticBuilder.cs +++ b/src/Bicep.Core/Diagnostics/DiagnosticBuilder.cs @@ -23,8 +23,6 @@ public static class DiagnosticBuilder { public const string UseStringInterpolationInsteadClause = "Use string interpolation instead."; - public delegate ErrorDiagnostic ErrorBuilderDelegate(DiagnosticBuilderInternal builder); - public delegate Diagnostic DiagnosticBuilderDelegate(DiagnosticBuilderInternal builder); public class DiagnosticBuilderInternal @@ -71,153 +69,183 @@ private static string BuildBicepConfigurationClause(Uri? configFileUri) => confi ? $"Bicep configuration \"{configFileUri.LocalPath}\"" : $"built-in Bicep configuration"; - public ErrorDiagnostic UnrecognizedToken(string token) => new( + public Diagnostic UnrecognizedToken(string token) => new( TextSpan, + DiagnosticLevel.Error, "BCP001", $"The following token is not recognized: \"{token}\"."); - public ErrorDiagnostic UnterminatedMultilineComment() => new( + public Diagnostic UnterminatedMultilineComment() => new( TextSpan, + DiagnosticLevel.Error, "BCP002", "The multi-line comment at this location is not terminated. Terminate it with the */ character sequence."); - public ErrorDiagnostic UnterminatedString() => new( + public Diagnostic UnterminatedString() => new( TextSpan, + DiagnosticLevel.Error, "BCP003", "The string at this location is not terminated. Terminate the string with a single quote character."); - public ErrorDiagnostic UnterminatedStringWithNewLine() => new( + public Diagnostic UnterminatedStringWithNewLine() => new( TextSpan, + DiagnosticLevel.Error, "BCP004", "The string at this location is not terminated due to an unexpected new line character."); - public ErrorDiagnostic UnterminatedStringEscapeSequenceAtEof() => new( + public Diagnostic UnterminatedStringEscapeSequenceAtEof() => new( TextSpan, + DiagnosticLevel.Error, "BCP005", "The string at this location is not terminated. Complete the escape sequence and terminate the string with a single unescaped quote character."); - public ErrorDiagnostic UnterminatedStringEscapeSequenceUnrecognized(IEnumerable escapeSequences) => new( + public Diagnostic UnterminatedStringEscapeSequenceUnrecognized(IEnumerable escapeSequences) => new( TextSpan, + DiagnosticLevel.Error, "BCP006", $"The specified escape sequence is not recognized. Only the following escape sequences are allowed: {ToQuotedString(escapeSequences)}."); - public ErrorDiagnostic UnrecognizedDeclaration() => new( + public Diagnostic UnrecognizedDeclaration() => new( TextSpan, + DiagnosticLevel.Error, "BCP007", "This declaration type is not recognized. Specify a metadata, parameter, variable, resource, or output declaration."); - public ErrorDiagnostic ExpectedParameterContinuation() => new( + public Diagnostic ExpectedParameterContinuation() => new( TextSpan, + DiagnosticLevel.Error, "BCP008", "Expected the \"=\" token, or a newline at this location."); - public ErrorDiagnostic UnrecognizedExpression() => new( + public Diagnostic UnrecognizedExpression() => new( TextSpan, + DiagnosticLevel.Error, "BCP009", "Expected a literal value, an array, an object, a parenthesized expression, or a function call at this location."); - public ErrorDiagnostic InvalidInteger() => new( + public Diagnostic InvalidInteger() => new( TextSpan, + DiagnosticLevel.Error, "BCP010", "Expected a valid 64-bit signed integer."); - public ErrorDiagnostic InvalidType() => new( + public Diagnostic InvalidType() => new( TextSpan, + DiagnosticLevel.Error, "BCP011", "The type of the specified value is incorrect. Specify a string, boolean, or integer literal."); - public ErrorDiagnostic ExpectedKeyword(string keyword) => new( + public Diagnostic ExpectedKeyword(string keyword) => new( TextSpan, + DiagnosticLevel.Error, "BCP012", $"Expected the \"{keyword}\" keyword at this location."); - public ErrorDiagnostic ExpectedParameterIdentifier() => new( + public Diagnostic ExpectedParameterIdentifier() => new( TextSpan, + DiagnosticLevel.Error, "BCP013", "Expected a parameter identifier at this location."); - public ErrorDiagnostic ExpectedVariableIdentifier() => new( + public Diagnostic ExpectedVariableIdentifier() => new( TextSpan, + DiagnosticLevel.Error, "BCP015", "Expected a variable identifier at this location."); - public ErrorDiagnostic ExpectedOutputIdentifier() => new( + public Diagnostic ExpectedOutputIdentifier() => new( TextSpan, + DiagnosticLevel.Error, "BCP016", "Expected an output identifier at this location."); - public ErrorDiagnostic ExpectedResourceIdentifier() => new( + public Diagnostic ExpectedResourceIdentifier() => new( TextSpan, + DiagnosticLevel.Error, "BCP017", "Expected a resource identifier at this location."); - public ErrorDiagnostic ExpectedCharacter(string character) => new( + public Diagnostic ExpectedCharacter(string character) => new( TextSpan, + DiagnosticLevel.Error, "BCP018", $"Expected the \"{character}\" character at this location."); - public ErrorDiagnostic ExpectedNewLine() => new( + public Diagnostic ExpectedNewLine() => new( TextSpan, + DiagnosticLevel.Error, "BCP019", "Expected a new line character at this location."); - public ErrorDiagnostic ExpectedFunctionOrPropertyName() => new( + public Diagnostic ExpectedFunctionOrPropertyName() => new( TextSpan, + DiagnosticLevel.Error, "BCP020", "Expected a function or property name at this location."); - public ErrorDiagnostic ExpectedNumericLiteral() => new( + public Diagnostic ExpectedNumericLiteral() => new( TextSpan, + DiagnosticLevel.Error, "BCP021", "Expected a numeric literal at this location."); - public ErrorDiagnostic ExpectedPropertyName() => new( + public Diagnostic ExpectedPropertyName() => new( TextSpan, + DiagnosticLevel.Error, "BCP022", "Expected a property name at this location."); - public ErrorDiagnostic ExpectedVariableOrFunctionName() => new( + public Diagnostic ExpectedVariableOrFunctionName() => new( TextSpan, + DiagnosticLevel.Error, "BCP023", "Expected a variable or function name at this location."); - public ErrorDiagnostic IdentifierNameExceedsLimit() => new( + public Diagnostic IdentifierNameExceedsLimit() => new( TextSpan, + DiagnosticLevel.Error, "BCP024", $"The identifier exceeds the limit of {LanguageConstants.MaxIdentifierLength}. Reduce the length of the identifier."); - public ErrorDiagnostic PropertyMultipleDeclarations(string property) => new( + public Diagnostic PropertyMultipleDeclarations(string property) => new( TextSpan, + DiagnosticLevel.Error, "BCP025", $"The property \"{property}\" is declared multiple times in this object. Remove or rename the duplicate properties."); - public ErrorDiagnostic OutputTypeMismatch(TypeSymbol expectedType, TypeSymbol actualType) => new( + public Diagnostic OutputTypeMismatch(TypeSymbol expectedType, TypeSymbol actualType) => new( TextSpan, + DiagnosticLevel.Error, "BCP026", $"The output expects a value of type \"{expectedType}\" but the provided value is of type \"{actualType}\"."); - public ErrorDiagnostic IdentifierMultipleDeclarations(string identifier) => new( + public Diagnostic IdentifierMultipleDeclarations(string identifier) => new( TextSpan, + DiagnosticLevel.Error, "BCP028", $"Identifier \"{identifier}\" is declared multiple times. Remove or rename the duplicates."); - public ErrorDiagnostic InvalidResourceType() => new( + public Diagnostic InvalidResourceType() => new( TextSpan, + DiagnosticLevel.Error, "BCP029", "The resource type is not valid. Specify a valid resource type of format \"@\"."); - public ErrorDiagnostic InvalidOutputType(IEnumerable validTypes) => new( + public Diagnostic InvalidOutputType(IEnumerable validTypes) => new( TextSpan, + DiagnosticLevel.Error, "BCP030", $"The output type is not valid. Please specify one of the following types: {ToQuotedString(validTypes)}."); - public ErrorDiagnostic InvalidParameterType(IEnumerable validTypes) => new( + public Diagnostic InvalidParameterType(IEnumerable validTypes) => new( TextSpan, + DiagnosticLevel.Error, "BCP031", $"The parameter type is not valid. Please specify one of the following types: {ToQuotedString(validTypes)}."); - public ErrorDiagnostic CompileTimeConstantRequired() => new( + public Diagnostic CompileTimeConstantRequired() => new( TextSpan, + DiagnosticLevel.Error, "BCP032", "The value must be a compile-time constant."); @@ -314,37 +342,43 @@ public Diagnostic DisallowedInterpolatedKeyProperty(bool warnInsteadOfError, Sym $"String interpolation is not supported for keys on objects of type \"{type}\"{sourceDeclarationClause}.{permissiblePropertiesClause}"); } - public ErrorDiagnostic VariableTypeAssignmentDisallowed(TypeSymbol valueType) => new( + public Diagnostic VariableTypeAssignmentDisallowed(TypeSymbol valueType) => new( TextSpan, + DiagnosticLevel.Error, "BCP041", $"Values of type \"{valueType}\" cannot be assigned to a variable."); - public ErrorDiagnostic InvalidExpression() => new( + public Diagnostic InvalidExpression() => new( TextSpan, + DiagnosticLevel.Error, "BCP043", "This is not a valid expression."); - public ErrorDiagnostic UnaryOperatorInvalidType(string operatorName, TypeSymbol type) => new( + public Diagnostic UnaryOperatorInvalidType(string operatorName, TypeSymbol type) => new( TextSpan, + DiagnosticLevel.Error, "BCP044", $"Cannot apply operator \"{operatorName}\" to operand of type \"{type}\"."); - public ErrorDiagnostic BinaryOperatorInvalidType(string operatorName, TypeSymbol type1, TypeSymbol type2, string? additionalInfo) => new( + public Diagnostic BinaryOperatorInvalidType(string operatorName, TypeSymbol type1, TypeSymbol type2, string? additionalInfo) => new( TextSpan, + DiagnosticLevel.Error, "BCP045", $"Cannot apply operator \"{operatorName}\" to operands of type \"{type1}\" and \"{type2}\".{(additionalInfo is null ? string.Empty : " " + additionalInfo)}"); - public ErrorDiagnostic ValueTypeMismatch(TypeSymbol type) => new( + public Diagnostic ValueTypeMismatch(TypeSymbol type) => new( TextSpan, + DiagnosticLevel.Error, "BCP046", $"Expected a value of type \"{type}\"."); - public ErrorDiagnostic ResourceTypeInterpolationUnsupported() => new( + public Diagnostic ResourceTypeInterpolationUnsupported() => new( TextSpan, + DiagnosticLevel.Error, "BCP047", "String interpolation is unsupported for specifying the resource type."); - public ErrorDiagnostic CannotResolveFunctionOverload(IList overloadSignatures, TypeSymbol argumentType, IList parameterTypes) + public Diagnostic CannotResolveFunctionOverload(IList overloadSignatures, TypeSymbol argumentType, IList parameterTypes) { var messageBuilder = new StringBuilder(); var overloadCount = overloadSignatures.Count; @@ -361,24 +395,28 @@ public ErrorDiagnostic CannotResolveFunctionOverload(IList overloadSigna var message = messageBuilder.ToString(); - return new ErrorDiagnostic( + return new( TextSpan, + DiagnosticLevel.Error, "BCP048", message); } - public ErrorDiagnostic StringOrIntegerIndexerRequired(TypeSymbol wrongType) => new( + public Diagnostic StringOrIntegerIndexerRequired(TypeSymbol wrongType) => new( TextSpan, + DiagnosticLevel.Error, "BCP049", $"The array index must be of type \"{LanguageConstants.String}\" or \"{LanguageConstants.Int}\" but the provided index was of type \"{wrongType}\"."); - public ErrorDiagnostic FilePathIsEmpty() => new( + public Diagnostic FilePathIsEmpty() => new( TextSpan, + DiagnosticLevel.Error, "BCP050", "The specified path is empty."); - public ErrorDiagnostic FilePathBeginsWithForwardSlash() => new( + public Diagnostic FilePathBeginsWithForwardSlash() => new( TextSpan, + DiagnosticLevel.Error, "BCP051", "The specified path begins with \"/\". Files must be referenced using relative paths."); @@ -394,87 +432,103 @@ public ErrorDiagnostic CannotResolveFunctionOverload(IList overloadSigna "BCP053", $"The type \"{type}\" does not contain property \"{badProperty}\". Available properties include {ToQuotedString(availableProperties)}."); - public ErrorDiagnostic NoPropertiesAllowed(TypeSymbol type) => new( + public Diagnostic NoPropertiesAllowed(TypeSymbol type) => new( TextSpan, + DiagnosticLevel.Error, "BCP054", $"The type \"{type}\" does not contain any properties."); - public ErrorDiagnostic ObjectRequiredForPropertyAccess(TypeSymbol wrongType) => new( + public Diagnostic ObjectRequiredForPropertyAccess(TypeSymbol wrongType) => new( TextSpan, + DiagnosticLevel.Error, "BCP055", $"Cannot access properties of type \"{wrongType}\". An \"{LanguageConstants.Object}\" type is required."); - public ErrorDiagnostic AmbiguousSymbolReference(string name, IEnumerable namespaces) => new( + public Diagnostic AmbiguousSymbolReference(string name, IEnumerable namespaces) => new( TextSpan, + DiagnosticLevel.Error, "BCP056", $"The reference to name \"{name}\" is ambiguous because it exists in namespaces {ToQuotedString(namespaces)}. The reference must be fully-qualified."); - public ErrorDiagnostic SymbolicNameDoesNotExist(string name) => new( + public Diagnostic SymbolicNameDoesNotExist(string name) => new( TextSpan, + DiagnosticLevel.Error, "BCP057", $"The name \"{name}\" does not exist in the current context."); - public ErrorDiagnostic SymbolicNameIsNotAFunction(string name) => new( + public Diagnostic SymbolicNameIsNotAFunction(string name) => new( TextSpan, + DiagnosticLevel.Error, "BCP059", $"The name \"{name}\" is not a function."); - public ErrorDiagnostic VariablesFunctionNotSupported() => new( + public Diagnostic VariablesFunctionNotSupported() => new( TextSpan, + DiagnosticLevel.Error, "BCP060", $"The \"variables\" function is not supported. Directly reference variables by their symbolic names."); - public ErrorDiagnostic ParametersFunctionNotSupported() => new( + public Diagnostic ParametersFunctionNotSupported() => new( TextSpan, + DiagnosticLevel.Error, "BCP061", $"The \"parameters\" function is not supported. Directly reference parameters by their symbolic names."); - public ErrorDiagnostic ReferencedSymbolHasErrors(string name) => new( + public Diagnostic ReferencedSymbolHasErrors(string name) => new( TextSpan, + DiagnosticLevel.Error, "BCP062", $"The referenced declaration with name \"{name}\" is not valid."); - public ErrorDiagnostic SymbolicNameIsNotAVariableOrParameter(string name) => new( + public Diagnostic SymbolicNameIsNotAVariableOrParameter(string name) => new( TextSpan, + DiagnosticLevel.Error, "BCP063", $"The name \"{name}\" is not a parameter, variable, resource or module."); - public ErrorDiagnostic UnexpectedTokensInInterpolation() => new( + public Diagnostic UnexpectedTokensInInterpolation() => new( TextSpan, + DiagnosticLevel.Error, "BCP064", "Found unexpected tokens in interpolated expression."); - public ErrorDiagnostic FunctionOnlyValidInParameterDefaults(string functionName) => new( + public Diagnostic FunctionOnlyValidInParameterDefaults(string functionName) => new( TextSpan, + DiagnosticLevel.Error, "BCP065", $"Function \"{functionName}\" is not valid at this location. It can only be used as a parameter default value."); - public ErrorDiagnostic FunctionOnlyValidInResourceBody(string functionName) => new( + public Diagnostic FunctionOnlyValidInResourceBody(string functionName) => new( TextSpan, + DiagnosticLevel.Error, "BCP066", $"Function \"{functionName}\" is not valid at this location. It can only be used in resource declarations."); - public ErrorDiagnostic ObjectRequiredForMethodAccess(TypeSymbol wrongType) => new( + public Diagnostic ObjectRequiredForMethodAccess(TypeSymbol wrongType) => new( TextSpan, + DiagnosticLevel.Error, "BCP067", $"Cannot call functions on type \"{wrongType}\". An \"{LanguageConstants.Object}\" type is required."); - public ErrorDiagnostic ExpectedResourceTypeString() => new( + public Diagnostic ExpectedResourceTypeString() => new( TextSpan, + DiagnosticLevel.Error, "BCP068", "Expected a resource type string. Specify a valid resource type of format \"@\"."); - public ErrorDiagnostic FunctionNotSupportedOperatorAvailable(string function, string @operator) => new( + public Diagnostic FunctionNotSupportedOperatorAvailable(string function, string @operator) => new( TextSpan, + DiagnosticLevel.Error, "BCP069", $"The function \"{function}\" is not supported. Use the \"{@operator}\" operator instead."); - public ErrorDiagnostic ArgumentTypeMismatch(TypeSymbol argumentType, TypeSymbol parameterType) => new( + public Diagnostic ArgumentTypeMismatch(TypeSymbol argumentType, TypeSymbol parameterType) => new( TextSpan, + DiagnosticLevel.Error, "BCP070", $"Argument of type \"{argumentType}\" is not assignable to parameter of type \"{parameterType}\"."); - public ErrorDiagnostic ArgumentCountMismatch(int argumentCount, int minimumArgumentCount, int? maximumArgumentCount) + public Diagnostic ArgumentCountMismatch(int argumentCount, int minimumArgumentCount, int? maximumArgumentCount) { string expected; @@ -491,14 +545,16 @@ public ErrorDiagnostic ArgumentCountMismatch(int argumentCount, int minimumArgum expected = $"{minimumArgumentCount} to {maximumArgumentCount} arguments"; } - return new ErrorDiagnostic( + return new( TextSpan, + DiagnosticLevel.Error, "BCP071", $"Expected {expected}, but got {argumentCount}."); } - public ErrorDiagnostic CannotReferenceSymbolInParamDefaultValue() => new( + public Diagnostic CannotReferenceSymbolInParamDefaultValue() => new( TextSpan, + DiagnosticLevel.Error, "BCP072", "This symbol cannot be referenced here. Only other parameters can be referenced in parameter default values."); @@ -508,18 +564,21 @@ public ErrorDiagnostic ArgumentCountMismatch(int argumentCount, int minimumArgum "BCP073", $"The property \"{property}\" is read-only. Expressions cannot be assigned to read-only properties.{(showTypeInaccuracy ? TypeInaccuracyClause : string.Empty)}", showTypeInaccuracy ? TypeInaccuracyLink : null); - public ErrorDiagnostic ArraysRequireIntegerIndex(TypeSymbol wrongType) => new( + public Diagnostic ArraysRequireIntegerIndex(TypeSymbol wrongType) => new( TextSpan, + DiagnosticLevel.Error, "BCP074", $"Indexing over arrays requires an index of type \"{LanguageConstants.Int}\" but the provided index was of type \"{wrongType}\"."); - public ErrorDiagnostic ObjectsRequireStringIndex(TypeSymbol wrongType) => new( + public Diagnostic ObjectsRequireStringIndex(TypeSymbol wrongType) => new( TextSpan, + DiagnosticLevel.Error, "BCP075", $"Indexing over objects requires an index of type \"{LanguageConstants.String}\" but the provided index was of type \"{wrongType}\"."); - public ErrorDiagnostic IndexerRequiresObjectOrArray(TypeSymbol wrongType) => new( + public Diagnostic IndexerRequiresObjectOrArray(TypeSymbol wrongType) => new( TextSpan, + DiagnosticLevel.Error, "BCP076", $"Cannot index over expression of type \"{wrongType}\". Arrays or objects are required."); @@ -535,13 +594,15 @@ public ErrorDiagnostic ArgumentCountMismatch(int argumentCount, int minimumArgum "BCP078", $"The property \"{propertyName}\" requires a value of type \"{expectedType}\", but none was supplied."); - public ErrorDiagnostic CyclicExpressionSelfReference() => new( + public Diagnostic CyclicExpressionSelfReference() => new( TextSpan, + DiagnosticLevel.Error, "BCP079", "This expression is referencing its own declaration, which is not allowed."); - public ErrorDiagnostic CyclicExpression(IEnumerable cycle) => new( + public Diagnostic CyclicExpression(IEnumerable cycle) => new( TextSpan, + DiagnosticLevel.Error, "BCP080", $"The expression is involved in a cycle (\"{string.Join("\" -> \"", cycle)}\")."); @@ -551,8 +612,9 @@ public ErrorDiagnostic ArgumentCountMismatch(int argumentCount, int minimumArgum "BCP081", $"Resource type \"{resourceTypeReference.FormatName()}\" does not have types available. Bicep is unable to validate resource properties prior to deployment, but this will not block the resource from being deployed."); - public FixableErrorDiagnostic SymbolicNameDoesNotExistWithSuggestion(string name, string suggestedName) => new( + public FixableDiagnostic SymbolicNameDoesNotExistWithSuggestion(string name, string suggestedName) => new( TextSpan, + DiagnosticLevel.Error, "BCP082", $"The name \"{name}\" does not exist in the current context. Did you mean \"{suggestedName}\"?", null, @@ -568,23 +630,27 @@ public ErrorDiagnostic ArgumentCountMismatch(int argumentCount, int minimumArgum DiagnosticStyling.Default, new CodeFix($"Change \"{badProperty}\" to \"{suggestedProperty}\"", true, CodeFixKind.QuickFix, CodeManipulator.Replace(TextSpan, suggestedProperty))); - public ErrorDiagnostic SymbolicNameCannotUseReservedNamespaceName(string name, IEnumerable namespaces) => new( + public Diagnostic SymbolicNameCannotUseReservedNamespaceName(string name, IEnumerable namespaces) => new( TextSpan, + DiagnosticLevel.Error, "BCP084", $"The symbolic name \"{name}\" is reserved. Please use a different symbolic name. Reserved namespaces are {ToQuotedString(namespaces.OrderBy(ns => ns))}."); - public ErrorDiagnostic FilePathContainsForbiddenCharacters(IEnumerable forbiddenChars) => new( + public Diagnostic FilePathContainsForbiddenCharacters(IEnumerable forbiddenChars) => new( TextSpan, + DiagnosticLevel.Error, "BCP085", $"The specified file path contains one ore more invalid path characters. The following are not permitted: {ToQuotedString(forbiddenChars.OrderBy(x => x).Select(x => x.ToString()))}."); - public ErrorDiagnostic FilePathHasForbiddenTerminator(IEnumerable forbiddenPathTerminatorChars) => new( + public Diagnostic FilePathHasForbiddenTerminator(IEnumerable forbiddenPathTerminatorChars) => new( TextSpan, + DiagnosticLevel.Error, "BCP086", $"The specified file path ends with an invalid character. The following are not permitted: {ToQuotedString(forbiddenPathTerminatorChars.OrderBy(x => x).Select(x => x.ToString()))}."); - public ErrorDiagnostic ComplexLiteralsNotAllowed() => new( + public Diagnostic ComplexLiteralsNotAllowed() => new( TextSpan, + DiagnosticLevel.Error, "BCP087", "Array and object literals are not allowed here."); @@ -606,124 +672,147 @@ public ErrorDiagnostic ArgumentCountMismatch(int argumentCount, int minimumArgum DiagnosticStyling.Default, new CodeFix($"Change \"{property}\" to \"{suggestedProperty}\"", true, CodeFixKind.QuickFix, CodeManipulator.Replace(TextSpan, suggestedProperty))); - public ErrorDiagnostic ModulePathHasNotBeenSpecified() => new( + public Diagnostic ModulePathHasNotBeenSpecified() => new( TextSpan, + DiagnosticLevel.Error, "BCP090", "This module declaration is missing a file path reference."); - public ErrorDiagnostic ErrorOccurredReadingFile(string failureMessage) => new( + public Diagnostic ErrorOccurredReadingFile(string failureMessage) => new( TextSpan, + DiagnosticLevel.Error, "BCP091", $"An error occurred reading file. {failureMessage}"); - public ErrorDiagnostic FilePathInterpolationUnsupported() => new( + public Diagnostic FilePathInterpolationUnsupported() => new( TextSpan, + DiagnosticLevel.Error, "BCP092", "String interpolation is not supported in file paths."); - public ErrorDiagnostic FilePathCouldNotBeResolved(string filePath, string parentPath) => new( + public Diagnostic FilePathCouldNotBeResolved(string filePath, string parentPath) => new( TextSpan, + DiagnosticLevel.Error, "BCP093", $"File path \"{filePath}\" could not be resolved relative to \"{parentPath}\"."); - public ErrorDiagnostic CyclicModuleSelfReference() => new( + public Diagnostic CyclicModuleSelfReference() => new( TextSpan, + DiagnosticLevel.Error, "BCP094", "This module references itself, which is not allowed."); - public ErrorDiagnostic CyclicFile(IEnumerable cycle) => new( + public Diagnostic CyclicFile(IEnumerable cycle) => new( TextSpan, + DiagnosticLevel.Error, "BCP095", $"The file is involved in a cycle (\"{string.Join("\" -> \"", cycle)}\")."); - public ErrorDiagnostic ExpectedModuleIdentifier() => new( + public Diagnostic ExpectedModuleIdentifier() => new( TextSpan, + DiagnosticLevel.Error, "BCP096", "Expected a module identifier at this location."); - public ErrorDiagnostic ExpectedModulePathString() => new( + public Diagnostic ExpectedModulePathString() => new( TextSpan, + DiagnosticLevel.Error, "BCP097", "Expected a module path string. This should be a relative path to another bicep file, e.g. 'myModule.bicep' or '../parent/myModule.bicep'"); - public ErrorDiagnostic FilePathContainsBackSlash() => new( + public Diagnostic FilePathContainsBackSlash() => new( TextSpan, + DiagnosticLevel.Error, "BCP098", "The specified file path contains a \"\\\" character. Use \"/\" instead as the directory separator character."); - public ErrorDiagnostic AllowedMustContainItems() => new( + public Diagnostic AllowedMustContainItems() => new( TextSpan, + DiagnosticLevel.Error, "BCP099", $"The \"{LanguageConstants.ParameterAllowedPropertyName}\" array must contain one or more items."); - public ErrorDiagnostic IfFunctionNotSupported() => new( + public Diagnostic IfFunctionNotSupported() => new( TextSpan, + DiagnosticLevel.Error, "BCP100", "The function \"if\" is not supported. Use the \"?:\" (ternary conditional) operator instead, e.g. condition ? ValueIfTrue : ValueIfFalse"); - public ErrorDiagnostic CreateArrayFunctionNotSupported() => new( + public Diagnostic CreateArrayFunctionNotSupported() => new( TextSpan, + DiagnosticLevel.Error, "BCP101", "The \"createArray\" function is not supported. Construct an array literal using []."); - public ErrorDiagnostic CreateObjectFunctionNotSupported() => new( + public Diagnostic CreateObjectFunctionNotSupported() => new( TextSpan, + DiagnosticLevel.Error, "BCP102", "The \"createObject\" function is not supported. Construct an object literal using {}."); - public ErrorDiagnostic DoubleQuoteToken(string token) => new( + public Diagnostic DoubleQuoteToken(string token) => new( TextSpan, + DiagnosticLevel.Error, "BCP103", $"The following token is not recognized: \"{token}\". Strings are defined using single quotes in bicep."); - public ErrorDiagnostic ReferencedModuleHasErrors() => new( + public Diagnostic ReferencedModuleHasErrors() => new( TextSpan, + DiagnosticLevel.Error, "BCP104", $"The referenced module has errors."); - public ErrorDiagnostic UnableToLoadNonFileUri(Uri fileUri) => new( + public Diagnostic UnableToLoadNonFileUri(Uri fileUri) => new( TextSpan, + DiagnosticLevel.Error, "BCP105", $"Unable to load file from URI \"{fileUri}\"."); - public ErrorDiagnostic UnexpectedCommaSeparator() => new( + public Diagnostic UnexpectedCommaSeparator() => new( TextSpan, + DiagnosticLevel.Error, "BCP106", "Expected a new line character at this location. Commas are not used as separator delimiters."); - public ErrorDiagnostic FunctionDoesNotExistInNamespace(Symbol namespaceType, string name) => new( + public Diagnostic FunctionDoesNotExistInNamespace(Symbol namespaceType, string name) => new( TextSpan, + DiagnosticLevel.Error, "BCP107", $"The function \"{name}\" does not exist in namespace \"{namespaceType.Name}\"."); - public FixableErrorDiagnostic FunctionDoesNotExistInNamespaceWithSuggestion(Symbol namespaceType, string name, string suggestedName) => new( + public FixableDiagnostic FunctionDoesNotExistInNamespaceWithSuggestion(Symbol namespaceType, string name, string suggestedName) => new( TextSpan, + DiagnosticLevel.Error, "BCP108", $"The function \"{name}\" does not exist in namespace \"{namespaceType.Name}\". Did you mean \"{suggestedName}\"?", null, DiagnosticStyling.Default, new CodeFix($"Change \"{name}\" to \"{suggestedName}\"", true, CodeFixKind.QuickFix, CodeManipulator.Replace(TextSpan, suggestedName))); - public ErrorDiagnostic FunctionDoesNotExistOnObject(TypeSymbol type, string name) => new( + public Diagnostic FunctionDoesNotExistOnObject(TypeSymbol type, string name) => new( TextSpan, + DiagnosticLevel.Error, "BCP109", $"The type \"{type}\" does not contain function \"{name}\"."); - public FixableErrorDiagnostic FunctionDoesNotExistOnObjectWithSuggestion(TypeSymbol type, string name, string suggestedName) => new( + public FixableDiagnostic FunctionDoesNotExistOnObjectWithSuggestion(TypeSymbol type, string name, string suggestedName) => new( TextSpan, + DiagnosticLevel.Error, "BCP110", $"The type \"{type}\" does not contain function \"{name}\". Did you mean \"{suggestedName}\"?", null, DiagnosticStyling.Default, new CodeFix($"Change \"{name}\" to \"{suggestedName}\"", true, CodeFixKind.QuickFix, CodeManipulator.Replace(TextSpan, suggestedName))); - public ErrorDiagnostic FilePathContainsControlChars() => new( + public Diagnostic FilePathContainsControlChars() => new( TextSpan, + DiagnosticLevel.Error, "BCP111", $"The specified file path contains invalid control code characters."); - public ErrorDiagnostic TargetScopeMultipleDeclarations() => new( + public Diagnostic TargetScopeMultipleDeclarations() => new( TextSpan, + DiagnosticLevel.Error, "BCP112", $"The \"{LanguageConstants.TargetScopeKeyword}\" cannot be declared multiple times in one file."); @@ -755,14 +844,16 @@ public ErrorDiagnostic ArgumentCountMismatch(int argumentCount, int minimumArgum $"Unsupported scope for module deployment in a \"{LanguageConstants.TargetScopeTypeResourceGroup}\" target scope. Omit this property to inherit the current scope, or specify a valid scope. " + $"Permissible scopes include current resource group: resourceGroup(), named resource group in same subscription: resourceGroup(), named resource group in a different subscription: resourceGroup(, ), current subscription: subscription(), named subscription: subscription() or tenant: tenant()."); - public ErrorDiagnostic EmptyIndexerNotAllowed() => new( + public Diagnostic EmptyIndexerNotAllowed() => new( TextSpan, + DiagnosticLevel.Error, "BCP117", "An empty indexer is not allowed. Specify a valid expression." ); - public ErrorDiagnostic ExpectBodyStartOrIfOrLoopStart() => new( + public Diagnostic ExpectBodyStartOrIfOrLoopStart() => new( TextSpan, + DiagnosticLevel.Error, "BCP118", "Expected the \"{\" character, the \"[\" character, or the \"if\" keyword at this location."); @@ -777,69 +868,82 @@ public Diagnostic RuntimeValueNotAllowedInProperty(string propertyName, string? var variableDependencyChainClause = BuildVariableDependencyChainClause(variableDependencyChain); var accessiblePropertiesClause = BuildAccessiblePropertiesClause(accessedSymbolName, accessiblePropertyNames); - return new ErrorDiagnostic( + return new( TextSpan, + DiagnosticLevel.Error, "BCP120", $"This expression is being used in an assignment to the \"{propertyName}\" property of the \"{objectTypeName}\" type, which requires a value that can be calculated at the start of the deployment.{variableDependencyChainClause}{accessiblePropertiesClause}"); } - public ErrorDiagnostic ResourceMultipleDeclarations(IEnumerable resourceNames) => new( + public Diagnostic ResourceMultipleDeclarations(IEnumerable resourceNames) => new( TextSpan, + DiagnosticLevel.Error, "BCP121", $"Resources: {ToQuotedString(resourceNames)} are defined with this same name in a file. Rename them or split into different modules."); - public ErrorDiagnostic ModuleMultipleDeclarations(IEnumerable moduleNames) => new( + public Diagnostic ModuleMultipleDeclarations(IEnumerable moduleNames) => new( TextSpan, + DiagnosticLevel.Error, "BCP122", $"Modules: {ToQuotedString(moduleNames)} are defined with this same name and this same scope in a file. Rename them or split into different modules."); - public ErrorDiagnostic ExpectedNamespaceOrDecoratorName() => new( + public Diagnostic ExpectedNamespaceOrDecoratorName() => new( TextSpan, + DiagnosticLevel.Error, "BCP123", "Expected a namespace or decorator name at this location."); - public ErrorDiagnostic CannotAttachDecoratorToTarget(string decoratorName, TypeSymbol attachableType, TypeSymbol targetType) => new( + public Diagnostic CannotAttachDecoratorToTarget(string decoratorName, TypeSymbol attachableType, TypeSymbol targetType) => new( TextSpan, + DiagnosticLevel.Error, "BCP124", $"The decorator \"{decoratorName}\" can only be attached to targets of type \"{attachableType}\", but the target has type \"{targetType}\"."); - public ErrorDiagnostic CannotUseFunctionAsParameterDecorator(string functionName) => new( + public Diagnostic CannotUseFunctionAsParameterDecorator(string functionName) => new( TextSpan, + DiagnosticLevel.Error, "BCP125", $"Function \"{functionName}\" cannot be used as a parameter decorator."); - public ErrorDiagnostic CannotUseFunctionAsVariableDecorator(string functionName) => new( + public Diagnostic CannotUseFunctionAsVariableDecorator(string functionName) => new( TextSpan, + DiagnosticLevel.Error, "BCP126", $"Function \"{functionName}\" cannot be used as a variable decorator."); - public ErrorDiagnostic CannotUseFunctionAsResourceDecorator(string functionName) => new( + public Diagnostic CannotUseFunctionAsResourceDecorator(string functionName) => new( TextSpan, + DiagnosticLevel.Error, "BCP127", $"Function \"{functionName}\" cannot be used as a resource decorator."); - public ErrorDiagnostic CannotUseFunctionAsModuleDecorator(string functionName) => new( + public Diagnostic CannotUseFunctionAsModuleDecorator(string functionName) => new( TextSpan, + DiagnosticLevel.Error, "BCP128", $"Function \"{functionName}\" cannot be used as a module decorator."); - public ErrorDiagnostic CannotUseFunctionAsOutputDecorator(string functionName) => new( + public Diagnostic CannotUseFunctionAsOutputDecorator(string functionName) => new( TextSpan, + DiagnosticLevel.Error, "BCP129", $"Function \"{functionName}\" cannot be used as an output decorator."); - public ErrorDiagnostic DecoratorsNotAllowed() => new( + public Diagnostic DecoratorsNotAllowed() => new( TextSpan, + DiagnosticLevel.Error, "BCP130", "Decorators are not allowed here."); - public ErrorDiagnostic ExpectedDeclarationAfterDecorator() => new( + public Diagnostic ExpectedDeclarationAfterDecorator() => new( TextSpan, + DiagnosticLevel.Error, "BCP132", "Expected a declaration after the decorator."); - public ErrorDiagnostic InvalidUnicodeEscape() => new( + public Diagnostic InvalidUnicodeEscape() => new( TextSpan, + DiagnosticLevel.Error, "BCP133", "The unicode escape sequence is not valid. Valid unicode escape sequences range from \\u{0} to \\u{10FFFF}."); @@ -855,18 +959,21 @@ public Diagnostic RuntimeValueNotAllowedInProperty(string propertyName, string? "BCP135", $"Scope {ToQuotedString(LanguageConstants.GetResourceScopeDescriptions(suppliedScope))} is not valid for this resource type. Permitted scopes: {ToQuotedString(LanguageConstants.GetResourceScopeDescriptions(supportedScopes))}."); - public ErrorDiagnostic ExpectedLoopVariableIdentifier() => new( + public Diagnostic ExpectedLoopVariableIdentifier() => new( TextSpan, + DiagnosticLevel.Error, "BCP136", "Expected a loop item variable identifier at this location."); - public ErrorDiagnostic LoopArrayExpressionTypeMismatch(TypeSymbol actualType) => new( + public Diagnostic LoopArrayExpressionTypeMismatch(TypeSymbol actualType) => new( TextSpan, + DiagnosticLevel.Error, "BCP137", $"Loop expected an expression of type \"{LanguageConstants.Array}\" but the provided value is of type \"{actualType}\"."); - public ErrorDiagnostic ForExpressionsNotSupportedHere() => new( + public Diagnostic ForExpressionsNotSupportedHere() => new( TextSpan, + DiagnosticLevel.Error, "BCP138", "For-expressions are not supported in this context. For-expressions may be used as values of resource, module, variable, and output declarations, or values of resource and module properties."); @@ -876,27 +983,31 @@ public Diagnostic RuntimeValueNotAllowedInProperty(string propertyName, string? "BCP139", $"A resource's scope must match the scope of the Bicep file for it to be deployable. You must use modules to deploy resources to a different scope."); - public ErrorDiagnostic UnterminatedMultilineString() => new( + public Diagnostic UnterminatedMultilineString() => new( TextSpan, + DiagnosticLevel.Error, "BCP140", $"The multi-line string at this location is not terminated. Terminate it with \"'''\"."); - public ErrorDiagnostic ExpressionNotCallable() => new( + public Diagnostic ExpressionNotCallable() => new( TextSpan, + DiagnosticLevel.Error, "BCP141", "The expression cannot be used as a decorator as it is not callable."); - public ErrorDiagnostic TooManyPropertyForExpressions() => new( + public Diagnostic TooManyPropertyForExpressions() => new( TextSpan, + DiagnosticLevel.Error, "BCP142", "Property value for-expressions cannot be nested."); - public ErrorDiagnostic ExpressionedPropertiesNotAllowedWithLoops() => new( + public Diagnostic ExpressionedPropertiesNotAllowedWithLoops() => new( TextSpan, + DiagnosticLevel.Error, "BCP143", "For-expressions cannot be used with properties whose names are also expressions."); - public ErrorDiagnostic DirectAccessToCollectionNotSupported(IEnumerable? accessChain = null) + public Diagnostic DirectAccessToCollectionNotSupported(IEnumerable? accessChain = null) { var accessChainClause = accessChain?.Any() ?? false ? $"The collection was accessed by the chain of \"{string.Join("\" -> \"", accessChain)}\". " @@ -904,137 +1015,164 @@ public ErrorDiagnostic DirectAccessToCollectionNotSupported(IEnumerable? return new( TextSpan, + DiagnosticLevel.Error, "BCP144", $"Directly referencing a resource or module collection is not currently supported here. {accessChainClause}Apply an array indexer to the expression."); } - public ErrorDiagnostic OutputMultipleDeclarations(string identifier) => new( + public Diagnostic OutputMultipleDeclarations(string identifier) => new( TextSpan, + DiagnosticLevel.Error, "BCP145", $"Output \"{identifier}\" is declared multiple times. Remove or rename the duplicates."); - public ErrorDiagnostic ExpectedParameterDeclarationAfterDecorator() => new( + public Diagnostic ExpectedParameterDeclarationAfterDecorator() => new( TextSpan, + DiagnosticLevel.Error, "BCP147", "Expected a parameter declaration after the decorator."); - public ErrorDiagnostic ExpectedVariableDeclarationAfterDecorator() => new( + public Diagnostic ExpectedVariableDeclarationAfterDecorator() => new( TextSpan, + DiagnosticLevel.Error, "BCP148", "Expected a variable declaration after the decorator."); - public ErrorDiagnostic ExpectedResourceDeclarationAfterDecorator() => new( + public Diagnostic ExpectedResourceDeclarationAfterDecorator() => new( TextSpan, + DiagnosticLevel.Error, "BCP149", "Expected a resource declaration after the decorator."); - public ErrorDiagnostic ExpectedModuleDeclarationAfterDecorator() => new( + public Diagnostic ExpectedModuleDeclarationAfterDecorator() => new( TextSpan, + DiagnosticLevel.Error, "BCP150", "Expected a module declaration after the decorator."); - public ErrorDiagnostic ExpectedOutputDeclarationAfterDecorator() => new( + public Diagnostic ExpectedOutputDeclarationAfterDecorator() => new( TextSpan, + DiagnosticLevel.Error, "BCP151", "Expected an output declaration after the decorator."); - public ErrorDiagnostic CannotUseFunctionAsDecorator(string functionName) => new( + public Diagnostic CannotUseFunctionAsDecorator(string functionName) => new( TextSpan, + DiagnosticLevel.Error, "BCP152", $"Function \"{functionName}\" cannot be used as a decorator."); - public ErrorDiagnostic ExpectedResourceOrModuleDeclarationAfterDecorator() => new( + public Diagnostic ExpectedResourceOrModuleDeclarationAfterDecorator() => new( TextSpan, + DiagnosticLevel.Error, "BCP153", "Expected a resource or module declaration after the decorator."); - public ErrorDiagnostic BatchSizeTooSmall(long value, long limit) => new( + public Diagnostic BatchSizeTooSmall(long value, long limit) => new( TextSpan, + DiagnosticLevel.Error, "BCP154", $"Expected a batch size of at least {limit} but the specified value was \"{value}\"."); - public ErrorDiagnostic BatchSizeNotAllowed(string decoratorName) => new( + public Diagnostic BatchSizeNotAllowed(string decoratorName) => new( TextSpan, + DiagnosticLevel.Error, "BCP155", $"The decorator \"{decoratorName}\" can only be attached to resource or module collections."); - public ErrorDiagnostic InvalidResourceTypeSegment(string typeSegment) => new( + public Diagnostic InvalidResourceTypeSegment(string typeSegment) => new( TextSpan, + DiagnosticLevel.Error, "BCP156", $"The resource type segment \"{typeSegment}\" is invalid. Nested resources must specify a single type segment, and optionally can specify an api version using the format \"@\"."); - public ErrorDiagnostic InvalidAncestorResourceType() => new( + public Diagnostic InvalidAncestorResourceType() => new( TextSpan, + DiagnosticLevel.Error, "BCP157", $"The resource type cannot be determined due to an error in the containing resource."); - public ErrorDiagnostic ResourceRequiredForResourceAccess(string wrongType) => new( + public Diagnostic ResourceRequiredForResourceAccess(string wrongType) => new( TextSpan, + DiagnosticLevel.Error, "BCP158", $"Cannot access nested resources of type \"{wrongType}\". A resource type is required."); - public ErrorDiagnostic NestedResourceNotFound(string resourceName, string identifierName, IEnumerable nestedResourceNames) => new( + public Diagnostic NestedResourceNotFound(string resourceName, string identifierName, IEnumerable nestedResourceNames) => new( TextSpan, + DiagnosticLevel.Error, "BCP159", $"The resource \"{resourceName}\" does not contain a nested resource named \"{identifierName}\". Known nested resources are: {ToQuotedString(nestedResourceNames)}."); - public ErrorDiagnostic NestedResourceNotAllowedInLoop() => new( + public Diagnostic NestedResourceNotAllowedInLoop() => new( TextSpan, + DiagnosticLevel.Error, "BCP160", $"A nested resource cannot appear inside of a resource with a for-expression."); - public ErrorDiagnostic ExpectedLoopItemIdentifierOrVariableBlockStart() => new( + public Diagnostic ExpectedLoopItemIdentifierOrVariableBlockStart() => new( TextSpan, + DiagnosticLevel.Error, "BCP162", "Expected a loop item variable identifier or \"(\" at this location."); - public ErrorDiagnostic ScopeUnsupportedOnChildResource() => new( + public Diagnostic ScopeUnsupportedOnChildResource() => new( TextSpan, + DiagnosticLevel.Error, "BCP164", $"A child resource's scope is computed based on the scope of its ancestor resource. This means that using the \"{LanguageConstants.ResourceScopePropertyName}\" property on a child resource is unsupported."); - public ErrorDiagnostic ScopeDisallowedForAncestorResource(string ancestorIdentifier) => new( + public Diagnostic ScopeDisallowedForAncestorResource(string ancestorIdentifier) => new( TextSpan, + DiagnosticLevel.Error, "BCP165", $"A resource's computed scope must match that of the Bicep file for it to be deployable. This resource's scope is computed from the \"{LanguageConstants.ResourceScopePropertyName}\" property value assigned to ancestor resource \"{ancestorIdentifier}\". You must use modules to deploy resources to a different scope."); - public ErrorDiagnostic DuplicateDecorator(string decoratorName) => new( + public Diagnostic DuplicateDecorator(string decoratorName) => new( TextSpan, + DiagnosticLevel.Error, "BCP166", $"Duplicate \"{decoratorName}\" decorator."); - public ErrorDiagnostic ExpectBodyStartOrIf() => new( + public Diagnostic ExpectBodyStartOrIf() => new( TextSpan, + DiagnosticLevel.Error, "BCP167", "Expected the \"{\" character or the \"if\" keyword at this location."); - public ErrorDiagnostic LengthMustNotBeNegative() => new( + public Diagnostic LengthMustNotBeNegative() => new( TextSpan, + DiagnosticLevel.Error, "BCP168", $"Length must not be a negative value."); - public ErrorDiagnostic TopLevelChildResourceNameIncorrectQualifierCount(int expectedSlashCount) => new( + public Diagnostic TopLevelChildResourceNameIncorrectQualifierCount(int expectedSlashCount) => new( TextSpan, + DiagnosticLevel.Error, "BCP169", $"Expected resource name to contain {expectedSlashCount} \"/\" character(s). The number of name segments must match the number of segments in the resource type."); - public ErrorDiagnostic ChildResourceNameContainsQualifiers() => new( + public Diagnostic ChildResourceNameContainsQualifiers() => new( TextSpan, + DiagnosticLevel.Error, "BCP170", $"Expected resource name to not contain any \"/\" characters. Child resources with a parent resource reference (via the parent property or via nesting) must not contain a fully-qualified name."); - public ErrorDiagnostic ResourceTypeIsNotValidParent(string resourceType, string parentResourceType) => new( + public Diagnostic ResourceTypeIsNotValidParent(string resourceType, string parentResourceType) => new( TextSpan, + DiagnosticLevel.Error, "BCP171", $"Resource type \"{resourceType}\" is not a valid child resource of parent \"{parentResourceType}\"."); - public ErrorDiagnostic ParentResourceTypeHasErrors(string resourceName) => new( + public Diagnostic ParentResourceTypeHasErrors(string resourceName) => new( TextSpan, + DiagnosticLevel.Error, "BCP172", $"The resource type cannot be validated due to an error in parent resource \"{resourceName}\"."); - public ErrorDiagnostic CannotUsePropertyInExistingResource(string property) => new( + public Diagnostic CannotUsePropertyInExistingResource(string property) => new( TextSpan, + DiagnosticLevel.Error, "BCP173", $"The property \"{property}\" cannot be used in an existing resource declaration."); @@ -1045,29 +1183,32 @@ public ErrorDiagnostic DirectAccessToCollectionNotSupported(IEnumerable? $"Type validation is not available for resource types declared containing a \"/providers/\" segment. Please instead use the \"scope\" property.", new Uri("https://aka.ms/BicepScopes")); - public ErrorDiagnostic AnyTypeIsNotAllowed() => new( + public Diagnostic AnyTypeIsNotAllowed() => new( TextSpan, + DiagnosticLevel.Error, "BCP176", $"Values of the \"any\" type are not allowed here."); - public ErrorDiagnostic RuntimeValueNotAllowedInIfConditionExpression(string? accessedSymbolName, IEnumerable? accessiblePropertyNames, IEnumerable? variableDependencyChain) + public Diagnostic RuntimeValueNotAllowedInIfConditionExpression(string? accessedSymbolName, IEnumerable? accessiblePropertyNames, IEnumerable? variableDependencyChain) { var variableDependencyChainClause = BuildVariableDependencyChainClause(variableDependencyChain); var accessiblePropertiesClause = BuildAccessiblePropertiesClause(accessedSymbolName, accessiblePropertyNames); - return new ErrorDiagnostic( + return new( TextSpan, + DiagnosticLevel.Error, "BCP177", $"This expression is being used in the if-condition expression, which requires a value that can be calculated at the start of the deployment.{variableDependencyChainClause}{accessiblePropertiesClause}"); } - public ErrorDiagnostic RuntimeValueNotAllowedInForExpression(string? accessedSymbolName, IEnumerable? accessiblePropertyNames, IEnumerable? variableDependencyChain) + public Diagnostic RuntimeValueNotAllowedInForExpression(string? accessedSymbolName, IEnumerable? accessiblePropertyNames, IEnumerable? variableDependencyChain) { var variableDependencyChainClause = BuildVariableDependencyChainClause(variableDependencyChain); var accessiblePropertiesClause = BuildAccessiblePropertiesClause(accessedSymbolName, accessiblePropertyNames); - return new ErrorDiagnostic( + return new( TextSpan, + DiagnosticLevel.Error, "BCP178", $"This expression is being used in the for-expression, which requires a value that can be calculated at the start of the deployment.{variableDependencyChainClause}{accessiblePropertiesClause}"); } @@ -1080,41 +1221,46 @@ indexVariableName is null ? $"Unique resource or deployment name is required when looping. The loop item variable \"{itemVariableName}\" must be referenced in at least one of the value expressions of the following properties: {ToQuotedString(expectedVariantProperties)}" : $"Unique resource or deployment name is required when looping. The loop item variable \"{itemVariableName}\" or the index variable \"{indexVariableName}\" must be referenced in at least one of the value expressions of the following properties in the loop body: {ToQuotedString(expectedVariantProperties)}"); - public ErrorDiagnostic FunctionOnlyValidInModuleSecureParameterAssignment(string functionName) => new( + public Diagnostic FunctionOnlyValidInModuleSecureParameterAssignment(string functionName) => new( TextSpan, + DiagnosticLevel.Error, "BCP180", $"Function \"{functionName}\" is not valid at this location. It can only be used when directly assigning to a module parameter with a secure decorator."); - public ErrorDiagnostic RuntimeValueNotAllowedInRunTimeFunctionArguments(string functionName, string? accessedSymbolName, IEnumerable? accessiblePropertyNames, IEnumerable? variableDependencyChain) + public Diagnostic RuntimeValueNotAllowedInRunTimeFunctionArguments(string functionName, string? accessedSymbolName, IEnumerable? accessiblePropertyNames, IEnumerable? variableDependencyChain) { var variableDependencyChainClause = BuildVariableDependencyChainClause(variableDependencyChain); var accessiblePropertiesClause = BuildAccessiblePropertiesClause(accessedSymbolName, accessiblePropertyNames); - return new ErrorDiagnostic( + return new( TextSpan, + DiagnosticLevel.Error, "BCP181", $"This expression is being used in an argument of the function \"{functionName}\", which requires a value that can be calculated at the start of the deployment.{variableDependencyChainClause}{accessiblePropertiesClause}"); } - public ErrorDiagnostic RuntimeValueNotAllowedInVariableForBody(string variableName, string? accessedSymbolName, IEnumerable? accessiblePropertyNames, IEnumerable? variableDependencyChain, string? violatingPropertyName) + public Diagnostic RuntimeValueNotAllowedInVariableForBody(string variableName, string? accessedSymbolName, IEnumerable? accessiblePropertyNames, IEnumerable? variableDependencyChain, string? violatingPropertyName) { var variableDependencyChainClause = BuildVariableDependencyChainClause(variableDependencyChain); var violatingPropertyNameClause = BuildNonDeployTimeConstantPropertyClause(accessedSymbolName, violatingPropertyName); var accessiblePropertiesClause = BuildAccessiblePropertiesClause(accessedSymbolName, accessiblePropertyNames); - return new ErrorDiagnostic( + return new( TextSpan, + DiagnosticLevel.Error, "BCP182", $"This expression is being used in the for-body of the variable \"{variableName}\", which requires values that can be calculated at the start of the deployment.{variableDependencyChainClause}{violatingPropertyNameClause}{accessiblePropertiesClause}"); } - public ErrorDiagnostic ModuleParametersPropertyRequiresObjectLiteral() => new( + public Diagnostic ModuleParametersPropertyRequiresObjectLiteral() => new( TextSpan, + DiagnosticLevel.Error, "BCP183", $"The value of the module \"{LanguageConstants.ModuleParamsPropertyName}\" property must be an object literal."); - public ErrorDiagnostic FileExceedsMaximumSize(string filePath, long maxSize, string unit) => new( + public Diagnostic FileExceedsMaximumSize(string filePath, long maxSize, string unit) => new( TextSpan, + DiagnosticLevel.Error, "BCP184", $"File '{filePath}' exceeded maximum size of {maxSize} {unit}."); @@ -1124,8 +1270,9 @@ public ErrorDiagnostic RuntimeValueNotAllowedInVariableForBody(string variableNa "BCP185", $"Encoding mismatch. File was loaded with '{detectedEncoding}' encoding."); - public ErrorDiagnostic UnparsableJsonType() => new( + public Diagnostic UnparsableJsonType() => new( TextSpan, + DiagnosticLevel.Error, "BCP186", $"Unable to parse literal JSON value. Please ensure that it is well-formed."); @@ -1135,17 +1282,19 @@ public ErrorDiagnostic RuntimeValueNotAllowedInVariableForBody(string variableNa "BCP187", $"The property \"{property}\" does not exist in the resource or type definition, although it might still be valid.{TypeInaccuracyClause}", TypeInaccuracyLink); - public ErrorDiagnostic ReferencedArmTemplateHasErrors() => new( + public Diagnostic ReferencedArmTemplateHasErrors() => new( TextSpan, + DiagnosticLevel.Error, "BCP188", $"The referenced ARM template has errors. Please see https://aka.ms/arm-template for information on how to diagnose and fix the template."); - public ErrorDiagnostic UnknownModuleReferenceScheme(string badScheme, ImmutableArray allowedSchemes) + public Diagnostic UnknownModuleReferenceScheme(string badScheme, ImmutableArray allowedSchemes) { string FormatSchemes() => ToQuotedString(allowedSchemes.Where(scheme => !string.Equals(scheme, ArtifactReferenceSchemes.Local))); return new( TextSpan, + DiagnosticLevel.Error, "BCP189", (allowedSchemes.Contains(ArtifactReferenceSchemes.Local, StringComparer.Ordinal), allowedSchemes.Any(scheme => !string.Equals(scheme, ArtifactReferenceSchemes.Local, StringComparison.Ordinal))) switch { @@ -1161,183 +1310,217 @@ public ErrorDiagnostic UnknownModuleReferenceScheme(string badScheme, ImmutableA // - In VS code, it's transient until the background restore finishes. // // Should it be split into two separate errors instead? - public ErrorDiagnostic ArtifactRequiresRestore(string artifactRef) => new( + public Diagnostic ArtifactRequiresRestore(string artifactRef) => new( TextSpan, + DiagnosticLevel.Error, "BCP190", $"The artifact with reference \"{artifactRef}\" has not been restored."); - public ErrorDiagnostic ArtifactRestoreFailed(string artifactRef) => new( + public Diagnostic ArtifactRestoreFailed(string artifactRef) => new( TextSpan, + DiagnosticLevel.Error, "BCP191", $"Unable to restore the artifact with reference \"{artifactRef}\"."); - public ErrorDiagnostic ArtifactRestoreFailedWithMessage(string artifactRef, string message) => new( + public Diagnostic ArtifactRestoreFailedWithMessage(string artifactRef, string message) => new( TextSpan, + DiagnosticLevel.Error, "BCP192", $"Unable to restore the artifact with reference \"{artifactRef}\": {message}"); - public ErrorDiagnostic InvalidOciArtifactReference(string? aliasName, string badRef) => new( + public Diagnostic InvalidOciArtifactReference(string? aliasName, string badRef) => new( TextSpan, + DiagnosticLevel.Error, "BCP193", $"{BuildInvalidOciArtifactReferenceClause(aliasName, badRef)} Specify a reference in the format of \"{ArtifactReferenceSchemes.Oci}::\", or \"{ArtifactReferenceSchemes.Oci}/::\"."); - public ErrorDiagnostic InvalidTemplateSpecReference(string? aliasName, string badRef) => new( + public Diagnostic InvalidTemplateSpecReference(string? aliasName, string badRef) => new( TextSpan, + DiagnosticLevel.Error, "BCP194", $"{BuildInvalidTemplateSpecReferenceClause(aliasName, badRef)} Specify a reference in the format of \"{ArtifactReferenceSchemes.TemplateSpecs}://:\", or \"{ArtifactReferenceSchemes.TemplateSpecs}/::\"."); - public ErrorDiagnostic InvalidOciArtifactReferenceInvalidPathSegment(string? aliasName, string badRef, string badSegment) => new( + public Diagnostic InvalidOciArtifactReferenceInvalidPathSegment(string? aliasName, string badRef, string badSegment) => new( TextSpan, + DiagnosticLevel.Error, "BCP195", $"{BuildInvalidOciArtifactReferenceClause(aliasName, badRef)} The artifact path segment \"{badSegment}\" is not valid. Each artifact name path segment must be a lowercase alphanumeric string optionally separated by a \".\", \"_\" , or \"-\"."); - public ErrorDiagnostic InvalidOciArtifactReferenceMissingTagOrDigest(string? aliasName, string badRef) => new( + public Diagnostic InvalidOciArtifactReferenceMissingTagOrDigest(string? aliasName, string badRef) => new( TextSpan, + DiagnosticLevel.Error, "BCP196", $"{BuildInvalidOciArtifactReferenceClause(aliasName, badRef)} The module tag or digest is missing."); - public ErrorDiagnostic InvalidOciArtifactReferenceTagTooLong(string? aliasName, string badRef, string badTag, int maxLength) => new( + public Diagnostic InvalidOciArtifactReferenceTagTooLong(string? aliasName, string badRef, string badTag, int maxLength) => new( TextSpan, + DiagnosticLevel.Error, "BCP197", $"{BuildInvalidOciArtifactReferenceClause(aliasName, badRef)} The tag \"{badTag}\" exceeds the maximum length of {maxLength} characters."); - public ErrorDiagnostic InvalidOciArtifactReferenceInvalidTag(string? aliasName, string badRef, string badTag) => new( + public Diagnostic InvalidOciArtifactReferenceInvalidTag(string? aliasName, string badRef, string badTag) => new( TextSpan, + DiagnosticLevel.Error, "BCP198", $"{BuildInvalidOciArtifactReferenceClause(aliasName, badRef)} The tag \"{badTag}\" is not valid. Valid characters are alphanumeric, \".\", \"_\", or \"-\" but the tag cannot begin with \".\", \"_\", or \"-\"."); - public ErrorDiagnostic InvalidOciArtifactReferenceRepositoryTooLong(string? aliasName, string badRef, string badRepository, int maxLength) => new( + public Diagnostic InvalidOciArtifactReferenceRepositoryTooLong(string? aliasName, string badRef, string badRepository, int maxLength) => new( TextSpan, + DiagnosticLevel.Error, "BCP199", $"{BuildInvalidOciArtifactReferenceClause(aliasName, badRef)} Module path \"{badRepository}\" exceeds the maximum length of {maxLength} characters."); - public ErrorDiagnostic InvalidOciArtifactReferenceRegistryTooLong(string? aliasName, string badRef, string badRegistry, int maxLength) => new( + public Diagnostic InvalidOciArtifactReferenceRegistryTooLong(string? aliasName, string badRef, string badRegistry, int maxLength) => new( TextSpan, + DiagnosticLevel.Error, "BCP200", $"{BuildInvalidOciArtifactReferenceClause(aliasName, badRef)} The registry \"{badRegistry}\" exceeds the maximum length of {maxLength} characters."); - public ErrorDiagnostic ExpectedExtensionSpecification() + public Diagnostic ExpectedExtensionSpecification() { var message = """ Expected an extension specification string with a valid format at this location. Valid formats: * "br:/:" * "br/::" """; - return new(TextSpan, "BCP201", message); + return new(TextSpan, DiagnosticLevel.Error, "BCP201", message); } - public ErrorDiagnostic ExpectedExtensionAliasName() => new( + public Diagnostic ExpectedExtensionAliasName() => new( TextSpan, + DiagnosticLevel.Error, "BCP202", "Expected an extension alias name at this location."); - public ErrorDiagnostic ExtensionsAreDisabled() => new( + public Diagnostic ExtensionsAreDisabled() => new( TextSpan, + DiagnosticLevel.Error, "BCP203", $@"Using extension declaration requires enabling EXPERIMENTAL feature ""{nameof(ExperimentalFeaturesEnabled.Extensibility)}""."); - public ErrorDiagnostic UnrecognizedExtension(string identifier) => new( + public Diagnostic UnrecognizedExtension(string identifier) => new( TextSpan, + DiagnosticLevel.Error, "BCP204", $"Extension \"{identifier}\" is not recognized."); - public ErrorDiagnostic ExtensionDoesNotSupportConfiguration(string identifier) => new( + public Diagnostic ExtensionDoesNotSupportConfiguration(string identifier) => new( TextSpan, + DiagnosticLevel.Error, "BCP205", $"Extension \"{identifier}\" does not support configuration."); - public ErrorDiagnostic ExtensionRequiresConfiguration(string identifier) => new( + public Diagnostic ExtensionRequiresConfiguration(string identifier) => new( TextSpan, + DiagnosticLevel.Error, "BCP206", $"Extension \"{identifier}\" requires configuration, but none was provided."); - public ErrorDiagnostic NamespaceMultipleDeclarations(string identifier) => new( + public Diagnostic NamespaceMultipleDeclarations(string identifier) => new( TextSpan, + DiagnosticLevel.Error, "BCP207", $"Namespace \"{identifier}\" is declared multiple times. Remove the duplicates."); - public ErrorDiagnostic UnknownResourceReferenceScheme(string badNamespace, IEnumerable allowedNamespaces) => new( + public Diagnostic UnknownResourceReferenceScheme(string badNamespace, IEnumerable allowedNamespaces) => new( TextSpan, + DiagnosticLevel.Error, "BCP208", $"The specified namespace \"{badNamespace}\" is not recognized. Specify a resource reference using one of the following namespaces: {ToQuotedString(allowedNamespaces)}."); - public ErrorDiagnostic FailedToFindResourceTypeInNamespace(string @namespace, string resourceType) => new( + public Diagnostic FailedToFindResourceTypeInNamespace(string @namespace, string resourceType) => new( TextSpan, + DiagnosticLevel.Error, "BCP209", $"Failed to find resource type \"{resourceType}\" in namespace \"{@namespace}\"."); - public ErrorDiagnostic ParentResourceInDifferentNamespace(string childNamespace, string parentNamespace) => new( + public Diagnostic ParentResourceInDifferentNamespace(string childNamespace, string parentNamespace) => new( TextSpan, + DiagnosticLevel.Error, "BCP210", $"Resource type belonging to namespace \"{childNamespace}\" cannot have a parent resource type belonging to different namespace \"{parentNamespace}\"."); - public ErrorDiagnostic InvalidModuleAliasName(string aliasName) => new( + public Diagnostic InvalidModuleAliasName(string aliasName) => new( TextSpan, + DiagnosticLevel.Error, "BCP211", $"The module alias name \"{aliasName}\" is invalid. Valid characters are alphanumeric, \"_\", or \"-\"."); - public ErrorDiagnostic TemplateSpecModuleAliasNameDoesNotExistInConfiguration(string aliasName, Uri? configFileUri) => new( + public Diagnostic TemplateSpecModuleAliasNameDoesNotExistInConfiguration(string aliasName, Uri? configFileUri) => new( TextSpan, + DiagnosticLevel.Error, "BCP212", $"The Template Spec module alias name \"{aliasName}\" does not exist in the {BuildBicepConfigurationClause(configFileUri)}."); - public ErrorDiagnostic OciArtifactModuleAliasNameDoesNotExistInConfiguration(string aliasName, Uri? configFileUri) => new( + public Diagnostic OciArtifactModuleAliasNameDoesNotExistInConfiguration(string aliasName, Uri? configFileUri) => new( TextSpan, + DiagnosticLevel.Error, "BCP213", $"The OCI artifact module alias name \"{aliasName}\" does not exist in the {BuildBicepConfigurationClause(configFileUri)}."); - public ErrorDiagnostic InvalidTemplateSpecAliasSubscriptionNullOrUndefined(string aliasName, Uri? configFileUri) => new( + public Diagnostic InvalidTemplateSpecAliasSubscriptionNullOrUndefined(string aliasName, Uri? configFileUri) => new( TextSpan, + DiagnosticLevel.Error, "BCP214", $"The Template Spec module alias \"{aliasName}\" in the {BuildBicepConfigurationClause(configFileUri)} is in valid. The \"subscription\" property cannot be null or undefined."); - public ErrorDiagnostic InvalidTemplateSpecAliasResourceGroupNullOrUndefined(string aliasName, Uri? configFileUri) => new( + public Diagnostic InvalidTemplateSpecAliasResourceGroupNullOrUndefined(string aliasName, Uri? configFileUri) => new( TextSpan, + DiagnosticLevel.Error, "BCP215", $"The Template Spec module alias \"{aliasName}\" in the {BuildBicepConfigurationClause(configFileUri)} is in valid. The \"resourceGroup\" property cannot be null or undefined."); - public ErrorDiagnostic InvalidOciArtifactModuleAliasRegistryNullOrUndefined(string aliasName, Uri? configFileUri) => new( + public Diagnostic InvalidOciArtifactModuleAliasRegistryNullOrUndefined(string aliasName, Uri? configFileUri) => new( TextSpan, + DiagnosticLevel.Error, "BCP216", $"The OCI artifact module alias \"{aliasName}\" in the {BuildBicepConfigurationClause(configFileUri)} is invalid. The \"registry\" property cannot be null or undefined."); - public ErrorDiagnostic InvalidTemplateSpecReferenceInvalidSubscriptionId(string? aliasName, string subscriptionId, string referenceValue) => new( + public Diagnostic InvalidTemplateSpecReferenceInvalidSubscriptionId(string? aliasName, string subscriptionId, string referenceValue) => new( TextSpan, + DiagnosticLevel.Error, "BCP217", $"{BuildInvalidTemplateSpecReferenceClause(aliasName, referenceValue)} The subscription ID \"{subscriptionId}\" in is not a GUID."); - public ErrorDiagnostic InvalidTemplateSpecReferenceResourceGroupNameTooLong(string? aliasName, string resourceGroupName, string referenceValue, int maximumLength) => new( + public Diagnostic InvalidTemplateSpecReferenceResourceGroupNameTooLong(string? aliasName, string resourceGroupName, string referenceValue, int maximumLength) => new( TextSpan, + DiagnosticLevel.Error, "BCP218", $"{BuildInvalidTemplateSpecReferenceClause(aliasName, referenceValue)} The resource group name \"{resourceGroupName}\" exceeds the maximum length of {maximumLength} characters."); - public ErrorDiagnostic InvalidTemplateSpecReferenceInvalidResourceGroupName(string? aliasName, string resourceGroupName, string referenceValue) => new( + public Diagnostic InvalidTemplateSpecReferenceInvalidResourceGroupName(string? aliasName, string resourceGroupName, string referenceValue) => new( TextSpan, + DiagnosticLevel.Error, "BCP219", $"{BuildInvalidTemplateSpecReferenceClause(aliasName, referenceValue)} The resource group name \"{resourceGroupName}\" is invalid. Valid characters are alphanumeric, unicode characters, \".\", \"_\", \"-\", \"(\", or \")\", but the resource group name cannot end with \".\"."); - public ErrorDiagnostic InvalidTemplateSpecReferenceTemplateSpecNameTooLong(string? aliasName, string templateSpecName, string referenceValue, int maximumLength) => new( + public Diagnostic InvalidTemplateSpecReferenceTemplateSpecNameTooLong(string? aliasName, string templateSpecName, string referenceValue, int maximumLength) => new( TextSpan, + DiagnosticLevel.Error, "BCP220", $"{BuildInvalidTemplateSpecReferenceClause(aliasName, referenceValue)} The Template Spec name \"{templateSpecName}\" exceeds the maximum length of {maximumLength} characters."); - public ErrorDiagnostic InvalidTemplateSpecReferenceInvalidTemplateSpecName(string? aliasName, string templateSpecName, string referenceValue) => new( + public Diagnostic InvalidTemplateSpecReferenceInvalidTemplateSpecName(string? aliasName, string templateSpecName, string referenceValue) => new( TextSpan, + DiagnosticLevel.Error, "BCP221", $"{BuildInvalidTemplateSpecReferenceClause(aliasName, referenceValue)} The Template Spec name \"{templateSpecName}\" is invalid. Valid characters are alphanumeric, \".\", \"_\", \"-\", \"(\", or \")\", but the Template Spec name cannot end with \".\"."); - public ErrorDiagnostic InvalidTemplateSpecReferenceTemplateSpecVersionTooLong(string? aliasName, string templateSpecVersion, string referenceValue, int maximumLength) => new( + public Diagnostic InvalidTemplateSpecReferenceTemplateSpecVersionTooLong(string? aliasName, string templateSpecVersion, string referenceValue, int maximumLength) => new( TextSpan, + DiagnosticLevel.Error, "BCP222", $"{BuildInvalidTemplateSpecReferenceClause(aliasName, referenceValue)} The Template Spec version \"{templateSpecVersion}\" exceeds the maximum length of {maximumLength} characters."); - public ErrorDiagnostic InvalidTemplateSpecReferenceInvalidTemplateSpecVersion(string? aliasName, string templateSpecVersion, string referenceValue) => new( + public Diagnostic InvalidTemplateSpecReferenceInvalidTemplateSpecVersion(string? aliasName, string templateSpecVersion, string referenceValue) => new( TextSpan, + DiagnosticLevel.Error, "BCP223", $"{BuildInvalidTemplateSpecReferenceClause(aliasName, referenceValue)} The Template Spec version \"{templateSpecVersion}\" is invalid. Valid characters are alphanumeric, \".\", \"_\", \"-\", \"(\", or \")\", but the Template Spec name cannot end with \".\"."); - public ErrorDiagnostic InvalidOciArtifactReferenceInvalidDigest(string? aliasName, string badRef, string badDigest) => new( + public Diagnostic InvalidOciArtifactReferenceInvalidDigest(string? aliasName, string badRef, string badDigest) => new( TextSpan, + DiagnosticLevel.Error, "BCP224", $"{BuildInvalidOciArtifactReferenceClause(aliasName, badRef)} The digest \"{badDigest}\" is not valid. The valid format is a string \"sha256:\" followed by exactly 64 lowercase hexadecimal digits."); @@ -1347,19 +1530,22 @@ public ErrorDiagnostic ExpectedExtensionSpecification() "BCP225", $"The discriminator property \"{propertyName}\" value cannot be determined at compilation time. Type checking for this object is disabled."); - public ErrorDiagnostic MissingDiagnosticCodes() => new( + public Diagnostic MissingDiagnosticCodes() => new( TextSpan, + DiagnosticLevel.Error, "BCP226", "Expected at least one diagnostic code at this location. Valid format is \"#disable-next-line diagnosticCode1 diagnosticCode2 ...\"" ); - public ErrorDiagnostic UnsupportedResourceTypeParameterOrOutputType(string resourceType) => new( + public Diagnostic UnsupportedResourceTypeParameterOrOutputType(string resourceType) => new( TextSpan, + DiagnosticLevel.Error, "BCP227", $"The type \"{resourceType}\" cannot be used as a parameter or output type. Extensibility types are currently not supported as parameters or outputs."); - public ErrorDiagnostic InvalidResourceScopeCannotBeResourceTypeParameter(string parameterName) => new( + public Diagnostic InvalidResourceScopeCannotBeResourceTypeParameter(string parameterName) => new( TextSpan, + DiagnosticLevel.Error, "BCP229", $"The parameter \"{parameterName}\" cannot be used as a resource scope or parent. Resources passed as parameters cannot be used as a scope or parent of a resource."); @@ -1369,18 +1555,21 @@ public ErrorDiagnostic ExpectedExtensionSpecification() "BCP230", $"The referenced module uses resource type \"{resourceTypeReference.FormatName()}\" which does not have types available. Bicep is unable to validate resource properties prior to deployment, but this will not block the resource from being deployed."); - public ErrorDiagnostic ParamOrOutputResourceTypeUnsupported() => new( + public Diagnostic ParamOrOutputResourceTypeUnsupported() => new( TextSpan, + DiagnosticLevel.Error, "BCP231", $@"Using resource-typed parameters and outputs requires enabling EXPERIMENTAL feature ""{nameof(ExperimentalFeaturesEnabled.ResourceTypedParamsAndOutputs)}""."); - public ErrorDiagnostic ArtifactDeleteFailed(string moduleRef) => new( + public Diagnostic ArtifactDeleteFailed(string moduleRef) => new( TextSpan, + DiagnosticLevel.Error, "BCP232", $"Unable to delete the module with reference \"{moduleRef}\" from cache."); - public ErrorDiagnostic ArtifactDeleteFailedWithMessage(string moduleRef, string message) => new( + public Diagnostic ArtifactDeleteFailedWithMessage(string moduleRef, string message) => new( TextSpan, + DiagnosticLevel.Error, "BCP233", $"Unable to delete the module with reference \"{moduleRef}\" from cache: {message}"); @@ -1390,33 +1579,39 @@ public ErrorDiagnostic ExpectedExtensionSpecification() "BCP234", $"The ARM function \"{armFunctionName}\" failed when invoked on the value [{literalValue}]: {message}"); - public ErrorDiagnostic NoJsonTokenOnPathOrPathInvalid() => new( + public Diagnostic NoJsonTokenOnPathOrPathInvalid() => new( TextSpan, + DiagnosticLevel.Error, "BCP235", $"Specified JSONPath does not exist in the given file or is invalid."); - public ErrorDiagnostic ExpectedNewLineOrCommaSeparator() => new( + public Diagnostic ExpectedNewLineOrCommaSeparator() => new( TextSpan, + DiagnosticLevel.Error, "BCP236", "Expected a new line or comma character at this location."); - public ErrorDiagnostic ExpectedCommaSeparator() => new( + public Diagnostic ExpectedCommaSeparator() => new( TextSpan, + DiagnosticLevel.Error, "BCP237", "Expected a comma character at this location."); - public ErrorDiagnostic UnexpectedNewLineAfterCommaSeparator() => new( + public Diagnostic UnexpectedNewLineAfterCommaSeparator() => new( TextSpan, + DiagnosticLevel.Error, "BCP238", "Unexpected new line character after a comma."); - public ErrorDiagnostic ReservedIdentifier(string name) => new( + public Diagnostic ReservedIdentifier(string name) => new( TextSpan, + DiagnosticLevel.Error, "BCP239", $"Identifier \"{name}\" is a reserved Bicep symbol name and cannot be used in this context."); - public ErrorDiagnostic InvalidValueForParentProperty() => new( + public Diagnostic InvalidValueForParentProperty() => new( TextSpan, + DiagnosticLevel.Error, "BCP240", "The \"parent\" property only permits direct references to resources. Expressions are not supported."); @@ -1427,18 +1622,21 @@ public ErrorDiagnostic ExpectedExtensionSpecification() $"The \"{functionName}\" function is deprecated and will be removed in a future release of Bicep. Please add a comment to https://github.com/Azure/bicep/issues/2017 if you believe this will impact your workflow.", styling: DiagnosticStyling.ShowCodeDeprecated); - public ErrorDiagnostic LambdaFunctionsOnlyValidInFunctionArguments() => new( + public Diagnostic LambdaFunctionsOnlyValidInFunctionArguments() => new( TextSpan, + DiagnosticLevel.Error, "BCP242", $"Lambda functions may only be specified directly as function arguments."); - public ErrorDiagnostic ParenthesesMustHaveExactlyOneItem() => new( + public Diagnostic ParenthesesMustHaveExactlyOneItem() => new( TextSpan, + DiagnosticLevel.Error, "BCP243", "Parentheses must contain exactly one expression."); - public ErrorDiagnostic LambdaExpectedArgCountMismatch(TypeSymbol lambdaType, int minArgCount, int maxArgCount, int actualArgCount) => new( + public Diagnostic LambdaExpectedArgCountMismatch(TypeSymbol lambdaType, int minArgCount, int maxArgCount, int actualArgCount) => new( TextSpan, + DiagnosticLevel.Error, "BCP244", minArgCount == maxArgCount ? $"Expected lambda expression of type \"{lambdaType}\" with {minArgCount} arguments but received {actualArgCount} arguments." : @@ -1457,35 +1655,41 @@ public ErrorDiagnostic ExpectedExtensionSpecification() $"Resource type \"{resourceTypeReference.FormatName()}\" can only be used with the 'existing' keyword at the requested scope." + $" Permitted scopes for deployment: {ToQuotedString(LanguageConstants.GetResourceScopeDescriptions(writableScopes))}."); - public ErrorDiagnostic LambdaVariablesInResourceOrModuleArrayAccessUnsupported(IEnumerable variableNames) => new( + public Diagnostic LambdaVariablesInResourceOrModuleArrayAccessUnsupported(IEnumerable variableNames) => new( TextSpan, + DiagnosticLevel.Error, "BCP247", $"Using lambda variables inside resource or module array access is not currently supported." + $" Found the following lambda variable(s) being accessed: {ToQuotedString(variableNames)}."); - public ErrorDiagnostic LambdaVariablesInInlineFunctionUnsupported(string functionName, IEnumerable variableNames) => new( + public Diagnostic LambdaVariablesInInlineFunctionUnsupported(string functionName, IEnumerable variableNames) => new( TextSpan, + DiagnosticLevel.Error, "BCP248", $"Using lambda variables inside the \"{functionName}\" function is not currently supported." + $" Found the following lambda variable(s) being accessed: {ToQuotedString(variableNames)}."); - public ErrorDiagnostic ExpectedLoopVariableBlockWith2Elements(int actualCount) => new( + public Diagnostic ExpectedLoopVariableBlockWith2Elements(int actualCount) => new( TextSpan, + DiagnosticLevel.Error, "BCP249", $"Expected loop variable block to consist of exactly 2 elements (item variable and index variable), but found {actualCount}."); - public ErrorDiagnostic ParameterMultipleAssignments(string identifier) => new( + public Diagnostic ParameterMultipleAssignments(string identifier) => new( TextSpan, + DiagnosticLevel.Error, "BCP250", $"Parameter \"{identifier}\" is assigned multiple times. Remove or rename the duplicates."); - public ErrorDiagnostic UsingPathHasNotBeenSpecified() => new( + public Diagnostic UsingPathHasNotBeenSpecified() => new( TextSpan, + DiagnosticLevel.Error, "BCP256", "The using declaration is missing a bicep template file path reference."); - public ErrorDiagnostic ExpectedFilePathString() => new( + public Diagnostic ExpectedFilePathString() => new( TextSpan, + DiagnosticLevel.Error, "BCP257", "Expected a Bicep file path string. This should be a relative path to another bicep file, e.g. 'myModule.bicep' or '../parent/myModule.bicep'"); @@ -1501,76 +1705,90 @@ public IDiagnostic MissingParameterAssignment(IEnumerable identifiers, C insertMissingCodefix); } - public ErrorDiagnostic MissingParameterDeclaration(string? identifier) => new( + public Diagnostic MissingParameterDeclaration(string? identifier) => new( TextSpan, + DiagnosticLevel.Error, "BCP259", $"The parameter \"{identifier}\" is assigned in the params file without being declared in the Bicep file."); - public ErrorDiagnostic ParameterTypeMismatch(string? identifier, TypeSymbol expectedType, TypeSymbol actualType) => new( + public Diagnostic ParameterTypeMismatch(string? identifier, TypeSymbol expectedType, TypeSymbol actualType) => new( TextSpan, + DiagnosticLevel.Error, "BCP260", $"The parameter \"{identifier}\" expects a value of type \"{expectedType}\" but the provided value is of type \"{actualType}\"."); - public ErrorDiagnostic UsingDeclarationNotSpecified() => new( + public Diagnostic UsingDeclarationNotSpecified() => new( TextSpan, + DiagnosticLevel.Error, "BCP261", "A using declaration must be present in this parameters file."); - public ErrorDiagnostic MoreThanOneUsingDeclarationSpecified() => new( + public Diagnostic MoreThanOneUsingDeclarationSpecified() => new( TextSpan, + DiagnosticLevel.Error, "BCP262", "More than one using declaration are present"); - public ErrorDiagnostic UsingDeclarationReferencesInvalidFile() => new( + public Diagnostic UsingDeclarationReferencesInvalidFile() => new( TextSpan, + DiagnosticLevel.Error, "BCP263", "The file specified in the using declaration path does not exist"); - public ErrorDiagnostic AmbiguousResourceTypeBetweenImports(string resourceTypeName, IEnumerable namespaces) => new( + public Diagnostic AmbiguousResourceTypeBetweenImports(string resourceTypeName, IEnumerable namespaces) => new( TextSpan, + DiagnosticLevel.Error, "BCP264", $"Resource type \"{resourceTypeName}\" is declared in multiple imported namespaces ({ToQuotedStringWithCaseInsensitiveOrdering(namespaces)}), and must be fully-qualified."); - public FixableErrorDiagnostic SymbolicNameShadowsAKnownFunction(string name, string knownFunctionNamespace, string knownFunctionName) => new( + public FixableDiagnostic SymbolicNameShadowsAKnownFunction(string name, string knownFunctionNamespace, string knownFunctionName) => new( TextSpan, + DiagnosticLevel.Error, "BCP265", $"The name \"{name}\" is not a function. Did you mean \"{knownFunctionNamespace}.{knownFunctionName}\"?", null, DiagnosticStyling.Default, new CodeFix($"Change \"{name}\" to \"{knownFunctionNamespace}.{knownFunctionName}\"", true, CodeFixKind.QuickFix, CodeManipulator.Replace(TextSpan, $"{knownFunctionNamespace}.{knownFunctionName}"))); - public ErrorDiagnostic ExpectedMetadataIdentifier() => new( + public Diagnostic ExpectedMetadataIdentifier() => new( TextSpan, + DiagnosticLevel.Error, "BCP266", "Expected a metadata identifier at this location."); - public ErrorDiagnostic ExpectedMetadataDeclarationAfterDecorator() => new( + public Diagnostic ExpectedMetadataDeclarationAfterDecorator() => new( TextSpan, + DiagnosticLevel.Error, "BCP267", "Expected an metadata declaration after the decorator."); - public ErrorDiagnostic ReservedMetadataIdentifier(string name) => new( + public Diagnostic ReservedMetadataIdentifier(string name) => new( TextSpan, + DiagnosticLevel.Error, "BCP268", $"Invalid identifier: \"{name}\". Metadata identifiers starting with '_' are reserved. Please use a different identifier."); - public ErrorDiagnostic CannotUseFunctionAsMetadataDecorator(string functionName) => new( + public Diagnostic CannotUseFunctionAsMetadataDecorator(string functionName) => new( TextSpan, + DiagnosticLevel.Error, "BCP269", $"Function \"{functionName}\" cannot be used as a metadata decorator."); - public ErrorDiagnostic UnparsableBicepConfigFile(string configurationPath, string parsingErrorMessage) => new( + public Diagnostic UnparsableBicepConfigFile(string configurationPath, string parsingErrorMessage) => new( TextSpan, + DiagnosticLevel.Error, "BCP271", $"Failed to parse the contents of the Bicep configuration file \"{configurationPath}\" as valid JSON: {parsingErrorMessage.TrimEnd('.')}."); - public ErrorDiagnostic UnloadableBicepConfigFile(string configurationPath, string loadErrorMessage) => new( + public Diagnostic UnloadableBicepConfigFile(string configurationPath, string loadErrorMessage) => new( TextSpan, + DiagnosticLevel.Error, "BCP272", $"Could not load the Bicep configuration file \"{configurationPath}\": {loadErrorMessage.TrimEnd('.')}."); - public ErrorDiagnostic InvalidBicepConfigFile(string configurationPath, string parsingErrorMessage) => new( + public Diagnostic InvalidBicepConfigFile(string configurationPath, string parsingErrorMessage) => new( TextSpan, + DiagnosticLevel.Error, "BCP273", $"Failed to parse the contents of the Bicep configuration file \"{configurationPath}\": {parsingErrorMessage.TrimEnd('.')}."); @@ -1580,159 +1798,188 @@ public IDiagnostic MissingParameterAssignment(IEnumerable identifiers, C "BCP274", $"Error scanning \"{directoryPath}\" for bicep configuration: {scanErrorMessage.TrimEnd('.')}."); - public ErrorDiagnostic FoundDirectoryInsteadOfFile(string directoryPath) => new( + public Diagnostic FoundDirectoryInsteadOfFile(string directoryPath) => new( TextSpan, + DiagnosticLevel.Error, "BCP275", $"Unable to open file at path \"{directoryPath}\". Found a directory instead."); - public ErrorDiagnostic UsingDeclarationMustReferenceBicepFile() => new( + public Diagnostic UsingDeclarationMustReferenceBicepFile() => new( TextSpan, + DiagnosticLevel.Error, "BCP276", "A using declaration can only reference a Bicep file."); - public ErrorDiagnostic ModuleDeclarationMustReferenceBicepModule() => new( + public Diagnostic ModuleDeclarationMustReferenceBicepModule() => new( TextSpan, + DiagnosticLevel.Error, "BCP277", "A module declaration can only reference a Bicep File, an ARM template, a registry reference or a template spec reference."); - public ErrorDiagnostic CyclicParametersSelfReference() => new( + public Diagnostic CyclicParametersSelfReference() => new( TextSpan, + DiagnosticLevel.Error, "BCP278", "This parameters file references itself, which is not allowed."); - public ErrorDiagnostic UnrecognizedTypeExpression() => new( + public Diagnostic UnrecognizedTypeExpression() => new( TextSpan, + DiagnosticLevel.Error, "BCP279", $"Expected a type at this location. Please specify a valid type expression or one of the following types: {ToQuotedString(LanguageConstants.DeclarationTypes.Keys)}."); - public ErrorDiagnostic TypeExpressionLiteralConversionFailed() => new( + public Diagnostic TypeExpressionLiteralConversionFailed() => new( TextSpan, + DiagnosticLevel.Error, "BCP285", "The type expression could not be reduced to a literal value."); - public ErrorDiagnostic InvalidUnionTypeMember(string keystoneType) => new( + public Diagnostic InvalidUnionTypeMember(string keystoneType) => new( TextSpan, + DiagnosticLevel.Error, "BCP286", $"This union member is invalid because it cannot be assigned to the '{keystoneType}' type."); - public ErrorDiagnostic ValueSymbolUsedAsType(string symbolName) => new( + public Diagnostic ValueSymbolUsedAsType(string symbolName) => new( TextSpan, + DiagnosticLevel.Error, "BCP287", // TODO: Add "Did you mean 'typeof({symbolName})'?" When support for typeof has been added. $"'{symbolName}' refers to a value but is being used as a type here."); - public ErrorDiagnostic TypeSymbolUsedAsValue(string symbolName) => new( + public Diagnostic TypeSymbolUsedAsValue(string symbolName) => new( TextSpan, + DiagnosticLevel.Error, "BCP288", $"'{symbolName}' refers to a type but is being used as a value here."); - public ErrorDiagnostic InvalidTypeDefinition() => new( + public Diagnostic InvalidTypeDefinition() => new( TextSpan, + DiagnosticLevel.Error, "BCP289", $"The type definition is not valid."); - public ErrorDiagnostic ExpectedParameterOrTypeDeclarationAfterDecorator() => new( + public Diagnostic ExpectedParameterOrTypeDeclarationAfterDecorator() => new( TextSpan, + DiagnosticLevel.Error, "BCP290", "Expected a parameter or type declaration after the decorator."); - public ErrorDiagnostic ExpectedParameterOrOutputDeclarationAfterDecorator() => new( + public Diagnostic ExpectedParameterOrOutputDeclarationAfterDecorator() => new( TextSpan, + DiagnosticLevel.Error, "BCP291", "Expected a parameter or output declaration after the decorator."); - public ErrorDiagnostic ExpectedParameterOutputOrTypeDeclarationAfterDecorator() => new( + public Diagnostic ExpectedParameterOutputOrTypeDeclarationAfterDecorator() => new( TextSpan, + DiagnosticLevel.Error, "BCP292", "Expected a parameter, output, or type declaration after the decorator."); - public ErrorDiagnostic NonLiteralUnionMember() => new( + public Diagnostic NonLiteralUnionMember() => new( TextSpan, + DiagnosticLevel.Error, "BCP293", "All members of a union type declaration must be literal values."); - public ErrorDiagnostic InvalidTypeUnion() => new( + public Diagnostic InvalidTypeUnion() => new( TextSpan, + DiagnosticLevel.Error, "BCP294", "Type unions must be reducible to a single ARM type (such as 'string', 'int', or 'bool')."); - public ErrorDiagnostic DecoratorNotPermittedOnLiteralType(string decoratorName) => new( + public Diagnostic DecoratorNotPermittedOnLiteralType(string decoratorName) => new( TextSpan, + DiagnosticLevel.Error, "BCP295", $"The '{decoratorName}' decorator may not be used on targets of a union or literal type. The allowed values for this parameter or type definition will be derived from the union or literal type automatically."); - public ErrorDiagnostic NonConstantTypeProperty() => new( + public Diagnostic NonConstantTypeProperty() => new( TextSpan, + DiagnosticLevel.Error, "BCP296", "Property names on types must be compile-time constant values."); - public ErrorDiagnostic CannotUseFunctionAsTypeDecorator(string functionName) => new( + public Diagnostic CannotUseFunctionAsTypeDecorator(string functionName) => new( TextSpan, + DiagnosticLevel.Error, "BCP297", $"Function \"{functionName}\" cannot be used as a type decorator."); - public ErrorDiagnostic CyclicTypeSelfReference() => new( + public Diagnostic CyclicTypeSelfReference() => new( TextSpan, + DiagnosticLevel.Error, "BCP298", "This type definition includes itself as required component, which creates a constraint that cannot be fulfilled."); - public ErrorDiagnostic CyclicType(IEnumerable cycle) => new( + public Diagnostic CyclicType(IEnumerable cycle) => new( TextSpan, + DiagnosticLevel.Error, "BCP299", $"This type definition includes itself as a required component via a cycle (\"{string.Join("\" -> \"", cycle)}\")."); - public ErrorDiagnostic ExpectedTypeLiteral() => new( + public Diagnostic ExpectedTypeLiteral() => new( TextSpan, + DiagnosticLevel.Error, "BCP300", $"Expected a type literal at this location. Please specify a concrete value or a reference to a literal type."); - public ErrorDiagnostic ReservedTypeName(string reservedName) => new( + public Diagnostic ReservedTypeName(string reservedName) => new( TextSpan, + DiagnosticLevel.Error, "BCP301", $@"The type name ""{reservedName}"" is reserved and may not be attached to a user-defined type."); - public ErrorDiagnostic SymbolicNameIsNotAType(string name, IEnumerable validTypes) => new( + public Diagnostic SymbolicNameIsNotAType(string name, IEnumerable validTypes) => new( TextSpan, + DiagnosticLevel.Error, "BCP302", $@"The name ""{name}"" is not a valid type. Please specify one of the following types: {ToQuotedString(validTypes)}."); - public ErrorDiagnostic ExtensionSpecificationInterpolationUnsupported() => new( + public Diagnostic ExtensionSpecificationInterpolationUnsupported() => new( TextSpan, + DiagnosticLevel.Error, "BCP303", "String interpolation is unsupported for specifying the extension."); - public ErrorDiagnostic ExpectedWithOrAsKeywordOrNewLine() => new( + public Diagnostic ExpectedWithOrAsKeywordOrNewLine() => new( TextSpan, + DiagnosticLevel.Error, "BCP305", $"Expected the \"with\" keyword, \"as\" keyword, or a new line character at this location."); - public ErrorDiagnostic NamespaceSymbolUsedAsType(string name) => new( + public Diagnostic NamespaceSymbolUsedAsType(string name) => new( TextSpan, + DiagnosticLevel.Error, "BCP306", $@"The name ""{name}"" refers to a namespace, not to a type."); - public ErrorDiagnostic NestedRuntimePropertyAccessNotSupported(string? resourceSymbol, IEnumerable runtimePropertyNames, IEnumerable accessiblePropertyNames, IEnumerable accessibleFunctionNames) + public Diagnostic NestedRuntimePropertyAccessNotSupported(string? resourceSymbol, IEnumerable runtimePropertyNames, IEnumerable accessiblePropertyNames, IEnumerable accessibleFunctionNames) { var accessiblePropertyNamesClause = accessiblePropertyNames.Any() ? @$" the accessible properties of ""{resourceSymbol}"" include {ToQuotedString(accessiblePropertyNames.OrderBy(x => x))}." : ""; var accessibleFunctionNamesClause = accessibleFunctionNames.Any() ? @$" The accessible functions of ""{resourceSymbol}"" include {ToQuotedString(accessibleFunctionNames.OrderBy(x => x))}." : ""; return new( TextSpan, + DiagnosticLevel.Error, "BCP307", $"The expression cannot be evaluated, because the identifier properties of the referenced existing resource including {ToQuotedString(runtimePropertyNames.OrderBy(x => x))} cannot be calculated at the start of the deployment. In this situation,{accessiblePropertyNamesClause}{accessibleFunctionNamesClause}"); } - public ErrorDiagnostic DecoratorMayNotTargetTypeAlias(string decoratorName) => new( + public Diagnostic DecoratorMayNotTargetTypeAlias(string decoratorName) => new( TextSpan, + DiagnosticLevel.Error, "BCP308", $@"The decorator ""{decoratorName}"" may not be used on statements whose declared type is a reference to a user-defined type."); - public ErrorDiagnostic ValueCannotBeFlattened(TypeSymbol flattenInputType, TypeSymbol incompatibleType) => new( + public Diagnostic ValueCannotBeFlattened(TypeSymbol flattenInputType, TypeSymbol incompatibleType) => new( TextSpan, + DiagnosticLevel.Error, "BCP309", $@"Values of type ""{flattenInputType.Name}"" cannot be flattened because ""{incompatibleType.Name}"" is not an array type."); - public ErrorDiagnostic IndexOutOfBounds(string typeName, long tupleLength, long indexSought) + public Diagnostic IndexOutOfBounds(string typeName, long tupleLength, long indexSought) { var message = new StringBuilder("The provided index value of \"").Append(indexSought).Append("\" is not valid for type \"").Append(typeName).Append("\"."); if (tupleLength > 0) @@ -1740,21 +1987,24 @@ public ErrorDiagnostic IndexOutOfBounds(string typeName, long tupleLength, long message.Append(" Indexes for this type must be between 0 and ").Append(tupleLength - 1).Append('.'); } - return new(TextSpan, "BCP311", message.ToString()); + return new(TextSpan, DiagnosticLevel.Error, "BCP311", message.ToString()); } - public ErrorDiagnostic MultipleAdditionalPropertiesDeclarations() => new( + public Diagnostic MultipleAdditionalPropertiesDeclarations() => new( TextSpan, + DiagnosticLevel.Error, "BCP315", "An object type may have at most one additional properties declaration."); - public ErrorDiagnostic SealedIncompatibleWithAdditionalPropertiesDeclaration() => new( + public Diagnostic SealedIncompatibleWithAdditionalPropertiesDeclaration() => new( TextSpan, + DiagnosticLevel.Error, "BCP316", $@"The ""{LanguageConstants.ParameterSealedPropertyName}"" decorator may not be used on object types with an explicit additional properties type declaration."); - public ErrorDiagnostic ExpectedPropertyNameOrMatcher() => new( + public Diagnostic ExpectedPropertyNameOrMatcher() => new( TextSpan, + DiagnosticLevel.Error, "BCP317", "Expected an identifier, a string, or an asterisk at this location."); @@ -1778,13 +2028,15 @@ public ErrorDiagnostic IndexOutOfBounds(string typeName, long tupleLength, long CodeFixKind.QuickFix, new(expression.Span, SyntaxFactory.AsNonNullable(expression).ToString())); - public ErrorDiagnostic UnresolvableArmJsonType(string errorSource, string message) => new( + public Diagnostic UnresolvableArmJsonType(string errorSource, string message) => new( TextSpan, + DiagnosticLevel.Error, "BCP319", $@"The type at ""{errorSource}"" could not be resolved by the ARM JSON template engine. Original error message: ""{message}"""); - public ErrorDiagnostic ModuleOutputResourcePropertyAccessDetected() => new( + public Diagnostic ModuleOutputResourcePropertyAccessDetected() => new( TextSpan, + DiagnosticLevel.Error, "BCP320", "The properties of module output resources cannot be accessed directly. To use the properties of this resource, pass it as a resource-typed parameter to another module and access the parameter's properties therein."); @@ -1797,23 +2049,27 @@ public ErrorDiagnostic IndexOutOfBounds(string typeName, long tupleLength, long styling: DiagnosticStyling.Default, fix: AsNonNullable(expression)); - public ErrorDiagnostic SafeDereferenceNotPermittedOnInstanceFunctions() => new( + public Diagnostic SafeDereferenceNotPermittedOnInstanceFunctions() => new( TextSpan, + DiagnosticLevel.Error, "BCP322", "The `.?` (safe dereference) operator may not be used on instance function invocations."); - public ErrorDiagnostic SafeDereferenceNotPermittedOnResourceCollections() => new( + public Diagnostic SafeDereferenceNotPermittedOnResourceCollections() => new( TextSpan, + DiagnosticLevel.Error, "BCP323", "The `[?]` (safe dereference) operator may not be used on resource or module collections."); - public ErrorDiagnostic ExpectedTypeIdentifier() => new( + public Diagnostic ExpectedTypeIdentifier() => new( TextSpan, + DiagnosticLevel.Error, "BCP325", "Expected a type identifier at this location."); - public ErrorDiagnostic NullableTypedParamsMayNotHaveDefaultValues() => new( + public Diagnostic NullableTypedParamsMayNotHaveDefaultValues() => new( TextSpan, + DiagnosticLevel.Error, "BCP326", "Nullable-typed parameters may not be assigned default values. They have an implicit default of 'null' that cannot be overridden."); @@ -1841,8 +2097,9 @@ public ErrorDiagnostic IndexOutOfBounds(string typeName, long tupleLength, long "BCP330", $"The provided value can be as large as {sourceMax} and may be too large to assign to a target with a configured maximum of {targetMax}."); - public ErrorDiagnostic MinMayNotExceedMax(string minDecoratorName, long minValue, string maxDecoratorName, long maxValue) => new( + public Diagnostic MinMayNotExceedMax(string minDecoratorName, long minValue, string maxDecoratorName, long maxValue) => new( TextSpan, + DiagnosticLevel.Error, "BCP331", $@"A type's ""{minDecoratorName}"" must be less than or equal to its ""{maxDecoratorName}"", but a minimum of {minValue} and a maximum of {maxValue} were specified."); @@ -1870,203 +2127,242 @@ public ErrorDiagnostic IndexOutOfBounds(string typeName, long tupleLength, long "BCP335", $"The provided value can have a length as large as {sourceMaxLength} and may be too long to assign to a target with a configured maximum length of {targetMaxLength}."); - public ErrorDiagnostic UnrecognizedParamsFileDeclaration() => new( + public Diagnostic UnrecognizedParamsFileDeclaration() => new( TextSpan, + DiagnosticLevel.Error, "BCP337", $@"This declaration type is not valid for a Bicep Parameters file. Specify a ""{LanguageConstants.UsingKeyword}"", ""{LanguageConstants.ExtendsKeyword}"", ""{LanguageConstants.ParameterKeyword}"" or ""{LanguageConstants.VariableKeyword}"" declaration."); - public ErrorDiagnostic FailedToEvaluateParameter(string parameterName, string message) => new( + public Diagnostic FailedToEvaluateParameter(string parameterName, string message) => new( TextSpan, + DiagnosticLevel.Error, "BCP338", $"Failed to evaluate parameter \"{parameterName}\": {message}"); - public ErrorDiagnostic ArrayIndexOutOfBounds(long indexSought) => new( + public Diagnostic ArrayIndexOutOfBounds(long indexSought) => new( TextSpan, + DiagnosticLevel.Error, "BCP339", $"""The provided array index value of "{indexSought}" is not valid. Array index should be greater than or equal to 0."""); - public ErrorDiagnostic UnparsableYamlType() => new( + public Diagnostic UnparsableYamlType() => new( TextSpan, + DiagnosticLevel.Error, "BCP340", $"Unable to parse literal YAML value. Please ensure that it is well-formed."); - public ErrorDiagnostic RuntimeValueNotAllowedInFunctionDeclaration(string? accessedSymbolName, IEnumerable? accessiblePropertyNames, IEnumerable? variableDependencyChain) + public Diagnostic RuntimeValueNotAllowedInFunctionDeclaration(string? accessedSymbolName, IEnumerable? accessiblePropertyNames, IEnumerable? variableDependencyChain) { var variableDependencyChainClause = BuildVariableDependencyChainClause(variableDependencyChain); var accessiblePropertiesClause = BuildAccessiblePropertiesClause(accessedSymbolName, accessiblePropertyNames); - return new ErrorDiagnostic( + return new( TextSpan, + DiagnosticLevel.Error, "BCP341", $"This expression is being used inside a function declaration, which requires a value that can be calculated at the start of the deployment.{variableDependencyChainClause}{accessiblePropertiesClause}"); } - public ErrorDiagnostic UserDefinedTypesNotAllowedInFunctionDeclaration() => new( + public Diagnostic UserDefinedTypesNotAllowedInFunctionDeclaration() => new( TextSpan, + DiagnosticLevel.Error, "BCP342", $"""User-defined types are not supported in user-defined function parameters or outputs."""); - public ErrorDiagnostic ExpectedAssertIdentifier() => new( + public Diagnostic ExpectedAssertIdentifier() => new( TextSpan, + DiagnosticLevel.Error, "BCP344", "Expected an assert identifier at this location."); - public ErrorDiagnostic TestDeclarationMustReferenceBicepTest() => new( + public Diagnostic TestDeclarationMustReferenceBicepTest() => new( TextSpan, + DiagnosticLevel.Error, "BCP345", "A test declaration can only reference a Bicep File"); - public ErrorDiagnostic ExpectedTestIdentifier() => new( + public Diagnostic ExpectedTestIdentifier() => new( TextSpan, + DiagnosticLevel.Error, "BCP346", "Expected a test identifier at this location."); - public ErrorDiagnostic ExpectedTestPathString() => new( + public Diagnostic ExpectedTestPathString() => new( TextSpan, + DiagnosticLevel.Error, "BCP347", "Expected a test path string at this location."); - public ErrorDiagnostic TestDeclarationStatementsUnsupported() => new( + public Diagnostic TestDeclarationStatementsUnsupported() => new( TextSpan, + DiagnosticLevel.Error, "BCP348", $@"Using a test declaration statement requires enabling EXPERIMENTAL feature ""{nameof(ExperimentalFeaturesEnabled.TestFramework)}""."); - public ErrorDiagnostic AssertsUnsupported() => new( + public Diagnostic AssertsUnsupported() => new( TextSpan, + DiagnosticLevel.Error, "BCP349", $@"Using an assert declaration requires enabling EXPERIMENTAL feature ""{nameof(ExperimentalFeaturesEnabled.Assertions)}""."); - public ErrorDiagnostic InvalidAssertAssignment(TypeSymbol valueType) => new( + public Diagnostic InvalidAssertAssignment(TypeSymbol valueType) => new( TextSpan, + DiagnosticLevel.Error, "BCP350", $"Value of type \"{valueType}\" cannot be assigned to an assert. Asserts can take values of type 'bool' only."); - public ErrorDiagnostic FunctionOnlyValidWithDirectAssignment(string functionName) => new( + public Diagnostic FunctionOnlyValidWithDirectAssignment(string functionName) => new( TextSpan, + DiagnosticLevel.Error, "BCP351", $"Function \"{functionName}\" is not valid at this location. It can only be used when directly assigning to a parameter."); - public ErrorDiagnostic FailedToEvaluateVariable(string name, string message) => new( + public Diagnostic FailedToEvaluateVariable(string name, string message) => new( TextSpan, + DiagnosticLevel.Error, "BCP352", $"Failed to evaluate variable \"{name}\": {message}"); - public ErrorDiagnostic ItemsMustBeCaseInsensitivelyUnique(string itemTypePluralName, IEnumerable itemNames) => new( + public Diagnostic ItemsMustBeCaseInsensitivelyUnique(string itemTypePluralName, IEnumerable itemNames) => new( TextSpan, + DiagnosticLevel.Error, "BCP353", $"The {itemTypePluralName} {ToQuotedString(itemNames)} differ only in casing. The ARM deployments engine is not case sensitive and will not be able to distinguish between them."); - public ErrorDiagnostic ExpectedSymbolListOrWildcard() => new( + public Diagnostic ExpectedSymbolListOrWildcard() => new( TextSpan, + DiagnosticLevel.Error, "BCP354", "Expected left brace ('{') or asterisk ('*') character at this location."); - public ErrorDiagnostic ExpectedExportedSymbolName() => new( + public Diagnostic ExpectedExportedSymbolName() => new( TextSpan, + DiagnosticLevel.Error, "BCP355", "Expected the name of an exported symbol at this location."); - public ErrorDiagnostic ExpectedNamespaceIdentifier() => new( + public Diagnostic ExpectedNamespaceIdentifier() => new( TextSpan, + DiagnosticLevel.Error, "BCP356", "Expected a valid namespace identifier at this location."); - public ErrorDiagnostic PathHasNotBeenSpecified() => new( + public Diagnostic PathHasNotBeenSpecified() => new( TextSpan, + DiagnosticLevel.Error, "BCP358", "This declaration is missing a template file path reference."); - public ErrorDiagnostic ImportedSymbolNotFound(string symbolName) => new( + public Diagnostic ImportedSymbolNotFound(string symbolName) => new( TextSpan, + DiagnosticLevel.Error, "BCP360", $"The '{symbolName}' symbol was not found in (or was not exported by) the imported template."); - public ErrorDiagnostic ExportDecoratorMustTargetStatement() => new( + public Diagnostic ExportDecoratorMustTargetStatement() => new( TextSpan, + DiagnosticLevel.Error, "BCP361", @"The ""@export()"" decorator must target a top-level statement."); - public ErrorDiagnostic SymbolImportedMultipleTimes(params string[] importedAs) => new( + public Diagnostic SymbolImportedMultipleTimes(params string[] importedAs) => new( TextSpan, + DiagnosticLevel.Error, "BCP362", $"This symbol is imported multiple times under the names {string.Join(", ", importedAs.Select(identifier => $"'{identifier}'"))}."); - public ErrorDiagnostic DiscriminatorDecoratorOnlySupportedForObjectUnions() => new( + public Diagnostic DiscriminatorDecoratorOnlySupportedForObjectUnions() => new( TextSpan, + DiagnosticLevel.Error, "BCP363", $"The \"{LanguageConstants.TypeDiscriminatorDecoratorName}\" decorator can only be applied to object-only union types with unique member types."); - public ErrorDiagnostic DiscriminatorPropertyMustBeRequiredStringLiteral(string discriminatorPropertyName) => new( + public Diagnostic DiscriminatorPropertyMustBeRequiredStringLiteral(string discriminatorPropertyName) => new( TextSpan, + DiagnosticLevel.Error, "BCP364", $"The property \"{discriminatorPropertyName}\" must be a required string literal on all union member types."); - public ErrorDiagnostic DiscriminatorPropertyMemberDuplicatedValue(string discriminatorPropertyName, string discriminatorPropertyValue) => new( + public Diagnostic DiscriminatorPropertyMemberDuplicatedValue(string discriminatorPropertyName, string discriminatorPropertyValue) => new( TextSpan, + DiagnosticLevel.Error, "BCP365", $"The value \"{discriminatorPropertyValue}\" for discriminator property \"{discriminatorPropertyName}\" is duplicated across multiple union member types. The value must be unique across all union member types."); - public ErrorDiagnostic DiscriminatorPropertyNameMustMatch(string acceptablePropertyName) => new( + public Diagnostic DiscriminatorPropertyNameMustMatch(string acceptablePropertyName) => new( TextSpan, + DiagnosticLevel.Error, "BCP366", $"The discriminator property name must be \"{acceptablePropertyName}\" on all union member types."); - public ErrorDiagnostic FeatureIsTemporarilyDisabled(string featureName) => new( + public Diagnostic FeatureIsTemporarilyDisabled(string featureName) => new( TextSpan, + DiagnosticLevel.Error, "BCP367", $"The \"{featureName}\" feature is temporarily disabled."); - public ErrorDiagnostic ParameterReferencesKeyVaultSuppliedParameter(string targetName) => new( + public Diagnostic ParameterReferencesKeyVaultSuppliedParameter(string targetName) => new( TextSpan, + DiagnosticLevel.Error, "BCP368", $"The value of the \"{targetName}\" parameter cannot be known until the template deployment has started because it uses a reference to a secret value in Azure Key Vault. Expressions that refer to the \"{targetName}\" parameter may be used in {LanguageConstants.LanguageFileExtension} files but not in {LanguageConstants.ParamsFileExtension} files."); - public ErrorDiagnostic ParameterReferencesDefaultedParameter(string targetName) => new( + public Diagnostic ParameterReferencesDefaultedParameter(string targetName) => new( TextSpan, + DiagnosticLevel.Error, "BCP369", $"The value of the \"{targetName}\" parameter cannot be known until the template deployment has started because it uses the default value defined in the template. Expressions that refer to the \"{targetName}\" parameter may be used in {LanguageConstants.LanguageFileExtension} files but not in {LanguageConstants.ParamsFileExtension} files."); - public ErrorDiagnostic ClosureContainsNonExportableSymbols(IEnumerable nonExportableSymbols) => new( + public Diagnostic ClosureContainsNonExportableSymbols(IEnumerable nonExportableSymbols) => new( TextSpan, + DiagnosticLevel.Error, "BCP372", @$"The ""@export()"" decorator may not be applied to variables that refer to parameters, modules, or resource, either directly or indirectly. The target of this decorator contains direct or transitive references to the following unexportable symbols: {ToQuotedString(nonExportableSymbols)}."); - public ErrorDiagnostic ImportedSymbolHasErrors(string name, string message) => new( + public Diagnostic ImportedSymbolHasErrors(string name, string message) => new( TextSpan, + DiagnosticLevel.Error, "BCP373", $"Unable to import the symbol named \"{name}\": {message}"); - public ErrorDiagnostic ImportedModelContainsAmbiguousExports(IEnumerable ambiguousExportNames) => new( + public Diagnostic ImportedModelContainsAmbiguousExports(IEnumerable ambiguousExportNames) => new( TextSpan, + DiagnosticLevel.Error, "BCP374", $"The imported model cannot be loaded with a wildcard because it contains the following duplicated exports: {ToQuotedString(ambiguousExportNames)}."); - public ErrorDiagnostic ImportListItemDoesNotIncludeDeclaredSymbolName() => new( + public Diagnostic ImportListItemDoesNotIncludeDeclaredSymbolName() => new( TextSpan, + DiagnosticLevel.Error, "BCP375", "An import list item that identifies its target with a quoted string must include an 'as ' clause."); - public ErrorDiagnostic ImportedSymbolKindNotSupportedInSourceFileKind(string name, ExportMetadataKind exportMetadataKind, BicepSourceFileKind sourceFileKind) => new( + public Diagnostic ImportedSymbolKindNotSupportedInSourceFileKind(string name, ExportMetadataKind exportMetadataKind, BicepSourceFileKind sourceFileKind) => new( TextSpan, + DiagnosticLevel.Error, "BCP376", $"The \"{name}\" symbol cannot be imported because imports of kind {exportMetadataKind} are not supported in files of kind {sourceFileKind}."); - public ErrorDiagnostic InvalidExtensionAliasName(string aliasName) => new( + public Diagnostic InvalidExtensionAliasName(string aliasName) => new( TextSpan, + DiagnosticLevel.Error, "BCP377", $"The extension alias name \"{aliasName}\" is invalid. Valid characters are alphanumeric, \"_\", or \"-\"."); - public ErrorDiagnostic InvalidOciArtifactExtensionAliasRegistryNullOrUndefined(string aliasName, Uri? configFileUri) => new( + public Diagnostic InvalidOciArtifactExtensionAliasRegistryNullOrUndefined(string aliasName, Uri? configFileUri) => new( TextSpan, + DiagnosticLevel.Error, "BCP378", $"The OCI artifact extension alias \"{aliasName}\" in the {BuildBicepConfigurationClause(configFileUri)} is invalid. The \"registry\" property cannot be null or undefined."); - public ErrorDiagnostic OciArtifactExtensionAliasNameDoesNotExistInConfiguration(string aliasName, Uri? configFileUri) => new( + public Diagnostic OciArtifactExtensionAliasNameDoesNotExistInConfiguration(string aliasName, Uri? configFileUri) => new( TextSpan, + DiagnosticLevel.Error, "BCP379", $"The OCI artifact extension alias name \"{aliasName}\" does not exist in the {BuildBicepConfigurationClause(configFileUri)}."); - public ErrorDiagnostic UnsupportedArtifactType(ArtifactType artifactType) => new( + public Diagnostic UnsupportedArtifactType(ArtifactType artifactType) => new( TextSpan, + DiagnosticLevel.Error, "BCP380", $"Artifacts of type: \"{artifactType}\" are not supported." ); @@ -2089,48 +2385,57 @@ public FixableDiagnostic ExtensionDeclarationKeywordIsDeprecated(ExtensionDeclar codeFix); } - public ErrorDiagnostic TypeIsNotParameterizable(string typeName) => new( + public Diagnostic TypeIsNotParameterizable(string typeName) => new( TextSpan, + DiagnosticLevel.Error, "BCP383", $"The \"{typeName}\" type is not parameterizable."); - public ErrorDiagnostic TypeRequiresParameterization(string typeName, int requiredArgumentCount) => new( + public Diagnostic TypeRequiresParameterization(string typeName, int requiredArgumentCount) => new( TextSpan, + DiagnosticLevel.Error, "BCP384", $"The \"{typeName}\" type requires {requiredArgumentCount} argument(s)."); - public ErrorDiagnostic ResourceDerivedTypesUnsupported() => new( + public Diagnostic ResourceDerivedTypesUnsupported() => new( TextSpan, + DiagnosticLevel.Error, "BCP385", $@"Using resource-derived types requires enabling EXPERIMENTAL feature ""{nameof(ExperimentalFeaturesEnabled.ResourceDerivedTypes)}""."); - public ErrorDiagnostic DecoratorMayNotTargetResourceDerivedType(string decoratorName) => new( + public Diagnostic DecoratorMayNotTargetResourceDerivedType(string decoratorName) => new( TextSpan, + DiagnosticLevel.Error, "BCP386", $@"The decorator ""{decoratorName}"" may not be used on statements whose declared type is a reference to a resource-derived type."); - public ErrorDiagnostic NegatedTypeIndexSought() => new( + public Diagnostic NegatedTypeIndexSought() => new( TextSpan, + DiagnosticLevel.Error, "BCP387", "Indexing into a type requires an integer greater than or equal to 0."); - public ErrorDiagnostic TupleRequiredForIndexAccess(TypeSymbol wrongType) => new( + public Diagnostic TupleRequiredForIndexAccess(TypeSymbol wrongType) => new( TextSpan, + DiagnosticLevel.Error, "BCP388", $"Cannot access elements of type \"{wrongType}\" by index. An tuple type is required."); - public ErrorDiagnostic ExplicitAdditionalPropertiesTypeRequiredForAccessThereto(TypeSymbol wrongType) => new( + public Diagnostic ExplicitAdditionalPropertiesTypeRequiredForAccessThereto(TypeSymbol wrongType) => new( TextSpan, + DiagnosticLevel.Error, "BCP389", $"The type \"{wrongType}\" does not declare an additional properties type."); - public ErrorDiagnostic ExplicitItemsTypeRequiredForAccessThereto() => new( + public Diagnostic ExplicitItemsTypeRequiredForAccessThereto() => new( TextSpan, + DiagnosticLevel.Error, "BCP390", $"The array item type access operator ('[*]') can only be used with typed arrays."); - public ErrorDiagnostic AccessExpressionForbiddenBase() => new( + public Diagnostic AccessExpressionForbiddenBase() => new( TextSpan, + DiagnosticLevel.Error, "BCP391", "Type member access is only supported on a reference to a named type."); @@ -2146,43 +2451,51 @@ public FixableDiagnostic ExtensionDeclarationKeywordIsDeprecated(ExtensionDeclar "BCP393", $"""The type pointer segment "{unrecognizedSegment}" was not recognized. Supported pointer segments are: "properties", "items", "prefixItems", and "additionalProperties"."""); - public ErrorDiagnostic CannotUseEntireResourceBodyAsType() => new( + public Diagnostic CannotUseEntireResourceBodyAsType() => new( TextSpan, + DiagnosticLevel.Error, "BCP394", "Resource-derived type expressions must dereference a property within the resource body. Using the entire resource body type is not permitted."); - public ErrorDiagnostic InvalidTypesTgzPackage_DeserializationFailed() => new( + public Diagnostic InvalidTypesTgzPackage_DeserializationFailed() => new( TextSpan, + DiagnosticLevel.Error, "BCP396", "The referenced extension types artifact has been published with malformed content."); - public ErrorDiagnostic InvalidExtension_ImplicitExtensionMissingConfig(Uri? configFileUri, string name) => new( + public Diagnostic InvalidExtension_ImplicitExtensionMissingConfig(Uri? configFileUri, string name) => new( TextSpan, + DiagnosticLevel.Error, "BCP397", $"""Extension {name} is incorrectly configured in the {BuildBicepConfigurationClause(configFileUri)}. It is referenced in the "{RootConfiguration.ImplicitExtensionsKey}" section, but is missing corresponding configuration in the "{RootConfiguration.ExtensionsKey}" section."""); - public ErrorDiagnostic InvalidExtension_NotABuiltInExtension(Uri? configFileUri, string name) => new( + public Diagnostic InvalidExtension_NotABuiltInExtension(Uri? configFileUri, string name) => new( TextSpan, + DiagnosticLevel.Error, "BCP398", $"""Extension {name} is incorrectly configured in the {BuildBicepConfigurationClause(configFileUri)}. It is configured as built-in in the "{RootConfiguration.ExtensionsKey}" section, but no built-in extension exists."""); - public ErrorDiagnostic FetchingAzTypesRequiresExperimentalFeature() => new( + public Diagnostic FetchingAzTypesRequiresExperimentalFeature() => new( TextSpan, + DiagnosticLevel.Error, "BCP399", $"Fetching az types from the registry requires enabling EXPERIMENTAL feature \"{nameof(ExperimentalFeaturesEnabled.DynamicTypeLoading)}\"."); - public ErrorDiagnostic FetchingTypesRequiresExperimentalFeature() => new( + public Diagnostic FetchingTypesRequiresExperimentalFeature() => new( TextSpan, + DiagnosticLevel.Error, "BCP400", $"Fetching types from the registry requires enabling EXPERIMENTAL feature \"{nameof(ExperimentalFeaturesEnabled.ExtensionRegistry)}\"."); - public ErrorDiagnostic SpreadOperatorUnsupportedInLocation(SpreadExpressionSyntax spread) => new( + public Diagnostic SpreadOperatorUnsupportedInLocation(SpreadExpressionSyntax spread) => new( TextSpan, + DiagnosticLevel.Error, "BCP401", $"The spread operator \"{spread.Ellipsis.Text}\" is not permitted in this location."); - public ErrorDiagnostic SpreadOperatorRequiresAssignableValue(SpreadExpressionSyntax spread, TypeSymbol requiredType) => new( + public Diagnostic SpreadOperatorRequiresAssignableValue(SpreadExpressionSyntax spread, TypeSymbol requiredType) => new( TextSpan, + DiagnosticLevel.Error, "BCP402", $"The spread operator \"{spread.Ellipsis.Text}\" can only be used in this context for an expression assignable to type \"{requiredType}\"."); @@ -2192,18 +2505,21 @@ public FixableDiagnostic ExtensionDeclarationKeywordIsDeprecated(ExtensionDeclar "BCP403", $"The enclosing array expects elements of type \"{expectedType}\", but the array being spread contains elements of incompatible type \"{actualType}\"."); - public ErrorDiagnostic ExtendsPathHasNotBeenSpecified() => new( + public Diagnostic ExtendsPathHasNotBeenSpecified() => new( TextSpan, + DiagnosticLevel.Error, "BCP404", $"The \"{LanguageConstants.ExtendsKeyword}\" declaration is missing a bicepparam file path reference"); - public ErrorDiagnostic MoreThanOneExtendsDeclarationSpecified() => new( + public Diagnostic MoreThanOneExtendsDeclarationSpecified() => new( TextSpan, + DiagnosticLevel.Error, "BCP405", $"More than one \"{LanguageConstants.ExtendsKeyword}\" declaration are present"); - public ErrorDiagnostic ExtendsNotSupported() => new( + public Diagnostic ExtendsNotSupported() => new( TextSpan, + DiagnosticLevel.Error, "BCP406", $"The \"{LanguageConstants.ExtendsKeyword}\" keyword is not supported"); } diff --git a/src/Bicep.Core/Diagnostics/ErrorDiagnosticException.cs b/src/Bicep.Core/Diagnostics/DiagnosticException.cs similarity index 63% rename from src/Bicep.Core/Diagnostics/ErrorDiagnosticException.cs rename to src/Bicep.Core/Diagnostics/DiagnosticException.cs index 80661cfe00f..67a9c4e328a 100644 --- a/src/Bicep.Core/Diagnostics/ErrorDiagnosticException.cs +++ b/src/Bicep.Core/Diagnostics/DiagnosticException.cs @@ -7,14 +7,14 @@ namespace Bicep.Core.Diagnostics /// /// Exception with error diagnostic information attached. /// - public class ErrorDiagnosticException : BicepException + public class DiagnosticException : BicepException { - public ErrorDiagnosticException(ErrorDiagnostic diagnostic, Exception? inner = null) + public DiagnosticException(Diagnostic diagnostic, Exception? inner = null) : base(diagnostic.Message, inner) { Diagnostic = diagnostic; } - public ErrorDiagnostic Diagnostic { get; } + public Diagnostic Diagnostic { get; } } } diff --git a/src/Bicep.Core/Diagnostics/ErrorDiagnostic.cs b/src/Bicep.Core/Diagnostics/ErrorDiagnostic.cs deleted file mode 100644 index 64de25a5f52..00000000000 --- a/src/Bicep.Core/Diagnostics/ErrorDiagnostic.cs +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. -using Bicep.Core.Parsing; - -namespace Bicep.Core.Diagnostics -{ - // roughly equivalent to the 'SyntaxDiagnosticInfo' class in Roslyn - public class ErrorDiagnostic : Diagnostic - { - public ErrorDiagnostic(TextSpan span, string code, string message, Uri? documentationUri = null, DiagnosticStyling styling = DiagnosticStyling.Default) - : base(span, DiagnosticLevel.Error, code, message, documentationUri, styling) - { - } - - public ErrorDiagnostic WithSpan(TextSpan newSpan) - => new(newSpan, Code, Message); - } -} diff --git a/src/Bicep.Core/Diagnostics/FixableErrorDiagnostic.cs b/src/Bicep.Core/Diagnostics/FixableErrorDiagnostic.cs deleted file mode 100644 index 34abe332593..00000000000 --- a/src/Bicep.Core/Diagnostics/FixableErrorDiagnostic.cs +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. -using Bicep.Core.CodeAction; - -namespace Bicep.Core.Diagnostics -{ - public class FixableErrorDiagnostic : ErrorDiagnostic, IFixable - { - private readonly CodeFix fix; - private readonly IEnumerable? additionalFixes; - - public FixableErrorDiagnostic(Parsing.TextSpan span, string code, string message, Uri? documentationUri, DiagnosticStyling styling, CodeFix fix) - : base(span, code, message, documentationUri, styling) - { - this.fix = fix; - this.additionalFixes = null; - } - - public FixableErrorDiagnostic(Parsing.TextSpan span, string code, string message, Uri? documentationUri, DiagnosticStyling styling, CodeFix fix, params CodeFix[] additionalFixes) - : this(span, code, message, documentationUri, styling, fix) - { - this.additionalFixes = additionalFixes; - } - - public IEnumerable Fixes - { - get - { - yield return this.fix; - - if (this.additionalFixes != null) - { - foreach (var fix in this.additionalFixes) - { - yield return fix; - } - } - } - } - } -} diff --git a/src/Bicep.Core/Diagnostics/IDiagnosticExtensions.cs b/src/Bicep.Core/Diagnostics/IDiagnosticExtensions.cs index 7d736627956..7ba65a2657a 100644 --- a/src/Bicep.Core/Diagnostics/IDiagnosticExtensions.cs +++ b/src/Bicep.Core/Diagnostics/IDiagnosticExtensions.cs @@ -11,39 +11,12 @@ public static bool CanBeSuppressed(this IDiagnostic diagnostic) return !(diagnostic.Level == DiagnosticLevel.Error && diagnostic is not AnalyzerDiagnostic); } - public static ErrorDiagnostic? AsErrorDiagnostic(this IDiagnostic diagnostic) - { - if (diagnostic is ErrorDiagnostic alreadyErrorDiagnostic) - { - return alreadyErrorDiagnostic; - } - - return diagnostic.Level switch - { - DiagnosticLevel.Error => diagnostic switch - { - FixableDiagnostic fixable => new FixableErrorDiagnostic(fixable.Span, fixable.Code, fixable.Message, fixable.Uri, fixable.Styling, fixable.Fixes.First(), fixable.Fixes.Skip(1).ToArray()), - _ => new ErrorDiagnostic(diagnostic.Span, diagnostic.Code, diagnostic.Message, diagnostic.Uri, diagnostic.Styling), - }, - _ => null, - }; - } - public static Diagnostic WithMaximumDiagnosticLevel(this Diagnostic diagnostic, DiagnosticLevel maximumDiagnosticLevel) { if (diagnostic.Level > maximumDiagnosticLevel) { return diagnostic switch { - FixableErrorDiagnostic fixable => new FixableDiagnostic( - fixable.Span, - maximumDiagnosticLevel, - fixable.Code, - fixable.Message, - fixable.Uri, - fixable.Styling, - fixable.Fixes.First(), - fixable.Fixes.Skip(1).ToArray()), FixableDiagnostic fixable => new FixableDiagnostic( fixable.Span, maximumDiagnosticLevel, diff --git a/src/Bicep.Core/Diagnostics/ResultWithDiagnostic.cs b/src/Bicep.Core/Diagnostics/ResultWithDiagnostic.cs index 844b17f94fe..03489c30f08 100644 --- a/src/Bicep.Core/Diagnostics/ResultWithDiagnostic.cs +++ b/src/Bicep.Core/Diagnostics/ResultWithDiagnostic.cs @@ -5,9 +5,9 @@ namespace Bicep.Core.Diagnostics; -public class ResultWithDiagnostic : Result +public class ResultWithDiagnostic : Result { public ResultWithDiagnostic(TSuccess success) : base(success) { } - public ResultWithDiagnostic(DiagnosticBuilder.ErrorBuilderDelegate error) : base(error) { } + public ResultWithDiagnostic(IDiagnostic diagnostic) : base(diagnostic) { } } diff --git a/src/Bicep.Core/Diagnostics/ResultWithDiagnosticBuilder.cs b/src/Bicep.Core/Diagnostics/ResultWithDiagnosticBuilder.cs new file mode 100644 index 00000000000..2367c6b80c3 --- /dev/null +++ b/src/Bicep.Core/Diagnostics/ResultWithDiagnosticBuilder.cs @@ -0,0 +1,13 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +using Bicep.Core.Utils; + +namespace Bicep.Core.Diagnostics; + +public class ResultWithDiagnosticBuilder : Result +{ + public ResultWithDiagnosticBuilder(TSuccess success) : base(success) { } + + public ResultWithDiagnosticBuilder(DiagnosticBuilder.DiagnosticBuilderDelegate error) : base(error) { } +} diff --git a/src/Bicep.Core/Emit/ParameterAssignmentEvaluator.cs b/src/Bicep.Core/Emit/ParameterAssignmentEvaluator.cs index b7161ccc5ba..b211000173c 100644 --- a/src/Bicep.Core/Emit/ParameterAssignmentEvaluator.cs +++ b/src/Bicep.Core/Emit/ParameterAssignmentEvaluator.cs @@ -135,7 +135,7 @@ private Result(JToken? value, ParameterKeyVaultReferenceExpression? keyVaultRefe private readonly ConcurrentDictionary importResults = new(); private readonly ConcurrentDictionary wildcardImportVariableResults = new(); private readonly ConcurrentDictionary synthesizedVariableResults = new(); - private readonly ConcurrentDictionary> templateResults = new(); + private readonly ConcurrentDictionary> templateResults = new(); private readonly ConcurrentDictionary armEvaluators = new(); private readonly ImmutableDictionary paramsByName; private readonly ImmutableDictionary variablesByName; @@ -226,7 +226,7 @@ private Result EvaluateSynthesizeVariableExpression(string name, Expression expr } }); - private ResultWithDiagnostic