Skip to content

Commit

Permalink
Correct codegen for module name reference (#1733)
Browse files Browse the repository at this point in the history
* Correct codegen for module name reference

* Update baselines
  • Loading branch information
anthony-c-martin authored Mar 8, 2021
1 parent 270678b commit 30cb620
Show file tree
Hide file tree
Showing 4 changed files with 97 additions and 15 deletions.
48 changes: 48 additions & 0 deletions src/Bicep.Core.IntegrationTests/ScenarioTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -890,6 +890,54 @@ param stampLocations array {
diags.Should().ContainDiagnostic("BCP052", DiagnosticLevel.Error, "The type \"outputs\" does not contain property \"cosmosDbKey\".");
}

[TestMethod]
public void Test_Issue1592()
{
var (template, diags, _) = CompilationHelper.Compile(
("main.bicep", @"
module foo 'test.bicep' = {
name: 'foo'
}
output fooName string = foo.name
"),
("test.bicep", @""));

diags.Should().BeEmpty();
template!.Should().NotBeNull();
using (new AssertionScope())
{
template!.SelectToken("$.outputs['fooName'].value")!.Should().DeepEqual("foo");
}
}

[TestMethod]
public void Test_Issue1592_special_cases()
{
var (template, diags, _) = CompilationHelper.Compile(
("main.bicep", @"
param someParam string
module foo 'test.bicep' = {
name: '${someParam}-test'
}
output fooName string = foo.name
output fooOutput string = foo.outputs.test
"),
("test.bicep", @"
output test string = 'hello'
"));

diags.Should().BeEmpty();
template!.Should().NotBeNull();
using (new AssertionScope())
{
template!.SelectToken("$.outputs['fooName'].value")!.Should().DeepEqual("[format('{0}-test', parameters('someParam'))]");
template!.SelectToken("$.outputs['fooOutput'].value")!.Should().DeepEqual("[reference(resourceId('Microsoft.Resources/deployments', format('{0}-test', parameters('someParam'))), '2019-10-01').outputs.test.value]");
}
}

[TestMethod]
public void Test_Issue1432()
{
Expand Down
4 changes: 2 additions & 2 deletions src/Bicep.Core.Samples/Files/Loops_LF/main.json
Original file line number Diff line number Diff line change
Expand Up @@ -666,7 +666,7 @@
},
"indexedModulesName": {
"type": "string",
"value": "[reference(resourceId('Microsoft.Resources/deployments', variables('moduleSetup')[parameters('index')]), '2019-10-01').outputs.name]"
"value": "[variables('moduleSetup')[parameters('index')]]"
},
"indexedModuleOutput": {
"type": "string",
Expand Down Expand Up @@ -701,7 +701,7 @@
"_generator": {
"name": "bicep",
"version": "dev",
"templateHash": "29057223099977573"
"templateHash": "15563763134771957148"
}
}
}
16 changes: 8 additions & 8 deletions src/Bicep.Core.Samples/Files/Modules_CRLF/main.json
Original file line number Diff line number Diff line change
Expand Up @@ -41,12 +41,12 @@
{
"type": "Mock.Rp/mockResource",
"apiVersion": "2020-01-01",
"name": "[format('{0}{1}', reference(resourceId('Microsoft.Resources/deployments', 'optionalWithAllParamsAndManualDependency'), '2019-10-01').outputs.name, parameters('deployTimeSuffix'))]",
"name": "[format('{0}{1}', 'optionalWithAllParamsAndManualDependency', parameters('deployTimeSuffix'))]",
"properties": {
"modADep": "[reference(resourceId('Microsoft.Resources/deployments', format('{0}{1}', reference(resourceId('Microsoft.Resources/deployments', 'optionalWithAllParamsAndManualDependency'), '2019-10-01').outputs.name, parameters('deployTimeSuffix'))), '2019-10-01').outputs.outputObj.value]"
"modADep": "[reference(resourceId('Microsoft.Resources/deployments', format('{0}{1}', 'optionalWithAllParamsAndManualDependency', parameters('deployTimeSuffix'))), '2019-10-01').outputs.outputObj.value]"
},
"dependsOn": [
"[resourceId('Microsoft.Resources/deployments', format('{0}{1}', reference(resourceId('Microsoft.Resources/deployments', 'optionalWithAllParamsAndManualDependency'), '2019-10-01').outputs.name, parameters('deployTimeSuffix')))]",
"[resourceId('Microsoft.Resources/deployments', format('{0}{1}', 'optionalWithAllParamsAndManualDependency', parameters('deployTimeSuffix')))]",
"[resourceId('Microsoft.Resources/deployments', 'optionalWithAllParamsAndManualDependency')]"
]
},
Expand Down Expand Up @@ -467,7 +467,7 @@
"mode": "Incremental",
"parameters": {
"optionalString": {
"value": "[concat(resourceId('Mock.Rp/mockResource', 'harry'), reference(resourceId('Microsoft.Resources/deployments', 'optionalWithAllParamsAndManualDependency'), '2019-10-01').outputs.name)]"
"value": "[concat(resourceId('Mock.Rp/mockResource', 'harry'), 'optionalWithAllParamsAndManualDependency')]"
},
"optionalInt": {
"value": 42
Expand Down Expand Up @@ -529,15 +529,15 @@
{
"type": "Microsoft.Resources/deployments",
"apiVersion": "2019-10-01",
"name": "[format('{0}{1}', reference(resourceId('Microsoft.Resources/deployments', 'optionalWithAllParamsAndManualDependency'), '2019-10-01').outputs.name, parameters('deployTimeSuffix'))]",
"name": "[format('{0}{1}', 'optionalWithAllParamsAndManualDependency', parameters('deployTimeSuffix'))]",
"properties": {
"expressionEvaluationOptions": {
"scope": "inner"
},
"mode": "Incremental",
"parameters": {
"optionalString": {
"value": "[concat(resourceId('Mock.Rp/mockResource', 'harry'), reference(resourceId('Microsoft.Resources/deployments', 'optionalWithAllParamsAndManualDependency'), '2019-10-01').outputs.name)]"
"value": "[concat(resourceId('Mock.Rp/mockResource', 'harry'), 'optionalWithAllParamsAndManualDependency')]"
},
"optionalInt": {
"value": 42
Expand Down Expand Up @@ -1287,14 +1287,14 @@
},
"modCalculatedNameOutput": {
"type": "object",
"value": "[reference(resourceId('Microsoft.Resources/deployments', format('{0}{1}', reference(resourceId('Microsoft.Resources/deployments', 'optionalWithAllParamsAndManualDependency'), '2019-10-01').outputs.name, parameters('deployTimeSuffix'))), '2019-10-01').outputs.outputObj.value]"
"value": "[reference(resourceId('Microsoft.Resources/deployments', format('{0}{1}', 'optionalWithAllParamsAndManualDependency', parameters('deployTimeSuffix'))), '2019-10-01').outputs.outputObj.value]"
}
},
"metadata": {
"_generator": {
"name": "bicep",
"version": "dev",
"templateHash": "5916075395955971227"
"templateHash": "16918224688153038135"
}
}
}
44 changes: 39 additions & 5 deletions src/Bicep.Core/Emit/ExpressionConverter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,20 @@ private LanguageExpression ConvertPropertyAccess(PropertyAccessSyntax propertyAc
return null;
}

LanguageExpression? ConvertModulePropertyAccess(ModuleSymbol moduleSymbol, SyntaxBase? indexExpression)
{
switch (propertyAccess.PropertyName.IdentifierName)
{
case "name":
// the name is dependent on the name expression which could involve locals in case of a resource collection
return this
.CreateConverterForIndexReplacement(GetModuleNameSyntax(moduleSymbol), indexExpression, propertyAccess)
.GetModuleNameExpression(moduleSymbol);
}

return null;
}

if ((propertyAccess.BaseExpression is VariableAccessSyntax || propertyAccess.BaseExpression is ResourceAccessSyntax) &&
context.SemanticModel.GetSymbolInfo(propertyAccess.BaseExpression) is ResourceSymbol resourceSymbol &&
ConvertResourcePropertyAccess(resourceSymbol, indexExpression: null) is { } convertedSingle)
Expand All @@ -230,27 +244,47 @@ private LanguageExpression ConvertPropertyAccess(PropertyAccessSyntax propertyAc
return convertedCollection;
}

if (propertyAccess.BaseExpression is VariableAccessSyntax modulePropVariableAccess &&
context.SemanticModel.GetSymbolInfo(modulePropVariableAccess) is ModuleSymbol moduleSymbol &&
ConvertModulePropertyAccess(moduleSymbol, indexExpression: null) is { } moduleConvertedSingle)
{
// we are doing property access on a single module
// and we are dealing with special case properties
return moduleConvertedSingle;
}

if (propertyAccess.BaseExpression is ArrayAccessSyntax modulePropArrayAccess &&
modulePropArrayAccess.BaseExpression is VariableAccessSyntax moduleArrayVariableAccess &&
context.SemanticModel.GetSymbolInfo(moduleArrayVariableAccess) is ModuleSymbol moduleCollectionSymbol &&
ConvertModulePropertyAccess(moduleCollectionSymbol, modulePropArrayAccess.IndexExpression) is { } moduleConvertedCollection)
{

// we are doing property access on an array access of a module collection
// and we are dealing with special case properties
return moduleConvertedCollection;
}

// is this a (<child>.outputs).<prop> propertyAccess?
if (propertyAccess.BaseExpression is PropertyAccessSyntax childPropertyAccess && childPropertyAccess.PropertyName.IdentifierName == LanguageConstants.ModuleOutputsPropertyName)
{
// is <child> a variable which points to a non-collection module symbol?
if (childPropertyAccess.BaseExpression is VariableAccessSyntax grandChildVariableAccess &&
context.SemanticModel.GetSymbolInfo(grandChildVariableAccess) is ModuleSymbol { IsCollection: false } moduleSymbol)
context.SemanticModel.GetSymbolInfo(grandChildVariableAccess) is ModuleSymbol { IsCollection: false } outputsModuleSymbol)
{
return AppendProperties(
this.GetModuleOutputsReferenceExpression(moduleSymbol),
this.GetModuleOutputsReferenceExpression(outputsModuleSymbol),
new JTokenExpression(propertyAccess.PropertyName.IdentifierName),
new JTokenExpression("value"));
}

// is <child> an array access operating on a module collection
if (childPropertyAccess.BaseExpression is ArrayAccessSyntax grandChildArrayAccess &&
grandChildArrayAccess.BaseExpression is VariableAccessSyntax grandGrandChildVariableAccess &&
context.SemanticModel.GetSymbolInfo(grandGrandChildVariableAccess) is ModuleSymbol { IsCollection: true } moduleCollectionSymbol)
context.SemanticModel.GetSymbolInfo(grandGrandChildVariableAccess) is ModuleSymbol { IsCollection: true } outputsModuleCollectionSymbol)
{
var updatedConverter = this.CreateConverterForIndexReplacement(GetModuleNameSyntax(moduleCollectionSymbol), grandChildArrayAccess.IndexExpression, propertyAccess);
var updatedConverter = this.CreateConverterForIndexReplacement(GetModuleNameSyntax(outputsModuleCollectionSymbol), grandChildArrayAccess.IndexExpression, propertyAccess);
return AppendProperties(
updatedConverter.GetModuleOutputsReferenceExpression(moduleCollectionSymbol),
updatedConverter.GetModuleOutputsReferenceExpression(outputsModuleCollectionSymbol),
new JTokenExpression(propertyAccess.PropertyName.IdentifierName),
new JTokenExpression("value"));
}
Expand Down

0 comments on commit 30cb620

Please sign in to comment.