From 14af56cb1a3ba68501dc627dcc4b04f83ce1560b Mon Sep 17 00:00:00 2001 From: Jonny Eskew Date: Tue, 5 Mar 2024 11:31:08 -0500 Subject: [PATCH] Update AzResourceTypeFactory cache key to take account of required flags (#13535) Resolves #13534 The cache within `AzResourceTypeFactory` was using the serialized type as a key, but since the AZ resource types reuse types pretty aggressively, this was leading to values being cached with the wrong flag assignments (which are dependent on *where* in a resource a particular type is used). This PR updates the cache to use a compound key instead to keep these usages separate. ###### Microsoft Reviewers: [Open in CodeFlow](https://microsoft.github.io/open-pr/?codeflow=https://github.com/Azure/bicep/pull/13535) --- .../ScenarioTests.cs | 53 +++++++++++++++++++ .../Providers/Az/AzResourceTypeFactory.cs | 6 ++- 2 files changed, 57 insertions(+), 2 deletions(-) diff --git a/src/Bicep.Core.IntegrationTests/ScenarioTests.cs b/src/Bicep.Core.IntegrationTests/ScenarioTests.cs index 30bc0192f1a..ac3cde84765 100644 --- a/src/Bicep.Core.IntegrationTests/ScenarioTests.cs +++ b/src/Bicep.Core.IntegrationTests/ScenarioTests.cs @@ -5845,4 +5845,57 @@ public void Test_Issue13462() result.ExcludingLinterDiagnostics().Should().NotHaveAnyDiagnostics(); } + + // https://github.com/Azure/bicep/issues/13534 + [TestMethod] + public void Test_Issue13534() + { + var result = CompilationHelper.Compile(""" + var username = '' + var password = '' + var fileshareConnection = { + name: '' + authType: '' + rootfolder: '' + odgw: { + name: '' + resourceGroup: '' + } + } + + var general = { + location: '' + } + + resource resFileshareConnection 'Microsoft.Web/connections@2016-06-01' = { + name: fileshareConnection.name + location: general.location + kind: 'V2' + properties: { + displayName: fileshareConnection.name + customParameterValues: {} + parameterValues: { + rootfolder: fileshareConnection.rootfolder + authType: fileshareConnection.authType + gateway: { + name: fileshareConnection.odgw.name + id: resourceId(fileshareConnection.odgw.resourceGroup, 'Microsoft.Web/connectionGateways', fileshareConnection.odgw.name) + type: 'Microsoft.Web/connectionGateways' + } + username: username + password: password + } + api: { + id: subscriptionResourceId('Microsoft.Web/locations/managedApis', general.location, 'filesystem') + } + } + } + """); + + result.ExcludingLinterDiagnostics().Should().HaveDiagnostics(new[] + { + ("BCP187", DiagnosticLevel.Warning, """The property "kind" does not exist in the resource or type definition, although it might still be valid. If this is an inaccuracy in the documentation, please report it to the Bicep Team."""), + ("BCP036", DiagnosticLevel.Warning, """The property "gateway" expected a value of type "string" but the provided value is of type "object"."""), + }); + } } diff --git a/src/Bicep.Core/TypeSystem/Providers/Az/AzResourceTypeFactory.cs b/src/Bicep.Core/TypeSystem/Providers/Az/AzResourceTypeFactory.cs index c81bf34ccd5..305ae209634 100644 --- a/src/Bicep.Core/TypeSystem/Providers/Az/AzResourceTypeFactory.cs +++ b/src/Bicep.Core/TypeSystem/Providers/Az/AzResourceTypeFactory.cs @@ -9,7 +9,7 @@ namespace Bicep.Core.TypeSystem.Providers.Az { public class AzResourceTypeFactory { - private readonly ConcurrentDictionary typeCache; + private readonly ConcurrentDictionary<(Azure.Bicep.Types.Concrete.TypeBase definedType, bool isResourceBodyType, bool isResourceBodyTopLevelPropertyType), TypeSymbol> typeCache; public AzResourceTypeFactory() { @@ -57,7 +57,9 @@ public IEnumerable GetResourceFunctionOverloads(Azure.Bicep.Ty } private TypeSymbol GetTypeSymbol(Azure.Bicep.Types.Concrete.TypeBase serializedType, bool isResourceBodyType, bool isResourceBodyTopLevelPropertyType) - => typeCache.GetOrAdd(serializedType, serializedType => ToTypeSymbol(serializedType, isResourceBodyType, isResourceBodyTopLevelPropertyType)); + // The cache key should always include *all* arguments passed to this function + => typeCache.GetOrAdd((serializedType, isResourceBodyType, isResourceBodyTopLevelPropertyType), + t => ToTypeSymbol(t.definedType, t.isResourceBodyType, t.isResourceBodyTopLevelPropertyType)); private ITypeReference GetTypeReference(Azure.Bicep.Types.Concrete.ITypeReference input, bool isResourceBodyType, bool isResourceBodyTopLevelPropertyType) => new DeferredTypeReference(() => GetTypeSymbol(input.Type, isResourceBodyType, isResourceBodyTopLevelPropertyType));