From abb1ef80764b1508c2fc248bcaac5fa4aba5b202 Mon Sep 17 00:00:00 2001 From: David Cho Date: Thu, 16 Jun 2022 17:56:39 -0400 Subject: [PATCH 1/6] Added diagnostic for invalid value for parent property. --- .../ScenarioTests.cs | 156 ++++++++++++++++++ .../Diagnostics/DiagnosticBuilder.cs | 5 + .../Emit/EmitLimitationCalculator.cs | 23 +++ 3 files changed, 184 insertions(+) diff --git a/src/Bicep.Core.IntegrationTests/ScenarioTests.cs b/src/Bicep.Core.IntegrationTests/ScenarioTests.cs index cc0c3f5da7c..9eb2ef425b1 100644 --- a/src/Bicep.Core.IntegrationTests/ScenarioTests.cs +++ b/src/Bicep.Core.IntegrationTests/ScenarioTests.cs @@ -3251,5 +3251,161 @@ param userAssignedManagedIdentityName string ("BCP179", DiagnosticLevel.Warning, "Unique resource or deployment name is required when looping. The loop item variable \"roleId\" or the index variable \"index\" must be referenced in at least one of the value expressions of the following properties in the loop body: \"name\", \"scope\"") }); } + + /// + /// https://github.com/Azure/bicep/issues/7154 + /// + [TestMethod] + public void Test_Issue_7154_Ternary_Syntax_Produces_Error() + { + var result = CompilationHelper.Compile(@" +var deployServerlessCosmosDb = true + +resource cosmosDbServer 'Microsoft.DocumentDB/databaseAccounts@2021-07-01-preview' = { + kind: 'GlobalDocumentDB' + name: 'cosmosdbname' + location: resourceGroup().location + properties: { + createMode: 'Default' + locations: [ + { + locationName: resourceGroup().location + failoverPriority: 0 + } + ] + databaseAccountOfferType: 'Standard' + consistencyPolicy: { + defaultConsistencyLevel: 'Session' + maxIntervalInSeconds: 5 + maxStalenessPrefix: 100 + } + diagnosticLogSettings: { + enableFullTextQuery: 'None' + } + } +} + +resource PassDb 'Microsoft.DocumentDB/databaseAccounts/sqlDatabases@2021-07-01-preview' = { + parent: cosmosDbServer + name: 'PassDb' + properties: { + resource: { + id: 'PassDb' + } + } +} + +resource QPDB 'Microsoft.DocumentDB/databaseAccounts/sqlDatabases@2021-07-01-preview' = if(!deployServerlessCosmosDb) { + parent: cosmosDbServer + name: 'QPDB' + properties: { + resource: { + id: 'QPDB' + } + } +} + +resource container_ActorColdStorage 'Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers@2021-07-01-preview' = { + parent: deployServerlessCosmosDb? PassDb: QPDB + name: 'ActorColdStorage' + properties: { + resource: { + id: 'ActorColdStorage' + partitionKey: { + paths: [ + '/Type' + ] + kind: 'Hash' + } + conflictResolutionPolicy: { + mode: 'LastWriterWins' + conflictResolutionPath: '/_ts' + } + } + } +} +"); + result.ExcludingLinterDiagnostics().Should().HaveDiagnostics(new[] { + ("BCP239", DiagnosticLevel.Error, "Unexpected value for parent property.") + }); + } + + /// + /// https://github.com/Azure/bicep/issues/7154 + /// + [TestMethod] + public void Test_Issue_7154_2_Ternary_Syntax_With_Parentheses_Produces_Error() + { + var result = CompilationHelper.Compile(@" +var deployServerlessCosmosDb = true + +resource cosmosDbServer 'Microsoft.DocumentDB/databaseAccounts@2021-07-01-preview' = { + kind: 'GlobalDocumentDB' + name: 'cosmosdbname' + location: resourceGroup().location + properties: { + createMode: 'Default' + locations: [ + { + locationName: resourceGroup().location + failoverPriority: 0 + } + ] + databaseAccountOfferType: 'Standard' + consistencyPolicy: { + defaultConsistencyLevel: 'Session' + maxIntervalInSeconds: 5 + maxStalenessPrefix: 100 + } + diagnosticLogSettings: { + enableFullTextQuery: 'None' + } + } +} + +resource PassDb 'Microsoft.DocumentDB/databaseAccounts/sqlDatabases@2021-07-01-preview' = { + parent: cosmosDbServer + name: 'PassDb' + properties: { + resource: { + id: 'PassDb' + } + } +} + +resource QPDB 'Microsoft.DocumentDB/databaseAccounts/sqlDatabases@2021-07-01-preview' = if(!deployServerlessCosmosDb) { + parent: cosmosDbServer + name: 'QPDB' + properties: { + resource: { + id: 'QPDB' + } + } +} + +resource container_ActorColdStorage 'Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers@2021-07-01-preview' = { + parent: (deployServerlessCosmosDb)? PassDb: QPDB + name: 'ActorColdStorage' + properties: { + resource: { + id: 'ActorColdStorage' + partitionKey: { + paths: [ + '/Type' + ] + kind: 'Hash' + } + conflictResolutionPolicy: { + mode: 'LastWriterWins' + conflictResolutionPath: '/_ts' + } + } + } +} +"); + result.ExcludingLinterDiagnostics().Should().HaveDiagnostics(new[] { + ("BCP239", DiagnosticLevel.Error, "Unexpected value for parent property.") + }); + } } } diff --git a/src/Bicep.Core/Diagnostics/DiagnosticBuilder.cs b/src/Bicep.Core/Diagnostics/DiagnosticBuilder.cs index c64c0e99627..93ed71b4c2a 100644 --- a/src/Bicep.Core/Diagnostics/DiagnosticBuilder.cs +++ b/src/Bicep.Core/Diagnostics/DiagnosticBuilder.cs @@ -1406,6 +1406,11 @@ public ErrorDiagnostic UnknownModuleReferenceScheme(string badScheme, ImmutableA TextSpan, "BCP238", "Unexpected new line character after a comma."); + + public ErrorDiagnostic InvalidValueForParentProperty() => new( + TextSpan, + "BCP239", + "Unexpected value for parent property."); } public static DiagnosticBuilderInternal ForPosition(TextSpan span) diff --git a/src/Bicep.Core/Emit/EmitLimitationCalculator.cs b/src/Bicep.Core/Emit/EmitLimitationCalculator.cs index b9dd9ca434e..c2b52f1efba 100644 --- a/src/Bicep.Core/Emit/EmitLimitationCalculator.cs +++ b/src/Bicep.Core/Emit/EmitLimitationCalculator.cs @@ -33,6 +33,7 @@ public static EmitLimitationInfo Calculate(SemanticModel model) DetectUnexpectedResourceLoopInvariantProperties(model, diagnosticWriter); DetectUnexpectedModuleLoopInvariantProperties(model, diagnosticWriter); DetectUnsupportedModuleParameterAssignments(model, diagnosticWriter); + DetectInvalidValueForParentProperty(model, diagnosticWriter); return new EmitLimitationInfo(diagnosticWriter.GetDiagnostics(), moduleScopeData, resourceScopeData); } @@ -316,6 +317,28 @@ public static void DetectUnsupportedModuleParameterAssignments(SemanticModel sem } } + public static void DetectInvalidValueForParentProperty(SemanticModel semanticModel, IDiagnosticWriter diagnosticWriter) + { + foreach (var resourceDeclarationSymbol in semanticModel.Root.ResourceDeclarations) + { + if (resourceDeclarationSymbol.TryGetBodyPropertyValue(LanguageConstants.ResourceParentPropertyName) is { } referenceParentSyntax) + { + /*SyntaxBase? indexExpression = null;*/ + if (referenceParentSyntax is ArrayAccessSyntax arrayAccess) + { + referenceParentSyntax = arrayAccess.BaseExpression; + /*indexExpression = arrayAccess.IndexExpression;*/ + } + + // throw a diagnostic if parent syntax can not be found + if (semanticModel.ResourceMetadata.TryLookup(referenceParentSyntax) is not { }) + { + diagnosticWriter.Write(DiagnosticBuilder.ForPosition(referenceParentSyntax.Span).InvalidValueForParentProperty()); + } + } + } + } + private static bool IsInvariant(SemanticModel semanticModel, LocalVariableSyntax itemVariable, LocalVariableSyntax? indexVariable, SyntaxBase expression) { var referencedLocals = LocalSymbolDependencyVisitor.GetLocalSymbolDependencies(semanticModel, expression); From 89d0546332afe96904f465c843aedd81857dd036 Mon Sep 17 00:00:00 2001 From: David Cho Date: Thu, 16 Jun 2022 18:01:53 -0400 Subject: [PATCH 2/6] Removed unnecessary lines. --- src/Bicep.Core/Emit/EmitLimitationCalculator.cs | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/Bicep.Core/Emit/EmitLimitationCalculator.cs b/src/Bicep.Core/Emit/EmitLimitationCalculator.cs index c2b52f1efba..efcfe8a8a0c 100644 --- a/src/Bicep.Core/Emit/EmitLimitationCalculator.cs +++ b/src/Bicep.Core/Emit/EmitLimitationCalculator.cs @@ -323,14 +323,11 @@ public static void DetectInvalidValueForParentProperty(SemanticModel semanticMod { if (resourceDeclarationSymbol.TryGetBodyPropertyValue(LanguageConstants.ResourceParentPropertyName) is { } referenceParentSyntax) { - /*SyntaxBase? indexExpression = null;*/ if (referenceParentSyntax is ArrayAccessSyntax arrayAccess) { referenceParentSyntax = arrayAccess.BaseExpression; - /*indexExpression = arrayAccess.IndexExpression;*/ } - // throw a diagnostic if parent syntax can not be found if (semanticModel.ResourceMetadata.TryLookup(referenceParentSyntax) is not { }) { diagnosticWriter.Write(DiagnosticBuilder.ForPosition(referenceParentSyntax.Span).InvalidValueForParentProperty()); From 6b03de62ca8c47b8b7b44bddacfa647a12ebcf52 Mon Sep 17 00:00:00 2001 From: David Cho Date: Thu, 16 Jun 2022 18:19:36 -0400 Subject: [PATCH 3/6] Added baseline test changes. --- .../Files/InvalidResources_CRLF/main.diagnostics.bicep | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/Bicep.Core.Samples/Files/InvalidResources_CRLF/main.diagnostics.bicep b/src/Bicep.Core.Samples/Files/InvalidResources_CRLF/main.diagnostics.bicep index a3df91cfd04..738749b6aa5 100644 --- a/src/Bicep.Core.Samples/Files/InvalidResources_CRLF/main.diagnostics.bicep +++ b/src/Bicep.Core.Samples/Files/InvalidResources_CRLF/main.diagnostics.bicep @@ -1882,6 +1882,7 @@ resource p2_res2child 'Microsoft.Rp2/resource2/child2@2020-06-01' = { resource p3_vmExt 'Microsoft.Compute/virtualMachines/extensions@2020-06-01' = { parent: p3_vmExt //@[010:018) [BCP079 (Error)] This expression is referencing its own declaration, which is not allowed. (CodeDescription: none) |p3_vmExt| +//@[010:018) [BCP239 (Error)] Unexpected value for parent property. (CodeDescription: none) |p3_vmExt| location: 'eastus' //@[012:020) [no-hardcoded-location (Warning)] A resource location should not use a hard-coded string or variable value. Please use a parameter value, an expression, or the string 'global'. Found: 'eastus' (CodeDescription: bicep core(https://aka.ms/bicep/linter/no-hardcoded-location)) |'eastus'| } @@ -1890,6 +1891,7 @@ resource p3_vmExt 'Microsoft.Compute/virtualMachines/extensions@2020-06-01' = { resource p4_vm 'Microsoft.Compute/virtualMachines@2020-06-01' = { parent: p4_vmExt //@[010:018) [BCP080 (Error)] The expression is involved in a cycle ("p4_vmExt" -> "p4_vm"). (CodeDescription: none) |p4_vmExt| +//@[010:018) [BCP239 (Error)] Unexpected value for parent property. (CodeDescription: none) |p4_vmExt| location: 'eastus' //@[012:020) [no-hardcoded-location (Warning)] A resource location should not use a hard-coded string or variable value. Please use a parameter value, an expression, or the string 'global'. Found: 'eastus' (CodeDescription: bicep core(https://aka.ms/bicep/linter/no-hardcoded-location)) |'eastus'| } @@ -1897,6 +1899,7 @@ resource p4_vm 'Microsoft.Compute/virtualMachines@2020-06-01' = { resource p4_vmExt 'Microsoft.Compute/virtualMachines/extensions@2020-06-01' = { parent: p4_vm //@[010:015) [BCP080 (Error)] The expression is involved in a cycle ("p4_vm" -> "p4_vmExt"). (CodeDescription: none) |p4_vm| +//@[010:015) [BCP239 (Error)] Unexpected value for parent property. (CodeDescription: none) |p4_vm| location: 'eastus' //@[012:020) [no-hardcoded-location (Warning)] A resource location should not use a hard-coded string or variable value. Please use a parameter value, an expression, or the string 'global'. Found: 'eastus' (CodeDescription: bicep core(https://aka.ms/bicep/linter/no-hardcoded-location)) |'eastus'| } @@ -1925,6 +1928,7 @@ resource p6_res2 'Microsoft.Rp1/resource1/child2@2020-06-01' = { //@[017:060) [BCP081 (Warning)] Resource type "Microsoft.Rp1/resource1/child2@2020-06-01" does not have types available. (CodeDescription: none) |'Microsoft.Rp1/resource1/child2@2020-06-01'| parent: p6_res1 //@[010:017) [BCP062 (Error)] The referenced declaration with name "p6_res1" is not valid. (CodeDescription: none) |p6_res1| +//@[010:017) [BCP239 (Error)] Unexpected value for parent property. (CodeDescription: none) |p6_res1| name: 'res2' } @@ -1989,12 +1993,14 @@ resource anyTypeInDependsOn 'Microsoft.Network/dnsZones@2018-05-01' = { resource anyTypeInParent 'Microsoft.Network/dnsZones/CNAME@2018-05-01' = { //@[009:024) [BCP035 (Error)] The specified "resource" declaration is missing the following required properties: "name". (CodeDescription: none) |anyTypeInParent| parent: any(true) +//@[010:019) [BCP239 (Error)] Unexpected value for parent property. (CodeDescription: none) |any(true)| //@[010:019) [BCP176 (Error)] Values of the "any" type are not allowed here. (CodeDescription: none) |any(true)| } resource anyTypeInParentLoop 'Microsoft.Network/dnsZones/CNAME@2018-05-01' = [for thing in []: { //@[009:028) [BCP035 (Error)] The specified "resource" declaration is missing the following required properties: "name". (CodeDescription: none) |anyTypeInParentLoop| parent: any(true) +//@[010:019) [BCP239 (Error)] Unexpected value for parent property. (CodeDescription: none) |any(true)| //@[010:019) [BCP176 (Error)] Values of the "any" type are not allowed here. (CodeDescription: none) |any(true)| }] @@ -2013,6 +2019,7 @@ resource anyTypeInScopeConditional 'Microsoft.Authorization/locks@2016-09-01' = resource anyTypeInExistingScope 'Microsoft.Network/dnsZones/AAAA@2018-05-01' existing = { //@[009:031) [BCP035 (Error)] The specified "resource" declaration is missing the following required properties: "name". (CodeDescription: none) |anyTypeInExistingScope| parent: any('') +//@[010:017) [BCP239 (Error)] Unexpected value for parent property. (CodeDescription: none) |any('')| //@[010:017) [BCP176 (Error)] Values of the "any" type are not allowed here. (CodeDescription: none) |any('')| scope: any(false) //@[009:019) [BCP176 (Error)] Values of the "any" type are not allowed here. (CodeDescription: none) |any(false)| @@ -2021,6 +2028,7 @@ resource anyTypeInExistingScope 'Microsoft.Network/dnsZones/AAAA@2018-05-01' exi resource anyTypeInExistingScopeLoop 'Microsoft.Network/dnsZones/AAAA@2018-05-01' existing = [for thing in []: { //@[009:035) [BCP035 (Error)] The specified "resource" declaration is missing the following required properties: "name". (CodeDescription: none) |anyTypeInExistingScopeLoop| parent: any('') +//@[010:017) [BCP239 (Error)] Unexpected value for parent property. (CodeDescription: none) |any('')| //@[010:017) [BCP176 (Error)] Values of the "any" type are not allowed here. (CodeDescription: none) |any('')| scope: any(false) //@[009:019) [BCP176 (Error)] Values of the "any" type are not allowed here. (CodeDescription: none) |any(false)| From 704b54630d6939262a3134da7fe7ee40906435ad Mon Sep 17 00:00:00 2001 From: David Cho Date: Fri, 17 Jun 2022 16:20:39 -0400 Subject: [PATCH 4/6] Added changes to error message and other things. --- .../ScenarioTests.cs | 22 +++++++++++++++++-- .../main.diagnostics.bicep | 16 +++++++------- .../Diagnostics/DiagnosticBuilder.cs | 2 +- .../Emit/EmitLimitationCalculator.cs | 11 +++++----- 4 files changed, 34 insertions(+), 17 deletions(-) diff --git a/src/Bicep.Core.IntegrationTests/ScenarioTests.cs b/src/Bicep.Core.IntegrationTests/ScenarioTests.cs index 9eb2ef425b1..042d9aa95e9 100644 --- a/src/Bicep.Core.IntegrationTests/ScenarioTests.cs +++ b/src/Bicep.Core.IntegrationTests/ScenarioTests.cs @@ -3326,7 +3326,7 @@ public void Test_Issue_7154_Ternary_Syntax_Produces_Error() } "); result.ExcludingLinterDiagnostics().Should().HaveDiagnostics(new[] { - ("BCP239", DiagnosticLevel.Error, "Unexpected value for parent property.") + ("BCP239", DiagnosticLevel.Error, "The \"parent\" property only permits direct references to resources. Expressions are not supported.") }); } @@ -3404,7 +3404,25 @@ public void Test_Issue_7154_2_Ternary_Syntax_With_Parentheses_Produces_Error() } "); result.ExcludingLinterDiagnostics().Should().HaveDiagnostics(new[] { - ("BCP239", DiagnosticLevel.Error, "Unexpected value for parent property.") + ("BCP239", DiagnosticLevel.Error, "The \"parent\" property only permits direct references to resources. Expressions are not supported.") + }); + } + + /// + /// https://github.com/Azure/bicep/issues/7154 + /// + [TestMethod] + public void Test_Issue_7154_3_Both_Type_Check_And_Parent_Errors_Should_Raise() + { + var result = CompilationHelper.Compile(@" +resource foo 'Microsoft.Storage/storageAccounts/blobServices@2021-09-01' = { + parent: 123 + name: 'default' +} +"); + result.ExcludingLinterDiagnostics().Should().HaveDiagnostics(new[] { + ("BCP036", DiagnosticLevel.Error, "The property \"parent\" expected a value of type \"Microsoft.Storage/storageAccounts\" but the provided value is of type \"int\"."), + ("BCP239", DiagnosticLevel.Error, "The \"parent\" property only permits direct references to resources. Expressions are not supported.") }); } } diff --git a/src/Bicep.Core.Samples/Files/InvalidResources_CRLF/main.diagnostics.bicep b/src/Bicep.Core.Samples/Files/InvalidResources_CRLF/main.diagnostics.bicep index 738749b6aa5..3774bc63f47 100644 --- a/src/Bicep.Core.Samples/Files/InvalidResources_CRLF/main.diagnostics.bicep +++ b/src/Bicep.Core.Samples/Files/InvalidResources_CRLF/main.diagnostics.bicep @@ -1881,8 +1881,8 @@ resource p2_res2child 'Microsoft.Rp2/resource2/child2@2020-06-01' = { // parent property self-cycle resource p3_vmExt 'Microsoft.Compute/virtualMachines/extensions@2020-06-01' = { parent: p3_vmExt +//@[010:018) [BCP239 (Error)] The "parent" property only permits direct references to resources. Expressions are not supported. (CodeDescription: none) |p3_vmExt| //@[010:018) [BCP079 (Error)] This expression is referencing its own declaration, which is not allowed. (CodeDescription: none) |p3_vmExt| -//@[010:018) [BCP239 (Error)] Unexpected value for parent property. (CodeDescription: none) |p3_vmExt| location: 'eastus' //@[012:020) [no-hardcoded-location (Warning)] A resource location should not use a hard-coded string or variable value. Please use a parameter value, an expression, or the string 'global'. Found: 'eastus' (CodeDescription: bicep core(https://aka.ms/bicep/linter/no-hardcoded-location)) |'eastus'| } @@ -1890,16 +1890,16 @@ resource p3_vmExt 'Microsoft.Compute/virtualMachines/extensions@2020-06-01' = { // parent property 2-cycle resource p4_vm 'Microsoft.Compute/virtualMachines@2020-06-01' = { parent: p4_vmExt +//@[010:018) [BCP239 (Error)] The "parent" property only permits direct references to resources. Expressions are not supported. (CodeDescription: none) |p4_vmExt| //@[010:018) [BCP080 (Error)] The expression is involved in a cycle ("p4_vmExt" -> "p4_vm"). (CodeDescription: none) |p4_vmExt| -//@[010:018) [BCP239 (Error)] Unexpected value for parent property. (CodeDescription: none) |p4_vmExt| location: 'eastus' //@[012:020) [no-hardcoded-location (Warning)] A resource location should not use a hard-coded string or variable value. Please use a parameter value, an expression, or the string 'global'. Found: 'eastus' (CodeDescription: bicep core(https://aka.ms/bicep/linter/no-hardcoded-location)) |'eastus'| } resource p4_vmExt 'Microsoft.Compute/virtualMachines/extensions@2020-06-01' = { parent: p4_vm +//@[010:015) [BCP239 (Error)] The "parent" property only permits direct references to resources. Expressions are not supported. (CodeDescription: none) |p4_vm| //@[010:015) [BCP080 (Error)] The expression is involved in a cycle ("p4_vm" -> "p4_vmExt"). (CodeDescription: none) |p4_vm| -//@[010:015) [BCP239 (Error)] Unexpected value for parent property. (CodeDescription: none) |p4_vm| location: 'eastus' //@[012:020) [no-hardcoded-location (Warning)] A resource location should not use a hard-coded string or variable value. Please use a parameter value, an expression, or the string 'global'. Found: 'eastus' (CodeDescription: bicep core(https://aka.ms/bicep/linter/no-hardcoded-location)) |'eastus'| } @@ -1927,8 +1927,8 @@ resource p6_res1 '${true}' = { resource p6_res2 'Microsoft.Rp1/resource1/child2@2020-06-01' = { //@[017:060) [BCP081 (Warning)] Resource type "Microsoft.Rp1/resource1/child2@2020-06-01" does not have types available. (CodeDescription: none) |'Microsoft.Rp1/resource1/child2@2020-06-01'| parent: p6_res1 +//@[010:017) [BCP239 (Error)] The "parent" property only permits direct references to resources. Expressions are not supported. (CodeDescription: none) |p6_res1| //@[010:017) [BCP062 (Error)] The referenced declaration with name "p6_res1" is not valid. (CodeDescription: none) |p6_res1| -//@[010:017) [BCP239 (Error)] Unexpected value for parent property. (CodeDescription: none) |p6_res1| name: 'res2' } @@ -1993,14 +1993,14 @@ resource anyTypeInDependsOn 'Microsoft.Network/dnsZones@2018-05-01' = { resource anyTypeInParent 'Microsoft.Network/dnsZones/CNAME@2018-05-01' = { //@[009:024) [BCP035 (Error)] The specified "resource" declaration is missing the following required properties: "name". (CodeDescription: none) |anyTypeInParent| parent: any(true) -//@[010:019) [BCP239 (Error)] Unexpected value for parent property. (CodeDescription: none) |any(true)| +//@[010:019) [BCP239 (Error)] The "parent" property only permits direct references to resources. Expressions are not supported. (CodeDescription: none) |any(true)| //@[010:019) [BCP176 (Error)] Values of the "any" type are not allowed here. (CodeDescription: none) |any(true)| } resource anyTypeInParentLoop 'Microsoft.Network/dnsZones/CNAME@2018-05-01' = [for thing in []: { //@[009:028) [BCP035 (Error)] The specified "resource" declaration is missing the following required properties: "name". (CodeDescription: none) |anyTypeInParentLoop| parent: any(true) -//@[010:019) [BCP239 (Error)] Unexpected value for parent property. (CodeDescription: none) |any(true)| +//@[010:019) [BCP239 (Error)] The "parent" property only permits direct references to resources. Expressions are not supported. (CodeDescription: none) |any(true)| //@[010:019) [BCP176 (Error)] Values of the "any" type are not allowed here. (CodeDescription: none) |any(true)| }] @@ -2019,7 +2019,7 @@ resource anyTypeInScopeConditional 'Microsoft.Authorization/locks@2016-09-01' = resource anyTypeInExistingScope 'Microsoft.Network/dnsZones/AAAA@2018-05-01' existing = { //@[009:031) [BCP035 (Error)] The specified "resource" declaration is missing the following required properties: "name". (CodeDescription: none) |anyTypeInExistingScope| parent: any('') -//@[010:017) [BCP239 (Error)] Unexpected value for parent property. (CodeDescription: none) |any('')| +//@[010:017) [BCP239 (Error)] The "parent" property only permits direct references to resources. Expressions are not supported. (CodeDescription: none) |any('')| //@[010:017) [BCP176 (Error)] Values of the "any" type are not allowed here. (CodeDescription: none) |any('')| scope: any(false) //@[009:019) [BCP176 (Error)] Values of the "any" type are not allowed here. (CodeDescription: none) |any(false)| @@ -2028,7 +2028,7 @@ resource anyTypeInExistingScope 'Microsoft.Network/dnsZones/AAAA@2018-05-01' exi resource anyTypeInExistingScopeLoop 'Microsoft.Network/dnsZones/AAAA@2018-05-01' existing = [for thing in []: { //@[009:035) [BCP035 (Error)] The specified "resource" declaration is missing the following required properties: "name". (CodeDescription: none) |anyTypeInExistingScopeLoop| parent: any('') -//@[010:017) [BCP239 (Error)] Unexpected value for parent property. (CodeDescription: none) |any('')| +//@[010:017) [BCP239 (Error)] The "parent" property only permits direct references to resources. Expressions are not supported. (CodeDescription: none) |any('')| //@[010:017) [BCP176 (Error)] Values of the "any" type are not allowed here. (CodeDescription: none) |any('')| scope: any(false) //@[009:019) [BCP176 (Error)] Values of the "any" type are not allowed here. (CodeDescription: none) |any(false)| diff --git a/src/Bicep.Core/Diagnostics/DiagnosticBuilder.cs b/src/Bicep.Core/Diagnostics/DiagnosticBuilder.cs index 93ed71b4c2a..c44537d7e05 100644 --- a/src/Bicep.Core/Diagnostics/DiagnosticBuilder.cs +++ b/src/Bicep.Core/Diagnostics/DiagnosticBuilder.cs @@ -1410,7 +1410,7 @@ public ErrorDiagnostic UnknownModuleReferenceScheme(string badScheme, ImmutableA public ErrorDiagnostic InvalidValueForParentProperty() => new( TextSpan, "BCP239", - "Unexpected value for parent property."); + "The \"parent\" property only permits direct references to resources. Expressions are not supported."); } public static DiagnosticBuilderInternal ForPosition(TextSpan span) diff --git a/src/Bicep.Core/Emit/EmitLimitationCalculator.cs b/src/Bicep.Core/Emit/EmitLimitationCalculator.cs index efcfe8a8a0c..ec79b144e8d 100644 --- a/src/Bicep.Core/Emit/EmitLimitationCalculator.cs +++ b/src/Bicep.Core/Emit/EmitLimitationCalculator.cs @@ -323,14 +323,13 @@ public static void DetectInvalidValueForParentProperty(SemanticModel semanticMod { if (resourceDeclarationSymbol.TryGetBodyPropertyValue(LanguageConstants.ResourceParentPropertyName) is { } referenceParentSyntax) { - if (referenceParentSyntax is ArrayAccessSyntax arrayAccess) - { - referenceParentSyntax = arrayAccess.BaseExpression; - } + var (baseSyntax, _) = SyntaxHelper.UnwrapArrayAccessSyntax(referenceParentSyntax); - if (semanticModel.ResourceMetadata.TryLookup(referenceParentSyntax) is not { }) + if (semanticModel.ResourceMetadata.TryLookup(referenceParentSyntax) is not { } && !semanticModel.GetTypeInfo(referenceParentSyntax).IsError()) { - diagnosticWriter.Write(DiagnosticBuilder.ForPosition(referenceParentSyntax.Span).InvalidValueForParentProperty()); + // we throw an error diagnostic when the parent property contains a value that cannot be computed or does not directly reference another resource. + // this includes ternary operator expressions, which Bicep does not support + diagnosticWriter.Write(referenceParentSyntax, x => x.InvalidValueForParentProperty()); } } } From 76e94ef8a9e200468c6eeeae430d78e7f08939b1 Mon Sep 17 00:00:00 2001 From: David Cho Date: Mon, 20 Jun 2022 14:59:19 -0400 Subject: [PATCH 5/6] Fixed logic for ArrayAccessSyntax. --- .../ScenarioTests.cs | 18 ------------------ .../main.diagnostics.bicep | 4 ---- .../Emit/EmitLimitationCalculator.cs | 2 +- 3 files changed, 1 insertion(+), 23 deletions(-) diff --git a/src/Bicep.Core.IntegrationTests/ScenarioTests.cs b/src/Bicep.Core.IntegrationTests/ScenarioTests.cs index 042d9aa95e9..a1cdcd6d72b 100644 --- a/src/Bicep.Core.IntegrationTests/ScenarioTests.cs +++ b/src/Bicep.Core.IntegrationTests/ScenarioTests.cs @@ -3407,23 +3407,5 @@ public void Test_Issue_7154_2_Ternary_Syntax_With_Parentheses_Produces_Error() ("BCP239", DiagnosticLevel.Error, "The \"parent\" property only permits direct references to resources. Expressions are not supported.") }); } - - /// - /// https://github.com/Azure/bicep/issues/7154 - /// - [TestMethod] - public void Test_Issue_7154_3_Both_Type_Check_And_Parent_Errors_Should_Raise() - { - var result = CompilationHelper.Compile(@" -resource foo 'Microsoft.Storage/storageAccounts/blobServices@2021-09-01' = { - parent: 123 - name: 'default' -} -"); - result.ExcludingLinterDiagnostics().Should().HaveDiagnostics(new[] { - ("BCP036", DiagnosticLevel.Error, "The property \"parent\" expected a value of type \"Microsoft.Storage/storageAccounts\" but the provided value is of type \"int\"."), - ("BCP239", DiagnosticLevel.Error, "The \"parent\" property only permits direct references to resources. Expressions are not supported.") - }); - } } } diff --git a/src/Bicep.Core.Samples/Files/InvalidResources_CRLF/main.diagnostics.bicep b/src/Bicep.Core.Samples/Files/InvalidResources_CRLF/main.diagnostics.bicep index 3774bc63f47..b8f0e52f008 100644 --- a/src/Bicep.Core.Samples/Files/InvalidResources_CRLF/main.diagnostics.bicep +++ b/src/Bicep.Core.Samples/Files/InvalidResources_CRLF/main.diagnostics.bicep @@ -1881,7 +1881,6 @@ resource p2_res2child 'Microsoft.Rp2/resource2/child2@2020-06-01' = { // parent property self-cycle resource p3_vmExt 'Microsoft.Compute/virtualMachines/extensions@2020-06-01' = { parent: p3_vmExt -//@[010:018) [BCP239 (Error)] The "parent" property only permits direct references to resources. Expressions are not supported. (CodeDescription: none) |p3_vmExt| //@[010:018) [BCP079 (Error)] This expression is referencing its own declaration, which is not allowed. (CodeDescription: none) |p3_vmExt| location: 'eastus' //@[012:020) [no-hardcoded-location (Warning)] A resource location should not use a hard-coded string or variable value. Please use a parameter value, an expression, or the string 'global'. Found: 'eastus' (CodeDescription: bicep core(https://aka.ms/bicep/linter/no-hardcoded-location)) |'eastus'| @@ -1890,7 +1889,6 @@ resource p3_vmExt 'Microsoft.Compute/virtualMachines/extensions@2020-06-01' = { // parent property 2-cycle resource p4_vm 'Microsoft.Compute/virtualMachines@2020-06-01' = { parent: p4_vmExt -//@[010:018) [BCP239 (Error)] The "parent" property only permits direct references to resources. Expressions are not supported. (CodeDescription: none) |p4_vmExt| //@[010:018) [BCP080 (Error)] The expression is involved in a cycle ("p4_vmExt" -> "p4_vm"). (CodeDescription: none) |p4_vmExt| location: 'eastus' //@[012:020) [no-hardcoded-location (Warning)] A resource location should not use a hard-coded string or variable value. Please use a parameter value, an expression, or the string 'global'. Found: 'eastus' (CodeDescription: bicep core(https://aka.ms/bicep/linter/no-hardcoded-location)) |'eastus'| @@ -1898,7 +1896,6 @@ resource p4_vm 'Microsoft.Compute/virtualMachines@2020-06-01' = { resource p4_vmExt 'Microsoft.Compute/virtualMachines/extensions@2020-06-01' = { parent: p4_vm -//@[010:015) [BCP239 (Error)] The "parent" property only permits direct references to resources. Expressions are not supported. (CodeDescription: none) |p4_vm| //@[010:015) [BCP080 (Error)] The expression is involved in a cycle ("p4_vm" -> "p4_vmExt"). (CodeDescription: none) |p4_vm| location: 'eastus' //@[012:020) [no-hardcoded-location (Warning)] A resource location should not use a hard-coded string or variable value. Please use a parameter value, an expression, or the string 'global'. Found: 'eastus' (CodeDescription: bicep core(https://aka.ms/bicep/linter/no-hardcoded-location)) |'eastus'| @@ -1927,7 +1924,6 @@ resource p6_res1 '${true}' = { resource p6_res2 'Microsoft.Rp1/resource1/child2@2020-06-01' = { //@[017:060) [BCP081 (Warning)] Resource type "Microsoft.Rp1/resource1/child2@2020-06-01" does not have types available. (CodeDescription: none) |'Microsoft.Rp1/resource1/child2@2020-06-01'| parent: p6_res1 -//@[010:017) [BCP239 (Error)] The "parent" property only permits direct references to resources. Expressions are not supported. (CodeDescription: none) |p6_res1| //@[010:017) [BCP062 (Error)] The referenced declaration with name "p6_res1" is not valid. (CodeDescription: none) |p6_res1| name: 'res2' } diff --git a/src/Bicep.Core/Emit/EmitLimitationCalculator.cs b/src/Bicep.Core/Emit/EmitLimitationCalculator.cs index ec79b144e8d..f224a1f78f1 100644 --- a/src/Bicep.Core/Emit/EmitLimitationCalculator.cs +++ b/src/Bicep.Core/Emit/EmitLimitationCalculator.cs @@ -325,7 +325,7 @@ public static void DetectInvalidValueForParentProperty(SemanticModel semanticMod { var (baseSyntax, _) = SyntaxHelper.UnwrapArrayAccessSyntax(referenceParentSyntax); - if (semanticModel.ResourceMetadata.TryLookup(referenceParentSyntax) is not { } && !semanticModel.GetTypeInfo(referenceParentSyntax).IsError()) + if (semanticModel.ResourceMetadata.TryLookup(baseSyntax) is not { } && !semanticModel.GetTypeInfo(baseSyntax).IsError()) { // we throw an error diagnostic when the parent property contains a value that cannot be computed or does not directly reference another resource. // this includes ternary operator expressions, which Bicep does not support From 6963ef43098920eadac7e23a8553c66ffb0c4596 Mon Sep 17 00:00:00 2001 From: David Cho Date: Mon, 20 Jun 2022 16:24:29 -0400 Subject: [PATCH 6/6] Fixed tests. --- src/Bicep.Core.IntegrationTests/ScenarioTests.cs | 3 +++ .../Files/InvalidResources_CRLF/main.diagnostics.bicep | 8 ++++---- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/Bicep.Core.IntegrationTests/ScenarioTests.cs b/src/Bicep.Core.IntegrationTests/ScenarioTests.cs index 94cae26aa2e..934df335ada 100644 --- a/src/Bicep.Core.IntegrationTests/ScenarioTests.cs +++ b/src/Bicep.Core.IntegrationTests/ScenarioTests.cs @@ -1947,6 +1947,7 @@ param zonesEnabled bool ("BCP036", DiagnosticLevel.Error, "The property \"scope\" expected a value of type \"resource | tenant\" but the provided value is of type \"null\"."), ("BCP036", DiagnosticLevel.Error, "The property \"name\" expected a value of type \"string\" but the provided value is of type \"null\"."), ("BCP036", DiagnosticLevel.Error, "The property \"parent\" expected a value of type \"Microsoft.Network/dnsZones\" but the provided value is of type \"null\"."), + ("BCP240", DiagnosticLevel.Error, "The \"parent\" property only permits direct references to resources. Expressions are not supported."), }); } @@ -2417,7 +2418,9 @@ public void Test_Issue4212() result.Should().HaveDiagnostics(new[] { ("BCP036", DiagnosticLevel.Error, "The property \"parent\" expected a value of type \"Microsoft.Network/virtualNetworks\" but the provided value is of type \"module\"."), + ("BCP240", DiagnosticLevel.Error, "The \"parent\" property only permits direct references to resources. Expressions are not supported."), ("BCP036", DiagnosticLevel.Error, "The property \"parent\" expected a value of type \"Microsoft.Network/virtualNetworks\" but the provided value is of type \"tenant\"."), + ("BCP240", DiagnosticLevel.Error, "The \"parent\" property only permits direct references to resources. Expressions are not supported."), }); } diff --git a/src/Bicep.Core.Samples/Files/InvalidResources_CRLF/main.diagnostics.bicep b/src/Bicep.Core.Samples/Files/InvalidResources_CRLF/main.diagnostics.bicep index b8f0e52f008..3d0e74d0546 100644 --- a/src/Bicep.Core.Samples/Files/InvalidResources_CRLF/main.diagnostics.bicep +++ b/src/Bicep.Core.Samples/Files/InvalidResources_CRLF/main.diagnostics.bicep @@ -1989,14 +1989,14 @@ resource anyTypeInDependsOn 'Microsoft.Network/dnsZones@2018-05-01' = { resource anyTypeInParent 'Microsoft.Network/dnsZones/CNAME@2018-05-01' = { //@[009:024) [BCP035 (Error)] The specified "resource" declaration is missing the following required properties: "name". (CodeDescription: none) |anyTypeInParent| parent: any(true) -//@[010:019) [BCP239 (Error)] The "parent" property only permits direct references to resources. Expressions are not supported. (CodeDescription: none) |any(true)| +//@[010:019) [BCP240 (Error)] The "parent" property only permits direct references to resources. Expressions are not supported. (CodeDescription: none) |any(true)| //@[010:019) [BCP176 (Error)] Values of the "any" type are not allowed here. (CodeDescription: none) |any(true)| } resource anyTypeInParentLoop 'Microsoft.Network/dnsZones/CNAME@2018-05-01' = [for thing in []: { //@[009:028) [BCP035 (Error)] The specified "resource" declaration is missing the following required properties: "name". (CodeDescription: none) |anyTypeInParentLoop| parent: any(true) -//@[010:019) [BCP239 (Error)] The "parent" property only permits direct references to resources. Expressions are not supported. (CodeDescription: none) |any(true)| +//@[010:019) [BCP240 (Error)] The "parent" property only permits direct references to resources. Expressions are not supported. (CodeDescription: none) |any(true)| //@[010:019) [BCP176 (Error)] Values of the "any" type are not allowed here. (CodeDescription: none) |any(true)| }] @@ -2015,7 +2015,7 @@ resource anyTypeInScopeConditional 'Microsoft.Authorization/locks@2016-09-01' = resource anyTypeInExistingScope 'Microsoft.Network/dnsZones/AAAA@2018-05-01' existing = { //@[009:031) [BCP035 (Error)] The specified "resource" declaration is missing the following required properties: "name". (CodeDescription: none) |anyTypeInExistingScope| parent: any('') -//@[010:017) [BCP239 (Error)] The "parent" property only permits direct references to resources. Expressions are not supported. (CodeDescription: none) |any('')| +//@[010:017) [BCP240 (Error)] The "parent" property only permits direct references to resources. Expressions are not supported. (CodeDescription: none) |any('')| //@[010:017) [BCP176 (Error)] Values of the "any" type are not allowed here. (CodeDescription: none) |any('')| scope: any(false) //@[009:019) [BCP176 (Error)] Values of the "any" type are not allowed here. (CodeDescription: none) |any(false)| @@ -2024,7 +2024,7 @@ resource anyTypeInExistingScope 'Microsoft.Network/dnsZones/AAAA@2018-05-01' exi resource anyTypeInExistingScopeLoop 'Microsoft.Network/dnsZones/AAAA@2018-05-01' existing = [for thing in []: { //@[009:035) [BCP035 (Error)] The specified "resource" declaration is missing the following required properties: "name". (CodeDescription: none) |anyTypeInExistingScopeLoop| parent: any('') -//@[010:017) [BCP239 (Error)] The "parent" property only permits direct references to resources. Expressions are not supported. (CodeDescription: none) |any('')| +//@[010:017) [BCP240 (Error)] The "parent" property only permits direct references to resources. Expressions are not supported. (CodeDescription: none) |any('')| //@[010:017) [BCP176 (Error)] Values of the "any" type are not allowed here. (CodeDescription: none) |any('')| scope: any(false) //@[009:019) [BCP176 (Error)] Values of the "any" type are not allowed here. (CodeDescription: none) |any(false)|