From ad7d66d7bd1a4eccd5652fc5ec5058868b8b6b9e Mon Sep 17 00:00:00 2001 From: Ryan Nowak Date: Fri, 22 Oct 2021 19:09:23 -0700 Subject: [PATCH] Add resource types in outputs and parameters Fixes: #2246 This change implements functionality for declaring strongly type parameters and outputs using resource types. Example: ``` param storage resource 'Microsoft.Storage/storageAccounts@2020-01-01' ``` This declares a parameter that can be interacted with as-if it were an 'existing' resource type declaration of the provided type. In addition you can do the same with outputs: ``` output out resource 'Microsoft.Storage/storageAccounts@2020-01-01' = foo ``` or using type inference (outputs): ``` output out resource = foo ``` These features together allow you to pass resources across module boundaries, and as command line parameters (using the resource ID). --- This PR implements #2246 with a few caveats that I discussed offline with one of the maintainers. 1. It does not include the 'any resource type' that's outlined in the proposal. It's not clear how that part of the proposal will work in the future with extensibility. 2. It does not support extensibility resources currently. To do this we need to define the semantics of how an extensibility resource can be serialized (what's the equivalent of `.id`). This is explicitly blocked in the first cut and can be added as extensibility is designed. 3. Parameter resources cannot be used with the `.parent` or `.scope` properties because it would allow you to bypass scope validation easily. The set of cases that we could actually provide validation for these use cases are really limited. --- docs/grammar.md | 9 +- .../ModuleTests.cs | 84 ++++++++ .../NestedResourceTests.cs | 29 +-- .../OutputsTests.cs | 129 ++++++++++++ .../ParametersTests.cs | 180 +++++++++++++++++ src/Bicep.Core.Samples/DataSets.cs | 7 +- .../Files/AKS_LF/main.syntax.bicep | 20 +- .../Files/Completions/outputTypes.json | 14 ++ .../Files/Completions/paramTypes.json | 14 ++ .../Files/Dependencies_LF/main.syntax.bicep | 8 +- .../InvalidExpressions_LF/main.syntax.bicep | 6 +- .../Files/InvalidModules_LF/main.syntax.bicep | 2 +- .../InvalidOutputs_CRLF/main.syntax.bicep | 92 ++++----- .../Completions/arrayPlusSymbols.json | 70 +++++++ .../Completions/boolPlusSymbols.json | 70 +++++++ .../Completions/justSymbols.json | 70 +++++++ .../Completions/objectPlusSymbols.json | 70 +++++++ .../Files/InvalidParameters_LF/main.bicep | 10 + .../main.diagnostics.bicep | 20 ++ .../InvalidParameters_LF/main.formatted.bicep | 10 + .../InvalidParameters_LF/main.symbols.bicep | 15 ++ .../InvalidParameters_LF/main.syntax.bicep | 189 ++++++++++++------ .../InvalidParameters_LF/main.tokens.bicep | 39 ++++ .../InvalidResources_CRLF/main.syntax.bicep | 10 +- .../Files/LoopsIndexed_LF/main.syntax.bicep | 38 ++-- .../Files/Loops_LF/main.syntax.bicep | 42 ++-- .../ModulesSubscription_LF/main.syntax.bicep | 2 +- .../ModulesWithScopes_LF/main.syntax.bicep | 4 +- .../Files/Modules_CRLF/main.syntax.bicep | 12 +- .../NestedResources_LF/main.syntax.bicep | 12 +- .../Files/Outputs_CRLF/main.syntax.bicep | 36 ++-- .../Files/Parameters_CRLF/main.bicep | 6 + .../Parameters_CRLF/main.diagnostics.bicep | 8 + .../Parameters_CRLF/main.formatted.bicep | 6 + .../Files/Parameters_CRLF/main.json | 15 +- .../Parameters_CRLF/main.symbolicnames.json | 15 +- .../Files/Parameters_CRLF/main.symbols.bicep | 8 + .../Files/Parameters_CRLF/main.syntax.bicep | 107 +++++++--- .../Files/Parameters_CRLF/main.tokens.bicep | 31 ++- .../Files/Parameters_LF/main.bicep | 6 + .../Parameters_LF/main.diagnostics.bicep | 8 + .../Files/Parameters_LF/main.formatted.bicep | 6 + .../Files/Parameters_LF/main.json | 15 +- .../Parameters_LF/main.symbolicnames.json | 15 +- .../Files/Parameters_LF/main.symbols.bicep | 8 + .../Files/Parameters_LF/main.syntax.bicep | 107 +++++++--- .../Files/Parameters_LF/main.tokens.bicep | 31 ++- .../Files/Registry_LF/main.syntax.bicep | 2 +- .../main.syntax.bicep | 6 +- .../main.syntax.bicep | 6 +- .../ResourcesTenant_CRLF/main.syntax.bicep | 2 +- .../Files/Resources_CRLF/main.syntax.bicep | 48 ++--- .../Files/Unicode_LF/main.syntax.bicep | 4 +- .../Files/Variables_LF/main.syntax.bicep | 6 +- .../Linter/Rules/UseStableVMImageRule.cs | 2 +- .../Diagnostics/DiagnosticBuilder.cs | 29 ++- .../Emit/EmitLimitationCalculator.cs | 12 +- src/Bicep.Core/Emit/EmitLimitationInfo.cs | 4 +- src/Bicep.Core/Emit/EmitterContext.cs | 2 +- src/Bicep.Core/Emit/ExpressionConverter.cs | 98 +++++++-- src/Bicep.Core/Emit/ExpressionEmitter.cs | 13 +- .../Emit/ResourceDependencyVisitor.cs | 5 +- src/Bicep.Core/Emit/ScopeHelper.cs | 40 +++- src/Bicep.Core/Emit/TemplateWriter.cs | 96 +++++++-- src/Bicep.Core/LanguageConstants.cs | 1 + src/Bicep.Core/Parsing/Parser.cs | 31 ++- .../Semantics/ArmTemplateSemanticModel.cs | 29 ++- .../Metadata/DeclaredResourceMetadata.cs | 19 ++ .../Metadata/ParameterResourceMetadata.cs | 17 ++ .../Semantics/Metadata/ResourceMetadata.cs | 6 +- .../Metadata/ResourceMetadataCache.cs | 30 ++- .../Semantics/ResourceAncestorGraph.cs | 17 +- .../Semantics/ResourceAncestorVisitor.cs | 19 +- src/Bicep.Core/Semantics/SemanticModel.cs | 20 +- src/Bicep.Core/Syntax/ISyntaxVisitor.cs | 4 +- .../Syntax/OutputDeclarationSyntax.cs | 17 +- .../Syntax/ParameterDeclarationSyntax.cs | 22 +- src/Bicep.Core/Syntax/ResourceTypeSyntax.cs | 31 +++ src/Bicep.Core/Syntax/SimpleTypeSyntax.cs | 28 +++ src/Bicep.Core/Syntax/SyntaxHelper.cs | 2 +- src/Bicep.Core/Syntax/SyntaxRewriteVisitor.cs | 20 +- src/Bicep.Core/Syntax/SyntaxVisitor.cs | 8 +- src/Bicep.Core/Syntax/TypeSyntax.cs | 21 +- .../TypeSystem/DeclaredTypeManager.cs | 113 ++++++++++- .../TypeSystem/ResourceParameterType.cs | 20 ++ .../TypeSystem/TypeAssignmentVisitor.cs | 16 +- src/Bicep.Core/TypeSystem/TypeValidator.cs | 4 + .../ParentChildResourceNameRewriter.cs | 7 +- src/Bicep.Decompiler/TemplateConverter.cs | 11 +- .../BicepCompletionProviderTests.cs | 17 +- .../Completions/BicepCompletionContext.cs | 36 +++- .../Completions/BicepCompletionProvider.cs | 39 +++- src/Bicep.LangServer/SemanticTokenVisitor.cs | 10 +- .../LanguageHelpers/SemanticTokenVisitor.cs | 12 +- 94 files changed, 2165 insertions(+), 542 deletions(-) create mode 100644 src/Bicep.Core.IntegrationTests/OutputsTests.cs create mode 100644 src/Bicep.Core.IntegrationTests/ParametersTests.cs create mode 100644 src/Bicep.Core/Semantics/Metadata/DeclaredResourceMetadata.cs create mode 100644 src/Bicep.Core/Semantics/Metadata/ParameterResourceMetadata.cs create mode 100644 src/Bicep.Core/Syntax/ResourceTypeSyntax.cs create mode 100644 src/Bicep.Core/Syntax/SimpleTypeSyntax.cs create mode 100644 src/Bicep.Core/TypeSystem/ResourceParameterType.cs diff --git a/docs/grammar.md b/docs/grammar.md index 0a666c3018a..c546c21ac8d 100644 --- a/docs/grammar.md +++ b/docs/grammar.md @@ -16,7 +16,9 @@ targetScopeDecl -> "targetScope" "=" expression importDecl -> decorator* "import" IDENTIFIER(aliasName) "from" IDENTIFIER(providerName) object? NL -parameterDecl -> decorator* "parameter" IDENTIFIER(name) IDENTIFIER(type) parameterDefaultValue? NL +parameterDecl -> + decorator* "parameter" IDENTIFIER(name) IDENTIFIER(type) parameterDefaultValue? NL | + decorator* "parameter" IDENTIFIER(name) "resource" interpString(type) parameterDefaultValue? NL | parameterDefaultValue -> "=" expression variableDecl -> decorator* "variable" IDENTIFIER(name) "=" expression NL @@ -25,8 +27,9 @@ resourceDecl -> decorator* "resource" IDENTIFIER(name) interpString(type) "exist moduleDecl -> decorator* "module" IDENTIFIER(name) interpString(type) "=" (ifCondition | object | forExpression) NL -outputDecl -> decorator* "output" IDENTIFIER(name) IDENTIFIER(type) "=" expression NL - +outputDecl -> + decorator* "output" IDENTIFIER(name) IDENTIFIER(type) "=" expression NL + decorator* "output" IDENTIFIER(name) "resource" interpString(type) "=" expression NL NL -> ("\n" | "\r")+ decorator -> "@" decoratorExpression NL diff --git a/src/Bicep.Core.IntegrationTests/ModuleTests.cs b/src/Bicep.Core.IntegrationTests/ModuleTests.cs index c61697434ec..78365881f0e 100644 --- a/src/Bicep.Core.IntegrationTests/ModuleTests.cs +++ b/src/Bicep.Core.IntegrationTests/ModuleTests.cs @@ -407,6 +407,90 @@ public void External_module_reference_with_oci_scheme_should_be_rejected_if_regi }); } + [TestMethod] + public void Module_can_pass_correct_resource_type_as_parameter() + { + var result = CompilationHelper.Compile( +("main.bicep", @" +resource resource 'Microsoft.Storage/storageAccounts@2019-06-01' existing = { + name: 'test' +} + +module mod './module.bicep' = { + name: 'test' + params: { + p: resource + } +} + +"), +("module.bicep", @" +param p resource 'Microsoft.Storage/storageAccounts@2019-06-01' +output out string = p.properties.accessTier + +")); + result.Should().NotHaveAnyDiagnostics(); + + var model = result.Compilation.GetEntrypointSemanticModel(); + result.Template.Should().HaveValueAtPath("$.resources[0].properties.parameters.p.value", "[resourceId('Microsoft.Storage/storageAccounts', 'test')]"); + } + + [TestMethod] + public void Module_can_pass_correct_resource_type_with_different_api_version_as_parameter() + { + var result = CompilationHelper.Compile( +("main.bicep", @" +resource resource 'Microsoft.Storage/storageAccounts@2019-06-01' existing = { + name: 'test' +} + +module mod './module.bicep' = { + name: 'test' + params: { + p: resource + } +} + +"), +("module.bicep", @" +param p resource 'Microsoft.Storage/storageAccounts@2021-04-01' +output out string = p.properties.accessTier + +")); + result.Should().NotHaveAnyDiagnostics(); + + var model = result.Compilation.GetEntrypointSemanticModel(); + result.Template.Should().HaveValueAtPath("$.resources[0].properties.parameters.p.value", "[resourceId('Microsoft.Storage/storageAccounts', 'test')]"); + } + + [TestMethod] + public void Module_cannot_pass_incorrect_resource_type_as_parameter() + { + var result = CompilationHelper.Compile( +("main.bicep", @" +resource resource 'Microsoft.Storage/storageAccounts@2019-06-01' existing = { + name: 'test' +} + +module mod './module.bicep' = { + name: 'test' + params: { + p: resource + } +} + +"), +("module.bicep", @" +param p resource 'Microsoft.Sql/servers@2021-02-01-preview' +output out string = p.properties.minimalTlsVersion + +")); + result.Should().HaveDiagnostics(new [] + { + ("BCP036", DiagnosticLevel.Error, "The property \"p\" expected a value of type \"Microsoft.Sql/servers\" but the provided value is of type \"Microsoft.Storage/storageAccounts@2019-06-01\"."), + }); + } + private static string GetTemplate(Compilation compilation) { var stringBuilder = new StringBuilder(); diff --git a/src/Bicep.Core.IntegrationTests/NestedResourceTests.cs b/src/Bicep.Core.IntegrationTests/NestedResourceTests.cs index 82cab763f5d..67d5405742d 100644 --- a/src/Bicep.Core.IntegrationTests/NestedResourceTests.cs +++ b/src/Bicep.Core.IntegrationTests/NestedResourceTests.cs @@ -9,6 +9,7 @@ using Bicep.Core.Emit; using Bicep.Core.FileSystem; using Bicep.Core.Semantics; +using Bicep.Core.Semantics.Metadata; using Bicep.Core.TypeSystem; using Bicep.Core.UnitTests; using Bicep.Core.UnitTests.Assertions; @@ -65,7 +66,7 @@ public void NestedResources_symbols_are_bound() new { name = "sibling", type = "My.RP/parentType/childType@2020-01-02", }, }; - model.AllResources.Select(x => x.Symbol) + model.AllResources.OfType().Select(x => x.Symbol) .Select(s => new { name = s.Name, type = (s.Type as ResourceType)?.TypeReference.FormatName(), }) .OrderBy(n => n.name) .Should().BeEquivalentTo(expected); @@ -104,7 +105,7 @@ public void NestedResources_resource_can_contain_property_called_resource() new { name = "parent", type = "My.RP/parentType@2020-01-01", }, }; - model.AllResources.Select(x => x.Symbol) + model.AllResources.OfType().Select(x => x.Symbol) .Select(s => new { name = s.Name, type = (s.Type as ResourceType)?.TypeReference.FormatName(), }) .OrderBy(n => n.name) .Should().BeEquivalentTo(expected); @@ -154,19 +155,19 @@ public void NestedResources_valid_resource_references() model.GetAllDiagnostics().ExcludingMissingTypes().Should().BeEmpty(); - var parent = model.AllResources.Select(x => x.Symbol).Single(r => r.Name == "parent"); + var parent = model.AllResources.OfType().Select(x => x.Symbol).Single(r => r.Name == "parent"); var references = model.FindReferences(parent); references.Should().HaveCount(6); - var child = model.AllResources.Select(x => x.Symbol).Single(r => r.Name == "child"); + var child = model.AllResources.OfType().Select(x => x.Symbol).Single(r => r.Name == "child"); references = model.FindReferences(child); references.Should().HaveCount(6); - var grandchild = model.AllResources.Select(x => x.Symbol).Single(r => r.Name == "grandchild"); + var grandchild = model.AllResources.OfType().Select(x => x.Symbol).Single(r => r.Name == "grandchild"); references = model.FindReferences(grandchild); references.Should().HaveCount(4); - var sibling = model.AllResources.Select(x => x.Symbol).Single(r => r.Name == "sibling"); + var sibling = model.AllResources.OfType().Select(x => x.Symbol).Single(r => r.Name == "sibling"); references = model.FindReferences(sibling); references.Should().HaveCount(1); @@ -417,13 +418,13 @@ public void NestedResources_ancestors_are_detected() var model = compilation.GetEntrypointSemanticModel(); model.GetAllDiagnostics().ExcludingMissingTypes().Should().BeEmpty(); - var parent = model.ResourceMetadata.TryLookup(model.AllResources.Select(x => x.Symbol).Single(r => r.Name == "parent").DeclaringSyntax)!; + var parent = (DeclaredResourceMetadata)model.ResourceMetadata.TryLookup(model.AllResources.OfType().Select(x => x.Symbol).Single(r => r.Name == "parent").DeclaringSyntax)!; model.ResourceAncestors.GetAncestors(parent).Should().BeEmpty(); - var child = model.ResourceMetadata.TryLookup(model.AllResources.Select(x => x.Symbol).Single(r => r.Name == "child").DeclaringSyntax)!; + var child = (DeclaredResourceMetadata)model.ResourceMetadata.TryLookup(model.AllResources.OfType().Select(x => x.Symbol).Single(r => r.Name == "child").DeclaringSyntax)!; model.ResourceAncestors.GetAncestors(child).Select(x => x.Resource).Should().Equal(new[] { parent, }); - var grandchild = model.ResourceMetadata.TryLookup(model.AllResources.Select(x => x.Symbol).Single(r => r.Name == "grandchild").DeclaringSyntax)!; + var grandchild = (DeclaredResourceMetadata)model.ResourceMetadata.TryLookup(model.AllResources.OfType().Select(x => x.Symbol).Single(r => r.Name == "grandchild").DeclaringSyntax)!; model.ResourceAncestors.GetAncestors(grandchild).Select(x => x.Resource).Should().Equal(new[] { parent, child, }); // order matters } @@ -466,19 +467,19 @@ public void NestedResources_scopes_isolate_names() var model = compilation.GetEntrypointSemanticModel(); model.GetAllDiagnostics().ExcludingMissingTypes().Should().BeEmpty(); - var parent = model.ResourceMetadata.TryLookup(model.AllResources.Select(x => x.Symbol).Single(r => r.Name == "parent").DeclaringSyntax)!; + var parent = (DeclaredResourceMetadata)model.ResourceMetadata.TryLookup(model.AllResources.OfType().Select(x => x.Symbol).Single(r => r.Name == "parent").DeclaringSyntax)!; model.ResourceAncestors.GetAncestors(parent).Should().BeEmpty(); - var child = model.ResourceMetadata.TryLookup(model.AllResources.Select(x => x.Symbol).Single(r => r.Name == "child").DeclaringSyntax)!; + var child = (DeclaredResourceMetadata)model.ResourceMetadata.TryLookup(model.AllResources.OfType().Select(x => x.Symbol).Single(r => r.Name == "child").DeclaringSyntax)!; model.ResourceAncestors.GetAncestors(child).Select(x => x.Resource).Should().Equal(new[] { parent, }); - var childGrandChild = model.ResourceMetadata.TryLookup(child.Symbol.DeclaringResource.GetBody().Resources.Single())!; + var childGrandChild = (DeclaredResourceMetadata)model.ResourceMetadata.TryLookup(child.Symbol.DeclaringResource.GetBody().Resources.Single())!; model.ResourceAncestors.GetAncestors(childGrandChild).Select(x => x.Resource).Should().Equal(new[] { parent, child, }); - var sibling = model.ResourceMetadata.TryLookup(model.AllResources.Select(x => x.Symbol).Single(r => r.Name == "sibling").DeclaringSyntax)!; + var sibling = (DeclaredResourceMetadata)model.ResourceMetadata.TryLookup(model.AllResources.OfType().Select(x => x.Symbol).Single(r => r.Name == "sibling").DeclaringSyntax)!; model.ResourceAncestors.GetAncestors(child).Select(x => x.Resource).Should().Equal(new[] { parent, }); - var siblingGrandChild = model.ResourceMetadata.TryLookup(sibling.Symbol.DeclaringResource.GetBody().Resources.Single())!; + var siblingGrandChild = (DeclaredResourceMetadata)model.ResourceMetadata.TryLookup(sibling.Symbol.DeclaringResource.GetBody().Resources.Single())!; model.ResourceAncestors.GetAncestors(siblingGrandChild).Select(x => x.Resource).Should().Equal(new[] { parent, sibling, }); } diff --git a/src/Bicep.Core.IntegrationTests/OutputsTests.cs b/src/Bicep.Core.IntegrationTests/OutputsTests.cs new file mode 100644 index 00000000000..3e4fdead0c9 --- /dev/null +++ b/src/Bicep.Core.IntegrationTests/OutputsTests.cs @@ -0,0 +1,129 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. +using System.Diagnostics.CodeAnalysis; +using Bicep.Core.Diagnostics; +using Bicep.Core.IntegrationTests.Extensibility; +using Bicep.Core.TypeSystem; +using Bicep.Core.UnitTests; +using Bicep.Core.UnitTests.Assertions; +using Bicep.Core.UnitTests.Utils; +using FluentAssertions; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Newtonsoft.Json.Linq; + +namespace Bicep.Core.IntegrationTests +{ + [TestClass] + public class OutputsTests + { + [NotNull] + public TestContext? TestContext { get; set; } + + private CompilationHelper.CompilationHelperContext GetExtensibilityCompilationContext() + { + var features = BicepTestConstants.CreateFeaturesProvider(TestContext, importsEnabled: true); + var resourceTypeLoader = BicepTestConstants.AzResourceTypeLoader; + var namespaceProvider = new ExtensibilityNamespaceProvider(resourceTypeLoader, features); + + return new( + AzResourceTypeLoader: resourceTypeLoader, + Features: features, + NamespaceProvider: namespaceProvider); + } + + [TestMethod] + public void Output_can_have_inferred_resource_type() + { + var result = CompilationHelper.Compile(@" +resource resource 'Microsoft.Storage/storageAccounts@2019-06-01' = { + name: 'test' + location: 'eastus' + kind: 'StorageV2' + sku: { + name: 'Standard_LRS' + } + identity: { + type: 'SystemAssigned' + } + properties:{ + accessTier: 'Cool' + } +} +output out resource = resource +"); + result.Should().NotHaveAnyDiagnostics(); + + var model = result.Compilation.GetEntrypointSemanticModel(); + var @out = model.Root.OutputDeclarations.Should().ContainSingle().Subject; + var typeInfo = model.GetTypeInfo(@out.DeclaringSyntax); + typeInfo.Should().BeOfType().Which.TypeReference.FormatName().Should().BeEquivalentTo("Microsoft.Storage/storageAccounts@2019-06-01"); + + result.Template.Should().HaveValueAtPath("$.outputs.out", new JObject() + { + ["type"] = "string", + ["value"] = "[resourceId('Microsoft.Storage/storageAccounts', 'test')]", + ["metadata"] = new JObject() + { + ["resourceType"] = new JValue("Microsoft.Storage/storageAccounts@2019-06-01"), + }, + }); + } + + [TestMethod] + public void Output_can_have_specified_resource_type() + { + var result = CompilationHelper.Compile(@" +resource resource 'Microsoft.Storage/storageAccounts@2019-06-01' = { + name: 'test' + location: 'eastus' + kind: 'StorageV2' + sku: { + name: 'Standard_LRS' + } + identity: { + type: 'SystemAssigned' + } + properties:{ + accessTier: 'Cool' + } +} +output out resource 'Microsoft.Storage/storageAccounts@2019-06-01' = resource +"); + result.Should().NotHaveAnyDiagnostics(); + + var model = result.Compilation.GetEntrypointSemanticModel(); + var @out = model.Root.OutputDeclarations.Should().ContainSingle().Subject; + var typeInfo = model.GetTypeInfo(@out.DeclaringSyntax); + typeInfo.Should().BeOfType().Which.TypeReference.FormatName().Should().BeEquivalentTo("Microsoft.Storage/storageAccounts@2019-06-01"); + + result.Template.Should().HaveValueAtPath("$.outputs.out", new JObject() + { + ["type"] = "string", + ["value"] = "[resourceId('Microsoft.Storage/storageAccounts', 'test')]", + ["metadata"] = new JObject() + { + ["resourceType"] = new JValue("Microsoft.Storage/storageAccounts@2019-06-01"), + }, + }); + } + + [TestMethod] + public void Output_cannot_use_extensibility_resource_type() + { + var result = CompilationHelper.Compile(GetExtensibilityCompilationContext(), @" +import stg from storage { + connectionString: 'asdf' +} + +resource container 'AzureStorage/containers@2020-01-01' = { + name: 'myblob' +} +output out resource = container +"); + result.Should().HaveDiagnostics(new [] + { + ("BCP225", DiagnosticLevel.Error, "The type \"AzureStorage/containers@2020-01-01\" cannot be used as an output type."), + }); + } + } +} diff --git a/src/Bicep.Core.IntegrationTests/ParametersTests.cs b/src/Bicep.Core.IntegrationTests/ParametersTests.cs new file mode 100644 index 00000000000..acabbefb37e --- /dev/null +++ b/src/Bicep.Core.IntegrationTests/ParametersTests.cs @@ -0,0 +1,180 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. +using System.Diagnostics.CodeAnalysis; +using System.Linq; +using Bicep.Core.Diagnostics; +using Bicep.Core.IntegrationTests.Extensibility; +using Bicep.Core.Syntax; +using Bicep.Core.TypeSystem; +using Bicep.Core.UnitTests; +using Bicep.Core.UnitTests.Assertions; +using Bicep.Core.UnitTests.Utils; +using FluentAssertions; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Newtonsoft.Json.Linq; + +namespace Bicep.Core.IntegrationTests +{ + [TestClass] + public class ParameterTests + { + [NotNull] + public TestContext? TestContext { get; set; } + + private CompilationHelper.CompilationHelperContext GetExtensibilityCompilationContext() + { + var features = BicepTestConstants.CreateFeaturesProvider(TestContext, importsEnabled: true); + var resourceTypeLoader = BicepTestConstants.AzResourceTypeLoader; + var namespaceProvider = new ExtensibilityNamespaceProvider(resourceTypeLoader, features); + + return new( + AzResourceTypeLoader: resourceTypeLoader, + Features: features, + NamespaceProvider: namespaceProvider); + } + + [TestMethod] + public void Parameter_can_have_resource_type() + { + var result = CompilationHelper.Compile(@" +param p resource 'Microsoft.Storage/storageAccounts@2019-06-01' + +resource resource 'Microsoft.Storage/storageAccounts@2019-06-01' = { + name: 'test' + location: 'eastus' + kind: 'StorageV2' + sku: { + name: 'Standard_LRS' + } + identity: { + type: 'SystemAssigned' + } + properties:{ + accessTier: p.properties.accessTier + } +} +"); + result.Should().NotHaveAnyDiagnostics(); + + var model = result.Compilation.GetEntrypointSemanticModel(); + var parameterSymbol = model.Root.ParameterDeclarations.Should().ContainSingle().Subject; + var typeInfo = model.GetTypeInfo(parameterSymbol.DeclaringSyntax); + typeInfo.Should().BeOfType().Which.TypeReference.FormatName().Should().BeEquivalentTo("Microsoft.Storage/storageAccounts@2019-06-01"); + + var reference = model.FindReferences(parameterSymbol).OfType().Should().ContainSingle().Subject; + model.GetDeclaredType(reference).Should().NotBeNull(); + model.GetTypeInfo(reference).Should().NotBeNull(); + + result.Template.Should().HaveValueAtPath("$.resources[0].properties.accessTier", "[reference(parameters('p'), '2019-06-01').accessTier]"); + result.Template.Should().HaveValueAtPath("$.parameters.p", new JObject() + { + ["type"] = new JValue("string"), + ["metadata"] = new JObject() + { + ["resourceType"] = new JValue("Microsoft.Storage/storageAccounts@2019-06-01"), + }, + }); + } + + [TestMethod] + public void Parameter_with_resource_type_can_have_properties_evaluated() + { + var result = CompilationHelper.Compile(@" +param p resource 'Microsoft.Storage/storageAccounts@2019-06-01' + +output id string = p.id +output name string = p.name +output type string = p.type +output apiVersion string = p.apiVersion +output accessTier string = p.properties.accessTier +"); + result.Should().NotHaveAnyDiagnostics(); + + result.Template.Should().HaveValueAtPath("$.outputs.id", new JObject() + { + ["type"] = new JValue("string"), + ["value"] = new JValue("[parameters('p')]"), + }); + result.Template.Should().HaveValueAtPath("$.outputs.name", new JObject() + { + ["type"] = new JValue("string"), + ["value"] = new JValue("[reference(parameters('p'), '2019-06-01', 'full').name]"), + }); + result.Template.Should().HaveValueAtPath("$.outputs.type", new JObject() + { + ["type"] = new JValue("string"), + ["value"] = new JValue("Microsoft.Storage/storageAccounts"), + }); + result.Template.Should().HaveValueAtPath("$.outputs.apiVersion", new JObject() + { + ["type"] = new JValue("string"), + ["value"] = new JValue("2019-06-01"), + }); + result.Template.Should().HaveValueAtPath("$.outputs.accessTier", new JObject() + { + ["type"] = new JValue("string"), + ["value"] = new JValue("[reference(parameters('p'), '2019-06-01').accessTier]"), + }); + } + + [TestMethod] + public void Parameter_cannot_use_extensibility_resource_type() + { + var result = CompilationHelper.Compile(GetExtensibilityCompilationContext(), @" +import stg from storage { + connectionString: 'asdf' +} + +param container resource 'AzureStorage/containers@2020-01-01' +output name string = container.name // silence unused params warning +"); + result.Should().HaveDiagnostics(new [] + { + ("BCP224", DiagnosticLevel.Error, "The type \"AzureStorage/containers@2020-01-01\" cannot be used as a parameter type."), + ("BCP062", DiagnosticLevel.Error, "The referenced declaration with name \"container\" is not valid."), + }); + } + + [TestMethod] + public void Parameter_with_resource_type_cannot_be_used_as_extension_scope() + { + var result = CompilationHelper.Compile(@" +param p resource 'Microsoft.Storage/storageAccounts@2019-06-01' + +resource resource 'My.Rp/myResource@2020-01-01' = { + scope: p + name: 'resource' +}"); + + result.Should().HaveDiagnostics(new [] + { + ("BCP081", DiagnosticLevel.Warning, "Resource type \"My.Rp/myResource@2020-01-01\" does not have types available."), + ("BCP226", DiagnosticLevel.Error, "The parameter \"p\" cannot be used as a resource scope or parent. Resources passed as parameters cannot be used as a scope or parent of a resource."), + }); + } + + [TestMethod] + public void Parameter_with_resource_type_cannot_be_used_as_parent() + { + var result = CompilationHelper.Compile(@" +param p resource 'Microsoft.Storage/storageAccounts@2019-06-01' + +resource resource 'Microsoft.Storage/storageAccounts/tableServices@2020-06-01' = { + parent: p + name: 'child1' + properties: { + cors: { + corsRules: [] + } + } +}"); + + result.Should().HaveDiagnostics(new [] + { + ("BCP081", DiagnosticLevel.Warning, "Resource type \"Microsoft.Storage/storageAccounts/tableServices@2020-06-01\" does not have types available."), + ("BCP226", DiagnosticLevel.Error, "The parameter \"p\" cannot be used as a resource scope or parent. Resources passed as parameters cannot be used as a scope or parent of a resource."), + ("BCP169", DiagnosticLevel.Error, "Expected resource name to contain 1 \"/\" character(s). The number of name segments must match the number of segments in the resource type."), + }); + } + } +} diff --git a/src/Bicep.Core.Samples/DataSets.cs b/src/Bicep.Core.Samples/DataSets.cs index 426032422b4..791b61440f7 100644 --- a/src/Bicep.Core.Samples/DataSets.cs +++ b/src/Bicep.Core.Samples/DataSets.cs @@ -11,9 +11,9 @@ namespace Bicep.Core.Samples { public static class DataSets { - public static DataSet AKS_LF => CreateDataSet(); + public static DataSet AKS_LF => CreateDataSet(); - public static DataSet Dependencies_LF => CreateDataSet(); + public static DataSet Dependencies_LF => CreateDataSet(); public static DataSet Empty => CreateDataSet(); @@ -100,7 +100,8 @@ public static class DataSets public static ImmutableDictionary Functions => DataSet.ReadDataSetDictionary($"{DataSet.Prefix}{DataSet.TestFunctionsPrefix}"); - private static DataSet CreateDataSet([CallerMemberName] string? dataSetName = null) => new DataSet(dataSetName!); + private static readonly System.Collections.Concurrent.ConcurrentDictionary cache = new(); + private static DataSet CreateDataSet([CallerMemberName] string? dataSetName = null) => cache.GetOrAdd(dataSetName!, dataSetName => new DataSet(dataSetName)); } } diff --git a/src/Bicep.Core.Samples/Files/AKS_LF/main.syntax.bicep b/src/Bicep.Core.Samples/Files/AKS_LF/main.syntax.bicep index 3eaf5f8ed5a..c642c7af145 100644 --- a/src/Bicep.Core.Samples/Files/AKS_LF/main.syntax.bicep +++ b/src/Bicep.Core.Samples/Files/AKS_LF/main.syntax.bicep @@ -5,7 +5,7 @@ param dnsPrefix string //@[0:5) Identifier |param| //@[6:15) IdentifierSyntax //@[6:15) Identifier |dnsPrefix| -//@[16:22) TypeSyntax +//@[16:22) SimpleTypeSyntax //@[16:22) Identifier |string| //@[22:23) NewLine |\n| param linuxAdminUsername string @@ -13,7 +13,7 @@ param linuxAdminUsername string //@[0:5) Identifier |param| //@[6:24) IdentifierSyntax //@[6:24) Identifier |linuxAdminUsername| -//@[25:31) TypeSyntax +//@[25:31) SimpleTypeSyntax //@[25:31) Identifier |string| //@[31:32) NewLine |\n| param sshRSAPublicKey string @@ -21,7 +21,7 @@ param sshRSAPublicKey string //@[0:5) Identifier |param| //@[6:21) IdentifierSyntax //@[6:21) Identifier |sshRSAPublicKey| -//@[22:28) TypeSyntax +//@[22:28) SimpleTypeSyntax //@[22:28) Identifier |string| //@[28:30) NewLine |\n\n| @@ -39,7 +39,7 @@ param servcePrincipalClientId string //@[0:5) Identifier |param| //@[6:29) IdentifierSyntax //@[6:29) Identifier |servcePrincipalClientId| -//@[30:36) TypeSyntax +//@[30:36) SimpleTypeSyntax //@[30:36) Identifier |string| //@[36:38) NewLine |\n\n| @@ -57,7 +57,7 @@ param servicePrincipalClientSecret string //@[0:5) Identifier |param| //@[6:34) IdentifierSyntax //@[6:34) Identifier |servicePrincipalClientSecret| -//@[35:41) TypeSyntax +//@[35:41) SimpleTypeSyntax //@[35:41) Identifier |string| //@[41:43) NewLine |\n\n| @@ -68,7 +68,7 @@ param clusterName string = 'aks101cluster' //@[0:5) Identifier |param| //@[6:17) IdentifierSyntax //@[6:17) Identifier |clusterName| -//@[18:24) TypeSyntax +//@[18:24) SimpleTypeSyntax //@[18:24) Identifier |string| //@[25:42) ParameterDefaultValueSyntax //@[25:26) Assignment |=| @@ -80,7 +80,7 @@ param location string = resourceGroup().location //@[0:5) Identifier |param| //@[6:14) IdentifierSyntax //@[6:14) Identifier |location| -//@[15:21) TypeSyntax +//@[15:21) SimpleTypeSyntax //@[15:21) Identifier |string| //@[22:48) ParameterDefaultValueSyntax //@[22:23) Assignment |=| @@ -124,7 +124,7 @@ param osDiskSizeGB int = 0 //@[0:5) Identifier |param| //@[6:18) IdentifierSyntax //@[6:18) Identifier |osDiskSizeGB| -//@[19:22) TypeSyntax +//@[19:22) SimpleTypeSyntax //@[19:22) Identifier |int| //@[23:26) ParameterDefaultValueSyntax //@[23:24) Assignment |=| @@ -161,7 +161,7 @@ param agentCount int = 3 //@[0:5) Identifier |param| //@[6:16) IdentifierSyntax //@[6:16) Identifier |agentCount| -//@[17:20) TypeSyntax +//@[17:20) SimpleTypeSyntax //@[17:20) Identifier |int| //@[21:24) ParameterDefaultValueSyntax //@[21:22) Assignment |=| @@ -174,7 +174,7 @@ param agentVMSize string = 'Standard_DS2_v2' //@[0:5) Identifier |param| //@[6:17) IdentifierSyntax //@[6:17) Identifier |agentVMSize| -//@[18:24) TypeSyntax +//@[18:24) SimpleTypeSyntax //@[18:24) Identifier |string| //@[25:44) ParameterDefaultValueSyntax //@[25:26) Assignment |=| diff --git a/src/Bicep.Core.Samples/Files/Completions/outputTypes.json b/src/Bicep.Core.Samples/Files/Completions/outputTypes.json index 85644481142..764012d92ed 100644 --- a/src/Bicep.Core.Samples/Files/Completions/outputTypes.json +++ b/src/Bicep.Core.Samples/Files/Completions/outputTypes.json @@ -55,6 +55,20 @@ "newText": "object" } }, + { + "label": "resource", + "kind": "class", + "detail": "resource", + "deprecated": false, + "preselect": false, + "sortText": "2_resource", + "insertTextFormat": "plainText", + "insertTextMode": "adjustIndentation", + "textEdit": { + "range": {}, + "newText": "resource" + } + }, { "label": "string", "kind": "class", diff --git a/src/Bicep.Core.Samples/Files/Completions/paramTypes.json b/src/Bicep.Core.Samples/Files/Completions/paramTypes.json index f38419bb44d..9065d867ad6 100644 --- a/src/Bicep.Core.Samples/Files/Completions/paramTypes.json +++ b/src/Bicep.Core.Samples/Files/Completions/paramTypes.json @@ -55,6 +55,20 @@ "newText": "object" } }, + { + "label": "resource", + "kind": "class", + "detail": "resource", + "deprecated": false, + "preselect": false, + "sortText": "2_resource", + "insertTextFormat": "plainText", + "insertTextMode": "adjustIndentation", + "textEdit": { + "range": {}, + "newText": "resource" + } + }, { "label": "secureObject", "kind": "snippet", diff --git a/src/Bicep.Core.Samples/Files/Dependencies_LF/main.syntax.bicep b/src/Bicep.Core.Samples/Files/Dependencies_LF/main.syntax.bicep index 08616aa04c6..db1b510cf7b 100644 --- a/src/Bicep.Core.Samples/Files/Dependencies_LF/main.syntax.bicep +++ b/src/Bicep.Core.Samples/Files/Dependencies_LF/main.syntax.bicep @@ -3,7 +3,7 @@ param deployTimeParam string = 'steve' //@[0:5) Identifier |param| //@[6:21) IdentifierSyntax //@[6:21) Identifier |deployTimeParam| -//@[22:28) TypeSyntax +//@[22:28) SimpleTypeSyntax //@[22:28) Identifier |string| //@[29:38) ParameterDefaultValueSyntax //@[29:30) Assignment |=| @@ -142,7 +142,7 @@ output resourceAType string = resA.type //@[0:6) Identifier |output| //@[7:20) IdentifierSyntax //@[7:20) Identifier |resourceAType| -//@[21:27) TypeSyntax +//@[21:27) SimpleTypeSyntax //@[21:27) Identifier |string| //@[28:29) Assignment |=| //@[30:39) PropertyAccessSyntax @@ -209,7 +209,7 @@ output resourceBId string = resB.id //@[0:6) Identifier |output| //@[7:18) IdentifierSyntax //@[7:18) Identifier |resourceBId| -//@[19:25) TypeSyntax +//@[19:25) SimpleTypeSyntax //@[19:25) Identifier |string| //@[26:27) Assignment |=| //@[28:35) PropertyAccessSyntax @@ -439,7 +439,7 @@ output resourceCProperties object = resC.properties //@[0:6) Identifier |output| //@[7:26) IdentifierSyntax //@[7:26) Identifier |resourceCProperties| -//@[27:33) TypeSyntax +//@[27:33) SimpleTypeSyntax //@[27:33) Identifier |object| //@[34:35) Assignment |=| //@[36:51) PropertyAccessSyntax diff --git a/src/Bicep.Core.Samples/Files/InvalidExpressions_LF/main.syntax.bicep b/src/Bicep.Core.Samples/Files/InvalidExpressions_LF/main.syntax.bicep index 436dd341665..783b560463f 100644 --- a/src/Bicep.Core.Samples/Files/InvalidExpressions_LF/main.syntax.bicep +++ b/src/Bicep.Core.Samples/Files/InvalidExpressions_LF/main.syntax.bicep @@ -1130,7 +1130,7 @@ param funcvarparam bool = concat //@[0:5) Identifier |param| //@[6:18) IdentifierSyntax //@[6:18) Identifier |funcvarparam| -//@[19:23) TypeSyntax +//@[19:23) SimpleTypeSyntax //@[19:23) Identifier |bool| //@[24:32) ParameterDefaultValueSyntax //@[24:25) Assignment |=| @@ -1143,7 +1143,7 @@ output funcvarout array = padLeft //@[0:6) Identifier |output| //@[7:17) IdentifierSyntax //@[7:17) Identifier |funcvarout| -//@[18:23) TypeSyntax +//@[18:23) SimpleTypeSyntax //@[18:23) Identifier |array| //@[24:25) Assignment |=| //@[26:33) VariableAccessSyntax @@ -1184,7 +1184,7 @@ param fakeFuncP string = blue() //@[0:5) Identifier |param| //@[6:15) IdentifierSyntax //@[6:15) Identifier |fakeFuncP| -//@[16:22) TypeSyntax +//@[16:22) SimpleTypeSyntax //@[16:22) Identifier |string| //@[23:31) ParameterDefaultValueSyntax //@[23:24) Assignment |=| diff --git a/src/Bicep.Core.Samples/Files/InvalidModules_LF/main.syntax.bicep b/src/Bicep.Core.Samples/Files/InvalidModules_LF/main.syntax.bicep index ae714be27ac..59885c4b826 100644 --- a/src/Bicep.Core.Samples/Files/InvalidModules_LF/main.syntax.bicep +++ b/src/Bicep.Core.Samples/Files/InvalidModules_LF/main.syntax.bicep @@ -3168,7 +3168,7 @@ output directRefToCollectionViaOutput array = nonexistentArrays //@[0:6) Identifier |output| //@[7:37) IdentifierSyntax //@[7:37) Identifier |directRefToCollectionViaOutput| -//@[38:43) TypeSyntax +//@[38:43) SimpleTypeSyntax //@[38:43) Identifier |array| //@[44:45) Assignment |=| //@[46:63) VariableAccessSyntax diff --git a/src/Bicep.Core.Samples/Files/InvalidOutputs_CRLF/main.syntax.bicep b/src/Bicep.Core.Samples/Files/InvalidOutputs_CRLF/main.syntax.bicep index ba59db37497..bac5c22bcac 100644 --- a/src/Bicep.Core.Samples/Files/InvalidOutputs_CRLF/main.syntax.bicep +++ b/src/Bicep.Core.Samples/Files/InvalidOutputs_CRLF/main.syntax.bicep @@ -48,7 +48,7 @@ output missingValue string = //@[0:6) Identifier |output| //@[7:19) IdentifierSyntax //@[7:19) Identifier |missingValue| -//@[20:26) TypeSyntax +//@[20:26) SimpleTypeSyntax //@[20:26) Identifier |string| //@[27:28) Assignment |=| //@[29:29) SkippedTriviaSyntax @@ -61,7 +61,7 @@ output arrayCompletions array = //@[0:6) Identifier |output| //@[7:23) IdentifierSyntax //@[7:23) Identifier |arrayCompletions| -//@[24:29) TypeSyntax +//@[24:29) SimpleTypeSyntax //@[24:29) Identifier |array| //@[30:31) Assignment |=| //@[32:32) SkippedTriviaSyntax @@ -74,7 +74,7 @@ output objectCompletions object = //@[0:6) Identifier |output| //@[7:24) IdentifierSyntax //@[7:24) Identifier |objectCompletions| -//@[25:31) TypeSyntax +//@[25:31) SimpleTypeSyntax //@[25:31) Identifier |object| //@[32:33) Assignment |=| //@[34:34) SkippedTriviaSyntax @@ -87,7 +87,7 @@ output boolCompletions bool = //@[0:6) Identifier |output| //@[7:22) IdentifierSyntax //@[7:22) Identifier |boolCompletions| -//@[23:27) TypeSyntax +//@[23:27) SimpleTypeSyntax //@[23:27) Identifier |bool| //@[28:29) Assignment |=| //@[30:30) SkippedTriviaSyntax @@ -134,7 +134,7 @@ output partialType obj //@[0:6) Identifier |output| //@[7:18) IdentifierSyntax //@[7:18) Identifier |partialType| -//@[19:22) TypeSyntax +//@[19:22) SimpleTypeSyntax //@[19:22) Identifier |obj| //@[22:22) SkippedTriviaSyntax //@[22:22) SkippedTriviaSyntax @@ -219,7 +219,7 @@ output foo fluffy //@[0:6) Identifier |output| //@[7:10) IdentifierSyntax //@[7:10) Identifier |foo| -//@[11:17) TypeSyntax +//@[11:17) SimpleTypeSyntax //@[11:17) Identifier |fluffy| //@[17:17) SkippedTriviaSyntax //@[17:17) SkippedTriviaSyntax @@ -232,7 +232,7 @@ output foo string //@[0:6) Identifier |output| //@[7:10) IdentifierSyntax //@[7:10) Identifier |foo| -//@[11:17) TypeSyntax +//@[11:17) SimpleTypeSyntax //@[11:17) Identifier |string| //@[17:17) SkippedTriviaSyntax //@[17:17) SkippedTriviaSyntax @@ -245,7 +245,7 @@ output foo string = //@[0:6) Identifier |output| //@[7:10) IdentifierSyntax //@[7:10) Identifier |foo| -//@[11:17) TypeSyntax +//@[11:17) SimpleTypeSyntax //@[11:17) Identifier |string| //@[18:19) Assignment |=| //@[19:19) SkippedTriviaSyntax @@ -258,7 +258,7 @@ output str string = true //@[0:6) Identifier |output| //@[7:10) IdentifierSyntax //@[7:10) Identifier |str| -//@[11:17) TypeSyntax +//@[11:17) SimpleTypeSyntax //@[11:17) Identifier |string| //@[18:19) Assignment |=| //@[20:24) BooleanLiteralSyntax @@ -269,7 +269,7 @@ output str string = false //@[0:6) Identifier |output| //@[7:10) IdentifierSyntax //@[7:10) Identifier |str| -//@[11:17) TypeSyntax +//@[11:17) SimpleTypeSyntax //@[11:17) Identifier |string| //@[18:19) Assignment |=| //@[20:25) BooleanLiteralSyntax @@ -280,7 +280,7 @@ output str string = [ //@[0:6) Identifier |output| //@[7:10) IdentifierSyntax //@[7:10) Identifier |str| -//@[11:17) TypeSyntax +//@[11:17) SimpleTypeSyntax //@[11:17) Identifier |string| //@[18:19) Assignment |=| //@[20:24) ArraySyntax @@ -294,7 +294,7 @@ output str string = { //@[0:6) Identifier |output| //@[7:10) IdentifierSyntax //@[7:10) Identifier |str| -//@[11:17) TypeSyntax +//@[11:17) SimpleTypeSyntax //@[11:17) Identifier |string| //@[18:19) Assignment |=| //@[20:24) ObjectSyntax @@ -308,7 +308,7 @@ output str string = 52 //@[0:6) Identifier |output| //@[7:10) IdentifierSyntax //@[7:10) Identifier |str| -//@[11:17) TypeSyntax +//@[11:17) SimpleTypeSyntax //@[11:17) Identifier |string| //@[18:19) Assignment |=| //@[20:22) IntegerLiteralSyntax @@ -322,7 +322,7 @@ output i int = true //@[0:6) Identifier |output| //@[7:8) IdentifierSyntax //@[7:8) Identifier |i| -//@[9:12) TypeSyntax +//@[9:12) SimpleTypeSyntax //@[9:12) Identifier |int| //@[13:14) Assignment |=| //@[15:19) BooleanLiteralSyntax @@ -333,7 +333,7 @@ output i int = false //@[0:6) Identifier |output| //@[7:8) IdentifierSyntax //@[7:8) Identifier |i| -//@[9:12) TypeSyntax +//@[9:12) SimpleTypeSyntax //@[9:12) Identifier |int| //@[13:14) Assignment |=| //@[15:20) BooleanLiteralSyntax @@ -344,7 +344,7 @@ output i int = [ //@[0:6) Identifier |output| //@[7:8) IdentifierSyntax //@[7:8) Identifier |i| -//@[9:12) TypeSyntax +//@[9:12) SimpleTypeSyntax //@[9:12) Identifier |int| //@[13:14) Assignment |=| //@[15:19) ArraySyntax @@ -358,7 +358,7 @@ output i int = } //@[0:6) Identifier |output| //@[7:8) IdentifierSyntax //@[7:8) Identifier |i| -//@[9:12) TypeSyntax +//@[9:12) SimpleTypeSyntax //@[9:12) Identifier |int| //@[13:14) Assignment |=| //@[15:16) SkippedTriviaSyntax @@ -373,7 +373,7 @@ output i int = 'test' //@[0:6) Identifier |output| //@[7:8) IdentifierSyntax //@[7:8) Identifier |i| -//@[9:12) TypeSyntax +//@[9:12) SimpleTypeSyntax //@[9:12) Identifier |int| //@[13:14) Assignment |=| //@[15:21) StringSyntax @@ -387,7 +387,7 @@ output b bool = [ //@[0:6) Identifier |output| //@[7:8) IdentifierSyntax //@[7:8) Identifier |b| -//@[9:13) TypeSyntax +//@[9:13) SimpleTypeSyntax //@[9:13) Identifier |bool| //@[14:15) Assignment |=| //@[16:20) ArraySyntax @@ -401,7 +401,7 @@ output b bool = { //@[0:6) Identifier |output| //@[7:8) IdentifierSyntax //@[7:8) Identifier |b| -//@[9:13) TypeSyntax +//@[9:13) SimpleTypeSyntax //@[9:13) Identifier |bool| //@[14:15) Assignment |=| //@[16:20) ObjectSyntax @@ -415,7 +415,7 @@ output b bool = 32 //@[0:6) Identifier |output| //@[7:8) IdentifierSyntax //@[7:8) Identifier |b| -//@[9:13) TypeSyntax +//@[9:13) SimpleTypeSyntax //@[9:13) Identifier |bool| //@[14:15) Assignment |=| //@[16:18) IntegerLiteralSyntax @@ -426,7 +426,7 @@ output b bool = 'str' //@[0:6) Identifier |output| //@[7:8) IdentifierSyntax //@[7:8) Identifier |b| -//@[9:13) TypeSyntax +//@[9:13) SimpleTypeSyntax //@[9:13) Identifier |bool| //@[14:15) Assignment |=| //@[16:21) StringSyntax @@ -440,7 +440,7 @@ output arr array = 32 //@[0:6) Identifier |output| //@[7:10) IdentifierSyntax //@[7:10) Identifier |arr| -//@[11:16) TypeSyntax +//@[11:16) SimpleTypeSyntax //@[11:16) Identifier |array| //@[17:18) Assignment |=| //@[19:21) IntegerLiteralSyntax @@ -451,7 +451,7 @@ output arr array = true //@[0:6) Identifier |output| //@[7:10) IdentifierSyntax //@[7:10) Identifier |arr| -//@[11:16) TypeSyntax +//@[11:16) SimpleTypeSyntax //@[11:16) Identifier |array| //@[17:18) Assignment |=| //@[19:23) BooleanLiteralSyntax @@ -462,7 +462,7 @@ output arr array = false //@[0:6) Identifier |output| //@[7:10) IdentifierSyntax //@[7:10) Identifier |arr| -//@[11:16) TypeSyntax +//@[11:16) SimpleTypeSyntax //@[11:16) Identifier |array| //@[17:18) Assignment |=| //@[19:24) BooleanLiteralSyntax @@ -473,7 +473,7 @@ output arr array = { //@[0:6) Identifier |output| //@[7:10) IdentifierSyntax //@[7:10) Identifier |arr| -//@[11:16) TypeSyntax +//@[11:16) SimpleTypeSyntax //@[11:16) Identifier |array| //@[17:18) Assignment |=| //@[19:23) ObjectSyntax @@ -487,7 +487,7 @@ output arr array = 'str' //@[0:6) Identifier |output| //@[7:10) IdentifierSyntax //@[7:10) Identifier |arr| -//@[11:16) TypeSyntax +//@[11:16) SimpleTypeSyntax //@[11:16) Identifier |array| //@[17:18) Assignment |=| //@[19:24) StringSyntax @@ -501,7 +501,7 @@ output o object = 32 //@[0:6) Identifier |output| //@[7:8) IdentifierSyntax //@[7:8) Identifier |o| -//@[9:15) TypeSyntax +//@[9:15) SimpleTypeSyntax //@[9:15) Identifier |object| //@[16:17) Assignment |=| //@[18:20) IntegerLiteralSyntax @@ -512,7 +512,7 @@ output o object = true //@[0:6) Identifier |output| //@[7:8) IdentifierSyntax //@[7:8) Identifier |o| -//@[9:15) TypeSyntax +//@[9:15) SimpleTypeSyntax //@[9:15) Identifier |object| //@[16:17) Assignment |=| //@[18:22) BooleanLiteralSyntax @@ -523,7 +523,7 @@ output o object = false //@[0:6) Identifier |output| //@[7:8) IdentifierSyntax //@[7:8) Identifier |o| -//@[9:15) TypeSyntax +//@[9:15) SimpleTypeSyntax //@[9:15) Identifier |object| //@[16:17) Assignment |=| //@[18:23) BooleanLiteralSyntax @@ -534,7 +534,7 @@ output o object = [ //@[0:6) Identifier |output| //@[7:8) IdentifierSyntax //@[7:8) Identifier |o| -//@[9:15) TypeSyntax +//@[9:15) SimpleTypeSyntax //@[9:15) Identifier |object| //@[16:17) Assignment |=| //@[18:22) ArraySyntax @@ -548,7 +548,7 @@ output o object = 'str' //@[0:6) Identifier |output| //@[7:8) IdentifierSyntax //@[7:8) Identifier |o| -//@[9:15) TypeSyntax +//@[9:15) SimpleTypeSyntax //@[9:15) Identifier |object| //@[16:17) Assignment |=| //@[18:23) StringSyntax @@ -562,7 +562,7 @@ output exp string = 2 + 3 //@[0:6) Identifier |output| //@[7:10) IdentifierSyntax //@[7:10) Identifier |exp| -//@[11:17) TypeSyntax +//@[11:17) SimpleTypeSyntax //@[11:17) Identifier |string| //@[18:19) Assignment |=| //@[20:25) BinaryOperationSyntax @@ -577,7 +577,7 @@ output union string = true ? 's' : 1 //@[0:6) Identifier |output| //@[7:12) IdentifierSyntax //@[7:12) Identifier |union| -//@[13:19) TypeSyntax +//@[13:19) SimpleTypeSyntax //@[13:19) Identifier |string| //@[20:21) Assignment |=| //@[22:36) TernaryOperationSyntax @@ -595,7 +595,7 @@ output bad int = true && !4 //@[0:6) Identifier |output| //@[7:10) IdentifierSyntax //@[7:10) Identifier |bad| -//@[11:14) TypeSyntax +//@[11:14) SimpleTypeSyntax //@[11:14) Identifier |int| //@[15:16) Assignment |=| //@[17:27) BinaryOperationSyntax @@ -612,7 +612,7 @@ output deeper bool = true ? -true : (14 && 's') + 10 //@[0:6) Identifier |output| //@[7:13) IdentifierSyntax //@[7:13) Identifier |deeper| -//@[14:18) TypeSyntax +//@[14:18) SimpleTypeSyntax //@[14:18) Identifier |bool| //@[19:20) Assignment |=| //@[21:52) TernaryOperationSyntax @@ -644,7 +644,7 @@ output myOutput string = 'hello' //@[0:6) Identifier |output| //@[7:15) IdentifierSyntax //@[7:15) Identifier |myOutput| -//@[16:22) TypeSyntax +//@[16:22) SimpleTypeSyntax //@[16:22) Identifier |string| //@[23:24) Assignment |=| //@[25:32) StringSyntax @@ -694,7 +694,7 @@ output notAttachableDecorators int = 32 //@[0:6) Identifier |output| //@[7:30) IdentifierSyntax //@[7:30) Identifier |notAttachableDecorators| -//@[31:34) TypeSyntax +//@[31:34) SimpleTypeSyntax //@[31:34) Identifier |int| //@[35:36) Assignment |=| //@[37:39) IntegerLiteralSyntax @@ -708,7 +708,7 @@ output noNestedLoops array = [for thing in things: { //@[0:6) Identifier |output| //@[7:20) IdentifierSyntax //@[7:20) Identifier |noNestedLoops| -//@[21:26) TypeSyntax +//@[21:26) SimpleTypeSyntax //@[21:26) Identifier |array| //@[27:28) Assignment |=| //@[29:110) ForSyntax @@ -765,7 +765,7 @@ output noInnerLoopsInOutputs object = { //@[0:6) Identifier |output| //@[7:28) IdentifierSyntax //@[7:28) Identifier |noInnerLoopsInOutputs| -//@[29:35) TypeSyntax +//@[29:35) SimpleTypeSyntax //@[29:35) Identifier |object| //@[36:37) Assignment |=| //@[38:74) ObjectSyntax @@ -809,7 +809,7 @@ output noInnerLoopsInOutputs2 object = { //@[0:6) Identifier |output| //@[7:29) IdentifierSyntax //@[7:29) Identifier |noInnerLoopsInOutputs2| -//@[30:36) TypeSyntax +//@[30:36) SimpleTypeSyntax //@[30:36) Identifier |object| //@[37:38) Assignment |=| //@[39:116) ObjectSyntax @@ -917,7 +917,7 @@ output keyVaultSecretOutput string = kv.getSecret('mySecret') //@[0:6) Identifier |output| //@[7:27) IdentifierSyntax //@[7:27) Identifier |keyVaultSecretOutput| -//@[28:34) TypeSyntax +//@[28:34) SimpleTypeSyntax //@[28:34) Identifier |string| //@[35:36) Assignment |=| //@[37:61) InstanceFunctionCallSyntax @@ -938,7 +938,7 @@ output keyVaultSecretInterpolatedOutput string = '${kv.getSecret('mySecret')}' //@[0:6) Identifier |output| //@[7:39) IdentifierSyntax //@[7:39) Identifier |keyVaultSecretInterpolatedOutput| -//@[40:46) TypeSyntax +//@[40:46) SimpleTypeSyntax //@[40:46) Identifier |string| //@[47:48) Assignment |=| //@[49:78) StringSyntax @@ -962,7 +962,7 @@ output keyVaultSecretObjectOutput object = { //@[0:6) Identifier |output| //@[7:33) IdentifierSyntax //@[7:33) Identifier |keyVaultSecretObjectOutput| -//@[34:40) TypeSyntax +//@[34:40) SimpleTypeSyntax //@[34:40) Identifier |object| //@[41:42) Assignment |=| //@[43:83) ObjectSyntax @@ -994,7 +994,7 @@ output keyVaultSecretArrayOutput array = [ //@[0:6) Identifier |output| //@[7:32) IdentifierSyntax //@[7:32) Identifier |keyVaultSecretArrayOutput| -//@[33:38) TypeSyntax +//@[33:38) SimpleTypeSyntax //@[33:38) Identifier |array| //@[39:40) Assignment |=| //@[41:73) ArraySyntax @@ -1023,7 +1023,7 @@ output keyVaultSecretArrayInterpolatedOutput array = [ //@[0:6) Identifier |output| //@[7:44) IdentifierSyntax //@[7:44) Identifier |keyVaultSecretArrayInterpolatedOutput| -//@[45:50) TypeSyntax +//@[45:50) SimpleTypeSyntax //@[45:50) Identifier |array| //@[51:52) Assignment |=| //@[53:90) ArraySyntax diff --git a/src/Bicep.Core.Samples/Files/InvalidParameters_LF/Completions/arrayPlusSymbols.json b/src/Bicep.Core.Samples/Files/InvalidParameters_LF/Completions/arrayPlusSymbols.json index 0cea0320964..724370cfa4e 100644 --- a/src/Bicep.Core.Samples/Files/InvalidParameters_LF/Completions/arrayPlusSymbols.json +++ b/src/Bicep.Core.Samples/Files/InvalidParameters_LF/Completions/arrayPlusSymbols.json @@ -583,6 +583,34 @@ "command": "editor.action.triggerParameterHints" } }, + { + "label": "invalidDefaultValueObject", + "kind": "field", + "detail": "invalidDefaultValueObject", + "deprecated": false, + "preselect": false, + "sortText": "2_invalidDefaultValueObject", + "insertTextFormat": "plainText", + "insertTextMode": "adjustIndentation", + "textEdit": { + "range": {}, + "newText": "invalidDefaultValueObject" + } + }, + { + "label": "invalidDefaultValueString", + "kind": "field", + "detail": "invalidDefaultValueString", + "deprecated": false, + "preselect": false, + "sortText": "2_invalidDefaultValueString", + "insertTextFormat": "plainText", + "insertTextMode": "adjustIndentation", + "textEdit": { + "range": {}, + "newText": "invalidDefaultValueString" + } + }, { "label": "invalidDefaultWithAllowedArrayDecorator", "kind": "field", @@ -625,6 +653,20 @@ "newText": "invalidPermutation" } }, + { + "label": "invalidResourceType", + "kind": "field", + "detail": "invalidResourceType", + "deprecated": false, + "preselect": false, + "sortText": "2_invalidResourceType", + "insertTextFormat": "plainText", + "insertTextMode": "adjustIndentation", + "textEdit": { + "range": {}, + "newText": "invalidResourceType" + } + }, { "label": "items", "kind": "function", @@ -1295,6 +1337,20 @@ "command": "editor.action.triggerParameterHints" } }, + { + "label": "resourceTypeMissing", + "kind": "field", + "detail": "resourceTypeMissing", + "deprecated": false, + "preselect": false, + "sortText": "2_resourceTypeMissing", + "insertTextFormat": "plainText", + "insertTextMode": "adjustIndentation", + "textEdit": { + "range": {}, + "newText": "resourceTypeMissing" + } + }, { "label": "sampleResource", "kind": "interface", @@ -1707,6 +1763,20 @@ "command": "editor.action.triggerParameterHints" } }, + { + "label": "unknownResourceType", + "kind": "field", + "detail": "unknownResourceType", + "deprecated": false, + "preselect": false, + "sortText": "2_unknownResourceType", + "insertTextFormat": "plainText", + "insertTextMode": "adjustIndentation", + "textEdit": { + "range": {}, + "newText": "unknownResourceType" + } + }, { "label": "uri", "kind": "function", diff --git a/src/Bicep.Core.Samples/Files/InvalidParameters_LF/Completions/boolPlusSymbols.json b/src/Bicep.Core.Samples/Files/InvalidParameters_LF/Completions/boolPlusSymbols.json index afb80841245..a666f625473 100644 --- a/src/Bicep.Core.Samples/Files/InvalidParameters_LF/Completions/boolPlusSymbols.json +++ b/src/Bicep.Core.Samples/Files/InvalidParameters_LF/Completions/boolPlusSymbols.json @@ -583,6 +583,34 @@ "command": "editor.action.triggerParameterHints" } }, + { + "label": "invalidDefaultValueObject", + "kind": "field", + "detail": "invalidDefaultValueObject", + "deprecated": false, + "preselect": false, + "sortText": "2_invalidDefaultValueObject", + "insertTextFormat": "plainText", + "insertTextMode": "adjustIndentation", + "textEdit": { + "range": {}, + "newText": "invalidDefaultValueObject" + } + }, + { + "label": "invalidDefaultValueString", + "kind": "field", + "detail": "invalidDefaultValueString", + "deprecated": false, + "preselect": false, + "sortText": "2_invalidDefaultValueString", + "insertTextFormat": "plainText", + "insertTextMode": "adjustIndentation", + "textEdit": { + "range": {}, + "newText": "invalidDefaultValueString" + } + }, { "label": "invalidDefaultWithAllowedArrayDecorator", "kind": "field", @@ -625,6 +653,20 @@ "newText": "invalidPermutation" } }, + { + "label": "invalidResourceType", + "kind": "field", + "detail": "invalidResourceType", + "deprecated": false, + "preselect": false, + "sortText": "2_invalidResourceType", + "insertTextFormat": "plainText", + "insertTextMode": "adjustIndentation", + "textEdit": { + "range": {}, + "newText": "invalidResourceType" + } + }, { "label": "items", "kind": "function", @@ -1295,6 +1337,20 @@ "command": "editor.action.triggerParameterHints" } }, + { + "label": "resourceTypeMissing", + "kind": "field", + "detail": "resourceTypeMissing", + "deprecated": false, + "preselect": false, + "sortText": "2_resourceTypeMissing", + "insertTextFormat": "plainText", + "insertTextMode": "adjustIndentation", + "textEdit": { + "range": {}, + "newText": "resourceTypeMissing" + } + }, { "label": "sampleResource", "kind": "interface", @@ -1721,6 +1777,20 @@ "command": "editor.action.triggerParameterHints" } }, + { + "label": "unknownResourceType", + "kind": "field", + "detail": "unknownResourceType", + "deprecated": false, + "preselect": false, + "sortText": "2_unknownResourceType", + "insertTextFormat": "plainText", + "insertTextMode": "adjustIndentation", + "textEdit": { + "range": {}, + "newText": "unknownResourceType" + } + }, { "label": "uri", "kind": "function", diff --git a/src/Bicep.Core.Samples/Files/InvalidParameters_LF/Completions/justSymbols.json b/src/Bicep.Core.Samples/Files/InvalidParameters_LF/Completions/justSymbols.json index 337154e2fe4..fe6636e3a76 100644 --- a/src/Bicep.Core.Samples/Files/InvalidParameters_LF/Completions/justSymbols.json +++ b/src/Bicep.Core.Samples/Files/InvalidParameters_LF/Completions/justSymbols.json @@ -569,6 +569,34 @@ "command": "editor.action.triggerParameterHints" } }, + { + "label": "invalidDefaultValueObject", + "kind": "field", + "detail": "invalidDefaultValueObject", + "deprecated": false, + "preselect": false, + "sortText": "2_invalidDefaultValueObject", + "insertTextFormat": "plainText", + "insertTextMode": "adjustIndentation", + "textEdit": { + "range": {}, + "newText": "invalidDefaultValueObject" + } + }, + { + "label": "invalidDefaultValueString", + "kind": "field", + "detail": "invalidDefaultValueString", + "deprecated": false, + "preselect": false, + "sortText": "2_invalidDefaultValueString", + "insertTextFormat": "plainText", + "insertTextMode": "adjustIndentation", + "textEdit": { + "range": {}, + "newText": "invalidDefaultValueString" + } + }, { "label": "invalidDefaultWithAllowedArrayDecorator", "kind": "field", @@ -611,6 +639,20 @@ "newText": "invalidPermutation" } }, + { + "label": "invalidResourceType", + "kind": "field", + "detail": "invalidResourceType", + "deprecated": false, + "preselect": false, + "sortText": "2_invalidResourceType", + "insertTextFormat": "plainText", + "insertTextMode": "adjustIndentation", + "textEdit": { + "range": {}, + "newText": "invalidResourceType" + } + }, { "label": "items", "kind": "function", @@ -1281,6 +1323,20 @@ "command": "editor.action.triggerParameterHints" } }, + { + "label": "resourceTypeMissing", + "kind": "field", + "detail": "resourceTypeMissing", + "deprecated": false, + "preselect": false, + "sortText": "2_resourceTypeMissing", + "insertTextFormat": "plainText", + "insertTextMode": "adjustIndentation", + "textEdit": { + "range": {}, + "newText": "resourceTypeMissing" + } + }, { "label": "sampleResource", "kind": "interface", @@ -1693,6 +1749,20 @@ "command": "editor.action.triggerParameterHints" } }, + { + "label": "unknownResourceType", + "kind": "field", + "detail": "unknownResourceType", + "deprecated": false, + "preselect": false, + "sortText": "2_unknownResourceType", + "insertTextFormat": "plainText", + "insertTextMode": "adjustIndentation", + "textEdit": { + "range": {}, + "newText": "unknownResourceType" + } + }, { "label": "uri", "kind": "function", diff --git a/src/Bicep.Core.Samples/Files/InvalidParameters_LF/Completions/objectPlusSymbols.json b/src/Bicep.Core.Samples/Files/InvalidParameters_LF/Completions/objectPlusSymbols.json index c145f87731e..08abc574cc8 100644 --- a/src/Bicep.Core.Samples/Files/InvalidParameters_LF/Completions/objectPlusSymbols.json +++ b/src/Bicep.Core.Samples/Files/InvalidParameters_LF/Completions/objectPlusSymbols.json @@ -583,6 +583,34 @@ "command": "editor.action.triggerParameterHints" } }, + { + "label": "invalidDefaultValueObject", + "kind": "field", + "detail": "invalidDefaultValueObject", + "deprecated": false, + "preselect": false, + "sortText": "2_invalidDefaultValueObject", + "insertTextFormat": "plainText", + "insertTextMode": "adjustIndentation", + "textEdit": { + "range": {}, + "newText": "invalidDefaultValueObject" + } + }, + { + "label": "invalidDefaultValueString", + "kind": "field", + "detail": "invalidDefaultValueString", + "deprecated": false, + "preselect": false, + "sortText": "2_invalidDefaultValueString", + "insertTextFormat": "plainText", + "insertTextMode": "adjustIndentation", + "textEdit": { + "range": {}, + "newText": "invalidDefaultValueString" + } + }, { "label": "invalidDefaultWithAllowedArrayDecorator", "kind": "field", @@ -625,6 +653,20 @@ "newText": "invalidPermutation" } }, + { + "label": "invalidResourceType", + "kind": "field", + "detail": "invalidResourceType", + "deprecated": false, + "preselect": false, + "sortText": "2_invalidResourceType", + "insertTextFormat": "plainText", + "insertTextMode": "adjustIndentation", + "textEdit": { + "range": {}, + "newText": "invalidResourceType" + } + }, { "label": "items", "kind": "function", @@ -1281,6 +1323,20 @@ "command": "editor.action.triggerParameterHints" } }, + { + "label": "resourceTypeMissing", + "kind": "field", + "detail": "resourceTypeMissing", + "deprecated": false, + "preselect": false, + "sortText": "2_resourceTypeMissing", + "insertTextFormat": "plainText", + "insertTextMode": "adjustIndentation", + "textEdit": { + "range": {}, + "newText": "resourceTypeMissing" + } + }, { "label": "sampleResource", "kind": "interface", @@ -1693,6 +1749,20 @@ "command": "editor.action.triggerParameterHints" } }, + { + "label": "unknownResourceType", + "kind": "field", + "detail": "unknownResourceType", + "deprecated": false, + "preselect": false, + "sortText": "2_unknownResourceType", + "insertTextFormat": "plainText", + "insertTextMode": "adjustIndentation", + "textEdit": { + "range": {}, + "newText": "unknownResourceType" + } + }, { "label": "uri", "kind": "function", diff --git a/src/Bicep.Core.Samples/Files/InvalidParameters_LF/main.bicep b/src/Bicep.Core.Samples/Files/InvalidParameters_LF/main.bicep index 825fa2f7928..050e88ea016 100644 --- a/src/Bicep.Core.Samples/Files/InvalidParameters_LF/main.bicep +++ b/src/Bicep.Core.Samples/Files/InvalidParameters_LF/main.bicep @@ -275,5 +275,15 @@ param invalidPermutation array = [ ]) param invalidDefaultWithAllowedArrayDecorator array = true +param resourceTypeMissing resource + +param invalidResourceType resource 'Some/fake' + +param unknownResourceType resource 'Some/fake@2020-01-01' + +param invalidDefaultValueObject resource 'Microsoft.Storage/storageAccounts@2019-06-01' = {} + +param invalidDefaultValueString resource 'Microsoft.Storage/storageAccounts@2019-06-01' = 'hey there' + // unterminated multi-line comment /* diff --git a/src/Bicep.Core.Samples/Files/InvalidParameters_LF/main.diagnostics.bicep b/src/Bicep.Core.Samples/Files/InvalidParameters_LF/main.diagnostics.bicep index 39de2379803..1481994748a 100644 --- a/src/Bicep.Core.Samples/Files/InvalidParameters_LF/main.diagnostics.bicep +++ b/src/Bicep.Core.Samples/Files/InvalidParameters_LF/main.diagnostics.bicep @@ -495,6 +495,26 @@ param invalidDefaultWithAllowedArrayDecorator array = true //@[6:45) [no-unused-params (Warning)] Parameter "invalidDefaultWithAllowedArrayDecorator" is declared but never used. (CodeDescription: bicep core(https://aka.ms/bicep/linter/no-unused-params)) |invalidDefaultWithAllowedArrayDecorator| //@[54:58) [BCP027 (Error)] The parameter expects a default value of type "array" but provided value is of type "bool". (CodeDescription: none) |true| +param resourceTypeMissing resource +//@[6:25) [no-unused-params (Warning)] Parameter "resourceTypeMissing" is declared but never used. (CodeDescription: bicep core(https://aka.ms/bicep/linter/no-unused-params)) |resourceTypeMissing| +//@[34:34) [BCP068 (Error)] Expected a resource type string. Specify a valid resource type of format "/@". (CodeDescription: none) || +//@[34:34) [BCP029 (Error)] The resource type is not valid. Specify a valid resource type of format "/@". (CodeDescription: none) || + +param invalidResourceType resource 'Some/fake' +//@[6:25) [no-unused-params (Warning)] Parameter "invalidResourceType" is declared but never used. (CodeDescription: bicep core(https://aka.ms/bicep/linter/no-unused-params)) |invalidResourceType| +//@[35:46) [BCP029 (Error)] The resource type is not valid. Specify a valid resource type of format "/@". (CodeDescription: none) |'Some/fake'| + +param unknownResourceType resource 'Some/fake@2020-01-01' +//@[6:25) [no-unused-params (Warning)] Parameter "unknownResourceType" is declared but never used. (CodeDescription: bicep core(https://aka.ms/bicep/linter/no-unused-params)) |unknownResourceType| + +param invalidDefaultValueObject resource 'Microsoft.Storage/storageAccounts@2019-06-01' = {} +//@[6:31) [no-unused-params (Warning)] Parameter "invalidDefaultValueObject" is declared but never used. (CodeDescription: bicep core(https://aka.ms/bicep/linter/no-unused-params)) |invalidDefaultValueObject| +//@[90:92) [BCP027 (Error)] The parameter expects a default value of type "Microsoft.Storage/storageAccounts@2019-06-01" but provided value is of type "object". (CodeDescription: none) |{}| + +param invalidDefaultValueString resource 'Microsoft.Storage/storageAccounts@2019-06-01' = 'hey there' +//@[6:31) [no-unused-params (Warning)] Parameter "invalidDefaultValueString" is declared but never used. (CodeDescription: bicep core(https://aka.ms/bicep/linter/no-unused-params)) |invalidDefaultValueString| +//@[90:101) [BCP027 (Error)] The parameter expects a default value of type "Microsoft.Storage/storageAccounts@2019-06-01" but provided value is of type "'hey there'". (CodeDescription: none) |'hey there'| + // unterminated multi-line comment /* //@[0:7) [BCP002 (Error)] The multi-line comment at this location is not terminated. Terminate it with the */ character sequence. (CodeDescription: none) |/* \n| diff --git a/src/Bicep.Core.Samples/Files/InvalidParameters_LF/main.formatted.bicep b/src/Bicep.Core.Samples/Files/InvalidParameters_LF/main.formatted.bicep index c56032f0740..b15eb11b662 100644 --- a/src/Bicep.Core.Samples/Files/InvalidParameters_LF/main.formatted.bicep +++ b/src/Bicep.Core.Samples/Files/InvalidParameters_LF/main.formatted.bicep @@ -272,6 +272,16 @@ param invalidPermutation array = [ ]) param invalidDefaultWithAllowedArrayDecorator array = true +param resourceTypeMissing resource + +param invalidResourceType resource 'Some/fake' + +param unknownResourceType resource 'Some/fake@2020-01-01' + +param invalidDefaultValueObject resource 'Microsoft.Storage/storageAccounts@2019-06-01' = {} + +param invalidDefaultValueString resource 'Microsoft.Storage/storageAccounts@2019-06-01' = 'hey there' + // unterminated multi-line comment /* diff --git a/src/Bicep.Core.Samples/Files/InvalidParameters_LF/main.symbols.bicep b/src/Bicep.Core.Samples/Files/InvalidParameters_LF/main.symbols.bicep index 033d7a59328..8b8d740651f 100644 --- a/src/Bicep.Core.Samples/Files/InvalidParameters_LF/main.symbols.bicep +++ b/src/Bicep.Core.Samples/Files/InvalidParameters_LF/main.symbols.bicep @@ -352,6 +352,21 @@ param invalidPermutation array = [ param invalidDefaultWithAllowedArrayDecorator array = true //@[6:45) Parameter invalidDefaultWithAllowedArrayDecorator. Type: array. Declaration start char: 0, length: 245 +param resourceTypeMissing resource +//@[6:25) Parameter resourceTypeMissing. Type: error. Declaration start char: 0, length: 34 + +param invalidResourceType resource 'Some/fake' +//@[6:25) Parameter invalidResourceType. Type: error. Declaration start char: 0, length: 46 + +param unknownResourceType resource 'Some/fake@2020-01-01' +//@[6:25) Parameter unknownResourceType. Type: Some/fake@2020-01-01. Declaration start char: 0, length: 57 + +param invalidDefaultValueObject resource 'Microsoft.Storage/storageAccounts@2019-06-01' = {} +//@[6:31) Parameter invalidDefaultValueObject. Type: Microsoft.Storage/storageAccounts@2019-06-01. Declaration start char: 0, length: 92 + +param invalidDefaultValueString resource 'Microsoft.Storage/storageAccounts@2019-06-01' = 'hey there' +//@[6:31) Parameter invalidDefaultValueString. Type: Microsoft.Storage/storageAccounts@2019-06-01. Declaration start char: 0, length: 101 + // unterminated multi-line comment /* diff --git a/src/Bicep.Core.Samples/Files/InvalidParameters_LF/main.syntax.bicep b/src/Bicep.Core.Samples/Files/InvalidParameters_LF/main.syntax.bicep index 4b756f25dce..d80e00f0363 100644 --- a/src/Bicep.Core.Samples/Files/InvalidParameters_LF/main.syntax.bicep +++ b/src/Bicep.Core.Samples/Files/InvalidParameters_LF/main.syntax.bicep @@ -8,7 +8,7 @@ param myString string //@[0:5) Identifier |param| //@[6:14) IdentifierSyntax //@[6:14) Identifier |myString| -//@[15:21) TypeSyntax +//@[15:21) SimpleTypeSyntax //@[15:21) Identifier |string| //@[21:22) NewLine |\n| wrong @@ -21,7 +21,7 @@ param myInt int //@[0:5) Identifier |param| //@[6:11) IdentifierSyntax //@[6:11) Identifier |myInt| -//@[12:15) TypeSyntax +//@[12:15) SimpleTypeSyntax //@[12:15) Identifier |int| //@[15:16) NewLine |\n| param @@ -46,7 +46,7 @@ param % string //@[6:7) IdentifierSyntax //@[6:7) SkippedTriviaSyntax //@[6:7) Modulo |%| -//@[8:14) TypeSyntax +//@[8:14) SimpleTypeSyntax //@[8:14) Identifier |string| //@[14:15) NewLine |\n| param % string 3 = 's' @@ -55,7 +55,7 @@ param % string 3 = 's' //@[6:7) IdentifierSyntax //@[6:7) SkippedTriviaSyntax //@[6:7) Modulo |%| -//@[8:14) TypeSyntax +//@[8:14) SimpleTypeSyntax //@[8:14) Identifier |string| //@[15:22) SkippedTriviaSyntax //@[15:16) Integer |3| @@ -68,7 +68,7 @@ param myBool bool //@[0:5) Identifier |param| //@[6:12) IdentifierSyntax //@[6:12) Identifier |myBool| -//@[13:17) TypeSyntax +//@[13:17) SimpleTypeSyntax //@[13:17) Identifier |bool| //@[17:19) NewLine |\n\n| @@ -117,7 +117,7 @@ param partialType str //@[0:5) Identifier |param| //@[6:17) IdentifierSyntax //@[6:17) Identifier |partialType| -//@[18:21) TypeSyntax +//@[18:21) SimpleTypeSyntax //@[18:21) Identifier |str| //@[21:23) NewLine |\n\n| @@ -174,7 +174,7 @@ param myString2 string = 'string value' //@[0:5) Identifier |param| //@[6:15) IdentifierSyntax //@[6:15) Identifier |myString2| -//@[16:22) TypeSyntax +//@[16:22) SimpleTypeSyntax //@[16:22) Identifier |string| //@[23:39) ParameterDefaultValueSyntax //@[23:24) Assignment |=| @@ -187,7 +187,7 @@ param wrongDefaultValue string = 42 //@[0:5) Identifier |param| //@[6:23) IdentifierSyntax //@[6:23) Identifier |wrongDefaultValue| -//@[24:30) TypeSyntax +//@[24:30) SimpleTypeSyntax //@[24:30) Identifier |string| //@[31:35) ParameterDefaultValueSyntax //@[31:32) Assignment |=| @@ -200,7 +200,7 @@ param myInt2 int = 42 //@[0:5) Identifier |param| //@[6:12) IdentifierSyntax //@[6:12) Identifier |myInt2| -//@[13:16) TypeSyntax +//@[13:16) SimpleTypeSyntax //@[13:16) Identifier |int| //@[17:21) ParameterDefaultValueSyntax //@[17:18) Assignment |=| @@ -212,7 +212,7 @@ param noValueAfterColon int = //@[0:5) Identifier |param| //@[6:23) IdentifierSyntax //@[6:23) Identifier |noValueAfterColon| -//@[24:27) TypeSyntax +//@[24:27) SimpleTypeSyntax //@[24:27) Identifier |int| //@[28:32) ParameterDefaultValueSyntax //@[28:29) Assignment |=| @@ -224,7 +224,7 @@ param myTruth bool = 'not a boolean' //@[0:5) Identifier |param| //@[6:13) IdentifierSyntax //@[6:13) Identifier |myTruth| -//@[14:18) TypeSyntax +//@[14:18) SimpleTypeSyntax //@[14:18) Identifier |bool| //@[19:36) ParameterDefaultValueSyntax //@[19:20) Assignment |=| @@ -236,7 +236,7 @@ param myFalsehood bool = 'false' //@[0:5) Identifier |param| //@[6:17) IdentifierSyntax //@[6:17) Identifier |myFalsehood| -//@[18:22) TypeSyntax +//@[18:22) SimpleTypeSyntax //@[18:22) Identifier |bool| //@[23:32) ParameterDefaultValueSyntax //@[23:24) Assignment |=| @@ -249,7 +249,7 @@ param wrongAssignmentToken string: 'hello' //@[0:5) Identifier |param| //@[6:26) IdentifierSyntax //@[6:26) Identifier |wrongAssignmentToken| -//@[27:33) TypeSyntax +//@[27:33) SimpleTypeSyntax //@[27:33) Identifier |string| //@[33:42) SkippedTriviaSyntax //@[33:34) Colon |:| @@ -261,7 +261,7 @@ param WhySoLongWhySoLongWhySoLongWhySoLongWhySoLongWhySoLongWhySoLongWhySoLongWh //@[0:5) Identifier |param| //@[6:267) IdentifierSyntax //@[6:267) Identifier |WhySoLongWhySoLongWhySoLongWhySoLongWhySoLongWhySoLongWhySoLongWhySoLongWhySoLongWhySoLongWhySoLongWhySoLongWhySoLongWhySoLongWhySoLongWhySoLongWhySoLongWhySoLongWhySoLongWhySoLongWhySoLongWhySoLongWhySoLongWhySoLongWhySoLongWhySoLongWhySoLongWhySoLongWhySoLong| -//@[268:274) TypeSyntax +//@[268:274) SimpleTypeSyntax //@[268:274) Identifier |string| //@[275:287) ParameterDefaultValueSyntax //@[275:276) Assignment |=| @@ -276,7 +276,7 @@ param boolCompletions bool = //@[0:5) Identifier |param| //@[6:21) IdentifierSyntax //@[6:21) Identifier |boolCompletions| -//@[22:26) TypeSyntax +//@[22:26) SimpleTypeSyntax //@[22:26) Identifier |bool| //@[27:29) ParameterDefaultValueSyntax //@[27:28) Assignment |=| @@ -290,7 +290,7 @@ param arrayCompletions array = //@[0:5) Identifier |param| //@[6:22) IdentifierSyntax //@[6:22) Identifier |arrayCompletions| -//@[23:28) TypeSyntax +//@[23:28) SimpleTypeSyntax //@[23:28) Identifier |array| //@[29:31) ParameterDefaultValueSyntax //@[29:30) Assignment |=| @@ -304,7 +304,7 @@ param objectCompletions object = //@[0:5) Identifier |param| //@[6:23) IdentifierSyntax //@[6:23) Identifier |objectCompletions| -//@[24:30) TypeSyntax +//@[24:30) SimpleTypeSyntax //@[24:30) Identifier |object| //@[31:33) ParameterDefaultValueSyntax //@[31:32) Assignment |=| @@ -318,7 +318,7 @@ param wrongType fluffyBunny = 'what's up doc?' //@[0:5) Identifier |param| //@[6:15) IdentifierSyntax //@[6:15) Identifier |wrongType| -//@[16:27) TypeSyntax +//@[16:27) SimpleTypeSyntax //@[16:27) Identifier |fluffyBunny| //@[28:36) ParameterDefaultValueSyntax //@[28:29) Assignment |=| @@ -339,7 +339,7 @@ param wrongType fluffyBunny = 'what\s up doc?' //@[0:5) Identifier |param| //@[6:15) IdentifierSyntax //@[6:15) Identifier |wrongType| -//@[16:27) TypeSyntax +//@[16:27) SimpleTypeSyntax //@[16:27) Identifier |fluffyBunny| //@[28:46) ParameterDefaultValueSyntax //@[28:29) Assignment |=| @@ -354,7 +354,7 @@ param wrongType fluffyBunny = 'what\'s up doc? //@[0:5) Identifier |param| //@[6:15) IdentifierSyntax //@[6:15) Identifier |wrongType| -//@[16:27) TypeSyntax +//@[16:27) SimpleTypeSyntax //@[16:27) Identifier |fluffyBunny| //@[28:46) ParameterDefaultValueSyntax //@[28:29) Assignment |=| @@ -369,7 +369,7 @@ param wrongType fluffyBunny = 'what\'s ${ //@[0:5) Identifier |param| //@[6:15) IdentifierSyntax //@[6:15) Identifier |wrongType| -//@[16:27) TypeSyntax +//@[16:27) SimpleTypeSyntax //@[16:27) Identifier |fluffyBunny| //@[28:41) ParameterDefaultValueSyntax //@[28:29) Assignment |=| @@ -383,7 +383,7 @@ param wrongType fluffyBunny = 'what\'s ${up //@[0:5) Identifier |param| //@[6:15) IdentifierSyntax //@[6:15) Identifier |wrongType| -//@[16:27) TypeSyntax +//@[16:27) SimpleTypeSyntax //@[16:27) Identifier |fluffyBunny| //@[28:43) ParameterDefaultValueSyntax //@[28:29) Assignment |=| @@ -399,7 +399,7 @@ param wrongType fluffyBunny = 'what\'s ${up} //@[0:5) Identifier |param| //@[6:15) IdentifierSyntax //@[6:15) Identifier |wrongType| -//@[16:27) TypeSyntax +//@[16:27) SimpleTypeSyntax //@[16:27) Identifier |fluffyBunny| //@[28:44) ParameterDefaultValueSyntax //@[28:29) Assignment |=| @@ -415,7 +415,7 @@ param wrongType fluffyBunny = 'what\'s ${'up //@[0:5) Identifier |param| //@[6:15) IdentifierSyntax //@[6:15) Identifier |wrongType| -//@[16:27) TypeSyntax +//@[16:27) SimpleTypeSyntax //@[16:27) Identifier |fluffyBunny| //@[28:44) ParameterDefaultValueSyntax //@[28:29) Assignment |=| @@ -433,7 +433,7 @@ param wrongType fluffyBunny = 'what\'s ${'up${ //@[0:5) Identifier |param| //@[6:15) IdentifierSyntax //@[6:15) Identifier |wrongType| -//@[16:27) TypeSyntax +//@[16:27) SimpleTypeSyntax //@[16:27) Identifier |fluffyBunny| //@[28:46) ParameterDefaultValueSyntax //@[28:29) Assignment |=| @@ -449,7 +449,7 @@ param wrongType fluffyBunny = 'what\'s ${'up${ //@[0:5) Identifier |param| //@[6:15) IdentifierSyntax //@[6:15) Identifier |wrongType| -//@[16:27) TypeSyntax +//@[16:27) SimpleTypeSyntax //@[16:27) Identifier |fluffyBunny| //@[28:46) ParameterDefaultValueSyntax //@[28:29) Assignment |=| @@ -465,7 +465,7 @@ param wrongType fluffyBunny = 'what\'s ${'up${doc //@[0:5) Identifier |param| //@[6:15) IdentifierSyntax //@[6:15) Identifier |wrongType| -//@[16:27) TypeSyntax +//@[16:27) SimpleTypeSyntax //@[16:27) Identifier |fluffyBunny| //@[28:49) ParameterDefaultValueSyntax //@[28:29) Assignment |=| @@ -483,7 +483,7 @@ param wrongType fluffyBunny = 'what\'s ${'up${doc} //@[0:5) Identifier |param| //@[6:15) IdentifierSyntax //@[6:15) Identifier |wrongType| -//@[16:27) TypeSyntax +//@[16:27) SimpleTypeSyntax //@[16:27) Identifier |fluffyBunny| //@[28:50) ParameterDefaultValueSyntax //@[28:29) Assignment |=| @@ -502,7 +502,7 @@ param wrongType fluffyBunny = 'what\'s ${'up${doc}' //@[0:5) Identifier |param| //@[6:15) IdentifierSyntax //@[6:15) Identifier |wrongType| -//@[16:27) TypeSyntax +//@[16:27) SimpleTypeSyntax //@[16:27) Identifier |fluffyBunny| //@[28:51) ParameterDefaultValueSyntax //@[28:29) Assignment |=| @@ -521,7 +521,7 @@ param wrongType fluffyBunny = 'what\'s ${'up${doc}'}? //@[0:5) Identifier |param| //@[6:15) IdentifierSyntax //@[6:15) Identifier |wrongType| -//@[16:27) TypeSyntax +//@[16:27) SimpleTypeSyntax //@[16:27) Identifier |fluffyBunny| //@[28:53) ParameterDefaultValueSyntax //@[28:29) Assignment |=| @@ -543,7 +543,7 @@ param wrongType fluffyBunny = '${{this: doesnt}.work}' //@[0:5) Identifier |param| //@[6:15) IdentifierSyntax //@[6:15) Identifier |wrongType| -//@[16:27) TypeSyntax +//@[16:27) SimpleTypeSyntax //@[16:27) Identifier |fluffyBunny| //@[28:54) ParameterDefaultValueSyntax //@[28:29) Assignment |=| @@ -569,7 +569,7 @@ param badInterpolatedString string = 'hello ${}!' //@[0:5) Identifier |param| //@[6:27) IdentifierSyntax //@[6:27) Identifier |badInterpolatedString| -//@[28:34) TypeSyntax +//@[28:34) SimpleTypeSyntax //@[28:34) Identifier |string| //@[35:49) ParameterDefaultValueSyntax //@[35:36) Assignment |=| @@ -583,7 +583,7 @@ param badInterpolatedString2 string = 'hello ${a b c}!' //@[0:5) Identifier |param| //@[6:28) IdentifierSyntax //@[6:28) Identifier |badInterpolatedString2| -//@[29:35) TypeSyntax +//@[29:35) SimpleTypeSyntax //@[29:35) Identifier |string| //@[36:55) ParameterDefaultValueSyntax //@[36:37) Assignment |=| @@ -604,7 +604,7 @@ param wrongType fluffyBunny = 'what\'s up doc?' //@[0:5) Identifier |param| //@[6:15) IdentifierSyntax //@[6:15) Identifier |wrongType| -//@[16:27) TypeSyntax +//@[16:27) SimpleTypeSyntax //@[16:27) Identifier |fluffyBunny| //@[28:47) ParameterDefaultValueSyntax //@[28:29) Assignment |=| @@ -643,7 +643,7 @@ param someArray arra //@[0:5) Identifier |param| //@[6:15) IdentifierSyntax //@[6:15) Identifier |someArray| -//@[16:20) TypeSyntax +//@[16:20) SimpleTypeSyntax //@[16:20) Identifier |arra| //@[20:22) NewLine |\n\n| @@ -685,7 +685,7 @@ param secureInt int //@[0:5) Identifier |param| //@[6:15) IdentifierSyntax //@[6:15) Identifier |secureInt| -//@[16:19) TypeSyntax +//@[16:19) SimpleTypeSyntax //@[16:19) Identifier |int| //@[19:21) NewLine |\n\n| @@ -763,7 +763,7 @@ param wrongIntModifier int = true //@[0:5) Identifier |param| //@[6:22) IdentifierSyntax //@[6:22) Identifier |wrongIntModifier| -//@[23:26) TypeSyntax +//@[23:26) SimpleTypeSyntax //@[23:26) Identifier |int| //@[27:33) ParameterDefaultValueSyntax //@[27:28) Assignment |=| @@ -846,7 +846,7 @@ param wrongMetadataSchema string //@[0:5) Identifier |param| //@[6:25) IdentifierSyntax //@[6:25) Identifier |wrongMetadataSchema| -//@[26:32) TypeSyntax +//@[26:32) SimpleTypeSyntax //@[26:32) Identifier |string| //@[32:34) NewLine |\n\n| @@ -910,7 +910,7 @@ param expressionInModifier string = 2 + 3 //@[0:5) Identifier |param| //@[6:26) IdentifierSyntax //@[6:26) Identifier |expressionInModifier| -//@[27:33) TypeSyntax +//@[27:33) SimpleTypeSyntax //@[27:33) Identifier |string| //@[34:41) ParameterDefaultValueSyntax //@[34:35) Assignment |=| @@ -989,7 +989,7 @@ param nonCompileTimeConstant string //@[0:5) Identifier |param| //@[6:28) IdentifierSyntax //@[6:28) Identifier |nonCompileTimeConstant| -//@[29:35) TypeSyntax +//@[29:35) SimpleTypeSyntax //@[29:35) Identifier |string| //@[35:38) NewLine |\n\n\n| @@ -1012,7 +1012,7 @@ param emptyAllowedString string //@[0:5) Identifier |param| //@[6:24) IdentifierSyntax //@[6:24) Identifier |emptyAllowedString| -//@[25:31) TypeSyntax +//@[25:31) SimpleTypeSyntax //@[25:31) Identifier |string| //@[31:33) NewLine |\n\n| @@ -1034,7 +1034,7 @@ param emptyAllowedInt int //@[0:5) Identifier |param| //@[6:21) IdentifierSyntax //@[6:21) Identifier |emptyAllowedInt| -//@[22:25) TypeSyntax +//@[22:25) SimpleTypeSyntax //@[22:25) Identifier |int| //@[25:27) NewLine |\n\n| @@ -1045,7 +1045,7 @@ param paramDefaultOneCycle string = paramDefaultOneCycle //@[0:5) Identifier |param| //@[6:26) IdentifierSyntax //@[6:26) Identifier |paramDefaultOneCycle| -//@[27:33) TypeSyntax +//@[27:33) SimpleTypeSyntax //@[27:33) Identifier |string| //@[34:56) ParameterDefaultValueSyntax //@[34:35) Assignment |=| @@ -1061,7 +1061,7 @@ param paramDefaultTwoCycle1 string = paramDefaultTwoCycle2 //@[0:5) Identifier |param| //@[6:27) IdentifierSyntax //@[6:27) Identifier |paramDefaultTwoCycle1| -//@[28:34) TypeSyntax +//@[28:34) SimpleTypeSyntax //@[28:34) Identifier |string| //@[35:58) ParameterDefaultValueSyntax //@[35:36) Assignment |=| @@ -1074,7 +1074,7 @@ param paramDefaultTwoCycle2 string = paramDefaultTwoCycle1 //@[0:5) Identifier |param| //@[6:27) IdentifierSyntax //@[6:27) Identifier |paramDefaultTwoCycle2| -//@[28:34) TypeSyntax +//@[28:34) SimpleTypeSyntax //@[28:34) Identifier |string| //@[35:58) ParameterDefaultValueSyntax //@[35:36) Assignment |=| @@ -1109,7 +1109,7 @@ param paramModifierSelfCycle string //@[0:5) Identifier |param| //@[6:28) IdentifierSyntax //@[6:28) Identifier |paramModifierSelfCycle| -//@[29:35) TypeSyntax +//@[29:35) SimpleTypeSyntax //@[29:35) Identifier |string| //@[35:37) NewLine |\n\n| @@ -1151,7 +1151,7 @@ output sampleOutput string = 'hello' //@[0:6) Identifier |output| //@[7:19) IdentifierSyntax //@[7:19) Identifier |sampleOutput| -//@[20:26) TypeSyntax +//@[20:26) SimpleTypeSyntax //@[20:26) Identifier |string| //@[27:28) Assignment |=| //@[29:36) StringSyntax @@ -1163,7 +1163,7 @@ param paramAccessingVar string = concat(sampleVar, 's') //@[0:5) Identifier |param| //@[6:23) IdentifierSyntax //@[6:23) Identifier |paramAccessingVar| -//@[24:30) TypeSyntax +//@[24:30) SimpleTypeSyntax //@[24:30) Identifier |string| //@[31:55) ParameterDefaultValueSyntax //@[31:32) Assignment |=| @@ -1187,7 +1187,7 @@ param paramAccessingResource string = sampleResource //@[0:5) Identifier |param| //@[6:28) IdentifierSyntax //@[6:28) Identifier |paramAccessingResource| -//@[29:35) TypeSyntax +//@[29:35) SimpleTypeSyntax //@[29:35) Identifier |string| //@[36:52) ParameterDefaultValueSyntax //@[36:37) Assignment |=| @@ -1201,7 +1201,7 @@ param paramAccessingOutput string = sampleOutput //@[0:5) Identifier |param| //@[6:26) IdentifierSyntax //@[6:26) Identifier |paramAccessingOutput| -//@[27:33) TypeSyntax +//@[27:33) SimpleTypeSyntax //@[27:33) Identifier |string| //@[34:48) ParameterDefaultValueSyntax //@[34:35) Assignment |=| @@ -1227,7 +1227,7 @@ param defaultValueOneLinerCompletions string = //@[0:5) Identifier |param| //@[6:37) IdentifierSyntax //@[6:37) Identifier |defaultValueOneLinerCompletions| -//@[38:44) TypeSyntax +//@[38:44) SimpleTypeSyntax //@[38:44) Identifier |string| //@[45:47) ParameterDefaultValueSyntax //@[45:46) Assignment |=| @@ -1291,7 +1291,7 @@ param commaOne string //@[0:5) Identifier |param| //@[6:14) IdentifierSyntax //@[6:14) Identifier |commaOne| -//@[15:21) TypeSyntax +//@[15:21) SimpleTypeSyntax //@[15:21) Identifier |string| //@[21:23) NewLine |\n\n| @@ -1333,7 +1333,7 @@ param incompleteDecorators string //@[0:5) Identifier |param| //@[6:26) IdentifierSyntax //@[6:26) Identifier |incompleteDecorators| -//@[27:33) TypeSyntax +//@[27:33) SimpleTypeSyntax //@[27:33) Identifier |string| //@[33:35) NewLine |\n\n| @@ -1401,7 +1401,7 @@ param someString string //@[0:5) Identifier |param| //@[6:16) IdentifierSyntax //@[6:16) Identifier |someString| -//@[17:23) TypeSyntax +//@[17:23) SimpleTypeSyntax //@[17:23) Identifier |string| //@[23:25) NewLine |\n\n| @@ -1469,7 +1469,7 @@ param someInteger int = 20 //@[0:5) Identifier |param| //@[6:17) IdentifierSyntax //@[6:17) Identifier |someInteger| -//@[18:21) TypeSyntax +//@[18:21) SimpleTypeSyntax //@[18:21) Identifier |int| //@[22:26) ParameterDefaultValueSyntax //@[22:23) Assignment |=| @@ -1517,7 +1517,7 @@ param tooManyArguments1 int = 20 //@[0:5) Identifier |param| //@[6:23) IdentifierSyntax //@[6:23) Identifier |tooManyArguments1| -//@[24:27) TypeSyntax +//@[24:27) SimpleTypeSyntax //@[24:27) Identifier |int| //@[28:32) ParameterDefaultValueSyntax //@[28:29) Assignment |=| @@ -1581,7 +1581,7 @@ param tooManyArguments2 string //@[0:5) Identifier |param| //@[6:23) IdentifierSyntax //@[6:23) Identifier |tooManyArguments2| -//@[24:30) TypeSyntax +//@[24:30) SimpleTypeSyntax //@[24:30) Identifier |string| //@[30:32) NewLine |\n\n| @@ -1636,7 +1636,7 @@ param nonConstantInDecorator string //@[0:5) Identifier |param| //@[6:28) IdentifierSyntax //@[6:28) Identifier |nonConstantInDecorator| -//@[29:35) TypeSyntax +//@[29:35) SimpleTypeSyntax //@[29:35) Identifier |string| //@[35:37) NewLine |\n\n| @@ -1690,7 +1690,7 @@ param unaryMinusOnFunction int //@[0:5) Identifier |param| //@[6:26) IdentifierSyntax //@[6:26) Identifier |unaryMinusOnFunction| -//@[27:30) TypeSyntax +//@[27:30) SimpleTypeSyntax //@[27:30) Identifier |int| //@[30:32) NewLine |\n\n| @@ -1756,7 +1756,7 @@ param duplicateDecorators string //@[0:5) Identifier |param| //@[6:25) IdentifierSyntax //@[6:25) Identifier |duplicateDecorators| -//@[26:32) TypeSyntax +//@[26:32) SimpleTypeSyntax //@[26:32) Identifier |string| //@[32:34) NewLine |\n\n| @@ -1793,7 +1793,7 @@ param invalidLength string //@[0:5) Identifier |param| //@[6:19) IdentifierSyntax //@[6:19) Identifier |invalidLength| -//@[20:26) TypeSyntax +//@[20:26) SimpleTypeSyntax //@[20:26) Identifier |string| //@[26:28) NewLine |\n\n| @@ -1852,7 +1852,7 @@ param invalidPermutation array = [ //@[0:5) Identifier |param| //@[6:24) IdentifierSyntax //@[6:24) Identifier |invalidPermutation| -//@[25:30) TypeSyntax +//@[25:30) SimpleTypeSyntax //@[25:30) Identifier |array| //@[31:60) ParameterDefaultValueSyntax //@[31:32) Assignment |=| @@ -1934,7 +1934,7 @@ param invalidDefaultWithAllowedArrayDecorator array = true //@[0:5) Identifier |param| //@[6:45) IdentifierSyntax //@[6:45) Identifier |invalidDefaultWithAllowedArrayDecorator| -//@[46:51) TypeSyntax +//@[46:51) SimpleTypeSyntax //@[46:51) Identifier |array| //@[52:58) ParameterDefaultValueSyntax //@[52:53) Assignment |=| @@ -1942,6 +1942,69 @@ param invalidDefaultWithAllowedArrayDecorator array = true //@[54:58) TrueKeyword |true| //@[58:60) NewLine |\n\n| +param resourceTypeMissing resource +//@[0:34) ParameterDeclarationSyntax +//@[0:5) Identifier |param| +//@[6:25) IdentifierSyntax +//@[6:25) Identifier |resourceTypeMissing| +//@[26:34) ResourceTypeSyntax +//@[26:34) Identifier |resource| +//@[34:34) SkippedTriviaSyntax +//@[34:36) NewLine |\n\n| + +param invalidResourceType resource 'Some/fake' +//@[0:46) ParameterDeclarationSyntax +//@[0:5) Identifier |param| +//@[6:25) IdentifierSyntax +//@[6:25) Identifier |invalidResourceType| +//@[26:46) ResourceTypeSyntax +//@[26:34) Identifier |resource| +//@[35:46) StringSyntax +//@[35:46) StringComplete |'Some/fake'| +//@[46:48) NewLine |\n\n| + +param unknownResourceType resource 'Some/fake@2020-01-01' +//@[0:57) ParameterDeclarationSyntax +//@[0:5) Identifier |param| +//@[6:25) IdentifierSyntax +//@[6:25) Identifier |unknownResourceType| +//@[26:57) ResourceTypeSyntax +//@[26:34) Identifier |resource| +//@[35:57) StringSyntax +//@[35:57) StringComplete |'Some/fake@2020-01-01'| +//@[57:59) NewLine |\n\n| + +param invalidDefaultValueObject resource 'Microsoft.Storage/storageAccounts@2019-06-01' = {} +//@[0:92) ParameterDeclarationSyntax +//@[0:5) Identifier |param| +//@[6:31) IdentifierSyntax +//@[6:31) Identifier |invalidDefaultValueObject| +//@[32:87) ResourceTypeSyntax +//@[32:40) Identifier |resource| +//@[41:87) StringSyntax +//@[41:87) StringComplete |'Microsoft.Storage/storageAccounts@2019-06-01'| +//@[88:92) ParameterDefaultValueSyntax +//@[88:89) Assignment |=| +//@[90:92) ObjectSyntax +//@[90:91) LeftBrace |{| +//@[91:92) RightBrace |}| +//@[92:94) NewLine |\n\n| + +param invalidDefaultValueString resource 'Microsoft.Storage/storageAccounts@2019-06-01' = 'hey there' +//@[0:101) ParameterDeclarationSyntax +//@[0:5) Identifier |param| +//@[6:31) IdentifierSyntax +//@[6:31) Identifier |invalidDefaultValueString| +//@[32:87) ResourceTypeSyntax +//@[32:40) Identifier |resource| +//@[41:87) StringSyntax +//@[41:87) StringComplete |'Microsoft.Storage/storageAccounts@2019-06-01'| +//@[88:101) ParameterDefaultValueSyntax +//@[88:89) Assignment |=| +//@[90:101) StringSyntax +//@[90:101) StringComplete |'hey there'| +//@[101:103) NewLine |\n\n| + // unterminated multi-line comment //@[34:35) NewLine |\n| /* diff --git a/src/Bicep.Core.Samples/Files/InvalidParameters_LF/main.tokens.bicep b/src/Bicep.Core.Samples/Files/InvalidParameters_LF/main.tokens.bicep index 06602eb3e5a..2281fcf33d6 100644 --- a/src/Bicep.Core.Samples/Files/InvalidParameters_LF/main.tokens.bicep +++ b/src/Bicep.Core.Samples/Files/InvalidParameters_LF/main.tokens.bicep @@ -1209,6 +1209,45 @@ param invalidDefaultWithAllowedArrayDecorator array = true //@[54:58) TrueKeyword |true| //@[58:60) NewLine |\n\n| +param resourceTypeMissing resource +//@[0:5) Identifier |param| +//@[6:25) Identifier |resourceTypeMissing| +//@[26:34) Identifier |resource| +//@[34:36) NewLine |\n\n| + +param invalidResourceType resource 'Some/fake' +//@[0:5) Identifier |param| +//@[6:25) Identifier |invalidResourceType| +//@[26:34) Identifier |resource| +//@[35:46) StringComplete |'Some/fake'| +//@[46:48) NewLine |\n\n| + +param unknownResourceType resource 'Some/fake@2020-01-01' +//@[0:5) Identifier |param| +//@[6:25) Identifier |unknownResourceType| +//@[26:34) Identifier |resource| +//@[35:57) StringComplete |'Some/fake@2020-01-01'| +//@[57:59) NewLine |\n\n| + +param invalidDefaultValueObject resource 'Microsoft.Storage/storageAccounts@2019-06-01' = {} +//@[0:5) Identifier |param| +//@[6:31) Identifier |invalidDefaultValueObject| +//@[32:40) Identifier |resource| +//@[41:87) StringComplete |'Microsoft.Storage/storageAccounts@2019-06-01'| +//@[88:89) Assignment |=| +//@[90:91) LeftBrace |{| +//@[91:92) RightBrace |}| +//@[92:94) NewLine |\n\n| + +param invalidDefaultValueString resource 'Microsoft.Storage/storageAccounts@2019-06-01' = 'hey there' +//@[0:5) Identifier |param| +//@[6:31) Identifier |invalidDefaultValueString| +//@[32:40) Identifier |resource| +//@[41:87) StringComplete |'Microsoft.Storage/storageAccounts@2019-06-01'| +//@[88:89) Assignment |=| +//@[90:101) StringComplete |'hey there'| +//@[101:103) NewLine |\n\n| + // unterminated multi-line comment //@[34:35) NewLine |\n| /* diff --git a/src/Bicep.Core.Samples/Files/InvalidResources_CRLF/main.syntax.bicep b/src/Bicep.Core.Samples/Files/InvalidResources_CRLF/main.syntax.bicep index f593e4ee98d..6002080b75d 100644 --- a/src/Bicep.Core.Samples/Files/InvalidResources_CRLF/main.syntax.bicep +++ b/src/Bicep.Core.Samples/Files/InvalidResources_CRLF/main.syntax.bicep @@ -949,7 +949,7 @@ param resrefpar string = foo.id //@[0:5) Identifier |param| //@[6:15) IdentifierSyntax //@[6:15) Identifier |resrefpar| -//@[16:22) TypeSyntax +//@[16:22) SimpleTypeSyntax //@[16:22) Identifier |string| //@[23:31) ParameterDefaultValueSyntax //@[23:24) Assignment |=| @@ -967,7 +967,7 @@ output resrefout bool = bar.id //@[0:6) Identifier |output| //@[7:16) IdentifierSyntax //@[7:16) Identifier |resrefout| -//@[17:21) TypeSyntax +//@[17:21) SimpleTypeSyntax //@[17:21) Identifier |bool| //@[22:23) Assignment |=| //@[24:30) PropertyAccessSyntax @@ -8963,7 +8963,7 @@ output directRefViaOutput array = union(premiumStorages, stuffs) //@[0:6) Identifier |output| //@[7:25) IdentifierSyntax //@[7:25) Identifier |directRefViaOutput| -//@[26:31) TypeSyntax +//@[26:31) SimpleTypeSyntax //@[26:31) Identifier |array| //@[32:33) Assignment |=| //@[34:64) FunctionCallSyntax @@ -11275,7 +11275,7 @@ param dataCollectionRule object //@[0:5) Identifier |param| //@[6:24) IdentifierSyntax //@[6:24) Identifier |dataCollectionRule| -//@[25:31) TypeSyntax +//@[25:31) SimpleTypeSyntax //@[25:31) Identifier |object| //@[31:33) NewLine |\r\n| param tags object @@ -11283,7 +11283,7 @@ param tags object //@[0:5) Identifier |param| //@[6:10) IdentifierSyntax //@[6:10) Identifier |tags| -//@[11:17) TypeSyntax +//@[11:17) SimpleTypeSyntax //@[11:17) Identifier |object| //@[17:21) NewLine |\r\n\r\n| diff --git a/src/Bicep.Core.Samples/Files/LoopsIndexed_LF/main.syntax.bicep b/src/Bicep.Core.Samples/Files/LoopsIndexed_LF/main.syntax.bicep index cf112e96e65..fb18bd6fa92 100644 --- a/src/Bicep.Core.Samples/Files/LoopsIndexed_LF/main.syntax.bicep +++ b/src/Bicep.Core.Samples/Files/LoopsIndexed_LF/main.syntax.bicep @@ -3,7 +3,7 @@ param name string //@[0:5) Identifier |param| //@[6:10) IdentifierSyntax //@[6:10) Identifier |name| -//@[11:17) TypeSyntax +//@[11:17) SimpleTypeSyntax //@[11:17) Identifier |string| //@[17:18) NewLine |\n| param accounts array @@ -11,7 +11,7 @@ param accounts array //@[0:5) Identifier |param| //@[6:14) IdentifierSyntax //@[6:14) Identifier |accounts| -//@[15:20) TypeSyntax +//@[15:20) SimpleTypeSyntax //@[15:20) Identifier |array| //@[20:21) NewLine |\n| param index int @@ -19,7 +19,7 @@ param index int //@[0:5) Identifier |param| //@[6:11) IdentifierSyntax //@[6:11) Identifier |index| -//@[12:15) TypeSyntax +//@[12:15) SimpleTypeSyntax //@[12:15) Identifier |int| //@[15:17) NewLine |\n\n| @@ -637,7 +637,7 @@ output indexedCollectionBlobEndpoint string = storageAccounts[index].properties. //@[0:6) Identifier |output| //@[7:36) IdentifierSyntax //@[7:36) Identifier |indexedCollectionBlobEndpoint| -//@[37:43) TypeSyntax +//@[37:43) SimpleTypeSyntax //@[37:43) Identifier |string| //@[44:45) Assignment |=| //@[46:101) PropertyAccessSyntax @@ -667,7 +667,7 @@ output indexedCollectionName string = storageAccounts[index].name //@[0:6) Identifier |output| //@[7:28) IdentifierSyntax //@[7:28) Identifier |indexedCollectionName| -//@[29:35) TypeSyntax +//@[29:35) SimpleTypeSyntax //@[29:35) Identifier |string| //@[36:37) Assignment |=| //@[38:65) PropertyAccessSyntax @@ -689,7 +689,7 @@ output indexedCollectionId string = storageAccounts[index].id //@[0:6) Identifier |output| //@[7:26) IdentifierSyntax //@[7:26) Identifier |indexedCollectionId| -//@[27:33) TypeSyntax +//@[27:33) SimpleTypeSyntax //@[27:33) Identifier |string| //@[34:35) Assignment |=| //@[36:61) PropertyAccessSyntax @@ -711,7 +711,7 @@ output indexedCollectionType string = storageAccounts[index].type //@[0:6) Identifier |output| //@[7:28) IdentifierSyntax //@[7:28) Identifier |indexedCollectionType| -//@[29:35) TypeSyntax +//@[29:35) SimpleTypeSyntax //@[29:35) Identifier |string| //@[36:37) Assignment |=| //@[38:65) PropertyAccessSyntax @@ -733,7 +733,7 @@ output indexedCollectionVersion string = storageAccounts[index].apiVersion //@[0:6) Identifier |output| //@[7:31) IdentifierSyntax //@[7:31) Identifier |indexedCollectionVersion| -//@[32:38) TypeSyntax +//@[32:38) SimpleTypeSyntax //@[32:38) Identifier |string| //@[39:40) Assignment |=| //@[41:74) PropertyAccessSyntax @@ -758,7 +758,7 @@ output indexedCollectionIdentity object = storageAccounts[index].identity //@[0:6) Identifier |output| //@[7:32) IdentifierSyntax //@[7:32) Identifier |indexedCollectionIdentity| -//@[33:39) TypeSyntax +//@[33:39) SimpleTypeSyntax //@[33:39) Identifier |object| //@[40:41) Assignment |=| //@[42:73) PropertyAccessSyntax @@ -783,7 +783,7 @@ output indexedEndpointPair object = { //@[0:6) Identifier |output| //@[7:26) IdentifierSyntax //@[7:26) Identifier |indexedEndpointPair| -//@[27:33) TypeSyntax +//@[27:33) SimpleTypeSyntax //@[27:33) Identifier |object| //@[34:35) Assignment |=| //@[36:181) ObjectSyntax @@ -858,7 +858,7 @@ output indexViaReference string = storageAccounts[int(storageAccounts[index].pro //@[0:6) Identifier |output| //@[7:24) IdentifierSyntax //@[7:24) Identifier |indexViaReference| -//@[25:31) TypeSyntax +//@[25:31) SimpleTypeSyntax //@[25:31) Identifier |string| //@[32:33) Assignment |=| //@[34:124) PropertyAccessSyntax @@ -2288,7 +2288,7 @@ output indexedModulesName string = moduleCollectionWithSingleDependency[index].n //@[0:6) Identifier |output| //@[7:25) IdentifierSyntax //@[7:25) Identifier |indexedModulesName| -//@[26:32) TypeSyntax +//@[26:32) SimpleTypeSyntax //@[26:32) Identifier |string| //@[33:34) Assignment |=| //@[35:83) PropertyAccessSyntax @@ -2310,7 +2310,7 @@ output indexedModuleOutput string = moduleCollectionWithSingleDependency[index * //@[0:6) Identifier |output| //@[7:26) IdentifierSyntax //@[7:26) Identifier |indexedModuleOutput| -//@[27:33) TypeSyntax +//@[27:33) SimpleTypeSyntax //@[27:33) Identifier |string| //@[34:35) Assignment |=| //@[36:100) PropertyAccessSyntax @@ -2402,7 +2402,7 @@ output existingIndexedResourceName string = existingStorageAccounts[index * 0].n //@[0:6) Identifier |output| //@[7:34) IdentifierSyntax //@[7:34) Identifier |existingIndexedResourceName| -//@[35:41) TypeSyntax +//@[35:41) SimpleTypeSyntax //@[35:41) Identifier |string| //@[42:43) Assignment |=| //@[44:83) PropertyAccessSyntax @@ -2428,7 +2428,7 @@ output existingIndexedResourceId string = existingStorageAccounts[index * 1].id //@[0:6) Identifier |output| //@[7:32) IdentifierSyntax //@[7:32) Identifier |existingIndexedResourceId| -//@[33:39) TypeSyntax +//@[33:39) SimpleTypeSyntax //@[33:39) Identifier |string| //@[40:41) Assignment |=| //@[42:79) PropertyAccessSyntax @@ -2454,7 +2454,7 @@ output existingIndexedResourceType string = existingStorageAccounts[index+2].typ //@[0:6) Identifier |output| //@[7:34) IdentifierSyntax //@[7:34) Identifier |existingIndexedResourceType| -//@[35:41) TypeSyntax +//@[35:41) SimpleTypeSyntax //@[35:41) Identifier |string| //@[42:43) Assignment |=| //@[44:81) PropertyAccessSyntax @@ -2480,7 +2480,7 @@ output existingIndexedResourceApiVersion string = existingStorageAccounts[index- //@[0:6) Identifier |output| //@[7:40) IdentifierSyntax //@[7:40) Identifier |existingIndexedResourceApiVersion| -//@[41:47) TypeSyntax +//@[41:47) SimpleTypeSyntax //@[41:47) Identifier |string| //@[48:49) Assignment |=| //@[50:93) PropertyAccessSyntax @@ -2506,7 +2506,7 @@ output existingIndexedResourceLocation string = existingStorageAccounts[index/2] //@[0:6) Identifier |output| //@[7:38) IdentifierSyntax //@[7:38) Identifier |existingIndexedResourceLocation| -//@[39:45) TypeSyntax +//@[39:45) SimpleTypeSyntax //@[39:45) Identifier |string| //@[46:47) Assignment |=| //@[48:89) PropertyAccessSyntax @@ -2532,7 +2532,7 @@ output existingIndexedResourceAccessTier string = existingStorageAccounts[index% //@[0:6) Identifier |output| //@[7:40) IdentifierSyntax //@[7:40) Identifier |existingIndexedResourceAccessTier| -//@[41:47) TypeSyntax +//@[41:47) SimpleTypeSyntax //@[41:47) Identifier |string| //@[48:49) Assignment |=| //@[50:104) PropertyAccessSyntax diff --git a/src/Bicep.Core.Samples/Files/Loops_LF/main.syntax.bicep b/src/Bicep.Core.Samples/Files/Loops_LF/main.syntax.bicep index e16edbcdb0a..a45e0ef4f42 100644 --- a/src/Bicep.Core.Samples/Files/Loops_LF/main.syntax.bicep +++ b/src/Bicep.Core.Samples/Files/Loops_LF/main.syntax.bicep @@ -3,7 +3,7 @@ param name string //@[0:5) Identifier |param| //@[6:10) IdentifierSyntax //@[6:10) Identifier |name| -//@[11:17) TypeSyntax +//@[11:17) SimpleTypeSyntax //@[11:17) Identifier |string| //@[17:18) NewLine |\n| param accounts array @@ -11,7 +11,7 @@ param accounts array //@[0:5) Identifier |param| //@[6:14) IdentifierSyntax //@[6:14) Identifier |accounts| -//@[15:20) TypeSyntax +//@[15:20) SimpleTypeSyntax //@[15:20) Identifier |array| //@[20:21) NewLine |\n| param index int @@ -19,7 +19,7 @@ param index int //@[0:5) Identifier |param| //@[6:11) IdentifierSyntax //@[6:11) Identifier |index| -//@[12:15) TypeSyntax +//@[12:15) SimpleTypeSyntax //@[12:15) Identifier |int| //@[15:17) NewLine |\n\n| @@ -586,7 +586,7 @@ output indexedCollectionBlobEndpoint string = storageAccounts[index].properties. //@[0:6) Identifier |output| //@[7:36) IdentifierSyntax //@[7:36) Identifier |indexedCollectionBlobEndpoint| -//@[37:43) TypeSyntax +//@[37:43) SimpleTypeSyntax //@[37:43) Identifier |string| //@[44:45) Assignment |=| //@[46:101) PropertyAccessSyntax @@ -616,7 +616,7 @@ output indexedCollectionName string = storageAccounts[index].name //@[0:6) Identifier |output| //@[7:28) IdentifierSyntax //@[7:28) Identifier |indexedCollectionName| -//@[29:35) TypeSyntax +//@[29:35) SimpleTypeSyntax //@[29:35) Identifier |string| //@[36:37) Assignment |=| //@[38:65) PropertyAccessSyntax @@ -638,7 +638,7 @@ output indexedCollectionId string = storageAccounts[index].id //@[0:6) Identifier |output| //@[7:26) IdentifierSyntax //@[7:26) Identifier |indexedCollectionId| -//@[27:33) TypeSyntax +//@[27:33) SimpleTypeSyntax //@[27:33) Identifier |string| //@[34:35) Assignment |=| //@[36:61) PropertyAccessSyntax @@ -660,7 +660,7 @@ output indexedCollectionType string = storageAccounts[index].type //@[0:6) Identifier |output| //@[7:28) IdentifierSyntax //@[7:28) Identifier |indexedCollectionType| -//@[29:35) TypeSyntax +//@[29:35) SimpleTypeSyntax //@[29:35) Identifier |string| //@[36:37) Assignment |=| //@[38:65) PropertyAccessSyntax @@ -682,7 +682,7 @@ output indexedCollectionVersion string = storageAccounts[index].apiVersion //@[0:6) Identifier |output| //@[7:31) IdentifierSyntax //@[7:31) Identifier |indexedCollectionVersion| -//@[32:38) TypeSyntax +//@[32:38) SimpleTypeSyntax //@[32:38) Identifier |string| //@[39:40) Assignment |=| //@[41:74) PropertyAccessSyntax @@ -707,7 +707,7 @@ output indexedCollectionIdentity object = storageAccounts[index].identity //@[0:6) Identifier |output| //@[7:32) IdentifierSyntax //@[7:32) Identifier |indexedCollectionIdentity| -//@[33:39) TypeSyntax +//@[33:39) SimpleTypeSyntax //@[33:39) Identifier |object| //@[40:41) Assignment |=| //@[42:73) PropertyAccessSyntax @@ -732,7 +732,7 @@ output indexedEndpointPair object = { //@[0:6) Identifier |output| //@[7:26) IdentifierSyntax //@[7:26) Identifier |indexedEndpointPair| -//@[27:33) TypeSyntax +//@[27:33) SimpleTypeSyntax //@[27:33) Identifier |object| //@[34:35) Assignment |=| //@[36:181) ObjectSyntax @@ -807,7 +807,7 @@ output indexViaReference string = storageAccounts[int(storageAccounts[index].pro //@[0:6) Identifier |output| //@[7:24) IdentifierSyntax //@[7:24) Identifier |indexViaReference| -//@[25:31) TypeSyntax +//@[25:31) SimpleTypeSyntax //@[25:31) Identifier |string| //@[32:33) Assignment |=| //@[34:124) PropertyAccessSyntax @@ -2124,7 +2124,7 @@ output indexedModulesName string = moduleCollectionWithSingleDependency[index].n //@[0:6) Identifier |output| //@[7:25) IdentifierSyntax //@[7:25) Identifier |indexedModulesName| -//@[26:32) TypeSyntax +//@[26:32) SimpleTypeSyntax //@[26:32) Identifier |string| //@[33:34) Assignment |=| //@[35:83) PropertyAccessSyntax @@ -2146,7 +2146,7 @@ output indexedModuleOutput string = moduleCollectionWithSingleDependency[index * //@[0:6) Identifier |output| //@[7:26) IdentifierSyntax //@[7:26) Identifier |indexedModuleOutput| -//@[27:33) TypeSyntax +//@[27:33) SimpleTypeSyntax //@[27:33) Identifier |string| //@[34:35) Assignment |=| //@[36:100) PropertyAccessSyntax @@ -2227,7 +2227,7 @@ output existingIndexedResourceName string = existingStorageAccounts[index * 0].n //@[0:6) Identifier |output| //@[7:34) IdentifierSyntax //@[7:34) Identifier |existingIndexedResourceName| -//@[35:41) TypeSyntax +//@[35:41) SimpleTypeSyntax //@[35:41) Identifier |string| //@[42:43) Assignment |=| //@[44:83) PropertyAccessSyntax @@ -2253,7 +2253,7 @@ output existingIndexedResourceId string = existingStorageAccounts[index * 1].id //@[0:6) Identifier |output| //@[7:32) IdentifierSyntax //@[7:32) Identifier |existingIndexedResourceId| -//@[33:39) TypeSyntax +//@[33:39) SimpleTypeSyntax //@[33:39) Identifier |string| //@[40:41) Assignment |=| //@[42:79) PropertyAccessSyntax @@ -2279,7 +2279,7 @@ output existingIndexedResourceType string = existingStorageAccounts[index+2].typ //@[0:6) Identifier |output| //@[7:34) IdentifierSyntax //@[7:34) Identifier |existingIndexedResourceType| -//@[35:41) TypeSyntax +//@[35:41) SimpleTypeSyntax //@[35:41) Identifier |string| //@[42:43) Assignment |=| //@[44:81) PropertyAccessSyntax @@ -2305,7 +2305,7 @@ output existingIndexedResourceApiVersion string = existingStorageAccounts[index- //@[0:6) Identifier |output| //@[7:40) IdentifierSyntax //@[7:40) Identifier |existingIndexedResourceApiVersion| -//@[41:47) TypeSyntax +//@[41:47) SimpleTypeSyntax //@[41:47) Identifier |string| //@[48:49) Assignment |=| //@[50:93) PropertyAccessSyntax @@ -2331,7 +2331,7 @@ output existingIndexedResourceLocation string = existingStorageAccounts[index/2] //@[0:6) Identifier |output| //@[7:38) IdentifierSyntax //@[7:38) Identifier |existingIndexedResourceLocation| -//@[39:45) TypeSyntax +//@[39:45) SimpleTypeSyntax //@[39:45) Identifier |string| //@[46:47) Assignment |=| //@[48:89) PropertyAccessSyntax @@ -2357,7 +2357,7 @@ output existingIndexedResourceAccessTier string = existingStorageAccounts[index% //@[0:6) Identifier |output| //@[7:40) IdentifierSyntax //@[7:40) Identifier |existingIndexedResourceAccessTier| -//@[41:47) TypeSyntax +//@[41:47) SimpleTypeSyntax //@[41:47) Identifier |string| //@[48:49) Assignment |=| //@[50:104) PropertyAccessSyntax @@ -3704,7 +3704,7 @@ output lastNameServers array = filteredIndexedZones[length(accounts) - 1].proper //@[0:6) Identifier |output| //@[7:22) IdentifierSyntax //@[7:22) Identifier |lastNameServers| -//@[23:28) TypeSyntax +//@[23:28) SimpleTypeSyntax //@[23:28) Identifier |array| //@[29:30) Assignment |=| //@[31:96) PropertyAccessSyntax @@ -3830,7 +3830,7 @@ output lastModuleOutput string = filteredIndexedModules[length(accounts) - 1].ou //@[0:6) Identifier |output| //@[7:23) IdentifierSyntax //@[7:23) Identifier |lastModuleOutput| -//@[24:30) TypeSyntax +//@[24:30) SimpleTypeSyntax //@[24:30) Identifier |string| //@[31:32) Assignment |=| //@[33:94) PropertyAccessSyntax diff --git a/src/Bicep.Core.Samples/Files/ModulesSubscription_LF/main.syntax.bicep b/src/Bicep.Core.Samples/Files/ModulesSubscription_LF/main.syntax.bicep index 352d3689943..0cc42019fe1 100644 --- a/src/Bicep.Core.Samples/Files/ModulesSubscription_LF/main.syntax.bicep +++ b/src/Bicep.Core.Samples/Files/ModulesSubscription_LF/main.syntax.bicep @@ -11,7 +11,7 @@ param prefix string = 'majastrz' //@[0:5) Identifier |param| //@[6:12) IdentifierSyntax //@[6:12) Identifier |prefix| -//@[13:19) TypeSyntax +//@[13:19) SimpleTypeSyntax //@[13:19) Identifier |string| //@[20:32) ParameterDefaultValueSyntax //@[20:21) Assignment |=| diff --git a/src/Bicep.Core.Samples/Files/ModulesWithScopes_LF/main.syntax.bicep b/src/Bicep.Core.Samples/Files/ModulesWithScopes_LF/main.syntax.bicep index 1e61c3335c2..3dacf9e8b54 100644 --- a/src/Bicep.Core.Samples/Files/ModulesWithScopes_LF/main.syntax.bicep +++ b/src/Bicep.Core.Samples/Files/ModulesWithScopes_LF/main.syntax.bicep @@ -212,7 +212,7 @@ output myManagementGroupOutput string = myManagementGroupMod.outputs.myOutput //@[0:6) Identifier |output| //@[7:30) IdentifierSyntax //@[7:30) Identifier |myManagementGroupOutput| -//@[31:37) TypeSyntax +//@[31:37) SimpleTypeSyntax //@[31:37) Identifier |string| //@[38:39) Assignment |=| //@[40:77) PropertyAccessSyntax @@ -232,7 +232,7 @@ output mySubscriptionOutput string = mySubscriptionMod.outputs.myOutput //@[0:6) Identifier |output| //@[7:27) IdentifierSyntax //@[7:27) Identifier |mySubscriptionOutput| -//@[28:34) TypeSyntax +//@[28:34) SimpleTypeSyntax //@[28:34) Identifier |string| //@[35:36) Assignment |=| //@[37:71) PropertyAccessSyntax diff --git a/src/Bicep.Core.Samples/Files/Modules_CRLF/main.syntax.bicep b/src/Bicep.Core.Samples/Files/Modules_CRLF/main.syntax.bicep index d1d363602dc..1115290edf7 100644 --- a/src/Bicep.Core.Samples/Files/Modules_CRLF/main.syntax.bicep +++ b/src/Bicep.Core.Samples/Files/Modules_CRLF/main.syntax.bicep @@ -21,7 +21,7 @@ param deployTimeSuffix string = newGuid() //@[0:5) Identifier |param| //@[6:22) IdentifierSyntax //@[6:22) Identifier |deployTimeSuffix| -//@[23:29) TypeSyntax +//@[23:29) SimpleTypeSyntax //@[23:29) Identifier |string| //@[30:41) ParameterDefaultValueSyntax //@[30:31) Assignment |=| @@ -929,7 +929,7 @@ output stringOutputA string = modATest.outputs.stringOutputA //@[0:6) Identifier |output| //@[7:20) IdentifierSyntax //@[7:20) Identifier |stringOutputA| -//@[21:27) TypeSyntax +//@[21:27) SimpleTypeSyntax //@[21:27) Identifier |string| //@[28:29) Assignment |=| //@[30:60) PropertyAccessSyntax @@ -949,7 +949,7 @@ output stringOutputB string = modATest.outputs.stringOutputB //@[0:6) Identifier |output| //@[7:20) IdentifierSyntax //@[7:20) Identifier |stringOutputB| -//@[21:27) TypeSyntax +//@[21:27) SimpleTypeSyntax //@[21:27) Identifier |string| //@[28:29) Assignment |=| //@[30:60) PropertyAccessSyntax @@ -969,7 +969,7 @@ output objOutput object = modATest.outputs.objOutput //@[0:6) Identifier |output| //@[7:16) IdentifierSyntax //@[7:16) Identifier |objOutput| -//@[17:23) TypeSyntax +//@[17:23) SimpleTypeSyntax //@[17:23) Identifier |object| //@[24:25) Assignment |=| //@[26:52) PropertyAccessSyntax @@ -989,7 +989,7 @@ output arrayOutput array = modATest.outputs.arrayOutput //@[0:6) Identifier |output| //@[7:18) IdentifierSyntax //@[7:18) Identifier |arrayOutput| -//@[19:24) TypeSyntax +//@[19:24) SimpleTypeSyntax //@[19:24) Identifier |array| //@[25:26) Assignment |=| //@[27:55) PropertyAccessSyntax @@ -1009,7 +1009,7 @@ output modCalculatedNameOutput object = moduleWithCalculatedName.outputs.outputO //@[0:6) Identifier |output| //@[7:30) IdentifierSyntax //@[7:30) Identifier |modCalculatedNameOutput| -//@[31:37) TypeSyntax +//@[31:37) SimpleTypeSyntax //@[31:37) Identifier |object| //@[38:39) Assignment |=| //@[40:82) PropertyAccessSyntax diff --git a/src/Bicep.Core.Samples/Files/NestedResources_LF/main.syntax.bicep b/src/Bicep.Core.Samples/Files/NestedResources_LF/main.syntax.bicep index 76ff7905e5e..ca2ef7ff67a 100644 --- a/src/Bicep.Core.Samples/Files/NestedResources_LF/main.syntax.bicep +++ b/src/Bicep.Core.Samples/Files/NestedResources_LF/main.syntax.bicep @@ -245,7 +245,7 @@ output referenceBasicChild string = basicParent::basicChild.properties.size //@[0:6) Identifier |output| //@[7:26) IdentifierSyntax //@[7:26) Identifier |referenceBasicChild| -//@[27:33) TypeSyntax +//@[27:33) SimpleTypeSyntax //@[27:33) Identifier |string| //@[34:35) Assignment |=| //@[36:75) PropertyAccessSyntax @@ -271,7 +271,7 @@ output referenceBasicGrandchild string = basicParent::basicChild::basicGrandchil //@[0:6) Identifier |output| //@[7:31) IdentifierSyntax //@[7:31) Identifier |referenceBasicGrandchild| -//@[32:38) TypeSyntax +//@[32:38) SimpleTypeSyntax //@[32:38) Identifier |string| //@[39:40) Assignment |=| //@[41:98) PropertyAccessSyntax @@ -416,7 +416,7 @@ param createParent bool //@[0:5) Identifier |param| //@[6:18) IdentifierSyntax //@[6:18) Identifier |createParent| -//@[19:23) TypeSyntax +//@[19:23) SimpleTypeSyntax //@[19:23) Identifier |bool| //@[23:24) NewLine |\n| param createChild bool @@ -424,7 +424,7 @@ param createChild bool //@[0:5) Identifier |param| //@[6:17) IdentifierSyntax //@[6:17) Identifier |createChild| -//@[18:22) TypeSyntax +//@[18:22) SimpleTypeSyntax //@[18:22) Identifier |bool| //@[22:23) NewLine |\n| param createGrandchild bool @@ -432,7 +432,7 @@ param createGrandchild bool //@[0:5) Identifier |param| //@[6:22) IdentifierSyntax //@[6:22) Identifier |createGrandchild| -//@[23:27) TypeSyntax +//@[23:27) SimpleTypeSyntax //@[23:27) Identifier |bool| //@[27:28) NewLine |\n| resource conditionParent 'My.Rp/parentType@2020-12-01' = if (createParent) { @@ -658,7 +658,7 @@ output loopChildOutput string = loopParent::loopChild[0].name //@[0:6) Identifier |output| //@[7:22) IdentifierSyntax //@[7:22) Identifier |loopChildOutput| -//@[23:29) TypeSyntax +//@[23:29) SimpleTypeSyntax //@[23:29) Identifier |string| //@[30:31) Assignment |=| //@[32:61) PropertyAccessSyntax diff --git a/src/Bicep.Core.Samples/Files/Outputs_CRLF/main.syntax.bicep b/src/Bicep.Core.Samples/Files/Outputs_CRLF/main.syntax.bicep index e30d876d4ab..42576c04205 100644 --- a/src/Bicep.Core.Samples/Files/Outputs_CRLF/main.syntax.bicep +++ b/src/Bicep.Core.Samples/Files/Outputs_CRLF/main.syntax.bicep @@ -21,7 +21,7 @@ output myStr string = 'hello' //@[0:6) Identifier |output| //@[7:12) IdentifierSyntax //@[7:12) Identifier |myStr| -//@[13:19) TypeSyntax +//@[13:19) SimpleTypeSyntax //@[13:19) Identifier |string| //@[20:21) Assignment |=| //@[22:29) StringSyntax @@ -49,7 +49,7 @@ output myInt int = 7 //@[0:6) Identifier |output| //@[7:12) IdentifierSyntax //@[7:12) Identifier |myInt| -//@[13:16) TypeSyntax +//@[13:16) SimpleTypeSyntax //@[13:16) Identifier |int| //@[17:18) Assignment |=| //@[19:20) IntegerLiteralSyntax @@ -60,7 +60,7 @@ output myOtherInt int = 20 / 13 + 80 % -4 //@[0:6) Identifier |output| //@[7:17) IdentifierSyntax //@[7:17) Identifier |myOtherInt| -//@[18:21) TypeSyntax +//@[18:21) SimpleTypeSyntax //@[18:21) Identifier |int| //@[22:23) Assignment |=| //@[24:41) BinaryOperationSyntax @@ -102,7 +102,7 @@ output myBool bool = !false //@[0:6) Identifier |output| //@[7:13) IdentifierSyntax //@[7:13) Identifier |myBool| -//@[14:18) TypeSyntax +//@[14:18) SimpleTypeSyntax //@[14:18) Identifier |bool| //@[19:20) Assignment |=| //@[21:27) UnaryOperationSyntax @@ -115,7 +115,7 @@ output myOtherBool bool = true //@[0:6) Identifier |output| //@[7:18) IdentifierSyntax //@[7:18) Identifier |myOtherBool| -//@[19:23) TypeSyntax +//@[19:23) SimpleTypeSyntax //@[19:23) Identifier |bool| //@[24:25) Assignment |=| //@[26:30) BooleanLiteralSyntax @@ -143,7 +143,7 @@ output suchEmpty array = [ //@[0:6) Identifier |output| //@[7:16) IdentifierSyntax //@[7:16) Identifier |suchEmpty| -//@[17:22) TypeSyntax +//@[17:22) SimpleTypeSyntax //@[17:22) Identifier |array| //@[23:24) Assignment |=| //@[25:29) ArraySyntax @@ -158,7 +158,7 @@ output suchEmpty2 object = { //@[0:6) Identifier |output| //@[7:17) IdentifierSyntax //@[7:17) Identifier |suchEmpty2| -//@[18:24) TypeSyntax +//@[18:24) SimpleTypeSyntax //@[18:24) Identifier |object| //@[25:26) Assignment |=| //@[27:31) ObjectSyntax @@ -189,7 +189,7 @@ output obj object = { //@[0:6) Identifier |output| //@[7:10) IdentifierSyntax //@[7:10) Identifier |obj| -//@[11:17) TypeSyntax +//@[11:17) SimpleTypeSyntax //@[11:17) Identifier |object| //@[18:19) Assignment |=| //@[20:178) ObjectSyntax @@ -302,7 +302,7 @@ output myArr array = [ //@[0:6) Identifier |output| //@[7:12) IdentifierSyntax //@[7:12) Identifier |myArr| -//@[13:18) TypeSyntax +//@[13:18) SimpleTypeSyntax //@[13:18) Identifier |array| //@[19:20) Assignment |=| //@[21:74) ArraySyntax @@ -339,7 +339,7 @@ output rgLocation string = resourceGroup().location //@[0:6) Identifier |output| //@[7:17) IdentifierSyntax //@[7:17) Identifier |rgLocation| -//@[18:24) TypeSyntax +//@[18:24) SimpleTypeSyntax //@[18:24) Identifier |string| //@[25:26) Assignment |=| //@[27:51) PropertyAccessSyntax @@ -358,7 +358,7 @@ output isWestUs bool = resourceGroup().location != 'westus' ? false : true //@[0:6) Identifier |output| //@[7:15) IdentifierSyntax //@[7:15) Identifier |isWestUs| -//@[16:20) TypeSyntax +//@[16:20) SimpleTypeSyntax //@[16:20) Identifier |bool| //@[21:22) Assignment |=| //@[23:74) TernaryOperationSyntax @@ -388,7 +388,7 @@ output expressionBasedIndexer string = { //@[0:6) Identifier |output| //@[7:29) IdentifierSyntax //@[7:29) Identifier |expressionBasedIndexer| -//@[30:36) TypeSyntax +//@[30:36) SimpleTypeSyntax //@[30:36) Identifier |string| //@[37:38) Assignment |=| //@[39:140) PropertyAccessSyntax @@ -491,7 +491,7 @@ output primaryKey string = listKeys(resourceId('Mock.RP/type', 'nigel'), '2020-0 //@[0:6) Identifier |output| //@[7:17) IdentifierSyntax //@[7:17) Identifier |primaryKey| -//@[18:24) TypeSyntax +//@[18:24) SimpleTypeSyntax //@[18:24) Identifier |string| //@[25:26) Assignment |=| //@[27:97) PropertyAccessSyntax @@ -526,7 +526,7 @@ output secondaryKey string = secondaryKeyIntermediateVar //@[0:6) Identifier |output| //@[7:19) IdentifierSyntax //@[7:19) Identifier |secondaryKey| -//@[20:26) TypeSyntax +//@[20:26) SimpleTypeSyntax //@[20:26) Identifier |string| //@[27:28) Assignment |=| //@[29:56) VariableAccessSyntax @@ -548,7 +548,7 @@ param paramWithOverlappingOutput string //@[0:5) Identifier |param| //@[6:32) IdentifierSyntax //@[6:32) Identifier |paramWithOverlappingOutput| -//@[33:39) TypeSyntax +//@[33:39) SimpleTypeSyntax //@[33:39) Identifier |string| //@[39:43) NewLine |\r\n\r\n| @@ -557,7 +557,7 @@ output varWithOverlappingOutput string = varWithOverlappingOutput //@[0:6) Identifier |output| //@[7:31) IdentifierSyntax //@[7:31) Identifier |varWithOverlappingOutput| -//@[32:38) TypeSyntax +//@[32:38) SimpleTypeSyntax //@[32:38) Identifier |string| //@[39:40) Assignment |=| //@[41:65) VariableAccessSyntax @@ -569,7 +569,7 @@ output paramWithOverlappingOutput string = paramWithOverlappingOutput //@[0:6) Identifier |output| //@[7:33) IdentifierSyntax //@[7:33) Identifier |paramWithOverlappingOutput| -//@[34:40) TypeSyntax +//@[34:40) SimpleTypeSyntax //@[34:40) Identifier |string| //@[41:42) Assignment |=| //@[43:69) VariableAccessSyntax @@ -584,7 +584,7 @@ output generatedArray array = [for i in range(0,10): i] //@[0:6) Identifier |output| //@[7:21) IdentifierSyntax //@[7:21) Identifier |generatedArray| -//@[22:27) TypeSyntax +//@[22:27) SimpleTypeSyntax //@[22:27) Identifier |array| //@[28:29) Assignment |=| //@[30:55) ForSyntax diff --git a/src/Bicep.Core.Samples/Files/Parameters_CRLF/main.bicep b/src/Bicep.Core.Samples/Files/Parameters_CRLF/main.bicep index 3aaca2f0358..9b5ca2fec26 100644 --- a/src/Bicep.Core.Samples/Files/Parameters_CRLF/main.bicep +++ b/src/Bicep.Core.Samples/Files/Parameters_CRLF/main.bicep @@ -187,3 +187,9 @@ param decoratedArray array = [ utcNow() newGuid() ] + +param resourceType resource 'Microsoft.Storage/storageAccounts@2019-06-01' + +@secure() +@sys.description('This is my resource, it is my favorite one') +param reallySecureResourceType resource 'Microsoft.Storage/storageAccounts@2019-06-01' diff --git a/src/Bicep.Core.Samples/Files/Parameters_CRLF/main.diagnostics.bicep b/src/Bicep.Core.Samples/Files/Parameters_CRLF/main.diagnostics.bicep index aa5ac5851d8..aa6672992dd 100644 --- a/src/Bicep.Core.Samples/Files/Parameters_CRLF/main.diagnostics.bicep +++ b/src/Bicep.Core.Samples/Files/Parameters_CRLF/main.diagnostics.bicep @@ -217,3 +217,11 @@ param decoratedArray array = [ newGuid() ] +param resourceType resource 'Microsoft.Storage/storageAccounts@2019-06-01' +//@[6:18) [no-unused-params (Warning)] Parameter "resourceType" is declared but never used. (CodeDescription: bicep core(https://aka.ms/bicep/linter/no-unused-params)) |resourceType| + +@secure() +@sys.description('This is my resource, it is my favorite one') +param reallySecureResourceType resource 'Microsoft.Storage/storageAccounts@2019-06-01' +//@[6:30) [no-unused-params (Warning)] Parameter "reallySecureResourceType" is declared but never used. (CodeDescription: bicep core(https://aka.ms/bicep/linter/no-unused-params)) |reallySecureResourceType| + diff --git a/src/Bicep.Core.Samples/Files/Parameters_CRLF/main.formatted.bicep b/src/Bicep.Core.Samples/Files/Parameters_CRLF/main.formatted.bicep index 979c67d2473..9c8e144158e 100644 --- a/src/Bicep.Core.Samples/Files/Parameters_CRLF/main.formatted.bicep +++ b/src/Bicep.Core.Samples/Files/Parameters_CRLF/main.formatted.bicep @@ -184,3 +184,9 @@ param decoratedArray array = [ utcNow() newGuid() ] + +param resourceType resource 'Microsoft.Storage/storageAccounts@2019-06-01' + +@secure() +@sys.description('This is my resource, it is my favorite one') +param reallySecureResourceType resource 'Microsoft.Storage/storageAccounts@2019-06-01' diff --git a/src/Bicep.Core.Samples/Files/Parameters_CRLF/main.json b/src/Bicep.Core.Samples/Files/Parameters_CRLF/main.json index 72c78be7d58..accad7ee4b4 100644 --- a/src/Bicep.Core.Samples/Files/Parameters_CRLF/main.json +++ b/src/Bicep.Core.Samples/Files/Parameters_CRLF/main.json @@ -5,7 +5,7 @@ "_generator": { "name": "bicep", "version": "dev", - "templateHash": "2537872389677377067" + "templateHash": "3862843593872390144" } }, "parameters": { @@ -220,6 +220,19 @@ "description": "An array." }, "maxLength": 20 + }, + "resourceType": { + "type": "string", + "metadata": { + "resourceType": "Microsoft.Storage/storageAccounts@2019-06-01" + } + }, + "reallySecureResourceType": { + "type": "string", + "metadata": { + "resourceType": "Microsoft.Storage/storageAccounts@2019-06-01", + "description": "This is my resource, it is my favorite one" + } } }, "functions": [], diff --git a/src/Bicep.Core.Samples/Files/Parameters_CRLF/main.symbolicnames.json b/src/Bicep.Core.Samples/Files/Parameters_CRLF/main.symbolicnames.json index c208105e259..ff000c23a50 100644 --- a/src/Bicep.Core.Samples/Files/Parameters_CRLF/main.symbolicnames.json +++ b/src/Bicep.Core.Samples/Files/Parameters_CRLF/main.symbolicnames.json @@ -7,7 +7,7 @@ "_generator": { "name": "bicep", "version": "dev", - "templateHash": "1604298324060108067" + "templateHash": "6057503138819674819" } }, "parameters": { @@ -222,6 +222,19 @@ "description": "An array." }, "maxLength": 20 + }, + "resourceType": { + "type": "string", + "metadata": { + "resourceType": "Microsoft.Storage/storageAccounts@2019-06-01" + } + }, + "reallySecureResourceType": { + "type": "string", + "metadata": { + "resourceType": "Microsoft.Storage/storageAccounts@2019-06-01", + "description": "This is my resource, it is my favorite one" + } } }, "functions": [], diff --git a/src/Bicep.Core.Samples/Files/Parameters_CRLF/main.symbols.bicep b/src/Bicep.Core.Samples/Files/Parameters_CRLF/main.symbols.bicep index 1a0cb5534ff..a2e234d54cd 100644 --- a/src/Bicep.Core.Samples/Files/Parameters_CRLF/main.symbols.bicep +++ b/src/Bicep.Core.Samples/Files/Parameters_CRLF/main.symbols.bicep @@ -217,3 +217,11 @@ param decoratedArray array = [ newGuid() ] +param resourceType resource 'Microsoft.Storage/storageAccounts@2019-06-01' +//@[6:18) Parameter resourceType. Type: Microsoft.Storage/storageAccounts@2019-06-01. Declaration start char: 0, length: 74 + +@secure() +@sys.description('This is my resource, it is my favorite one') +param reallySecureResourceType resource 'Microsoft.Storage/storageAccounts@2019-06-01' +//@[6:30) Parameter reallySecureResourceType. Type: Microsoft.Storage/storageAccounts@2019-06-01. Declaration start char: 0, length: 161 + diff --git a/src/Bicep.Core.Samples/Files/Parameters_CRLF/main.syntax.bicep b/src/Bicep.Core.Samples/Files/Parameters_CRLF/main.syntax.bicep index 153e851ddb3..562fc5f62ed 100644 --- a/src/Bicep.Core.Samples/Files/Parameters_CRLF/main.syntax.bicep +++ b/src/Bicep.Core.Samples/Files/Parameters_CRLF/main.syntax.bicep @@ -10,7 +10,7 @@ param myString string //@[0:5) Identifier |param| //@[6:14) IdentifierSyntax //@[6:14) Identifier |myString| -//@[15:21) TypeSyntax +//@[15:21) SimpleTypeSyntax //@[15:21) Identifier |string| //@[21:23) NewLine |\r\n| param myInt int @@ -18,7 +18,7 @@ param myInt int //@[0:5) Identifier |param| //@[6:11) IdentifierSyntax //@[6:11) Identifier |myInt| -//@[12:15) TypeSyntax +//@[12:15) SimpleTypeSyntax //@[12:15) Identifier |int| //@[15:17) NewLine |\r\n| param myBool bool @@ -26,7 +26,7 @@ param myBool bool //@[0:5) Identifier |param| //@[6:12) IdentifierSyntax //@[6:12) Identifier |myBool| -//@[13:17) TypeSyntax +//@[13:17) SimpleTypeSyntax //@[13:17) Identifier |bool| //@[17:21) NewLine |\r\n\r\n| @@ -37,7 +37,7 @@ param myString2 string = 'string value' //@[0:5) Identifier |param| //@[6:15) IdentifierSyntax //@[6:15) Identifier |myString2| -//@[16:22) TypeSyntax +//@[16:22) SimpleTypeSyntax //@[16:22) Identifier |string| //@[23:39) ParameterDefaultValueSyntax //@[23:24) Assignment |=| @@ -49,7 +49,7 @@ param myInt2 int = 42 //@[0:5) Identifier |param| //@[6:12) IdentifierSyntax //@[6:12) Identifier |myInt2| -//@[13:16) TypeSyntax +//@[13:16) SimpleTypeSyntax //@[13:16) Identifier |int| //@[17:21) ParameterDefaultValueSyntax //@[17:18) Assignment |=| @@ -61,7 +61,7 @@ param myTruth bool = true //@[0:5) Identifier |param| //@[6:13) IdentifierSyntax //@[6:13) Identifier |myTruth| -//@[14:18) TypeSyntax +//@[14:18) SimpleTypeSyntax //@[14:18) Identifier |bool| //@[19:25) ParameterDefaultValueSyntax //@[19:20) Assignment |=| @@ -73,7 +73,7 @@ param myFalsehood bool = false //@[0:5) Identifier |param| //@[6:17) IdentifierSyntax //@[6:17) Identifier |myFalsehood| -//@[18:22) TypeSyntax +//@[18:22) SimpleTypeSyntax //@[18:22) Identifier |bool| //@[23:30) ParameterDefaultValueSyntax //@[23:24) Assignment |=| @@ -85,7 +85,7 @@ param myEscapedString string = 'First line\r\nSecond\ttabbed\tline' //@[0:5) Identifier |param| //@[6:21) IdentifierSyntax //@[6:21) Identifier |myEscapedString| -//@[22:28) TypeSyntax +//@[22:28) SimpleTypeSyntax //@[22:28) Identifier |string| //@[29:67) ParameterDefaultValueSyntax //@[29:30) Assignment |=| @@ -100,7 +100,7 @@ param foo object = { //@[0:5) Identifier |param| //@[6:9) IdentifierSyntax //@[6:9) Identifier |foo| -//@[10:16) TypeSyntax +//@[10:16) SimpleTypeSyntax //@[10:16) Identifier |object| //@[17:253) ParameterDefaultValueSyntax //@[17:18) Assignment |=| @@ -232,7 +232,7 @@ param myArrayParam array = [ //@[0:5) Identifier |param| //@[6:18) IdentifierSyntax //@[6:18) Identifier |myArrayParam| -//@[19:24) TypeSyntax +//@[19:24) SimpleTypeSyntax //@[19:24) Identifier |array| //@[25:52) ParameterDefaultValueSyntax //@[25:26) Assignment |=| @@ -274,7 +274,7 @@ param password string //@[0:5) Identifier |param| //@[6:14) IdentifierSyntax //@[6:14) Identifier |password| -//@[15:21) TypeSyntax +//@[15:21) SimpleTypeSyntax //@[15:21) Identifier |string| //@[21:25) NewLine |\r\n\r\n| @@ -294,7 +294,7 @@ param secretObject object //@[0:5) Identifier |param| //@[6:18) IdentifierSyntax //@[6:18) Identifier |secretObject| -//@[19:25) TypeSyntax +//@[19:25) SimpleTypeSyntax //@[19:25) Identifier |object| //@[25:29) NewLine |\r\n\r\n| @@ -330,7 +330,7 @@ param storageSku string //@[0:5) Identifier |param| //@[6:16) IdentifierSyntax //@[6:16) Identifier |storageSku| -//@[17:23) TypeSyntax +//@[17:23) SimpleTypeSyntax //@[17:23) Identifier |string| //@[23:27) NewLine |\r\n\r\n| @@ -365,7 +365,7 @@ param storageName string //@[0:5) Identifier |param| //@[6:17) IdentifierSyntax //@[6:17) Identifier |storageName| -//@[18:24) TypeSyntax +//@[18:24) SimpleTypeSyntax //@[18:24) Identifier |string| //@[24:28) NewLine |\r\n\r\n| @@ -400,7 +400,7 @@ param someArray array //@[0:5) Identifier |param| //@[6:15) IdentifierSyntax //@[6:15) Identifier |someArray| -//@[16:21) TypeSyntax +//@[16:21) SimpleTypeSyntax //@[16:21) Identifier |array| //@[21:25) NewLine |\r\n\r\n| @@ -424,7 +424,7 @@ param emptyMetadata string //@[0:5) Identifier |param| //@[6:19) IdentifierSyntax //@[6:19) Identifier |emptyMetadata| -//@[20:26) TypeSyntax +//@[20:26) SimpleTypeSyntax //@[20:26) Identifier |string| //@[26:30) NewLine |\r\n\r\n| @@ -458,7 +458,7 @@ param description string //@[0:5) Identifier |param| //@[6:17) IdentifierSyntax //@[6:17) Identifier |description| -//@[18:24) TypeSyntax +//@[18:24) SimpleTypeSyntax //@[18:24) Identifier |string| //@[24:28) NewLine |\r\n\r\n| @@ -483,7 +483,7 @@ param description2 string //@[0:5) Identifier |param| //@[6:18) IdentifierSyntax //@[6:18) Identifier |description2| -//@[19:25) TypeSyntax +//@[19:25) SimpleTypeSyntax //@[19:25) Identifier |string| //@[25:29) NewLine |\r\n\r\n| @@ -563,7 +563,7 @@ param additionalMetadata string //@[0:5) Identifier |param| //@[6:24) IdentifierSyntax //@[6:24) Identifier |additionalMetadata| -//@[25:31) TypeSyntax +//@[25:31) SimpleTypeSyntax //@[25:31) Identifier |string| //@[31:35) NewLine |\r\n\r\n| @@ -660,7 +660,7 @@ param someParameter string //@[0:5) Identifier |param| //@[6:19) IdentifierSyntax //@[6:19) Identifier |someParameter| -//@[20:26) TypeSyntax +//@[20:26) SimpleTypeSyntax //@[20:26) Identifier |string| //@[26:30) NewLine |\r\n\r\n| @@ -669,7 +669,7 @@ param defaultExpression bool = 18 != (true || false) //@[0:5) Identifier |param| //@[6:23) IdentifierSyntax //@[6:23) Identifier |defaultExpression| -//@[24:28) TypeSyntax +//@[24:28) SimpleTypeSyntax //@[24:28) Identifier |bool| //@[29:52) ParameterDefaultValueSyntax //@[29:30) Assignment |=| @@ -718,7 +718,7 @@ param stringLiteral string //@[0:5) Identifier |param| //@[6:19) IdentifierSyntax //@[6:19) Identifier |stringLiteral| -//@[20:26) TypeSyntax +//@[20:26) SimpleTypeSyntax //@[20:26) Identifier |string| //@[26:30) NewLine |\r\n\r\n| @@ -757,7 +757,7 @@ param stringLiteralWithAllowedValuesSuperset string = stringLiteral //@[0:5) Identifier |param| //@[6:44) IdentifierSyntax //@[6:44) Identifier |stringLiteralWithAllowedValuesSuperset| -//@[45:51) TypeSyntax +//@[45:51) SimpleTypeSyntax //@[45:51) Identifier |string| //@[52:67) ParameterDefaultValueSyntax //@[52:53) Assignment |=| @@ -829,7 +829,7 @@ param decoratedString string //@[0:5) Identifier |param| //@[6:21) IdentifierSyntax //@[6:21) Identifier |decoratedString| -//@[22:28) TypeSyntax +//@[22:28) SimpleTypeSyntax //@[22:28) Identifier |string| //@[28:32) NewLine |\r\n\r\n| @@ -850,7 +850,7 @@ param decoratedInt int = 123 //@[0:5) Identifier |param| //@[6:18) IdentifierSyntax //@[6:18) Identifier |decoratedInt| -//@[19:22) TypeSyntax +//@[19:22) SimpleTypeSyntax //@[19:22) Identifier |int| //@[23:28) ParameterDefaultValueSyntax //@[23:24) Assignment |=| @@ -893,7 +893,7 @@ param negativeValues int //@[0:5) Identifier |param| //@[6:20) IdentifierSyntax //@[6:20) Identifier |negativeValues| -//@[21:24) TypeSyntax +//@[21:24) SimpleTypeSyntax //@[21:24) Identifier |int| //@[24:28) NewLine |\r\n\r\n| @@ -976,7 +976,7 @@ param decoratedBool bool = (true && false) != true //@[0:5) Identifier |param| //@[6:19) IdentifierSyntax //@[6:19) Identifier |decoratedBool| -//@[20:24) TypeSyntax +//@[20:24) SimpleTypeSyntax //@[20:24) Identifier |bool| //@[25:50) ParameterDefaultValueSyntax //@[25:26) Assignment |=| @@ -1009,7 +1009,7 @@ param decoratedObject object = { //@[0:5) Identifier |param| //@[6:21) IdentifierSyntax //@[6:21) Identifier |decoratedObject| -//@[22:28) TypeSyntax +//@[22:28) SimpleTypeSyntax //@[22:28) Identifier |object| //@[29:265) ParameterDefaultValueSyntax //@[29:30) Assignment |=| @@ -1198,7 +1198,7 @@ param decoratedArray array = [ //@[0:5) Identifier |param| //@[6:20) IdentifierSyntax //@[6:20) Identifier |decoratedArray| -//@[21:26) TypeSyntax +//@[21:26) SimpleTypeSyntax //@[21:26) Identifier |array| //@[27:62) ParameterDefaultValueSyntax //@[27:28) Assignment |=| @@ -1223,6 +1223,53 @@ param decoratedArray array = [ //@[13:15) NewLine |\r\n| ] //@[0:1) RightSquare |]| -//@[1:3) NewLine |\r\n| +//@[1:5) NewLine |\r\n\r\n| + +param resourceType resource 'Microsoft.Storage/storageAccounts@2019-06-01' +//@[0:74) ParameterDeclarationSyntax +//@[0:5) Identifier |param| +//@[6:18) IdentifierSyntax +//@[6:18) Identifier |resourceType| +//@[19:74) ResourceTypeSyntax +//@[19:27) Identifier |resource| +//@[28:74) StringSyntax +//@[28:74) StringComplete |'Microsoft.Storage/storageAccounts@2019-06-01'| +//@[74:78) NewLine |\r\n\r\n| + +@secure() +//@[0:161) ParameterDeclarationSyntax +//@[0:9) DecoratorSyntax +//@[0:1) At |@| +//@[1:9) FunctionCallSyntax +//@[1:7) IdentifierSyntax +//@[1:7) Identifier |secure| +//@[7:8) LeftParen |(| +//@[8:9) RightParen |)| +//@[9:11) NewLine |\r\n| +@sys.description('This is my resource, it is my favorite one') +//@[0:62) DecoratorSyntax +//@[0:1) At |@| +//@[1:62) InstanceFunctionCallSyntax +//@[1:4) VariableAccessSyntax +//@[1:4) IdentifierSyntax +//@[1:4) Identifier |sys| +//@[4:5) Dot |.| +//@[5:16) IdentifierSyntax +//@[5:16) Identifier |description| +//@[16:17) LeftParen |(| +//@[17:61) FunctionArgumentSyntax +//@[17:61) StringSyntax +//@[17:61) StringComplete |'This is my resource, it is my favorite one'| +//@[61:62) RightParen |)| +//@[62:64) NewLine |\r\n| +param reallySecureResourceType resource 'Microsoft.Storage/storageAccounts@2019-06-01' +//@[0:5) Identifier |param| +//@[6:30) IdentifierSyntax +//@[6:30) Identifier |reallySecureResourceType| +//@[31:86) ResourceTypeSyntax +//@[31:39) Identifier |resource| +//@[40:86) StringSyntax +//@[40:86) StringComplete |'Microsoft.Storage/storageAccounts@2019-06-01'| +//@[86:88) NewLine |\r\n| //@[0:0) EndOfFile || diff --git a/src/Bicep.Core.Samples/Files/Parameters_CRLF/main.tokens.bicep b/src/Bicep.Core.Samples/Files/Parameters_CRLF/main.tokens.bicep index 4adc03b92e4..2c06cf1107d 100644 --- a/src/Bicep.Core.Samples/Files/Parameters_CRLF/main.tokens.bicep +++ b/src/Bicep.Core.Samples/Files/Parameters_CRLF/main.tokens.bicep @@ -788,6 +788,35 @@ param decoratedArray array = [ //@[13:15) NewLine |\r\n| ] //@[0:1) RightSquare |]| -//@[1:3) NewLine |\r\n| +//@[1:5) NewLine |\r\n\r\n| + +param resourceType resource 'Microsoft.Storage/storageAccounts@2019-06-01' +//@[0:5) Identifier |param| +//@[6:18) Identifier |resourceType| +//@[19:27) Identifier |resource| +//@[28:74) StringComplete |'Microsoft.Storage/storageAccounts@2019-06-01'| +//@[74:78) NewLine |\r\n\r\n| + +@secure() +//@[0:1) At |@| +//@[1:7) Identifier |secure| +//@[7:8) LeftParen |(| +//@[8:9) RightParen |)| +//@[9:11) NewLine |\r\n| +@sys.description('This is my resource, it is my favorite one') +//@[0:1) At |@| +//@[1:4) Identifier |sys| +//@[4:5) Dot |.| +//@[5:16) Identifier |description| +//@[16:17) LeftParen |(| +//@[17:61) StringComplete |'This is my resource, it is my favorite one'| +//@[61:62) RightParen |)| +//@[62:64) NewLine |\r\n| +param reallySecureResourceType resource 'Microsoft.Storage/storageAccounts@2019-06-01' +//@[0:5) Identifier |param| +//@[6:30) Identifier |reallySecureResourceType| +//@[31:39) Identifier |resource| +//@[40:86) StringComplete |'Microsoft.Storage/storageAccounts@2019-06-01'| +//@[86:88) NewLine |\r\n| //@[0:0) EndOfFile || diff --git a/src/Bicep.Core.Samples/Files/Parameters_LF/main.bicep b/src/Bicep.Core.Samples/Files/Parameters_LF/main.bicep index 598c08bf48b..53ad74f9367 100644 --- a/src/Bicep.Core.Samples/Files/Parameters_LF/main.bicep +++ b/src/Bicep.Core.Samples/Files/Parameters_LF/main.bicep @@ -200,3 +200,9 @@ param decoratedArray array = [ utcNow() newGuid() ] + +param resourceType resource 'Microsoft.Storage/storageAccounts@2019-06-01' + +@secure() +@sys.description('This is my resource, it is my favorite one') +param reallySecureResourceType resource 'Microsoft.Storage/storageAccounts@2019-06-01' diff --git a/src/Bicep.Core.Samples/Files/Parameters_LF/main.diagnostics.bicep b/src/Bicep.Core.Samples/Files/Parameters_LF/main.diagnostics.bicep index fb38a693871..2a2c2c45f27 100644 --- a/src/Bicep.Core.Samples/Files/Parameters_LF/main.diagnostics.bicep +++ b/src/Bicep.Core.Samples/Files/Parameters_LF/main.diagnostics.bicep @@ -230,3 +230,11 @@ param decoratedArray array = [ newGuid() ] +param resourceType resource 'Microsoft.Storage/storageAccounts@2019-06-01' +//@[6:18) [no-unused-params (Warning)] Parameter "resourceType" is declared but never used. (CodeDescription: bicep core(https://aka.ms/bicep/linter/no-unused-params)) |resourceType| + +@secure() +@sys.description('This is my resource, it is my favorite one') +param reallySecureResourceType resource 'Microsoft.Storage/storageAccounts@2019-06-01' +//@[6:30) [no-unused-params (Warning)] Parameter "reallySecureResourceType" is declared but never used. (CodeDescription: bicep core(https://aka.ms/bicep/linter/no-unused-params)) |reallySecureResourceType| + diff --git a/src/Bicep.Core.Samples/Files/Parameters_LF/main.formatted.bicep b/src/Bicep.Core.Samples/Files/Parameters_LF/main.formatted.bicep index 12f3cbf4f35..df71210cba2 100644 --- a/src/Bicep.Core.Samples/Files/Parameters_LF/main.formatted.bicep +++ b/src/Bicep.Core.Samples/Files/Parameters_LF/main.formatted.bicep @@ -197,3 +197,9 @@ param decoratedArray array = [ utcNow() newGuid() ] + +param resourceType resource 'Microsoft.Storage/storageAccounts@2019-06-01' + +@secure() +@sys.description('This is my resource, it is my favorite one') +param reallySecureResourceType resource 'Microsoft.Storage/storageAccounts@2019-06-01' diff --git a/src/Bicep.Core.Samples/Files/Parameters_LF/main.json b/src/Bicep.Core.Samples/Files/Parameters_LF/main.json index d54dab35fbe..ba761e477f0 100644 --- a/src/Bicep.Core.Samples/Files/Parameters_LF/main.json +++ b/src/Bicep.Core.Samples/Files/Parameters_LF/main.json @@ -5,7 +5,7 @@ "_generator": { "name": "bicep", "version": "dev", - "templateHash": "1706136566230351855" + "templateHash": "11222853854258209553" } }, "parameters": { @@ -230,6 +230,19 @@ "description": "An array." }, "maxLength": 20 + }, + "resourceType": { + "type": "string", + "metadata": { + "resourceType": "Microsoft.Storage/storageAccounts@2019-06-01" + } + }, + "reallySecureResourceType": { + "type": "string", + "metadata": { + "resourceType": "Microsoft.Storage/storageAccounts@2019-06-01", + "description": "This is my resource, it is my favorite one" + } } }, "functions": [], diff --git a/src/Bicep.Core.Samples/Files/Parameters_LF/main.symbolicnames.json b/src/Bicep.Core.Samples/Files/Parameters_LF/main.symbolicnames.json index 9cf39ea440e..7cb9b770659 100644 --- a/src/Bicep.Core.Samples/Files/Parameters_LF/main.symbolicnames.json +++ b/src/Bicep.Core.Samples/Files/Parameters_LF/main.symbolicnames.json @@ -7,7 +7,7 @@ "_generator": { "name": "bicep", "version": "dev", - "templateHash": "14823644294419510839" + "templateHash": "918293749162111888" } }, "parameters": { @@ -232,6 +232,19 @@ "description": "An array." }, "maxLength": 20 + }, + "resourceType": { + "type": "string", + "metadata": { + "resourceType": "Microsoft.Storage/storageAccounts@2019-06-01" + } + }, + "reallySecureResourceType": { + "type": "string", + "metadata": { + "resourceType": "Microsoft.Storage/storageAccounts@2019-06-01", + "description": "This is my resource, it is my favorite one" + } } }, "functions": [], diff --git a/src/Bicep.Core.Samples/Files/Parameters_LF/main.symbols.bicep b/src/Bicep.Core.Samples/Files/Parameters_LF/main.symbols.bicep index a0f2ae5cb61..7c6cec179b2 100644 --- a/src/Bicep.Core.Samples/Files/Parameters_LF/main.symbols.bicep +++ b/src/Bicep.Core.Samples/Files/Parameters_LF/main.symbols.bicep @@ -230,3 +230,11 @@ param decoratedArray array = [ newGuid() ] +param resourceType resource 'Microsoft.Storage/storageAccounts@2019-06-01' +//@[6:18) Parameter resourceType. Type: Microsoft.Storage/storageAccounts@2019-06-01. Declaration start char: 0, length: 74 + +@secure() +@sys.description('This is my resource, it is my favorite one') +param reallySecureResourceType resource 'Microsoft.Storage/storageAccounts@2019-06-01' +//@[6:30) Parameter reallySecureResourceType. Type: Microsoft.Storage/storageAccounts@2019-06-01. Declaration start char: 0, length: 159 + diff --git a/src/Bicep.Core.Samples/Files/Parameters_LF/main.syntax.bicep b/src/Bicep.Core.Samples/Files/Parameters_LF/main.syntax.bicep index f5a77504b61..6099f582713 100644 --- a/src/Bicep.Core.Samples/Files/Parameters_LF/main.syntax.bicep +++ b/src/Bicep.Core.Samples/Files/Parameters_LF/main.syntax.bicep @@ -29,7 +29,7 @@ param myString string //@[0:5) Identifier |param| //@[6:14) IdentifierSyntax //@[6:14) Identifier |myString| -//@[15:21) TypeSyntax +//@[15:21) SimpleTypeSyntax //@[15:21) Identifier |string| //@[21:22) NewLine |\n| param myInt int @@ -37,7 +37,7 @@ param myInt int //@[0:5) Identifier |param| //@[6:11) IdentifierSyntax //@[6:11) Identifier |myInt| -//@[12:15) TypeSyntax +//@[12:15) SimpleTypeSyntax //@[12:15) Identifier |int| //@[15:16) NewLine |\n| param myBool bool @@ -45,7 +45,7 @@ param myBool bool //@[0:5) Identifier |param| //@[6:12) IdentifierSyntax //@[6:12) Identifier |myBool| -//@[13:17) TypeSyntax +//@[13:17) SimpleTypeSyntax //@[13:17) Identifier |bool| //@[17:19) NewLine |\n\n| @@ -95,7 +95,7 @@ param myString2 string = 'string value' //@[0:5) Identifier |param| //@[6:15) IdentifierSyntax //@[6:15) Identifier |myString2| -//@[16:22) TypeSyntax +//@[16:22) SimpleTypeSyntax //@[16:22) Identifier |string| //@[23:39) ParameterDefaultValueSyntax //@[23:24) Assignment |=| @@ -107,7 +107,7 @@ param myInt2 int = 42 //@[0:5) Identifier |param| //@[6:12) IdentifierSyntax //@[6:12) Identifier |myInt2| -//@[13:16) TypeSyntax +//@[13:16) SimpleTypeSyntax //@[13:16) Identifier |int| //@[17:21) ParameterDefaultValueSyntax //@[17:18) Assignment |=| @@ -119,7 +119,7 @@ param myTruth bool = true //@[0:5) Identifier |param| //@[6:13) IdentifierSyntax //@[6:13) Identifier |myTruth| -//@[14:18) TypeSyntax +//@[14:18) SimpleTypeSyntax //@[14:18) Identifier |bool| //@[19:25) ParameterDefaultValueSyntax //@[19:20) Assignment |=| @@ -131,7 +131,7 @@ param myFalsehood bool = false //@[0:5) Identifier |param| //@[6:17) IdentifierSyntax //@[6:17) Identifier |myFalsehood| -//@[18:22) TypeSyntax +//@[18:22) SimpleTypeSyntax //@[18:22) Identifier |bool| //@[23:30) ParameterDefaultValueSyntax //@[23:24) Assignment |=| @@ -143,7 +143,7 @@ param myEscapedString string = 'First line\r\nSecond\ttabbed\tline' //@[0:5) Identifier |param| //@[6:21) IdentifierSyntax //@[6:21) Identifier |myEscapedString| -//@[22:28) TypeSyntax +//@[22:28) SimpleTypeSyntax //@[22:28) Identifier |string| //@[29:67) ParameterDefaultValueSyntax //@[29:30) Assignment |=| @@ -205,7 +205,7 @@ param foo object = { //@[0:5) Identifier |param| //@[6:9) IdentifierSyntax //@[6:9) Identifier |foo| -//@[10:16) TypeSyntax +//@[10:16) SimpleTypeSyntax //@[10:16) Identifier |object| //@[17:232) ParameterDefaultValueSyntax //@[17:18) Assignment |=| @@ -337,7 +337,7 @@ param myArrayParam array = [ //@[0:5) Identifier |param| //@[6:18) IdentifierSyntax //@[6:18) Identifier |myArrayParam| -//@[19:24) TypeSyntax +//@[19:24) SimpleTypeSyntax //@[19:24) Identifier |array| //@[25:48) ParameterDefaultValueSyntax //@[25:26) Assignment |=| @@ -379,7 +379,7 @@ param password string //@[0:5) Identifier |param| //@[6:14) IdentifierSyntax //@[6:14) Identifier |password| -//@[15:21) TypeSyntax +//@[15:21) SimpleTypeSyntax //@[15:21) Identifier |string| //@[21:23) NewLine |\n\n| @@ -399,7 +399,7 @@ param secretObject object //@[0:5) Identifier |param| //@[6:18) IdentifierSyntax //@[6:18) Identifier |secretObject| -//@[19:25) TypeSyntax +//@[19:25) SimpleTypeSyntax //@[19:25) Identifier |object| //@[25:27) NewLine |\n\n| @@ -435,7 +435,7 @@ param storageSku string //@[0:5) Identifier |param| //@[6:16) IdentifierSyntax //@[6:16) Identifier |storageSku| -//@[17:23) TypeSyntax +//@[17:23) SimpleTypeSyntax //@[17:23) Identifier |string| //@[23:25) NewLine |\n\n| @@ -470,7 +470,7 @@ param storageName string //@[0:5) Identifier |param| //@[6:17) IdentifierSyntax //@[6:17) Identifier |storageName| -//@[18:24) TypeSyntax +//@[18:24) SimpleTypeSyntax //@[18:24) Identifier |string| //@[24:26) NewLine |\n\n| @@ -505,7 +505,7 @@ param someArray array //@[0:5) Identifier |param| //@[6:15) IdentifierSyntax //@[6:15) Identifier |someArray| -//@[16:21) TypeSyntax +//@[16:21) SimpleTypeSyntax //@[16:21) Identifier |array| //@[21:23) NewLine |\n\n| @@ -529,7 +529,7 @@ param emptyMetadata string //@[0:5) Identifier |param| //@[6:19) IdentifierSyntax //@[6:19) Identifier |emptyMetadata| -//@[20:26) TypeSyntax +//@[20:26) SimpleTypeSyntax //@[20:26) Identifier |string| //@[26:28) NewLine |\n\n| @@ -563,7 +563,7 @@ param description string //@[0:5) Identifier |param| //@[6:17) IdentifierSyntax //@[6:17) Identifier |description| -//@[18:24) TypeSyntax +//@[18:24) SimpleTypeSyntax //@[18:24) Identifier |string| //@[24:26) NewLine |\n\n| @@ -588,7 +588,7 @@ param description2 string //@[0:5) Identifier |param| //@[6:18) IdentifierSyntax //@[6:18) Identifier |description2| -//@[19:25) TypeSyntax +//@[19:25) SimpleTypeSyntax //@[19:25) Identifier |string| //@[25:27) NewLine |\n\n| @@ -668,7 +668,7 @@ param additionalMetadata string //@[0:5) Identifier |param| //@[6:24) IdentifierSyntax //@[6:24) Identifier |additionalMetadata| -//@[25:31) TypeSyntax +//@[25:31) SimpleTypeSyntax //@[25:31) Identifier |string| //@[31:33) NewLine |\n\n| @@ -765,7 +765,7 @@ param someParameter string //@[0:5) Identifier |param| //@[6:19) IdentifierSyntax //@[6:19) Identifier |someParameter| -//@[20:26) TypeSyntax +//@[20:26) SimpleTypeSyntax //@[20:26) Identifier |string| //@[26:28) NewLine |\n\n| @@ -774,7 +774,7 @@ param defaultExpression bool = 18 != (true || false) //@[0:5) Identifier |param| //@[6:23) IdentifierSyntax //@[6:23) Identifier |defaultExpression| -//@[24:28) TypeSyntax +//@[24:28) SimpleTypeSyntax //@[24:28) Identifier |bool| //@[29:52) ParameterDefaultValueSyntax //@[29:30) Assignment |=| @@ -823,7 +823,7 @@ param stringLiteral string //@[0:5) Identifier |param| //@[6:19) IdentifierSyntax //@[6:19) Identifier |stringLiteral| -//@[20:26) TypeSyntax +//@[20:26) SimpleTypeSyntax //@[20:26) Identifier |string| //@[26:28) NewLine |\n\n| @@ -862,7 +862,7 @@ param stringLiteralWithAllowedValuesSuperset string = stringLiteral //@[0:5) Identifier |param| //@[6:44) IdentifierSyntax //@[6:44) Identifier |stringLiteralWithAllowedValuesSuperset| -//@[45:51) TypeSyntax +//@[45:51) SimpleTypeSyntax //@[45:51) Identifier |string| //@[52:67) ParameterDefaultValueSyntax //@[52:53) Assignment |=| @@ -934,7 +934,7 @@ param decoratedString string //@[0:5) Identifier |param| //@[6:21) IdentifierSyntax //@[6:21) Identifier |decoratedString| -//@[22:28) TypeSyntax +//@[22:28) SimpleTypeSyntax //@[22:28) Identifier |string| //@[28:30) NewLine |\n\n| @@ -955,7 +955,7 @@ param decoratedInt int = 123 //@[0:5) Identifier |param| //@[6:18) IdentifierSyntax //@[6:18) Identifier |decoratedInt| -//@[19:22) TypeSyntax +//@[19:22) SimpleTypeSyntax //@[19:22) Identifier |int| //@[23:28) ParameterDefaultValueSyntax //@[23:24) Assignment |=| @@ -998,7 +998,7 @@ param negativeValues int //@[0:5) Identifier |param| //@[6:20) IdentifierSyntax //@[6:20) Identifier |negativeValues| -//@[21:24) TypeSyntax +//@[21:24) SimpleTypeSyntax //@[21:24) Identifier |int| //@[24:26) NewLine |\n\n| @@ -1081,7 +1081,7 @@ param decoratedBool bool = (true && false) != true //@[0:5) Identifier |param| //@[6:19) IdentifierSyntax //@[6:19) Identifier |decoratedBool| -//@[20:24) TypeSyntax +//@[20:24) SimpleTypeSyntax //@[20:24) Identifier |bool| //@[25:50) ParameterDefaultValueSyntax //@[25:26) Assignment |=| @@ -1114,7 +1114,7 @@ param decoratedObject object = { //@[0:5) Identifier |param| //@[6:21) IdentifierSyntax //@[6:21) Identifier |decoratedObject| -//@[22:28) TypeSyntax +//@[22:28) SimpleTypeSyntax //@[22:28) Identifier |object| //@[29:244) ParameterDefaultValueSyntax //@[29:30) Assignment |=| @@ -1303,7 +1303,7 @@ param decoratedArray array = [ //@[0:5) Identifier |param| //@[6:20) IdentifierSyntax //@[6:20) Identifier |decoratedArray| -//@[21:26) TypeSyntax +//@[21:26) SimpleTypeSyntax //@[21:26) Identifier |array| //@[27:59) ParameterDefaultValueSyntax //@[27:28) Assignment |=| @@ -1328,6 +1328,53 @@ param decoratedArray array = [ //@[13:14) NewLine |\n| ] //@[0:1) RightSquare |]| -//@[1:2) NewLine |\n| +//@[1:3) NewLine |\n\n| + +param resourceType resource 'Microsoft.Storage/storageAccounts@2019-06-01' +//@[0:74) ParameterDeclarationSyntax +//@[0:5) Identifier |param| +//@[6:18) IdentifierSyntax +//@[6:18) Identifier |resourceType| +//@[19:74) ResourceTypeSyntax +//@[19:27) Identifier |resource| +//@[28:74) StringSyntax +//@[28:74) StringComplete |'Microsoft.Storage/storageAccounts@2019-06-01'| +//@[74:76) NewLine |\n\n| + +@secure() +//@[0:159) ParameterDeclarationSyntax +//@[0:9) DecoratorSyntax +//@[0:1) At |@| +//@[1:9) FunctionCallSyntax +//@[1:7) IdentifierSyntax +//@[1:7) Identifier |secure| +//@[7:8) LeftParen |(| +//@[8:9) RightParen |)| +//@[9:10) NewLine |\n| +@sys.description('This is my resource, it is my favorite one') +//@[0:62) DecoratorSyntax +//@[0:1) At |@| +//@[1:62) InstanceFunctionCallSyntax +//@[1:4) VariableAccessSyntax +//@[1:4) IdentifierSyntax +//@[1:4) Identifier |sys| +//@[4:5) Dot |.| +//@[5:16) IdentifierSyntax +//@[5:16) Identifier |description| +//@[16:17) LeftParen |(| +//@[17:61) FunctionArgumentSyntax +//@[17:61) StringSyntax +//@[17:61) StringComplete |'This is my resource, it is my favorite one'| +//@[61:62) RightParen |)| +//@[62:63) NewLine |\n| +param reallySecureResourceType resource 'Microsoft.Storage/storageAccounts@2019-06-01' +//@[0:5) Identifier |param| +//@[6:30) IdentifierSyntax +//@[6:30) Identifier |reallySecureResourceType| +//@[31:86) ResourceTypeSyntax +//@[31:39) Identifier |resource| +//@[40:86) StringSyntax +//@[40:86) StringComplete |'Microsoft.Storage/storageAccounts@2019-06-01'| +//@[86:87) NewLine |\n| //@[0:0) EndOfFile || diff --git a/src/Bicep.Core.Samples/Files/Parameters_LF/main.tokens.bicep b/src/Bicep.Core.Samples/Files/Parameters_LF/main.tokens.bicep index 3843fbda847..8ddc135373f 100644 --- a/src/Bicep.Core.Samples/Files/Parameters_LF/main.tokens.bicep +++ b/src/Bicep.Core.Samples/Files/Parameters_LF/main.tokens.bicep @@ -853,6 +853,35 @@ param decoratedArray array = [ //@[13:14) NewLine |\n| ] //@[0:1) RightSquare |]| -//@[1:2) NewLine |\n| +//@[1:3) NewLine |\n\n| + +param resourceType resource 'Microsoft.Storage/storageAccounts@2019-06-01' +//@[0:5) Identifier |param| +//@[6:18) Identifier |resourceType| +//@[19:27) Identifier |resource| +//@[28:74) StringComplete |'Microsoft.Storage/storageAccounts@2019-06-01'| +//@[74:76) NewLine |\n\n| + +@secure() +//@[0:1) At |@| +//@[1:7) Identifier |secure| +//@[7:8) LeftParen |(| +//@[8:9) RightParen |)| +//@[9:10) NewLine |\n| +@sys.description('This is my resource, it is my favorite one') +//@[0:1) At |@| +//@[1:4) Identifier |sys| +//@[4:5) Dot |.| +//@[5:16) Identifier |description| +//@[16:17) LeftParen |(| +//@[17:61) StringComplete |'This is my resource, it is my favorite one'| +//@[61:62) RightParen |)| +//@[62:63) NewLine |\n| +param reallySecureResourceType resource 'Microsoft.Storage/storageAccounts@2019-06-01' +//@[0:5) Identifier |param| +//@[6:30) Identifier |reallySecureResourceType| +//@[31:39) Identifier |resource| +//@[40:86) StringComplete |'Microsoft.Storage/storageAccounts@2019-06-01'| +//@[86:87) NewLine |\n| //@[0:0) EndOfFile || diff --git a/src/Bicep.Core.Samples/Files/Registry_LF/main.syntax.bicep b/src/Bicep.Core.Samples/Files/Registry_LF/main.syntax.bicep index f5ee80fcf0d..6fa7d951aaf 100644 --- a/src/Bicep.Core.Samples/Files/Registry_LF/main.syntax.bicep +++ b/src/Bicep.Core.Samples/Files/Registry_LF/main.syntax.bicep @@ -692,7 +692,7 @@ output siteUrls array = [for (site, i) in websites: siteDeploy[i].outputs.siteUr //@[0:6) Identifier |output| //@[7:15) IdentifierSyntax //@[7:15) Identifier |siteUrls| -//@[16:21) TypeSyntax +//@[16:21) SimpleTypeSyntax //@[16:21) Identifier |array| //@[22:23) Assignment |=| //@[24:82) ForSyntax diff --git a/src/Bicep.Core.Samples/Files/ResourcesManagementGroup_CRLF/main.syntax.bicep b/src/Bicep.Core.Samples/Files/ResourcesManagementGroup_CRLF/main.syntax.bicep index 9573e313922..6621d9a1f53 100644 --- a/src/Bicep.Core.Samples/Files/ResourcesManagementGroup_CRLF/main.syntax.bicep +++ b/src/Bicep.Core.Samples/Files/ResourcesManagementGroup_CRLF/main.syntax.bicep @@ -11,7 +11,7 @@ param ownerPrincipalId string //@[0:5) Identifier |param| //@[6:22) IdentifierSyntax //@[6:22) Identifier |ownerPrincipalId| -//@[23:29) TypeSyntax +//@[23:29) SimpleTypeSyntax //@[23:29) Identifier |string| //@[29:33) NewLine |\r\n\r\n| @@ -20,7 +20,7 @@ param contributorPrincipals array //@[0:5) Identifier |param| //@[6:27) IdentifierSyntax //@[6:27) Identifier |contributorPrincipals| -//@[28:33) TypeSyntax +//@[28:33) SimpleTypeSyntax //@[28:33) Identifier |array| //@[33:35) NewLine |\r\n| param readerPrincipals array @@ -28,7 +28,7 @@ param readerPrincipals array //@[0:5) Identifier |param| //@[6:22) IdentifierSyntax //@[6:22) Identifier |readerPrincipals| -//@[23:28) TypeSyntax +//@[23:28) SimpleTypeSyntax //@[23:28) Identifier |array| //@[28:32) NewLine |\r\n\r\n| diff --git a/src/Bicep.Core.Samples/Files/ResourcesSubscription_CRLF/main.syntax.bicep b/src/Bicep.Core.Samples/Files/ResourcesSubscription_CRLF/main.syntax.bicep index 48d57e18ce3..2f91bb46769 100644 --- a/src/Bicep.Core.Samples/Files/ResourcesSubscription_CRLF/main.syntax.bicep +++ b/src/Bicep.Core.Samples/Files/ResourcesSubscription_CRLF/main.syntax.bicep @@ -11,7 +11,7 @@ param ownerPrincipalId string //@[0:5) Identifier |param| //@[6:22) IdentifierSyntax //@[6:22) Identifier |ownerPrincipalId| -//@[23:29) TypeSyntax +//@[23:29) SimpleTypeSyntax //@[23:29) Identifier |string| //@[29:33) NewLine |\r\n\r\n| @@ -20,7 +20,7 @@ param contributorPrincipals array //@[0:5) Identifier |param| //@[6:27) IdentifierSyntax //@[6:27) Identifier |contributorPrincipals| -//@[28:33) TypeSyntax +//@[28:33) SimpleTypeSyntax //@[28:33) Identifier |array| //@[33:35) NewLine |\r\n| param readerPrincipals array @@ -28,7 +28,7 @@ param readerPrincipals array //@[0:5) Identifier |param| //@[6:22) IdentifierSyntax //@[6:22) Identifier |readerPrincipals| -//@[23:28) TypeSyntax +//@[23:28) SimpleTypeSyntax //@[23:28) Identifier |array| //@[28:32) NewLine |\r\n\r\n| diff --git a/src/Bicep.Core.Samples/Files/ResourcesTenant_CRLF/main.syntax.bicep b/src/Bicep.Core.Samples/Files/ResourcesTenant_CRLF/main.syntax.bicep index e81e45463f2..701e540098c 100644 --- a/src/Bicep.Core.Samples/Files/ResourcesTenant_CRLF/main.syntax.bicep +++ b/src/Bicep.Core.Samples/Files/ResourcesTenant_CRLF/main.syntax.bicep @@ -426,7 +426,7 @@ output managementGroupIds array = [for i in range(0, length(managementGroups)): //@[0:6) Identifier |output| //@[7:25) IdentifierSyntax //@[7:25) Identifier |managementGroupIds| -//@[26:31) TypeSyntax +//@[26:31) SimpleTypeSyntax //@[26:31) Identifier |array| //@[32:33) Assignment |=| //@[34:172) ForSyntax diff --git a/src/Bicep.Core.Samples/Files/Resources_CRLF/main.syntax.bicep b/src/Bicep.Core.Samples/Files/Resources_CRLF/main.syntax.bicep index 2950650ac0b..f08ddbfecd4 100644 --- a/src/Bicep.Core.Samples/Files/Resources_CRLF/main.syntax.bicep +++ b/src/Bicep.Core.Samples/Files/Resources_CRLF/main.syntax.bicep @@ -462,7 +462,7 @@ param applicationName string = 'to-do-app${uniqueString(resourceGroup().id)}' //@[0:5) Identifier |param| //@[6:21) IdentifierSyntax //@[6:21) Identifier |applicationName| -//@[22:28) TypeSyntax +//@[22:28) SimpleTypeSyntax //@[22:28) Identifier |string| //@[29:77) ParameterDefaultValueSyntax //@[29:30) Assignment |=| @@ -501,7 +501,7 @@ param appServicePlanTier string //@[0:5) Identifier |param| //@[6:24) IdentifierSyntax //@[6:24) Identifier |appServicePlanTier| -//@[25:31) TypeSyntax +//@[25:31) SimpleTypeSyntax //@[25:31) Identifier |string| //@[31:33) NewLine |\r\n| param appServicePlanInstances int @@ -509,7 +509,7 @@ param appServicePlanInstances int //@[0:5) Identifier |param| //@[6:29) IdentifierSyntax //@[6:29) Identifier |appServicePlanInstances| -//@[30:33) TypeSyntax +//@[30:33) SimpleTypeSyntax //@[30:33) Identifier |int| //@[33:37) NewLine |\r\n\r\n| @@ -683,7 +683,7 @@ param webSiteName string //@[0:5) Identifier |param| //@[6:17) IdentifierSyntax //@[6:17) Identifier |webSiteName| -//@[18:24) TypeSyntax +//@[18:24) SimpleTypeSyntax //@[18:24) Identifier |string| //@[24:26) NewLine |\r\n| param cosmosDb object @@ -691,7 +691,7 @@ param cosmosDb object //@[0:5) Identifier |param| //@[6:14) IdentifierSyntax //@[6:14) Identifier |cosmosDb| -//@[15:21) TypeSyntax +//@[15:21) SimpleTypeSyntax //@[15:21) Identifier |object| //@[21:23) NewLine |\r\n| resource site 'Microsoft.Web/sites@2019-08-01' = { @@ -928,7 +928,7 @@ output siteApiVersion string = site.apiVersion //@[0:6) Identifier |output| //@[7:21) IdentifierSyntax //@[7:21) Identifier |siteApiVersion| -//@[22:28) TypeSyntax +//@[22:28) SimpleTypeSyntax //@[22:28) Identifier |string| //@[29:30) Assignment |=| //@[31:46) PropertyAccessSyntax @@ -944,7 +944,7 @@ output siteType string = site.type //@[0:6) Identifier |output| //@[7:15) IdentifierSyntax //@[7:15) Identifier |siteType| -//@[16:22) TypeSyntax +//@[16:22) SimpleTypeSyntax //@[16:22) Identifier |string| //@[23:24) Assignment |=| //@[25:34) PropertyAccessSyntax @@ -1631,7 +1631,7 @@ param shouldDeployVm bool = true //@[0:5) Identifier |param| //@[6:20) IdentifierSyntax //@[6:20) Identifier |shouldDeployVm| -//@[21:25) TypeSyntax +//@[21:25) SimpleTypeSyntax //@[21:25) Identifier |bool| //@[26:32) ParameterDefaultValueSyntax //@[26:27) Assignment |=| @@ -3255,7 +3255,7 @@ output p1_subnet1prefix string = p1_subnet1.properties.addressPrefix //@[0:6) Identifier |output| //@[7:23) IdentifierSyntax //@[7:23) Identifier |p1_subnet1prefix| -//@[24:30) TypeSyntax +//@[24:30) SimpleTypeSyntax //@[24:30) Identifier |string| //@[31:32) Assignment |=| //@[33:68) PropertyAccessSyntax @@ -3275,7 +3275,7 @@ output p1_subnet1name string = p1_subnet1.name //@[0:6) Identifier |output| //@[7:21) IdentifierSyntax //@[7:21) Identifier |p1_subnet1name| -//@[22:28) TypeSyntax +//@[22:28) SimpleTypeSyntax //@[22:28) Identifier |string| //@[29:30) Assignment |=| //@[31:46) PropertyAccessSyntax @@ -3291,7 +3291,7 @@ output p1_subnet1type string = p1_subnet1.type //@[0:6) Identifier |output| //@[7:21) IdentifierSyntax //@[7:21) Identifier |p1_subnet1type| -//@[22:28) TypeSyntax +//@[22:28) SimpleTypeSyntax //@[22:28) Identifier |string| //@[29:30) Assignment |=| //@[31:46) PropertyAccessSyntax @@ -3307,7 +3307,7 @@ output p1_subnet1id string = p1_subnet1.id //@[0:6) Identifier |output| //@[7:19) IdentifierSyntax //@[7:19) Identifier |p1_subnet1id| -//@[20:26) TypeSyntax +//@[20:26) SimpleTypeSyntax //@[20:26) Identifier |string| //@[27:28) Assignment |=| //@[29:42) PropertyAccessSyntax @@ -3445,7 +3445,7 @@ output p2_res2childprop string = p2_res2child.properties.someProp //@[0:6) Identifier |output| //@[7:23) IdentifierSyntax //@[7:23) Identifier |p2_res2childprop| -//@[24:30) TypeSyntax +//@[24:30) SimpleTypeSyntax //@[24:30) Identifier |string| //@[31:32) Assignment |=| //@[33:65) PropertyAccessSyntax @@ -3465,7 +3465,7 @@ output p2_res2childname string = p2_res2child.name //@[0:6) Identifier |output| //@[7:23) IdentifierSyntax //@[7:23) Identifier |p2_res2childname| -//@[24:30) TypeSyntax +//@[24:30) SimpleTypeSyntax //@[24:30) Identifier |string| //@[31:32) Assignment |=| //@[33:50) PropertyAccessSyntax @@ -3481,7 +3481,7 @@ output p2_res2childtype string = p2_res2child.type //@[0:6) Identifier |output| //@[7:23) IdentifierSyntax //@[7:23) Identifier |p2_res2childtype| -//@[24:30) TypeSyntax +//@[24:30) SimpleTypeSyntax //@[24:30) Identifier |string| //@[31:32) Assignment |=| //@[33:50) PropertyAccessSyntax @@ -3497,7 +3497,7 @@ output p2_res2childid string = p2_res2child.id //@[0:6) Identifier |output| //@[7:21) IdentifierSyntax //@[7:21) Identifier |p2_res2childid| -//@[22:28) TypeSyntax +//@[22:28) SimpleTypeSyntax //@[22:28) Identifier |string| //@[29:30) Assignment |=| //@[31:46) PropertyAccessSyntax @@ -3572,7 +3572,7 @@ output p3_res1childprop string = p3_child1.properties.someProp //@[0:6) Identifier |output| //@[7:23) IdentifierSyntax //@[7:23) Identifier |p3_res1childprop| -//@[24:30) TypeSyntax +//@[24:30) SimpleTypeSyntax //@[24:30) Identifier |string| //@[31:32) Assignment |=| //@[33:62) PropertyAccessSyntax @@ -3592,7 +3592,7 @@ output p3_res1childname string = p3_child1.name //@[0:6) Identifier |output| //@[7:23) IdentifierSyntax //@[7:23) Identifier |p3_res1childname| -//@[24:30) TypeSyntax +//@[24:30) SimpleTypeSyntax //@[24:30) Identifier |string| //@[31:32) Assignment |=| //@[33:47) PropertyAccessSyntax @@ -3608,7 +3608,7 @@ output p3_res1childtype string = p3_child1.type //@[0:6) Identifier |output| //@[7:23) IdentifierSyntax //@[7:23) Identifier |p3_res1childtype| -//@[24:30) TypeSyntax +//@[24:30) SimpleTypeSyntax //@[24:30) Identifier |string| //@[31:32) Assignment |=| //@[33:47) PropertyAccessSyntax @@ -3624,7 +3624,7 @@ output p3_res1childid string = p3_child1.id //@[0:6) Identifier |output| //@[7:21) IdentifierSyntax //@[7:21) Identifier |p3_res1childid| -//@[22:28) TypeSyntax +//@[22:28) SimpleTypeSyntax //@[22:28) Identifier |string| //@[29:30) Assignment |=| //@[31:43) PropertyAccessSyntax @@ -3711,7 +3711,7 @@ output p4_res1childprop string = p4_child1.properties.someProp //@[0:6) Identifier |output| //@[7:23) IdentifierSyntax //@[7:23) Identifier |p4_res1childprop| -//@[24:30) TypeSyntax +//@[24:30) SimpleTypeSyntax //@[24:30) Identifier |string| //@[31:32) Assignment |=| //@[33:62) PropertyAccessSyntax @@ -3731,7 +3731,7 @@ output p4_res1childname string = p4_child1.name //@[0:6) Identifier |output| //@[7:23) IdentifierSyntax //@[7:23) Identifier |p4_res1childname| -//@[24:30) TypeSyntax +//@[24:30) SimpleTypeSyntax //@[24:30) Identifier |string| //@[31:32) Assignment |=| //@[33:47) PropertyAccessSyntax @@ -3747,7 +3747,7 @@ output p4_res1childtype string = p4_child1.type //@[0:6) Identifier |output| //@[7:23) IdentifierSyntax //@[7:23) Identifier |p4_res1childtype| -//@[24:30) TypeSyntax +//@[24:30) SimpleTypeSyntax //@[24:30) Identifier |string| //@[31:32) Assignment |=| //@[33:47) PropertyAccessSyntax @@ -3763,7 +3763,7 @@ output p4_res1childid string = p4_child1.id //@[0:6) Identifier |output| //@[7:21) IdentifierSyntax //@[7:21) Identifier |p4_res1childid| -//@[22:28) TypeSyntax +//@[22:28) SimpleTypeSyntax //@[22:28) Identifier |string| //@[29:30) Assignment |=| //@[31:43) PropertyAccessSyntax diff --git a/src/Bicep.Core.Samples/Files/Unicode_LF/main.syntax.bicep b/src/Bicep.Core.Samples/Files/Unicode_LF/main.syntax.bicep index 8ea5f8cb273..72fc5669612 100644 --- a/src/Bicep.Core.Samples/Files/Unicode_LF/main.syntax.bicep +++ b/src/Bicep.Core.Samples/Files/Unicode_LF/main.syntax.bicep @@ -94,7 +94,7 @@ output concatUnicodeStrings string = concat('Θμ', '二头肌', 'α') //@[0:6) Identifier |output| //@[7:27) IdentifierSyntax //@[7:27) Identifier |concatUnicodeStrings| -//@[28:34) TypeSyntax +//@[28:34) SimpleTypeSyntax //@[28:34) Identifier |string| //@[35:36) Assignment |=| //@[37:61) FunctionCallSyntax @@ -119,7 +119,7 @@ output interpolateUnicodeStrings string = 'Θμ二${emojis}头肌${ninjaCat}α' //@[0:6) Identifier |output| //@[7:32) IdentifierSyntax //@[7:32) Identifier |interpolateUnicodeStrings| -//@[33:39) TypeSyntax +//@[33:39) SimpleTypeSyntax //@[33:39) Identifier |string| //@[40:41) Assignment |=| //@[42:70) StringSyntax diff --git a/src/Bicep.Core.Samples/Files/Variables_LF/main.syntax.bicep b/src/Bicep.Core.Samples/Files/Variables_LF/main.syntax.bicep index 92f12d44177..7d39b28c3bb 100644 --- a/src/Bicep.Core.Samples/Files/Variables_LF/main.syntax.bicep +++ b/src/Bicep.Core.Samples/Files/Variables_LF/main.syntax.bicep @@ -1639,7 +1639,7 @@ param parameters bool = true //@[0:5) Identifier |param| //@[6:16) IdentifierSyntax //@[6:16) Identifier |parameters| -//@[17:21) TypeSyntax +//@[17:21) SimpleTypeSyntax //@[17:21) Identifier |bool| //@[22:28) ParameterDefaultValueSyntax //@[22:23) Assignment |=| @@ -1714,7 +1714,7 @@ param mod bool = true //@[0:5) Identifier |param| //@[6:9) IdentifierSyntax //@[6:9) Identifier |mod| -//@[10:14) TypeSyntax +//@[10:14) SimpleTypeSyntax //@[10:14) Identifier |bool| //@[15:21) ParameterDefaultValueSyntax //@[15:16) Assignment |=| @@ -1762,7 +1762,7 @@ param equals bool = true //@[0:5) Identifier |param| //@[6:12) IdentifierSyntax //@[6:12) Identifier |equals| -//@[13:17) TypeSyntax +//@[13:17) SimpleTypeSyntax //@[13:17) Identifier |bool| //@[18:24) ParameterDefaultValueSyntax //@[18:19) Assignment |=| diff --git a/src/Bicep.Core/Analyzers/Linter/Rules/UseStableVMImageRule.cs b/src/Bicep.Core/Analyzers/Linter/Rules/UseStableVMImageRule.cs index 63b7d2f46d5..4a38186c915 100644 --- a/src/Bicep.Core/Analyzers/Linter/Rules/UseStableVMImageRule.cs +++ b/src/Bicep.Core/Analyzers/Linter/Rules/UseStableVMImageRule.cs @@ -35,7 +35,7 @@ public override IEnumerable AnalyzeInternal(SemanticModel model) { List diagnostics = new List(); - foreach (ResourceMetadata resource in model.AllResources) + foreach (DeclaredResourceMetadata resource in model.AllResources.OfType()) { ResourceDeclarationSyntax resourceSyntax = resource.Symbol.DeclaringResource; if (resourceSyntax.TryGetBody()?.SafeGetPropertyByNameRecursive("properties", "storageProfile", "imageReference") is ObjectPropertySyntax imageReferenceSyntax) diff --git a/src/Bicep.Core/Diagnostics/DiagnosticBuilder.cs b/src/Bicep.Core/Diagnostics/DiagnosticBuilder.cs index b3ca15c4c36..1ce9009752e 100644 --- a/src/Bicep.Core/Diagnostics/DiagnosticBuilder.cs +++ b/src/Bicep.Core/Diagnostics/DiagnosticBuilder.cs @@ -1277,37 +1277,52 @@ public ErrorDiagnostic UnknownModuleReferenceScheme(string badScheme, ImmutableA public ErrorDiagnostic InvalidTemplateSpecReferenceInvalidSubscirptionId(string? aliasName, string subscriptionId, string referenceValue) => new( TextSpan, "BCP217", - $"{BuildInvalidTemplateSpecReferenceClause(aliasName, referenceValue)} The subscription ID \"{subscriptionId}\" in is not a GUID."); + $"{BuildInvalidTemplateSpecReferenceClause(aliasName, referenceValue)} The subscription ID \"{subscriptionId}\" in is not a GUID."); public ErrorDiagnostic InvalidTemplateSpecReferenceResourceGroupNameTooLong(string? aliasName, string resourceGroupName, string referenceValue, int maximumLength) => new( TextSpan, "BCP218", - $"{BuildInvalidTemplateSpecReferenceClause(aliasName, referenceValue)} The resource group name \"{resourceGroupName}\" exceeds the maximum length of {maximumLength} characters."); + $"{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( TextSpan, "BCP219", - $"{BuildInvalidTemplateSpecReferenceClause(aliasName, referenceValue)} The resource group name \"{resourceGroupName}\" is invalid. Valid characters are alphanumeric, unicode charaters, \".\", \"_\", \"-\", \"(\", or \")\", but the resource group name cannot end with \".\"."); + $"{BuildInvalidTemplateSpecReferenceClause(aliasName, referenceValue)} The resource group name \"{resourceGroupName}\" is invalid. Valid characters are alphanumeric, unicode charaters, \".\", \"_\", \"-\", \"(\", or \")\", but the resource group name cannot end with \".\"."); public ErrorDiagnostic InvalidTemplateSpecReferenceTemplateSpecNameTooLong(string? aliasName, string templateSpecName, string referenceValue, int maximumLength) => new( TextSpan, "BCP220", - $"{BuildInvalidTemplateSpecReferenceClause(aliasName, referenceValue)} The Template Spec name \"{templateSpecName}\" exceeds the maximum length of {maximumLength} characters."); + $"{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( TextSpan, "BCP221", - $"{BuildInvalidTemplateSpecReferenceClause(aliasName, referenceValue)} The Template Spec name \"{templateSpecName}\" is invalid. Valid characters are alphanumeric, \".\", \"_\", \"-\", \"(\", or \")\", but the Template Spec name cannot end with \".\"."); + $"{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( TextSpan, "BCP222", - $"{BuildInvalidTemplateSpecReferenceClause(aliasName, referenceValue)} The Template Spec version \"{templateSpecVersion}\" exceeds the maximum length of {maximumLength} characters."); + $"{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( TextSpan, "BCP223", - $"{BuildInvalidTemplateSpecReferenceClause(aliasName, referenceValue)} The Template Spec version \"{templateSpecVersion}\" is invalid. Valid characters are alphanumeric, \".\", \"_\", \"-\", \"(\", or \")\", but the Template Spec name cannot end with \".\"."); + $"{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 InvalidResourceTypeParameterType(string resourceType) => new( + TextSpan, + "BCP224", + $"The type \"{resourceType}\" cannot be used as a parameter type."); + + public ErrorDiagnostic InvalidResourceTypeOutputType(string resourceType) => new( + TextSpan, + "BCP225", + $"The type \"{resourceType}\" cannot be used as an output type."); + + public ErrorDiagnostic InvalidResourceScopeCannotBeResourceTypeParameter(string parameterName) => new( + TextSpan, + "BCP226", + $"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."); } public static DiagnosticBuilderInternal ForPosition(TextSpan span) diff --git a/src/Bicep.Core/Emit/EmitLimitationCalculator.cs b/src/Bicep.Core/Emit/EmitLimitationCalculator.cs index fd0be8aba32..ffa1a23bbf1 100644 --- a/src/Bicep.Core/Emit/EmitLimitationCalculator.cs +++ b/src/Bicep.Core/Emit/EmitLimitationCalculator.cs @@ -35,7 +35,7 @@ public static EmitLimitationInfo Calculate(SemanticModel model) return new EmitLimitationInfo(diagnosticWriter.GetDiagnostics(), moduleScopeData, resourceScopeData); } - private static void DetectDuplicateNames(SemanticModel semanticModel, IDiagnosticWriter diagnosticWriter, ImmutableDictionary resourceScopeData, ImmutableDictionary moduleScopeData) + private static void DetectDuplicateNames(SemanticModel semanticModel, IDiagnosticWriter diagnosticWriter, ImmutableDictionary resourceScopeData, ImmutableDictionary moduleScopeData) { // This method only checks, if in one deployment we do not have 2 or more resources with this same name in one deployment to avoid template validation error // This will not check resource constraints such as necessity of having unique virtual network names within resource group @@ -88,9 +88,9 @@ private static IEnumerable GetModuleDefinitions(SemanticModel } } - private static IEnumerable GetResourceDefinitions(SemanticModel semanticModel, ImmutableDictionary resourceScopeData) + private static IEnumerable GetResourceDefinitions(SemanticModel semanticModel, ImmutableDictionary resourceScopeData) { - foreach (var resource in semanticModel.AllResources) + foreach (var resource in semanticModel.AllResources.OfType()) { if (resource.IsExistingResource) { @@ -121,7 +121,7 @@ private static IEnumerable GetResourceDefinitions(SemanticMo public static void DetectIncorrectlyFormattedNames(SemanticModel semanticModel, IDiagnosticWriter diagnosticWriter) { - foreach (var resource in semanticModel.AllResources) + foreach (var resource in semanticModel.AllResources.OfType()) { if (resource.NameSyntax is not StringSyntax resourceNameString) { @@ -150,7 +150,7 @@ public static void DetectIncorrectlyFormattedNames(SemanticModel semanticModel, // This is best-effort for interpolated strings, as variables may pull in additional '/' characters. // So we can only accurately show a diagnostic if there are TOO MANY '/' characters. if (slashCount > expectedSlashCount) - { + { diagnosticWriter.Write(resource.NameSyntax, x => x.TopLevelChildResourceNameIncorrectQualifierCount(expectedSlashCount)); } } @@ -168,7 +168,7 @@ public static void DetectIncorrectlyFormattedNames(SemanticModel semanticModel, public static void DetectUnexpectedResourceLoopInvariantProperties(SemanticModel semanticModel, IDiagnosticWriter diagnosticWriter) { - foreach (var resource in semanticModel.AllResources) + foreach (var resource in semanticModel.AllResources.OfType()) { if (resource.IsExistingResource) { diff --git a/src/Bicep.Core/Emit/EmitLimitationInfo.cs b/src/Bicep.Core/Emit/EmitLimitationInfo.cs index 5e2bb65ed87..6239c9726a4 100644 --- a/src/Bicep.Core/Emit/EmitLimitationInfo.cs +++ b/src/Bicep.Core/Emit/EmitLimitationInfo.cs @@ -14,9 +14,9 @@ public class EmitLimitationInfo public ImmutableDictionary ModuleScopeData { get; } - public ImmutableDictionary ResourceScopeData { get; } + public ImmutableDictionary ResourceScopeData { get; } - public EmitLimitationInfo(IReadOnlyList diagnostics, ImmutableDictionary moduleScopeData, ImmutableDictionary resourceScopeData) + public EmitLimitationInfo(IReadOnlyList diagnostics, ImmutableDictionary moduleScopeData, ImmutableDictionary resourceScopeData) { Diagnostics = diagnostics; ModuleScopeData = moduleScopeData; diff --git a/src/Bicep.Core/Emit/EmitterContext.cs b/src/Bicep.Core/Emit/EmitterContext.cs index 57cbadaffbb..5f0816d7302 100644 --- a/src/Bicep.Core/Emit/EmitterContext.cs +++ b/src/Bicep.Core/Emit/EmitterContext.cs @@ -30,6 +30,6 @@ public EmitterContext(SemanticModel semanticModel, EmitterSettings settings) public ImmutableDictionary ModuleScopeData => SemanticModel.EmitLimitationInfo.ModuleScopeData; - public ImmutableDictionary ResourceScopeData => SemanticModel.EmitLimitationInfo.ResourceScopeData; + public ImmutableDictionary ResourceScopeData => SemanticModel.EmitLimitationInfo.ResourceScopeData; } } diff --git a/src/Bicep.Core/Emit/ExpressionConverter.cs b/src/Bicep.Core/Emit/ExpressionConverter.cs index 713db4d1f32..d603a722f84 100644 --- a/src/Bicep.Core/Emit/ExpressionConverter.cs +++ b/src/Bicep.Core/Emit/ExpressionConverter.cs @@ -12,6 +12,7 @@ using Bicep.Core.Semantics; using Bicep.Core.Semantics.Metadata; using Bicep.Core.Syntax; +using Bicep.Core.TypeSystem; using Newtonsoft.Json.Linq; namespace Bicep.Core.Emit @@ -136,7 +137,7 @@ private LanguageExpression ConvertFunction(FunctionCallSyntaxBase functionCall) return CreateFunction( instanceFunctionCall.Name.IdentifierName, instanceFunctionCall.Arguments.Select(a => ConvertExpression(a.Expression))); - case ResourceSymbol resourceSymbol when context.SemanticModel.ResourceMetadata.TryLookup(resourceSymbol.DeclaringSyntax) is { } resource: + case ResourceSymbol resourceSymbol when context.SemanticModel.ResourceMetadata.TryLookup(resourceSymbol.DeclaringSyntax) is DeclaredResourceMetadata resource: if (instanceFunctionCall.Name.IdentifierName.StartsWithOrdinalInsensitively("list")) { var converter = indexExpression is not null ? @@ -174,7 +175,7 @@ public ExpressionConverter CreateConverterForIndexReplacement(SyntaxBase nameSyn { case 0: // moving the name expression does not produce any inaccessible locals (no locals means no loops) - // regardless if there is an index expression or not, we don't need to append replacements + // regardless if there is an index expression or not, we don't need to append replacements return this; case 1 when indexExpression != null: @@ -201,7 +202,7 @@ private LanguageExpression ConvertArrayAccess(ArrayAccessSyntax arrayAccess) // variable replaced with [this array access' index expression] if (arrayAccess.BaseExpression is VariableAccessSyntax || arrayAccess.BaseExpression is ResourceAccessSyntax) { - if (context.SemanticModel.ResourceMetadata.TryLookup(arrayAccess.BaseExpression) is { } resource && + if (context.SemanticModel.ResourceMetadata.TryLookup(arrayAccess.BaseExpression) is DeclaredResourceMetadata resource && resource.Symbol.IsCollection) { var resourceConverter = this.CreateConverterForIndexReplacement(resource.NameSyntax, arrayAccess.IndexExpression, arrayAccess); @@ -230,13 +231,39 @@ private LanguageExpression ConvertArrayAccess(ArrayAccessSyntax arrayAccess) // special cases for certain resource property access. if we recurse normally, we'll end up // generating statements like reference(resourceId(...)).id which are not accepted by ARM + // The cases for a parameter resource are much simpler and can be handled up front. These do not + // support symbolic names are are somewhat different from the declared resource case since we just have an + // ID and type. + if (resource is ParameterResourceMetadata parameter) + { + switch (propertyName) + { + case "id": + return new FunctionExpression( + "parameters", + new LanguageExpression[]{ new JTokenExpression(parameter.Symbol.Name), }, + new LanguageExpression[]{}); + case "type": + return new JTokenExpression(resource.TypeReference.FormatType()); + case "apiVersion": + return new JTokenExpression(resource.TypeReference.ApiVersion); + case "properties": + // use the reference() overload without "full" to generate a shorter expression + // this is dependent on the name expression which could involve locals in case of a resource collection + return GetReferenceExpression(resource, indexExpression, false); + default: + return null; + } + } + + var declaredResource = (DeclaredResourceMetadata)resource; switch ((propertyName, context.Settings.EnableSymbolicNames)) { case ("id", true): case ("name", true): case ("type", true): case ("apiVersion", true): - var symbolExpression = GenerateSymbolicReference(resource.Symbol.Name, indexExpression); + var symbolExpression = GenerateSymbolicReference(declaredResource.Symbol.Name, indexExpression); return AppendProperties( CreateFunction("resourceInfo", symbolExpression), @@ -244,12 +271,12 @@ private LanguageExpression ConvertArrayAccess(ArrayAccessSyntax arrayAccess) case ("id", false): // the ID is dependent on the name expression which could involve locals in case of a resource collection return GetFullyQualifiedResourceId(resource); - case ("name", false): + case ("name", false) : // the name is dependent on the name expression which could involve locals in case of a resource collection // Note that we don't want to return the fully-qualified resource name in the case of name property access. // we should return whatever the user has set as the value of the 'name' property for a predictable user experience. - return ConvertExpression(resource.NameSyntax); + return ConvertExpression(declaredResource.NameSyntax); case ("type", false): return new JTokenExpression(resource.TypeReference.FormatType()); case ("apiVersion", false): @@ -278,7 +305,7 @@ private LanguageExpression ConvertArrayAccess(ArrayAccessSyntax arrayAccess) private LanguageExpression ConvertPropertyAccess(PropertyAccessSyntax propertyAccess) { if ((propertyAccess.BaseExpression is VariableAccessSyntax || propertyAccess.BaseExpression is ResourceAccessSyntax) && - context.SemanticModel.ResourceMetadata.TryLookup(propertyAccess.BaseExpression) is { } resource && + context.SemanticModel.ResourceMetadata.TryLookup(propertyAccess.BaseExpression) is DeclaredResourceMetadata resource && CreateConverterForIndexReplacement(resource.NameSyntax, null, propertyAccess) .ConvertResourcePropertyAccess(resource, null, propertyAccess.PropertyName.IdentifierName) is { } convertedSingle) { @@ -287,9 +314,18 @@ private LanguageExpression ConvertPropertyAccess(PropertyAccessSyntax propertyAc return convertedSingle; } + if ((propertyAccess.BaseExpression is VariableAccessSyntax || propertyAccess.BaseExpression is ResourceAccessSyntax) && + context.SemanticModel.ResourceMetadata.TryLookup(propertyAccess.BaseExpression) is ParameterResourceMetadata parameter && + this.ConvertResourcePropertyAccess(parameter, null, propertyAccess.PropertyName.IdentifierName) is { } convertedSingleParameter) + { + // we are doing property access on a single resource + // and we are dealing with special case properties + return convertedSingleParameter; + } + if (propertyAccess.BaseExpression is ArrayAccessSyntax propArrayAccess && (propArrayAccess.BaseExpression is VariableAccessSyntax || propArrayAccess.BaseExpression is ResourceAccessSyntax) && - context.SemanticModel.ResourceMetadata.TryLookup(propArrayAccess.BaseExpression) is { } resourceCollection && + context.SemanticModel.ResourceMetadata.TryLookup(propArrayAccess.BaseExpression) is DeclaredResourceMetadata resourceCollection && CreateConverterForIndexReplacement(resourceCollection.NameSyntax, propArrayAccess.IndexExpression, propertyAccess) .ConvertResourcePropertyAccess(resourceCollection, propArrayAccess.IndexExpression, propertyAccess.PropertyName.IdentifierName) is { } convertedCollection) { @@ -372,7 +408,7 @@ when context.SemanticModel.GetSymbolInfo(grandGrandChildVariableAccess) is Modul new JTokenExpression(propertyAccess.PropertyName.IdentifierName)); } - public IEnumerable GetResourceNameSegments(ResourceMetadata resource) + public IEnumerable GetResourceNameSegments(DeclaredResourceMetadata resource) { var typeReference = resource.TypeReference; var ancestors = this.context.SemanticModel.ResourceAncestors.GetAncestors(resource); @@ -416,7 +452,7 @@ public IEnumerable GetResourceNameSegments(ResourceMetadata new JTokenExpression(i))); } - public LanguageExpression GetFullyQualifiedResourceName(ResourceMetadata resource) + public LanguageExpression GetFullyQualifiedResourceName(DeclaredResourceMetadata resource) { var nameValueSyntax = resource.NameSyntax; @@ -453,7 +489,7 @@ public static SyntaxBase GetModuleNameSyntax(ModuleSymbol moduleSymbol) return moduleSymbol.SafeGetBodyPropertyValue(LanguageConstants.ModuleNamePropertyName) ?? throw new ArgumentException($"Expected module syntax body to contain property 'name'"); } - public LanguageExpression GetUnqualifiedResourceId(ResourceMetadata resource) + public LanguageExpression GetUnqualifiedResourceId(DeclaredResourceMetadata resource) { return ScopeHelper.FormatUnqualifiedResourceId( context, @@ -465,12 +501,20 @@ public LanguageExpression GetUnqualifiedResourceId(ResourceMetadata resource) public LanguageExpression GetFullyQualifiedResourceId(ResourceMetadata resource) { + if (resource is ParameterResourceMetadata parameter) + { + return new FunctionExpression( + "parameters", + new LanguageExpression[]{ new JTokenExpression(parameter.Symbol.Name), }, + new LanguageExpression[]{}); + } + return ScopeHelper.FormatFullyQualifiedResourceId( context, this, - context.ResourceScopeData[resource], + context.ResourceScopeData[(DeclaredResourceMetadata)resource], resource.TypeReference.FormatType(), - GetResourceNameSegments(resource)); + GetResourceNameSegments((DeclaredResourceMetadata)resource)); } public LanguageExpression GetFullyQualifiedResourceId(ModuleSymbol moduleSymbol) @@ -504,9 +548,19 @@ public FunctionExpression GetModuleOutputsReferenceExpression(ModuleSymbol modul public FunctionExpression GetReferenceExpression(ResourceMetadata resource, SyntaxBase? indexExpression, bool full) { - var referenceExpression = context.Settings.EnableSymbolicNames ? - GenerateSymbolicReference(resource.Symbol.Name, indexExpression) : - GetFullyQualifiedResourceId(resource); + var referenceExpression = resource switch + { + ParameterResourceMetadata parameter => new FunctionExpression( + "parameters", + new LanguageExpression[]{ new JTokenExpression(parameter.Symbol.Name), }, + Array.Empty()), + + DeclaredResourceMetadata declared when context.Settings.EnableSymbolicNames => + GenerateSymbolicReference(declared.Symbol.Name, indexExpression), + DeclaredResourceMetadata => GetFullyQualifiedResourceId(resource), + + _ => throw new InvalidOperationException($"Unexpected resource metadata type: {resource.GetType()}"), + }; // full gives access to top-level resource properties, but generates a longer statement if (full) @@ -624,6 +678,18 @@ private LanguageExpression ConvertVariableAccess(VariableAccessSyntax variableAc switch (symbol) { + case ParameterSymbol parameterSymbol when parameterSymbol.Type is ResourceType resourceType: + // This is a reference to a pre-existing resource where the resource ID was passed in as a + // string. Generate a call to reference(). + return CreateFunction( + "reference", + CreateFunction("parameters", new JTokenExpression(name)), + new JTokenExpression(resourceType.TypeReference.ApiVersion), + new JTokenExpression("full")); + + case ParameterSymbol parameterSymbol when parameterSymbol.Type is ResourceType: + return CreateFunction("parameters", new JTokenExpression(name)); + case ParameterSymbol _: return CreateFunction("parameters", new JTokenExpression(name)); diff --git a/src/Bicep.Core/Emit/ExpressionEmitter.cs b/src/Bicep.Core/Emit/ExpressionEmitter.cs index 2ccb302d16b..30dba6d80d5 100644 --- a/src/Bicep.Core/Emit/ExpressionEmitter.cs +++ b/src/Bicep.Core/Emit/ExpressionEmitter.cs @@ -101,7 +101,7 @@ public void EmitExpression(SyntaxBase resourceNameSyntax, SyntaxBase? indexExpre writer.WriteValue(serialized); } - public void EmitUnqualifiedResourceId(ResourceMetadata resource, SyntaxBase? indexExpression, SyntaxBase newContext) + public void EmitUnqualifiedResourceId(DeclaredResourceMetadata resource, SyntaxBase? indexExpression, SyntaxBase newContext) { var converterForContext = converter.CreateConverterForIndexReplacement(resource.NameSyntax, indexExpression, newContext); @@ -111,7 +111,7 @@ public void EmitUnqualifiedResourceId(ResourceMetadata resource, SyntaxBase? ind writer.WriteValue(serialized); } - public void EmitIndexedSymbolReference(ResourceMetadata resource, SyntaxBase indexExpression, SyntaxBase newContext) + public void EmitIndexedSymbolReference(DeclaredResourceMetadata resource, SyntaxBase indexExpression, SyntaxBase newContext) { var expression = converter.CreateConverterForIndexReplacement(resource.NameSyntax, indexExpression, newContext) .GenerateSymbolicReference(resource.Symbol.Name, indexExpression); @@ -127,7 +127,7 @@ public void EmitIndexedSymbolReference(ModuleSymbol moduleSymbol, SyntaxBase ind writer.WriteValue(ExpressionSerializer.SerializeExpression(expression)); } - public void EmitResourceIdReference(ResourceMetadata resource, SyntaxBase? indexExpression, SyntaxBase newContext) + public void EmitResourceIdReference(DeclaredResourceMetadata resource, SyntaxBase? indexExpression, SyntaxBase newContext) { var converterForContext = this.converter.CreateConverterForIndexReplacement(resource.NameSyntax, indexExpression, newContext); @@ -147,7 +147,7 @@ public void EmitResourceIdReference(ModuleSymbol moduleSymbol, SyntaxBase? index writer.WriteValue(serialized); } - public LanguageExpression GetFullyQualifiedResourceName(ResourceMetadata resource) + public LanguageExpression GetFullyQualifiedResourceName(DeclaredResourceMetadata resource) { return converter.GetFullyQualifiedResourceName(resource); } @@ -361,8 +361,9 @@ public void EmitModuleParameterValue(SyntaxBase syntax) var keyVaultId = instanceFunctionCall.BaseExpression switch { - ArrayAccessSyntax arrayAccessSyntax => converter.CreateConverterForIndexReplacement(resource.NameSyntax, arrayAccessSyntax.IndexExpression, instanceFunctionCall) - .GetFullyQualifiedResourceId(resource), + ArrayAccessSyntax arrayAccessSyntax when resource is DeclaredResourceMetadata declared => converter + .CreateConverterForIndexReplacement(declared.NameSyntax, arrayAccessSyntax.IndexExpression, instanceFunctionCall) + .GetFullyQualifiedResourceId(resource), _ => converter.GetFullyQualifiedResourceId(resource) }; diff --git a/src/Bicep.Core/Emit/ResourceDependencyVisitor.cs b/src/Bicep.Core/Emit/ResourceDependencyVisitor.cs index 8a9eaee17fb..44abee39e20 100644 --- a/src/Bicep.Core/Emit/ResourceDependencyVisitor.cs +++ b/src/Bicep.Core/Emit/ResourceDependencyVisitor.cs @@ -7,6 +7,7 @@ using Bicep.Core.DataFlow; using Bicep.Core.Extensions; using Bicep.Core.Semantics; +using Bicep.Core.Semantics.Metadata; using Bicep.Core.Syntax; namespace Bicep.Core.Emit @@ -50,7 +51,7 @@ private ResourceDependencyVisitor(SemanticModel model) public override void VisitResourceDeclarationSyntax(ResourceDeclarationSyntax syntax) { - if (model.ResourceMetadata.TryLookup(syntax) is not {} resource) + if (model.ResourceMetadata.TryLookup(syntax) is not DeclaredResourceMetadata resource) { // When invoked by BicepDeploymentGraphHandler, it's possible that the declaration is unbound. return; @@ -178,7 +179,7 @@ public override void VisitResourceAccessSyntax(ResourceAccessSyntax syntax) return; } } - + private SyntaxBase? GetIndexExpression(SyntaxBase syntax, bool isCollection) { SyntaxBase? candidateIndexExpression = isCollection && this.model.Binder.GetParent(syntax) is ArrayAccessSyntax arrayAccess && ReferenceEquals(arrayAccess.BaseExpression, syntax) diff --git a/src/Bicep.Core/Emit/ScopeHelper.cs b/src/Bicep.Core/Emit/ScopeHelper.cs index c528fbd6f1a..d54f90f954b 100644 --- a/src/Bicep.Core/Emit/ScopeHelper.cs +++ b/src/Bicep.Core/Emit/ScopeHelper.cs @@ -42,10 +42,10 @@ public class ScopeData /// /// The symbol of the resource being extended or null. /// - public ResourceMetadata? ResourceScope { get; set; } + public DeclaredResourceMetadata? ResourceScope { get; set; } /// - /// The expression for the loop index. This is used with loops when indexing into resource collections. + /// The expression for the loop index. This is used with loops when indexing into resource collections. /// public SyntaxBase? IndexExpression { get; set; } } @@ -129,7 +129,7 @@ public class ScopeData _ => new ScopeData { RequestedScope = ResourceScope.ResourceGroup, SubscriptionIdProperty = type.Arguments[0].Expression, ResourceGroupProperty = type.Arguments[1].Expression, IndexExpression = indexExpression }, }; case { } when scopeSymbol is ResourceSymbol targetResourceSymbol: - if (semanticModel.ResourceMetadata.TryLookup(targetResourceSymbol.DeclaringSyntax) is not { } targetResource) + if (semanticModel.ResourceMetadata.TryLookup(targetResourceSymbol.DeclaringSyntax) is not DeclaredResourceMetadata targetResource) { return null; } @@ -254,7 +254,7 @@ public static LanguageExpression FormatFullyQualifiedResourceId(EmitterContext c { mgScope = converter.GenerateManagementGroupResourceId(scopeData.ManagementGroupNameProperty, true); } - else + else { // use managementGroup().id to format the scope. This will only work at management group scope, // but we only permit referencing a parameter-less management group function at this scope. @@ -317,7 +317,7 @@ public static LanguageExpression FormatUnqualifiedResourceId(EmitterContext cont public static void EmitResourceScopeProperties(SemanticModel semanticModel, ScopeData scopeData, ExpressionEmitter expressionEmitter, SyntaxBase newContext) { - if (scopeData.ResourceScope is { } scopeResource) + if (scopeData.ResourceScope is DeclaredResourceMetadata scopeResource) { // emit the resource id of the resource being extended expressionEmitter.EmitProperty("scope", () => expressionEmitter.EmitUnqualifiedResourceId(scopeResource, scopeData.IndexExpression, newContext)); @@ -389,7 +389,7 @@ private static TypeProperty CreateResourceScopePropertyInternal(ResourceScope va return new(LanguageConstants.ResourceScopePropertyName, scopeReference, scopePropertyFlags); } - private static ResourceMetadata? GetRootResource(IReadOnlyDictionary scopeInfo, ResourceMetadata resource) + private static DeclaredResourceMetadata? GetRootResource(IReadOnlyDictionary scopeInfo, DeclaredResourceMetadata resource) { if (!scopeInfo.TryGetValue(resource, out var scopeData)) { @@ -404,7 +404,7 @@ private static TypeProperty CreateResourceScopePropertyInternal(ResourceScope va return resource; } - private static void ValidateResourceScopeRestrictions(SemanticModel semanticModel, IReadOnlyDictionary scopeInfo, ResourceMetadata resource, Action writeScopeDiagnostic) + private static void ValidateResourceScopeRestrictions(SemanticModel semanticModel, IReadOnlyDictionary scopeInfo, DeclaredResourceMetadata resource, Action writeScopeDiagnostic) { if (resource.IsExistingResource) { @@ -449,13 +449,13 @@ scopeData.ResourceGroupProperty is null && return matchesTargetScope; } - public static ImmutableDictionary GetResourceScopeInfo(SemanticModel semanticModel, IDiagnosticWriter diagnosticWriter) + public static ImmutableDictionary GetResourceScopeInfo(SemanticModel semanticModel, IDiagnosticWriter diagnosticWriter) { void logInvalidScopeDiagnostic(IPositionable positionable, ResourceScope suppliedScope, ResourceScope supportedScopes) => diagnosticWriter.Write(positionable, x => x.UnsupportedResourceScope(suppliedScope, supportedScopes)); - var scopeInfo = new Dictionary(); - var ancestorsLookup = semanticModel.AllResources + var scopeInfo = new Dictionary(); + var ancestorsLookup = semanticModel.AllResources.OfType() .ToDictionary( x => x, x => semanticModel.ResourceAncestors.GetAncestors(x)); @@ -502,12 +502,30 @@ void logInvalidScopeDiagnostic(IPositionable positionable, ResourceScope supplie continue; } + // Resources cannot be scoped to a resource passed as a parameter, because we don't have a good + // way to validate scope-escaping. + if (resource.ScopeSyntax is not null && + semanticModel.ResourceMetadata.TryLookup(resource.ScopeSyntax!) is ParameterResourceMetadata scopeMetadata) + { + diagnosticWriter.Write(DiagnosticBuilder.ForPosition(resource.ScopeSyntax).InvalidResourceScopeCannotBeResourceTypeParameter(scopeMetadata.Symbol.Name)); + scopeInfo[resource] = defaultScopeData; + continue; + } + // This check has to live here because if here because this case is not handled when building the resource ancestor graph. + else if (resource.Symbol.SafeGetBodyPropertyValue(LanguageConstants.ResourceParentPropertyName) is {} referenceParentSyntax && + semanticModel.ResourceMetadata.TryLookup(referenceParentSyntax) is ParameterResourceMetadata parentMetadata) + { + diagnosticWriter.Write(DiagnosticBuilder.ForPosition(referenceParentSyntax).InvalidResourceScopeCannotBeResourceTypeParameter(parentMetadata.Symbol.Name)); + scopeInfo[resource] = defaultScopeData; + continue; + } + var validatedScopeData = ScopeHelper.ValidateScope(semanticModel, logInvalidScopeDiagnostic, resource.Type.ValidParentScopes, resource.Symbol.DeclaringResource.Value, resource.ScopeSyntax); scopeInfo[resource] = validatedScopeData ?? defaultScopeData; } - foreach (var resourceToValidate in semanticModel.AllResources) + foreach (var resourceToValidate in semanticModel.AllResources.OfType()) { ValidateResourceScopeRestrictions( semanticModel, diff --git a/src/Bicep.Core/Emit/TemplateWriter.cs b/src/Bicep.Core/Emit/TemplateWriter.cs index f32630ac382..bb7a10e3e28 100644 --- a/src/Bicep.Core/Emit/TemplateWriter.cs +++ b/src/Bicep.Core/Emit/TemplateWriter.cs @@ -30,7 +30,7 @@ public class TemplateWriter : ITemplateWriter { public const string GeneratorMetadataPath = "metadata._generator"; public const string NestedDeploymentResourceType = AzResourceTypeProvider.ResourceTypeDeployments; - + // IMPORTANT: Do not update this API version until the new one is confirmed to be deployed and available in ALL the clouds. public const string NestedDeploymentResourceApiVersion = "2020-06-01"; @@ -137,7 +137,7 @@ public void Write(JsonTextWriter writer) } emitter.EmitProperty("contentVersion", "1.0.0.0"); - + this.EmitMetadata(jsonWriter, emitter); this.EmitParametersIfPresent(jsonWriter, emitter); @@ -211,7 +211,26 @@ decoratorSymbol.DeclaringObject is NamespaceType namespaceType && private void EmitParameter(JsonTextWriter jsonWriter, ParameterSymbol parameterSymbol, ExpressionEmitter emitter) { var declaringParameter = parameterSymbol.DeclaringParameter; - if (SyntaxHelper.TryGetPrimitiveType(declaringParameter) is not TypeSymbol primitiveType) + + var properties = new List(); + if (parameterSymbol.Type is ResourceType resourceType) + { + // Encode a resource type as a string parameter with a metadata for the resource type. + properties.Add(SyntaxFactory.CreateObjectProperty("type", SyntaxFactory.CreateStringLiteral(LanguageConstants.String.Name))); + properties.Add(SyntaxFactory.CreateObjectProperty( + LanguageConstants.ParameterMetadataPropertyName, + SyntaxFactory.CreateObject(new[] + { + SyntaxFactory.CreateObjectProperty( + LanguageConstants.MetadataResourceTypePropertyName, + SyntaxFactory.CreateStringLiteral(resourceType.TypeReference.FormatName())), + }))); + } + else if (SyntaxHelper.TryGetPrimitiveType(declaringParameter) is TypeSymbol primitiveType) + { + properties.Add(SyntaxFactory.CreateObjectProperty("type", SyntaxFactory.CreateStringLiteral(primitiveType.Name))); + } + else { // this should have been caught by the type checker long ago throw new ArgumentException($"Unable to find primitive type for parameter {parameterSymbol.Name}"); @@ -219,15 +238,14 @@ private void EmitParameter(JsonTextWriter jsonWriter, ParameterSymbol parameterS jsonWriter.WriteStartObject(); - var parameterType = SyntaxFactory.CreateStringLiteral(primitiveType.Name); - var parameterObject = SyntaxFactory.CreateObject(SyntaxFactory.CreateObjectProperty("type", parameterType).AsEnumerable()); + var parameterObject = SyntaxFactory.CreateObject(properties); if (declaringParameter.Modifier is ParameterDefaultValueSyntax defaultValueSyntax) { parameterObject = parameterObject.MergeProperty("defaultValue", defaultValueSyntax.DefaultValue); } - parameterObject = AddDecoratorsToBody(declaringParameter, parameterObject, primitiveType); + parameterObject = AddDecoratorsToBody(declaringParameter, parameterObject, SyntaxHelper.TryGetPrimitiveType(declaringParameter) ?? parameterSymbol.Type); foreach (var property in parameterObject.Properties) { @@ -297,7 +315,7 @@ private void EmitImports(JsonTextWriter jsonWriter, ExpressionEmitter emitter) foreach (var import in this.context.SemanticModel.Root.ImportDeclarations) { - var namespaceType = context.SemanticModel.GetTypeInfo(import.DeclaringSyntax) as NamespaceType + var namespaceType = context.SemanticModel.GetTypeInfo(import.DeclaringSyntax) as NamespaceType ?? throw new ArgumentException("Imported namespace does not have namespace type"); jsonWriter.WritePropertyName(import.DeclaringImport.AliasName.IdentifierName); @@ -328,7 +346,7 @@ private void EmitResources(JsonTextWriter jsonWriter, ExpressionEmitter emitter) jsonWriter.WriteStartArray(); } - foreach (var resource in this.context.SemanticModel.AllResources) + foreach (var resource in this.context.SemanticModel.AllResources.OfType()) { if (resource.IsExistingResource && !context.Settings.EnableSymbolicNames) { @@ -380,7 +398,7 @@ private void EmitResources(JsonTextWriter jsonWriter, ExpressionEmitter emitter) return null; } - private void EmitResource(JsonTextWriter jsonWriter, ResourceMetadata resource, ExpressionEmitter emitter) + private void EmitResource(JsonTextWriter jsonWriter, DeclaredResourceMetadata resource, ExpressionEmitter emitter) { jsonWriter.WriteStartObject(); @@ -388,7 +406,7 @@ private void EmitResource(JsonTextWriter jsonWriter, ResourceMetadata resource, // // Children inherit the conditions of their parents, etc. This avoids a problem // where we emit a dependsOn to something that's not in the template, or not - // being evaulated i the template. + // being evaulated i the template. var conditions = new List(); var loops = new List<(string name, ForSyntax @for, SyntaxBase? input)>(); @@ -477,7 +495,7 @@ private void EmitResource(JsonTextWriter jsonWriter, ResourceMetadata resource, jsonWriter.WritePropertyName("existing"); jsonWriter.WriteValue(true); } - + body = AddDecoratorsToBody(resource.Symbol.DeclaringResource, (ObjectSyntax)body, resource.Type); emitter.EmitObjectProperties((ObjectSyntax)body, ResourcePropertiesToOmit); @@ -486,7 +504,7 @@ private void EmitResource(JsonTextWriter jsonWriter, ResourceMetadata resource, jsonWriter.WriteEndObject(); } - private static void EmitModuleParameters(JsonTextWriter jsonWriter, ModuleSymbol moduleSymbol, ExpressionEmitter emitter) + private void EmitModuleParameters(JsonTextWriter jsonWriter, ModuleSymbol moduleSymbol, ExpressionEmitter emitter) { var paramsValue = moduleSymbol.SafeGetBodyPropertyValue(LanguageConstants.ModuleParamsPropertyName); if(paramsValue is not ObjectSyntax paramsObjectSyntax) @@ -522,6 +540,12 @@ private static void EmitModuleParameters(JsonTextWriter jsonWriter, ModuleSymbol jsonWriter.WriteEndArray(); }); } + else if (this.context.SemanticModel.ResourceMetadata.TryLookup(propertySyntax.Value) is {} resourceMetadata) + { + // This is a resource being passed into a module, we actually want to pass in its id + // rather than the whole resource. + emitter.EmitProperty("value", new PropertyAccessSyntax(propertySyntax.Value, SyntaxFactory.DotToken, SyntaxFactory.CreateIdentifier("id"))); + } else { // the value is not a for-expression - can emit normally @@ -556,7 +580,7 @@ private void EmitModule(JsonTextWriter jsonWriter, ModuleSymbol moduleSymbol, Ex { body = @for.Body; } - + var batchSize = GetBatchSize(moduleSymbol.DeclaringModule); emitter.EmitProperty("copy", () => emitter.EmitCopyObject(moduleSymbol.Name, @for, input: null, batchSize: batchSize)); break; @@ -636,7 +660,7 @@ private void EmitSymbolicNameDependsOnEntry(JsonTextWriter jsonWriter, Expressio switch (dependency.Resource) { case ResourceSymbol resourceDependency: - var resource = context.SemanticModel.ResourceMetadata.TryLookup(resourceDependency.DeclaringSyntax) ?? + var resource = context.SemanticModel.ResourceMetadata.TryLookup(resourceDependency.DeclaringSyntax) as DeclaredResourceMetadata ?? throw new ArgumentException($"Unable to find resource metadata for dependency '{dependency.Resource.Name}'"); switch ((resourceDependency.IsCollection, dependency.IndexExpression)) @@ -674,7 +698,7 @@ private void EmitSymbolicNameDependsOnEntry(JsonTextWriter jsonWriter, Expressio break; default: throw new InvalidOperationException($"Found dependency '{dependency.Resource.Name}' of unexpected type {dependency.GetType()}"); - } + } } private void EmitClassicDependsOnEntry(JsonTextWriter jsonWriter, ExpressionEmitter emitter, SyntaxBase newContext, ResourceDependency dependency) @@ -691,7 +715,7 @@ private void EmitClassicDependsOnEntry(JsonTextWriter jsonWriter, ExpressionEmit break; } - var resource = context.SemanticModel.ResourceMetadata.TryLookup(resourceDependency.DeclaringSyntax) ?? + var resource = context.SemanticModel.ResourceMetadata.TryLookup(resourceDependency.DeclaringSyntax) as DeclaredResourceMetadata ?? throw new ArgumentException($"Unable to find resource metadata for dependency '{dependency.Resource.Name}'"); emitter.EmitResourceIdReference(resource, dependency.IndexExpression, newContext); @@ -764,19 +788,49 @@ private void EmitOutput(JsonTextWriter jsonWriter, OutputSymbol outputSymbol, Ex { jsonWriter.WriteStartObject(); - emitter.EmitProperty("type", outputSymbol.Type.Name); + var properties = new List(); + if (outputSymbol.Type is ResourceType resourceType) + { + // Resource-typed outputs are encoded as strings + emitter.EmitProperty("type", LanguageConstants.String.Name); + + properties.Add(SyntaxFactory.CreateObjectProperty( + LanguageConstants.ParameterMetadataPropertyName, + SyntaxFactory.CreateObject(new[] + { + SyntaxFactory.CreateObjectProperty( + LanguageConstants.MetadataResourceTypePropertyName, + SyntaxFactory.CreateStringLiteral(resourceType.TypeReference.FormatName())), + }))); + } + else + { + emitter.EmitProperty("type", outputSymbol.Type.Name); + } + + if (outputSymbol.Value is ForSyntax @for) { emitter.EmitProperty("copy", () => emitter.EmitCopyObject(name: null, @for, @for.Body)); } else { - emitter.EmitProperty("value", outputSymbol.Value); + if (outputSymbol.Type is ResourceType) + { + // Resource-typed outputs are serialized using the resource id. + var value = new PropertyAccessSyntax(outputSymbol.Value, SyntaxFactory.DotToken, SyntaxFactory.CreateIdentifier("id")); + emitter.EmitProperty("value", value); + } + else + { + emitter.EmitProperty("value", outputSymbol.Value); + } + // emit any decorators on this output var body = AddDecoratorsToBody( - outputSymbol.DeclaringOutput, - SyntaxFactory.CreateObject(Enumerable.Empty()), - outputSymbol.Type); + outputSymbol.DeclaringOutput, + SyntaxFactory.CreateObject(properties), + outputSymbol.Type); foreach (var (property, val) in body.ToNamedPropertyValueDictionary()) { emitter.EmitProperty(property, val); diff --git a/src/Bicep.Core/LanguageConstants.cs b/src/Bicep.Core/LanguageConstants.cs index 569204962f5..67b5a0e94e0 100644 --- a/src/Bicep.Core/LanguageConstants.cs +++ b/src/Bicep.Core/LanguageConstants.cs @@ -87,6 +87,7 @@ public static class LanguageConstants public const string ParameterMaxLengthPropertyName = "maxLength"; public const string ParameterMetadataPropertyName = "metadata"; public const string MetadataDescriptionPropertyName = "description"; + public const string MetadataResourceTypePropertyName = "resourceType"; public const string BatchSizePropertyName = "batchSize"; // module properties diff --git a/src/Bicep.Core/Parsing/Parser.cs b/src/Bicep.Core/Parsing/Parser.cs index 39970165868..d311147cc94 100644 --- a/src/Bicep.Core/Parsing/Parser.cs +++ b/src/Bicep.Core/Parsing/Parser.cs @@ -233,7 +233,7 @@ private SyntaxBase ParameterDeclaration(IEnumerable leadingNodes) { var keyword = ExpectKeyword(LanguageConstants.ParameterKeyword); var name = this.IdentifierWithRecovery(b => b.ExpectedParameterIdentifier(), RecoveryFlags.None, TokenType.Identifier, TokenType.NewLine); - var type = this.WithRecovery(() => Type(b => b.ExpectedParameterType()), GetSuppressionFlag(name), TokenType.Assignment, TokenType.LeftBrace, TokenType.NewLine); + var type = this.WithRecovery(() => Type(b => b.ExpectedParameterType(), allowOptionalResourceType: false), GetSuppressionFlag(name), TokenType.Assignment, TokenType.LeftBrace, TokenType.NewLine); // TODO: Need a better way to choose the terminating token SyntaxBase? modifier = this.WithRecoveryNullable( @@ -280,7 +280,7 @@ private SyntaxBase OutputDeclaration(IEnumerable leadingNodes) { var keyword = ExpectKeyword(LanguageConstants.OutputKeyword); var name = this.IdentifierWithRecovery(b => b.ExpectedOutputIdentifier(), RecoveryFlags.None, TokenType.Identifier, TokenType.NewLine); - var type = this.WithRecovery(() => Type(b => b.ExpectedOutputType()), GetSuppressionFlag(name), TokenType.Assignment, TokenType.NewLine); + var type = this.WithRecovery(() => Type(b => b.ExpectedOutputType(), allowOptionalResourceType: true), GetSuppressionFlag(name), TokenType.Assignment, TokenType.NewLine); var assignment = this.WithRecovery(this.Assignment, GetSuppressionFlag(type), TokenType.NewLine); var value = this.WithRecovery(() => this.Expression(ExpressionFlags.AllowComplexLiterals), GetSuppressionFlag(assignment), TokenType.NewLine); @@ -800,11 +800,30 @@ private SkippedTriviaSyntax SkipEmpty(DiagnosticBuilder.ErrorBuilderDelegate err return new SkippedTriviaSyntax(span, ImmutableArray.Empty, errorFunc(DiagnosticBuilder.ForPosition(span)).AsEnumerable()); } - private TypeSyntax Type(DiagnosticBuilder.ErrorBuilderDelegate errorFunc) + private TypeSyntax Type(DiagnosticBuilder.ErrorBuilderDelegate errorFunc, bool allowOptionalResourceType) { - var identifier = Expect(TokenType.Identifier, errorFunc); + if (GetOptionalKeyword(LanguageConstants.ResourceKeyword) is {} resourceKeyword) + { + var type = this.WithRecoveryNullable( + () => + { + // The resource type is optional for an output + if (allowOptionalResourceType && !this.Check(this.reader.Peek(), TokenType.StringComplete, TokenType.StringLeftPiece)) + { + return null; + } + else + { + return ThrowIfSkipped(this.InterpolableString, b => b.ExpectedResourceTypeString()); + } + }, + RecoveryFlags.None, + TokenType.Assignment, TokenType.NewLine); + return new ResourceTypeSyntax(resourceKeyword, type); + } - return new TypeSyntax(identifier); + var identifier = Expect(TokenType.Identifier, errorFunc); + return new SimpleTypeSyntax(identifier); } private IntegerLiteralSyntax NumericLiteral() @@ -1308,7 +1327,7 @@ private Token Expect(TokenType type, DiagnosticBuilder.ErrorBuilderDelegate erro private Token ExpectKeyword(string expectedKeyword) { - return GetOptionalKeyword(expectedKeyword) ?? + return GetOptionalKeyword(expectedKeyword) ?? throw new ExpectedTokenException(this.reader.Peek(), b => b.ExpectedKeyword(expectedKeyword)); } diff --git a/src/Bicep.Core/Semantics/ArmTemplateSemanticModel.cs b/src/Bicep.Core/Semantics/ArmTemplateSemanticModel.cs index 6948621e805..ab32394e7d6 100644 --- a/src/Bicep.Core/Semantics/ArmTemplateSemanticModel.cs +++ b/src/Bicep.Core/Semantics/ArmTemplateSemanticModel.cs @@ -5,10 +5,13 @@ using System.Collections.Generic; using System.Collections.Immutable; using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.Linq; using Azure.Deployments.Core.Definitions.Schema; using Azure.Deployments.Core.Entities; using Bicep.Core.Diagnostics; +using Bicep.Core.Parsing; +using Bicep.Core.Resources; using Bicep.Core.TypeSystem; using Bicep.Core.Workspaces; using Newtonsoft.Json.Linq; @@ -137,6 +140,9 @@ private static TypeSymbol GetType(TemplateInputParameter parameter) TemplateParameterType.String or TemplateParameterType.SecureString when AllowedStringLiteralsProvided() => TypeHelper.CreateTypeUnion(allowedValueTypes), + TemplateParameterType.String when TryCreateResourceTypeParameter(parameter, out var resourceType) => + resourceType, + TemplateParameterType.Array when AllowedStringLiteralsProvided() => new TypedArrayType(TypeHelper.CreateTypeUnion(allowedValueTypes), TypeSymbolValidationFlags.Default), @@ -175,7 +181,28 @@ private static IEnumerable GetAllowedValueTypes(TemplateInputParamet }; } } - + + private static bool TryCreateResourceTypeParameter(TemplateParameter parameter, [NotNullWhen(true)] out TypeSymbol? type) + { + if (parameter.Metadata?.Value is JObject metadata && + metadata.TryGetValue("resourceType", out var obj) && + obj.Value() is string resourceTypeRaw) + { + if (ResourceTypeReference.TryParse(resourceTypeRaw) is {} parsed) + { + type = new ResourceParameterType(parsed); + return true; + } + + // Return true here because it *was* a resource type, just a wrong one. + type = ErrorType.Create(DiagnosticBuilder.ForPosition(new TextSpan(0, 0)).InvalidResourceType()); + return true; + } + + type = null; + return false; + } + private static string? TryGetMetadataDescription(TemplateGenericProperty? metadata) { if (metadata?.Value?.SelectToken(LanguageConstants.MetadataDescriptionPropertyName) is { } descriptionToken diff --git a/src/Bicep.Core/Semantics/Metadata/DeclaredResourceMetadata.cs b/src/Bicep.Core/Semantics/Metadata/DeclaredResourceMetadata.cs new file mode 100644 index 00000000000..c90fed3561c --- /dev/null +++ b/src/Bicep.Core/Semantics/Metadata/DeclaredResourceMetadata.cs @@ -0,0 +1,19 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. +using Bicep.Core.Syntax; +using Bicep.Core.TypeSystem; + +namespace Bicep.Core.Semantics.Metadata +{ + // Represents a resource that is declared with Bicep code. + public record DeclaredResourceMetadata( + ResourceType Type, + bool IsExistingResource, + SyntaxBase NameSyntax, + ResourceSymbol Symbol, + ResourceMetadataParent? Parent, + SyntaxBase? ScopeSyntax) + : ResourceMetadata(Type, IsExistingResource) + { + } +} diff --git a/src/Bicep.Core/Semantics/Metadata/ParameterResourceMetadata.cs b/src/Bicep.Core/Semantics/Metadata/ParameterResourceMetadata.cs new file mode 100644 index 00000000000..9947027a6d7 --- /dev/null +++ b/src/Bicep.Core/Semantics/Metadata/ParameterResourceMetadata.cs @@ -0,0 +1,17 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. +using Bicep.Core.Resources; +using Bicep.Core.Syntax; +using Bicep.Core.TypeSystem; + +namespace Bicep.Core.Semantics.Metadata +{ + // Represents a resource that is declared as a parameter in Bicep. + public record ParameterResourceMetadata( + ResourceType Type, + bool IsExistingResource, + ParameterSymbol Symbol) + : ResourceMetadata(Type, IsExistingResource) + { + } +} diff --git a/src/Bicep.Core/Semantics/Metadata/ResourceMetadata.cs b/src/Bicep.Core/Semantics/Metadata/ResourceMetadata.cs index e20fbbf1459..2e5ece02718 100644 --- a/src/Bicep.Core/Semantics/Metadata/ResourceMetadata.cs +++ b/src/Bicep.Core/Semantics/Metadata/ResourceMetadata.cs @@ -1,17 +1,13 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. using Bicep.Core.Resources; -using Bicep.Core.Syntax; using Bicep.Core.TypeSystem; namespace Bicep.Core.Semantics.Metadata { + // Represents a logical resource, regardless of how it was declared. public record ResourceMetadata( ResourceType Type, - SyntaxBase NameSyntax, - ResourceSymbol Symbol, - ResourceMetadataParent? Parent, - SyntaxBase? ScopeSyntax, bool IsExistingResource) { public ResourceTypeReference TypeReference => Type.TypeReference; diff --git a/src/Bicep.Core/Semantics/Metadata/ResourceMetadataCache.cs b/src/Bicep.Core/Semantics/Metadata/ResourceMetadataCache.cs index 7f1bceabdee..2061e93b1c8 100644 --- a/src/Bicep.Core/Semantics/Metadata/ResourceMetadataCache.cs +++ b/src/Bicep.Core/Semantics/Metadata/ResourceMetadataCache.cs @@ -5,6 +5,7 @@ using System.Collections.Immutable; using System.Runtime.CompilerServices; using Bicep.Core.Syntax; +using Bicep.Core.TypeSystem; using Bicep.Core.TypeSystem.Az; namespace Bicep.Core.Semantics.Metadata @@ -40,10 +41,19 @@ public ResourceMetadataCache(SemanticModel semanticModel) break; } + case ParameterDeclarationSyntax parameterDeclarationSyntax: + { + var symbol = semanticModel.GetSymbolInfo(parameterDeclarationSyntax); + if (symbol is ParameterSymbol parameterSymbol && parameterSymbol.Type is ResourceType resourceType) + { + return new ParameterResourceMetadata(resourceType, true, parameterSymbol); + } + break; + } case ResourceDeclarationSyntax resourceDeclarationSyntax: { // Skip analysis for ErrorSymbol and similar cases, these are invalid cases, and won't be emitted. - if (!resourceSymbols.Value.TryGetValue(resourceDeclarationSyntax, out var symbol) || + if (!resourceSymbols.Value.TryGetValue(resourceDeclarationSyntax, out var symbol) || symbol.TryGetResourceType() is not {} resourceType || symbol.SafeGetBodyPropertyValue(AzResourceTypeProvider.ResourceNamePropertyName) is not {} nameSyntax) { @@ -60,13 +70,13 @@ public ResourceMetadataCache(SemanticModel semanticModel) // nested resource parent syntax if (TryLookup(nestedParentSyntax) is {} parentMetadata) { - return new( + return new DeclaredResourceMetadata( resourceType, + symbol.DeclaringResource.IsExistingResource(), nameSyntax, symbol, new(parentMetadata, null, true), - symbol.SafeGetBodyPropertyValue(LanguageConstants.ResourceScopePropertyName), - symbol.DeclaringResource.IsExistingResource()); + symbol.SafeGetBodyPropertyValue(LanguageConstants.ResourceScopePropertyName)); } } else if (symbol.SafeGetBodyPropertyValue(LanguageConstants.ResourceParentPropertyName) is {} referenceParentSyntax) @@ -81,24 +91,24 @@ public ResourceMetadataCache(SemanticModel semanticModel) // parent property reference syntax if (TryLookup(referenceParentSyntax) is {} parentMetadata) { - return new( + return new DeclaredResourceMetadata( resourceType, + symbol.DeclaringResource.IsExistingResource(), nameSyntax, symbol, new(parentMetadata, indexExpression, false), - symbol.SafeGetBodyPropertyValue(LanguageConstants.ResourceScopePropertyName), - symbol.DeclaringResource.IsExistingResource()); + symbol.SafeGetBodyPropertyValue(LanguageConstants.ResourceScopePropertyName)); } } else { - return new( + return new DeclaredResourceMetadata( resourceType, + symbol.DeclaringResource.IsExistingResource(), nameSyntax, symbol, null, - symbol.SafeGetBodyPropertyValue(LanguageConstants.ResourceScopePropertyName), - symbol.DeclaringResource.IsExistingResource()); + symbol.SafeGetBodyPropertyValue(LanguageConstants.ResourceScopePropertyName)); } break; diff --git a/src/Bicep.Core/Semantics/ResourceAncestorGraph.cs b/src/Bicep.Core/Semantics/ResourceAncestorGraph.cs index 9dd297cfe2b..f817dcfa1bd 100644 --- a/src/Bicep.Core/Semantics/ResourceAncestorGraph.cs +++ b/src/Bicep.Core/Semantics/ResourceAncestorGraph.cs @@ -5,7 +5,6 @@ using System.Linq; using Bicep.Core.Semantics.Metadata; using Bicep.Core.Syntax; -using Bicep.Core.Workspaces; namespace Bicep.Core.Semantics { @@ -20,7 +19,7 @@ public enum ResourceAncestorType public class ResourceAncestor { - public ResourceAncestor(ResourceAncestorType ancestorType, ResourceMetadata resource, SyntaxBase? indexExpression) + public ResourceAncestor(ResourceAncestorType ancestorType, DeclaredResourceMetadata resource, SyntaxBase? indexExpression) { AncestorType = ancestorType; Resource = resource; @@ -29,21 +28,21 @@ public ResourceAncestor(ResourceAncestorType ancestorType, ResourceMetadata reso public ResourceAncestorType AncestorType { get; } - public ResourceMetadata Resource { get; } + public DeclaredResourceMetadata Resource { get; } public SyntaxBase? IndexExpression { get; } } - private readonly ImmutableDictionary> data; + private readonly ImmutableDictionary> data; - public ResourceAncestorGraph(ImmutableDictionary> data) + public ResourceAncestorGraph(ImmutableDictionary> data) { this.data = data; } // Gets the ordered list of ancestors of this resource in order from 'oldest' to 'youngest' // this is the same order we need to compute the name of a resource using `/` separated segments in a string. - public ImmutableArray GetAncestors(ResourceMetadata resource) + public ImmutableArray GetAncestors(DeclaredResourceMetadata resource) { if (data.TryGetValue(resource, out var results)) { @@ -55,9 +54,9 @@ public ImmutableArray GetAncestors(ResourceMetadata resource) } } - private static IEnumerable GetAncestorsYoungestToOldest(ImmutableDictionary hierarchy, ResourceMetadata resource) + private static IEnumerable GetAncestorsYoungestToOldest(ImmutableDictionary hierarchy, DeclaredResourceMetadata resource) { - var visited = new HashSet(); + var visited = new HashSet(); while (hierarchy.TryGetValue(resource, out var ancestor) && !visited.Contains(ancestor.Resource)) { visited.Add(ancestor.Resource); @@ -76,7 +75,7 @@ public static ResourceAncestorGraph Compute(SemanticModel semanticModel) .ToImmutableDictionary( child => child, child => GetAncestorsYoungestToOldest(visitor.Ancestry, child).Reverse().ToImmutableArray()); - + return new ResourceAncestorGraph(ancestry); } } diff --git a/src/Bicep.Core/Semantics/ResourceAncestorVisitor.cs b/src/Bicep.Core/Semantics/ResourceAncestorVisitor.cs index 9935435cf61..babbe1e349d 100644 --- a/src/Bicep.Core/Semantics/ResourceAncestorVisitor.cs +++ b/src/Bicep.Core/Semantics/ResourceAncestorVisitor.cs @@ -11,30 +11,30 @@ namespace Bicep.Core.Semantics public sealed class ResourceAncestorVisitor : SyntaxVisitor { private readonly SemanticModel semanticModel; - private readonly ImmutableDictionary.Builder ancestry; + private readonly ImmutableDictionary.Builder ancestry; public ResourceAncestorVisitor(SemanticModel semanticModel) { this.semanticModel = semanticModel; - this.ancestry = ImmutableDictionary.CreateBuilder(); + this.ancestry = ImmutableDictionary.CreateBuilder(); } - public ImmutableDictionary Ancestry + public ImmutableDictionary Ancestry => this.ancestry.ToImmutableDictionary(); public override void VisitResourceDeclarationSyntax(ResourceDeclarationSyntax syntax) { // Skip analysis for ErrorSymbol and similar cases, these are invalid cases, and won't be emitted. - if (semanticModel.ResourceMetadata.TryLookup(syntax) is not {} resource) + if (semanticModel.ResourceMetadata.TryLookup(syntax) is not DeclaredResourceMetadata resource) { base.VisitResourceDeclarationSyntax(syntax); return; } - + if (semanticModel.Binder.GetNearestAncestor(syntax) is {} nestedParentSyntax) { // nested resource parent syntax - if (semanticModel.ResourceMetadata.TryLookup(nestedParentSyntax) is {} parentResource) + if (semanticModel.ResourceMetadata.TryLookup(nestedParentSyntax) is DeclaredResourceMetadata parentResource) { this.ancestry.Add(resource, new ResourceAncestor(ResourceAncestorType.Nested, parentResource, null)); } @@ -49,7 +49,10 @@ public override void VisitResourceDeclarationSyntax(ResourceDeclarationSyntax sy } // parent property reference syntax - if (semanticModel.ResourceMetadata.TryLookup(referenceParentSyntax) is {} parentResource) + // + // This check is safe because we don't allow resources declared as parameters to be used with the + // parent property. Resources provided as parameters have an unknown scope. + if (semanticModel.ResourceMetadata.TryLookup(referenceParentSyntax) is DeclaredResourceMetadata parentResource) { this.ancestry.Add(resource, new ResourceAncestor(ResourceAncestorType.ParentProperty, parentResource, indexExpression)); } @@ -59,4 +62,4 @@ public override void VisitResourceDeclarationSyntax(ResourceDeclarationSyntax sy return; } } -} \ No newline at end of file +} diff --git a/src/Bicep.Core/Semantics/SemanticModel.cs b/src/Bicep.Core/Semantics/SemanticModel.cs index 2cdb7129c79..69ca99ed3d5 100644 --- a/src/Bicep.Core/Semantics/SemanticModel.cs +++ b/src/Bicep.Core/Semantics/SemanticModel.cs @@ -86,7 +86,17 @@ public SemanticModel(Compilation compilation, BicepFile sourceFile, IFileResolve typePropertyFlags |= TypePropertyFlags.Required; } - paramTypeProperties.Add(new TypeProperty(param.Name, param.Type, typePropertyFlags)); + if (param.Type is ResourceType resourceType) + { + // Resource type parameters are a special case, we need to convert to a dedicated + // type so we can compare differently for assignment. + var type = new ResourceParameterType(resourceType.TypeReference); + paramTypeProperties.Add(new TypeProperty(param.Name, type, typePropertyFlags)); + } + else + { + paramTypeProperties.Add(new TypeProperty(param.Name, param.Type, typePropertyFlags)); + } } return paramTypeProperties.ToImmutableArray(); @@ -243,6 +253,14 @@ private ImmutableArray GetAllResourceMetadata() } } + foreach (var parameterSymbol in Root.ParameterDeclarations) + { + if (this.ResourceMetadata.TryLookup(parameterSymbol.DeclaringSyntax) is { } resource) + { + resources.Add(resource); + } + } + return resources.ToImmutable(); } diff --git a/src/Bicep.Core/Syntax/ISyntaxVisitor.cs b/src/Bicep.Core/Syntax/ISyntaxVisitor.cs index 69e4a247b5a..c8b9a3c126e 100644 --- a/src/Bicep.Core/Syntax/ISyntaxVisitor.cs +++ b/src/Bicep.Core/Syntax/ISyntaxVisitor.cs @@ -62,7 +62,9 @@ public interface ISyntaxVisitor void VisitToken(Token token); - void VisitTypeSyntax(TypeSyntax syntax); + void VisitSimpleTypeSyntax(SimpleTypeSyntax syntax); + + void VisitResourceTypeSyntax(ResourceTypeSyntax syntax); void VisitUnaryOperationSyntax(UnaryOperationSyntax syntax); diff --git a/src/Bicep.Core/Syntax/OutputDeclarationSyntax.cs b/src/Bicep.Core/Syntax/OutputDeclarationSyntax.cs index 0962c7f2da8..8193354eee8 100644 --- a/src/Bicep.Core/Syntax/OutputDeclarationSyntax.cs +++ b/src/Bicep.Core/Syntax/OutputDeclarationSyntax.cs @@ -17,7 +17,7 @@ public OutputDeclarationSyntax(IEnumerable leadingNodes, Token keywo { AssertKeyword(keyword, nameof(keyword), LanguageConstants.OutputKeyword); AssertSyntaxType(name, nameof(name), typeof(IdentifierSyntax), typeof(IdentifierSyntax)); - AssertSyntaxType(type, nameof(type), typeof(TypeSyntax), typeof(SkippedTriviaSyntax)); + AssertSyntaxType(type, nameof(type), typeof(SimpleTypeSyntax), typeof(ResourceTypeSyntax), typeof(SkippedTriviaSyntax)); AssertSyntaxType(assignment, nameof(assignment), typeof(Token), typeof(SkippedTriviaSyntax)); AssertTokenType(assignment as Token, nameof(assignment), TokenType.Assignment); @@ -43,20 +43,5 @@ public OutputDeclarationSyntax(IEnumerable leadingNodes, Token keywo public override TextSpan Span => TextSpan.Between(this.LeadingNodes.FirstOrDefault() ?? this.Keyword, Value); public TypeSyntax? OutputType => this.Type as TypeSyntax; - - public TypeSymbol GetDeclaredType() - { - // assume "any" type if the output type has parse errors (either missing or skipped) - var declaredType = this.OutputType == null - ? LanguageConstants.Any - : LanguageConstants.TryGetDeclarationType(this.OutputType.TypeName); - - if (declaredType == null) - { - return ErrorType.Create(DiagnosticBuilder.ForPosition(this.Type).InvalidOutputType()); - } - - return declaredType; - } } } diff --git a/src/Bicep.Core/Syntax/ParameterDeclarationSyntax.cs b/src/Bicep.Core/Syntax/ParameterDeclarationSyntax.cs index 8732f3efa2b..da6fc38e8c5 100644 --- a/src/Bicep.Core/Syntax/ParameterDeclarationSyntax.cs +++ b/src/Bicep.Core/Syntax/ParameterDeclarationSyntax.cs @@ -20,7 +20,7 @@ public ParameterDeclarationSyntax(IEnumerable leadingNodes, Token ke { AssertKeyword(keyword, nameof(keyword), LanguageConstants.ParameterKeyword); AssertSyntaxType(name, nameof(name), typeof(IdentifierSyntax)); - AssertSyntaxType(type, nameof(type), typeof(TypeSyntax), typeof(SkippedTriviaSyntax)); + AssertSyntaxType(type, nameof(type), typeof(SimpleTypeSyntax), typeof(ResourceTypeSyntax), typeof(SkippedTriviaSyntax)); AssertSyntaxType(modifier, nameof(modifier), typeof(ParameterDefaultValueSyntax), typeof(SkippedTriviaSyntax)); this.Keyword = keyword; @@ -48,25 +48,15 @@ public override void Accept(ISyntaxVisitor visitor) /// public TypeSyntax? ParameterType => this.Type as TypeSyntax; - public TypeSymbol GetDeclaredType() + public TypeSymbol GetAssignedType(ITypeManager typeManager, ArraySyntax? allowedSyntax) { - // assume "any" type when the parameter has parse errors (either missing or was skipped) - var declaredType = this.ParameterType == null - ? LanguageConstants.Any - : LanguageConstants.TryGetDeclarationType(this.ParameterType.TypeName); - - if (declaredType == null) + var assignedType = typeManager.GetDeclaredType(this); + if (assignedType is null) { - return ErrorType.Create(DiagnosticBuilder.ForPosition(this.Type).InvalidParameterType()); + // We don't expect this to happen for a parameter. + return ErrorType.Empty(); } - return declaredType; - } - - public TypeSymbol GetAssignedType(ITypeManager typeManager, ArraySyntax? allowedSyntax) - { - var assignedType = this.GetDeclaredType(); - // TODO: remove SyntaxHelper.TryGetAllowedSyntax when we drop parameter modifiers support. if (allowedSyntax is not null && !allowedSyntax.Items.Any()) { diff --git a/src/Bicep.Core/Syntax/ResourceTypeSyntax.cs b/src/Bicep.Core/Syntax/ResourceTypeSyntax.cs new file mode 100644 index 00000000000..7ec934eeb46 --- /dev/null +++ b/src/Bicep.Core/Syntax/ResourceTypeSyntax.cs @@ -0,0 +1,31 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. +using Bicep.Core.Parsing; + +namespace Bicep.Core.Syntax +{ + public class ResourceTypeSyntax : TypeSyntax + { + public ResourceTypeSyntax(Token keyword, SyntaxBase? type) + { + AssertKeyword(keyword, nameof(keyword), LanguageConstants.ResourceKeyword); + AssertSyntaxType(type, nameof(type), typeof(StringSyntax), typeof(SkippedTriviaSyntax)); + + this.Keyword = keyword; + this.Type = type; + } + + public Token Keyword { get; } + + public SyntaxBase? Type { get; } + + public StringSyntax? TypeString => Type as StringSyntax; + + public override void Accept(ISyntaxVisitor visitor) + { + visitor.VisitResourceTypeSyntax(this); + } + + public override TextSpan Span => TextSpan.Between(this.Keyword, this.Type ?? this.Keyword); + } +} diff --git a/src/Bicep.Core/Syntax/SimpleTypeSyntax.cs b/src/Bicep.Core/Syntax/SimpleTypeSyntax.cs new file mode 100644 index 00000000000..355242f8372 --- /dev/null +++ b/src/Bicep.Core/Syntax/SimpleTypeSyntax.cs @@ -0,0 +1,28 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. +using Bicep.Core.Parsing; + +namespace Bicep.Core.Syntax +{ + public class SimpleTypeSyntax : TypeSyntax + { + public SimpleTypeSyntax(Token identifier) + { + AssertTokenType(identifier, nameof(identifier), TokenType.Identifier); + Assert(string.IsNullOrEmpty(identifier.Text) == false, "Identifier must not be null or empty."); + + this.Identifier = identifier; + } + + public Token Identifier { get; } + + public string TypeName => this.Identifier.Text; + + public override void Accept(ISyntaxVisitor visitor) + { + visitor.VisitSimpleTypeSyntax(this); + } + + public override TextSpan Span => TextSpan.Between(this.Identifier, this.Identifier); + } +} diff --git a/src/Bicep.Core/Syntax/SyntaxHelper.cs b/src/Bicep.Core/Syntax/SyntaxHelper.cs index ef7c5c69644..b4f9e79e14b 100644 --- a/src/Bicep.Core/Syntax/SyntaxHelper.cs +++ b/src/Bicep.Core/Syntax/SyntaxHelper.cs @@ -40,7 +40,7 @@ public static class SyntaxHelper } public static TypeSymbol? TryGetPrimitiveType(ParameterDeclarationSyntax parameterDeclarationSyntax) - => LanguageConstants.TryGetDeclarationType(parameterDeclarationSyntax.ParameterType?.TypeName); + => LanguageConstants.TryGetDeclarationType((parameterDeclarationSyntax.ParameterType as SimpleTypeSyntax)?.TypeName); public static ResourceScope GetTargetScope(TargetScopeSyntax targetScopeSyntax) { diff --git a/src/Bicep.Core/Syntax/SyntaxRewriteVisitor.cs b/src/Bicep.Core/Syntax/SyntaxRewriteVisitor.cs index 3c047fdf4c0..70af02842ad 100644 --- a/src/Bicep.Core/Syntax/SyntaxRewriteVisitor.cs +++ b/src/Bicep.Core/Syntax/SyntaxRewriteVisitor.cs @@ -304,7 +304,21 @@ protected virtual SyntaxBase ReplaceIdentifierSyntax(IdentifierSyntax syntax) } void ISyntaxVisitor.VisitIdentifierSyntax(IdentifierSyntax syntax) => ReplaceCurrent(syntax, ReplaceIdentifierSyntax); - protected virtual SyntaxBase ReplaceTypeSyntax(TypeSyntax syntax) + protected virtual SyntaxBase ReplaceResourceTypeSyntax(ResourceTypeSyntax syntax) + { + var hasChanges = TryRewriteStrict(syntax.Keyword, out var keyword); + hasChanges |= TryRewriteStrict(syntax.Type, out var type); + + if (!hasChanges) + { + return syntax; + } + + return new ResourceTypeSyntax(keyword, type); + } + void ISyntaxVisitor.VisitResourceTypeSyntax(ResourceTypeSyntax syntax) => ReplaceCurrent(syntax, ReplaceResourceTypeSyntax); + + protected virtual SyntaxBase ReplaceSimpleTypeSyntax(SimpleTypeSyntax syntax) { var hasChanges = TryRewriteStrict(syntax.Identifier, out var identifier); @@ -313,9 +327,9 @@ protected virtual SyntaxBase ReplaceTypeSyntax(TypeSyntax syntax) return syntax; } - return new TypeSyntax(identifier); + return new SimpleTypeSyntax(identifier); } - void ISyntaxVisitor.VisitTypeSyntax(TypeSyntax syntax) => ReplaceCurrent(syntax, ReplaceTypeSyntax); + void ISyntaxVisitor.VisitSimpleTypeSyntax(SimpleTypeSyntax syntax) => ReplaceCurrent(syntax, ReplaceSimpleTypeSyntax); protected virtual SyntaxBase ReplaceBooleanLiteralSyntax(BooleanLiteralSyntax syntax) { diff --git a/src/Bicep.Core/Syntax/SyntaxVisitor.cs b/src/Bicep.Core/Syntax/SyntaxVisitor.cs index 122215db66c..406a8da1ff7 100644 --- a/src/Bicep.Core/Syntax/SyntaxVisitor.cs +++ b/src/Bicep.Core/Syntax/SyntaxVisitor.cs @@ -126,7 +126,13 @@ public virtual void VisitIdentifierSyntax(IdentifierSyntax syntax) this.Visit(syntax.Child); } - public virtual void VisitTypeSyntax(TypeSyntax syntax) + public virtual void VisitResourceTypeSyntax(ResourceTypeSyntax syntax) + { + this.Visit(syntax.Keyword); + this.Visit(syntax.Type); + } + + public virtual void VisitSimpleTypeSyntax(SimpleTypeSyntax syntax) { this.Visit(syntax.Identifier); } diff --git a/src/Bicep.Core/Syntax/TypeSyntax.cs b/src/Bicep.Core/Syntax/TypeSyntax.cs index a3c3db5208d..28aa1675bdf 100644 --- a/src/Bicep.Core/Syntax/TypeSyntax.cs +++ b/src/Bicep.Core/Syntax/TypeSyntax.cs @@ -1,28 +1,9 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -using Bicep.Core.Parsing; namespace Bicep.Core.Syntax { - public class TypeSyntax : SyntaxBase + public abstract class TypeSyntax : SyntaxBase { - public TypeSyntax(Token identifier) - { - AssertTokenType(identifier, nameof(identifier), TokenType.Identifier); - Assert(string.IsNullOrEmpty(identifier.Text) == false, "Identifier must not be null or empty."); - - this.Identifier = identifier; - } - - public Token Identifier { get; } - - public string TypeName => this.Identifier.Text; - - public override void Accept(ISyntaxVisitor visitor) - { - visitor.VisitTypeSyntax(this); - } - - public override TextSpan Span => TextSpan.Between(this.Identifier, this.Identifier); } } diff --git a/src/Bicep.Core/TypeSystem/DeclaredTypeManager.cs b/src/Bicep.Core/TypeSystem/DeclaredTypeManager.cs index df7a7d988dd..3884435abe1 100644 --- a/src/Bicep.Core/TypeSystem/DeclaredTypeManager.cs +++ b/src/Bicep.Core/TypeSystem/DeclaredTypeManager.cs @@ -12,6 +12,7 @@ using Bicep.Core.Parsing; using Bicep.Core.Resources; using Bicep.Core.Semantics; +using Bicep.Core.Semantics.Namespaces; using Bicep.Core.Syntax; namespace Bicep.Core.TypeSystem @@ -106,9 +107,55 @@ public DeclaredTypeManager(TypeManager typeManager, IBinder binder) return null; } - private DeclaredTypeAssignment GetParameterType(ParameterDeclarationSyntax syntax) => new(syntax.GetDeclaredType(), syntax); + private DeclaredTypeAssignment GetParameterType(ParameterDeclarationSyntax syntax) + { + var declaredType = TryGetTypeFromTypeSyntax(syntax.ParameterType); + declaredType ??= ErrorType.Create(DiagnosticBuilder.ForPosition(syntax.Type).InvalidParameterType()); + if (IsExtensibilityType(declaredType)) + { + declaredType = ErrorType.Create(DiagnosticBuilder.ForPosition(syntax.Type).InvalidResourceTypeParameterType(declaredType.Name)); + } + return new(declaredType, syntax); + } + + private DeclaredTypeAssignment GetOutputType(OutputDeclarationSyntax syntax) + { + TypeSymbol declaredType; + if (syntax.Type is ResourceTypeSyntax resourceTypeSyntax && resourceTypeSyntax.Type is null) + { + // The resource type of an output can be inferred. + declaredType = this.typeManager.GetTypeInfo(syntax.Value); + } + else + { + declaredType = TryGetTypeFromTypeSyntax(syntax.OutputType) ?? + ErrorType.Create(DiagnosticBuilder.ForPosition(syntax.Type).InvalidOutputType()); + } + + if (IsExtensibilityType(declaredType)) + { + declaredType = ErrorType.Create(DiagnosticBuilder.ForPosition(syntax.Type).InvalidResourceTypeOutputType(declaredType.Name)); + } - private DeclaredTypeAssignment GetOutputType(OutputDeclarationSyntax syntax) => new(syntax.GetDeclaredType(), syntax); + return new(declaredType, syntax); + } + + private bool IsExtensibilityType(TypeSymbol type) + { + return type is ResourceType resourceType && resourceType.DeclaringNamespace.ProviderName != AzNamespaceType.BuiltInName; + } + + private TypeSymbol? TryGetTypeFromTypeSyntax(TypeSyntax? syntax) + { + // assume "any" type when the parameter has parse errors (either missing or was skipped) + return syntax switch + { + null => LanguageConstants.Any, + SimpleTypeSyntax simple => LanguageConstants.TryGetDeclarationType(simple.TypeName), + ResourceTypeSyntax resource => GetDeclaredResourceType(this.binder, resource), + _ => null + }; + } private DeclaredTypeAssignment? GetImportType(ImportDeclarationSyntax syntax) { @@ -133,7 +180,7 @@ private DeclaredTypeAssignment GetResourceType(ResourceDeclarationSyntax syntax) private DeclaredTypeAssignment GetModuleType(ModuleDeclarationSyntax syntax) { var declaredModuleType = syntax.GetDeclaredType(this.binder); - + // if the value is a loop (not a condition or object), the type is an array of the declared module type return new DeclaredTypeAssignment( syntax.Value is ForSyntax ? new TypedArrayType(declaredModuleType, TypeSymbolValidationFlags.Default) : declaredModuleType, @@ -179,8 +226,20 @@ private DeclaredTypeAssignment GetModuleType(ModuleDeclarationSyntax syntax) } var baseExpressionAssignment = GetDeclaredTypeAssignment(syntax.BaseExpression); - - // it's ok to rely on useSyntax=true because those types have already been established + + // As a special case, a 'resource' parameter is a reference to an existing resource + // we can't rely on it's syntax because it doesn't declare the resource body. + if (baseExpressionAssignment?.DeclaringSyntax is ParameterDeclarationSyntax parameterSyntax && + baseExpressionAssignment.Reference.Type is ResourceType resourceType) + { + return GetObjectPropertyType( + resourceType.Body.Type, + null, + syntax.PropertyName.IdentifierName, + useSyntax: false); + } + + // If we get here, it's ok to rely on useSyntax=true because those types have already been established var body = baseExpressionAssignment?.DeclaringSyntax switch { @@ -188,6 +247,7 @@ private DeclaredTypeAssignment GetModuleType(ModuleDeclarationSyntax syntax) ModuleDeclarationSyntax moduleDeclarationSyntax => moduleDeclarationSyntax.TryGetBody(), _ => baseExpressionAssignment?.DeclaringSyntax as ObjectSyntax, }; + return GetObjectPropertyType( baseExpressionAssignment?.Reference.Type, body, @@ -228,7 +288,7 @@ private DeclaredTypeAssignment GetModuleType(ModuleDeclarationSyntax syntax) return this.GetDeclaredTypeAssignment(((ResourceSymbol)symbol).DeclaringResource.Value); } - + private DeclaredTypeAssignment? GetArrayAccessType(ArrayAccessSyntax syntax) { var baseExpressionAssignment = GetDeclaredTypeAssignment(syntax.BaseExpression); @@ -249,7 +309,7 @@ private DeclaredTypeAssignment GetModuleType(ModuleDeclarationSyntax syntax) ForSyntax { Body: IfConditionSyntax { Body: ObjectSyntax loopBody } } => loopBody, _ => null }; - + return new DeclaredTypeAssignment(arrayType.Item.Type, declaringSyntax); case ObjectType objectType when syntax.IndexExpression is StringSyntax potentialLiteralValue && potentialLiteralValue.TryGetLiteralValue() is { } propertyName: @@ -386,7 +446,7 @@ private DeclaredTypeAssignment GetModuleType(ModuleDeclarationSyntax syntax) } var parentType = parentTypeAssignment.Reference.Type; - + // a for-loop expressions are semantically valid in places that allow array values // for non-array types, there's no need to propagate them further since it won't lead to anything useful if (parentType is not ArrayType arrayType) @@ -460,7 +520,7 @@ private DeclaredTypeAssignment GetModuleType(ModuleDeclarationSyntax syntax) // if-condition declared type already resolved discriminators and used the object as the declaring syntax Debug.Assert(ReferenceEquals(syntax, ifParentTypeAssignment.DeclaringSyntax), "ReferenceEquals(syntax,parentTypeAssignment.DeclaringSyntax)"); - + // the declared type will be the same as the parent return ifParentTypeAssignment; @@ -640,13 +700,46 @@ private DeclaredTypeAssignment GetModuleType(ModuleDeclarationSyntax syntax) // we should not try to obtain the declared type for such symbols because we will likely never finish private bool IsCycleFree(DeclaredSymbol declaredSymbol) => this.binder.TryGetCycle(declaredSymbol) is null; + /// + /// Returns the declared type of the parameter/output based on a resource type. + /// + /// resource type provider + private static TypeSymbol GetDeclaredResourceType(IBinder binder, ResourceTypeSyntax typeSyntax) + { + // NOTE: this is closely related to the logic in the other overload. Keep them in sync. + var stringSyntax = typeSyntax.TypeString; + if (stringSyntax != null && stringSyntax.IsInterpolated()) + { + // TODO: in the future, we can relax this check to allow interpolation with compile-time constants. + // right now, codegen will still generate a format string however, which will cause problems for the type. + return ErrorType.Create(DiagnosticBuilder.ForPosition(typeSyntax.Type!).ResourceTypeInterpolationUnsupported()); + } + + var stringContent = stringSyntax?.TryGetLiteralValue(); + if (stringContent == null) + { + return ErrorType.Create(DiagnosticBuilder.ForPosition(typeSyntax.Type!).InvalidResourceType()); + } + + // Parameters/outputs have to provide a fully-qualified type if the provide one. + var typeReference = ResourceTypeReference.TryParse(stringContent); + if (typeReference == null) + { + return ErrorType.Create(DiagnosticBuilder.ForPosition(typeSyntax.Type!).InvalidResourceType()); + } + + // A parameter/output always refers to an 'existing' resource. + var flags = ResourceTypeGenerationFlags.ExistingResource; + return binder.NamespaceResolver.GetResourceType(typeReference, flags); + } + /// /// Returns the declared type of the resource body (based on the type string). /// Returns the same value for single resource or resource loops declarations. /// - /// resource type provider private static TypeSymbol GetDeclaredResourceType(IBinder binder, ResourceDeclarationSyntax resource) { + // NOTE: this is closely related to the logic in the other overload. Keep them in sync. var stringSyntax = resource.TypeString; if (stringSyntax != null && stringSyntax.IsInterpolated()) diff --git a/src/Bicep.Core/TypeSystem/ResourceParameterType.cs b/src/Bicep.Core/TypeSystem/ResourceParameterType.cs new file mode 100644 index 00000000000..642236edf28 --- /dev/null +++ b/src/Bicep.Core/TypeSystem/ResourceParameterType.cs @@ -0,0 +1,20 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +using Bicep.Core.Resources; + +namespace Bicep.Core.TypeSystem +{ + public class ResourceParameterType : TypeSymbol + { + public ResourceParameterType(ResourceTypeReference typeReference) + : base(typeReference.FormatType()) + { + this.TypeReference = typeReference; + } + + public ResourceTypeReference TypeReference { get; } + + public override TypeKind TypeKind => TypeKind.Resource; + } +} diff --git a/src/Bicep.Core/TypeSystem/TypeAssignmentVisitor.cs b/src/Bicep.Core/TypeSystem/TypeAssignmentVisitor.cs index f3c9ee98ec8..6c41f4a297f 100644 --- a/src/Bicep.Core/TypeSystem/TypeAssignmentVisitor.cs +++ b/src/Bicep.Core/TypeSystem/TypeAssignmentVisitor.cs @@ -296,7 +296,11 @@ public override void VisitModuleDeclarationSyntax(ModuleDeclarationSyntax syntax public override void VisitParameterDeclarationSyntax(ParameterDeclarationSyntax syntax) => AssignTypeWithDiagnostics(syntax, diagnostics => { - var declaredType = syntax.GetDeclaredType(); + var declaredType = typeManager.GetDeclaredType(syntax); + if (declaredType is null) + { + return ErrorType.Empty(); + } this.ValidateDecorators(syntax.Decorators, declaredType, diagnostics); @@ -466,7 +470,11 @@ public override void VisitVariableDeclarationSyntax(VariableDeclarationSyntax sy public override void VisitOutputDeclarationSyntax(OutputDeclarationSyntax syntax) => AssignTypeWithDiagnostics(syntax, diagnostics => { - var declaredType = syntax.GetDeclaredType(); + var declaredType = this.typeManager.GetDeclaredType(syntax); + if (declaredType is null) + { + return ErrorType.Empty(); + } this.ValidateDecorators(syntax.Decorators, declaredType, diagnostics); @@ -1358,7 +1366,9 @@ private IEnumerable GetOutputDeclarationDiagnostics(TypeSymbol assi return valueType.GetDiagnostics(); } - if (TypeValidator.AreTypesAssignable(valueType, assignedType) == false) + // Avoid reporting an additional error if we failed to bind the output type. + if (TypeValidator.AreTypesAssignable(valueType, assignedType) == false && + assignedType is not ErrorType) { return DiagnosticBuilder.ForPosition(syntax.Value).OutputTypeMismatch(assignedType, valueType).AsEnumerable(); } diff --git a/src/Bicep.Core/TypeSystem/TypeValidator.cs b/src/Bicep.Core/TypeSystem/TypeValidator.cs index b2580b0a112..764283a1538 100644 --- a/src/Bicep.Core/TypeSystem/TypeValidator.cs +++ b/src/Bicep.Core/TypeSystem/TypeValidator.cs @@ -103,6 +103,10 @@ public static bool AreTypesAssignable(TypeSymbol sourceType, TypeSymbol targetTy // Assigning a resource to a parent property. return sourceResourceType.TypeReference.IsParentOf(targetResourceParentType.ChildTypeReference); + case (ResourceType sourceResourceType, ResourceParameterType resourceParameterType): + // Assigning a resource to a parameter ignores the API Version + return sourceResourceType.TypeReference.FormatType().Equals(resourceParameterType.TypeReference.FormatType(), StringComparison.OrdinalIgnoreCase); + case (ResourceType sourceResourceType, _): // When assigning a resource, we're really assigning the value of the resource body. return AreTypesAssignable(sourceResourceType.Body.Type, targetType); diff --git a/src/Bicep.Decompiler/Rewriters/ParentChildResourceNameRewriter.cs b/src/Bicep.Decompiler/Rewriters/ParentChildResourceNameRewriter.cs index 5a4c9c019e1..be2da2e8092 100644 --- a/src/Bicep.Decompiler/Rewriters/ParentChildResourceNameRewriter.cs +++ b/src/Bicep.Decompiler/Rewriters/ParentChildResourceNameRewriter.cs @@ -6,6 +6,7 @@ using Bicep.Core.Extensions; using Bicep.Core.Parsing; using Bicep.Core.Semantics; +using Bicep.Core.Semantics.Metadata; using Bicep.Core.Syntax; using Bicep.Core.TypeSystem; @@ -17,7 +18,7 @@ namespace Bicep.Core.Decompiler.Rewriters // resource resA 'My.Rp/resA@2020-01-01' = { // name: parentName // } - // + // // resource resB 'My.Rp/resA/childB@2020-01-01' = { // name: '${parentName}/resB' // dependsOn: [ @@ -91,7 +92,7 @@ protected override SyntaxBase ReplaceResourceDeclarationSyntax(ResourceDeclarati return syntax; } - foreach (var otherResource in semanticModel.AllResources) + foreach (var otherResource in semanticModel.AllResources.OfType()) { var otherResourceSymbol = otherResource.Symbol; @@ -201,4 +202,4 @@ protected override SyntaxBase ReplaceResourceDeclarationSyntax(ResourceDeclarati return SyntaxFactory.CreateString(newNameValues, newExpressions); } } -} \ No newline at end of file +} diff --git a/src/Bicep.Decompiler/TemplateConverter.cs b/src/Bicep.Decompiler/TemplateConverter.cs index ec1448bb4d0..2bbcd072322 100644 --- a/src/Bicep.Decompiler/TemplateConverter.cs +++ b/src/Bicep.Decompiler/TemplateConverter.cs @@ -144,15 +144,16 @@ private LanguageExpression InlineVariables(LanguageExpression original) return ExpressionHelpers.FlattenStringOperations(inlined); } - private static TypeSyntax? TryParseType(JToken? value) + private static SimpleTypeSyntax? TryParseType(JToken? value) { + // ARM JSON always encodes the type as a simple type (not a resource type). var typeString = value?.Value(); if (typeString == null) { return null; } - return new TypeSyntax(SyntaxFactory.CreateToken(TokenType.Identifier, typeString.ToLowerInvariant())); + return new SimpleTypeSyntax(SyntaxFactory.CreateToken(TokenType.Identifier, typeString.ToLowerInvariant())); } private string? TryLookupResource(LanguageExpression expression) @@ -695,18 +696,18 @@ expression is ObjectSyntax metadataObject && switch (typeSyntax.TypeName) { case "securestring": - typeSyntax = new TypeSyntax(SyntaxFactory.CreateToken(TokenType.Identifier, "string")); + typeSyntax = new SimpleTypeSyntax(SyntaxFactory.CreateToken(TokenType.Identifier, "string")); decoratorsAndNewLines.Add(SyntaxFactory.CreateDecorator(LanguageConstants.ParameterSecurePropertyName)); decoratorsAndNewLines.Add(SyntaxFactory.NewlineToken); break; case "secureobject": - typeSyntax = new TypeSyntax(SyntaxFactory.CreateToken(TokenType.Identifier, "object")); + typeSyntax = new SimpleTypeSyntax(SyntaxFactory.CreateToken(TokenType.Identifier, "object")); decoratorsAndNewLines.Add(SyntaxFactory.CreateDecorator(LanguageConstants.ParameterSecurePropertyName)); decoratorsAndNewLines.Add(SyntaxFactory.NewlineToken); break; case "__bicep_replace": var fixupToken = SyntaxHelpers.CreatePlaceholderToken(TokenType.Identifier, "TODO: fill in correct type"); - typeSyntax = new TypeSyntax(fixupToken); + typeSyntax = new SimpleTypeSyntax(fixupToken); break; } diff --git a/src/Bicep.LangServer.UnitTests/BicepCompletionProviderTests.cs b/src/Bicep.LangServer.UnitTests/BicepCompletionProviderTests.cs index b782845c611..07e93e1e9cc 100644 --- a/src/Bicep.LangServer.UnitTests/BicepCompletionProviderTests.cs +++ b/src/Bicep.LangServer.UnitTests/BicepCompletionProviderTests.cs @@ -112,7 +112,7 @@ public void NonDeclarationContextShouldIncludeDeclaredSymbols() { var grouping = SourceFileGroupingFactory.CreateFromText(@" param p string -var v = +var v = resource r 'Microsoft.Foo/foos@2020-09-01' = { name: 'foo' } @@ -120,11 +120,11 @@ param p string ", BicepTestConstants.FileResolver); var offset = grouping.EntryPoint.ProgramSyntax.Declarations.OfType().Single().Value.Span.Position; var compilation = new Compilation(TestTypeHelper.CreateEmptyProvider(), grouping, BicepTestConstants.BuiltInConfiguration); - + var provider = new BicepCompletionProvider(BicepTestConstants.FileResolver, snippetsProvider, new TelemetryProvider(Server), BicepTestConstants.Features); var context = BicepCompletionContext.Create(BicepTestConstants.Features, compilation, offset); var completions = provider.GetFilteredCompletions(compilation, context).ToList(); - + AssertExpectedFunctions(completions, expectParamDefaultFunctions: false); // outputs can't be referenced so they should not show up in completions @@ -188,7 +188,7 @@ param concat string resource base64 'Microsoft.Foo/foos@2020-09-01' = { name: 'foo' } -output length int = +output length int = ", BicepTestConstants.FileResolver); var offset = grouping.EntryPoint.ProgramSyntax.Declarations.OfType().Single().Value.Span.Position; @@ -413,6 +413,15 @@ private static void AssertExpectedDeclarationTypeCompletions(List + { + const string expected = "resource"; + c.Label.Should().Be(expected); + c.Kind.Should().Be(CompletionItemKind.Class); + c.InsertTextFormat.Should().Be(InsertTextFormat.PlainText); + c.TextEdit!.TextEdit!.NewText.Should().Be(expected); + c.Detail.Should().Be(expected); }); } diff --git a/src/Bicep.LangServer/Completions/BicepCompletionContext.cs b/src/Bicep.LangServer/Completions/BicepCompletionContext.cs index fa205a6e612..b1d746518dd 100644 --- a/src/Bicep.LangServer/Completions/BicepCompletionContext.cs +++ b/src/Bicep.LangServer/Completions/BicepCompletionContext.cs @@ -128,7 +128,7 @@ public static BicepCompletionContext Create(IFeatureProvider featureProvider, Co ConvertFlag(IsOuterExpressionContext(matchingNodes, offset), BicepCompletionContextKind.Expression) | ConvertFlag(IsTargetScopeContext(matchingNodes, offset), BicepCompletionContextKind.TargetScope) | ConvertFlag(IsDecoratorNameContext(matchingNodes, offset), BicepCompletionContextKind.DecoratorName); - + if (featureProvider.ImportsEnabled) { kind |= ConvertFlag(IsImportSymbolFollower(matchingNodes, offset), BicepCompletionContextKind.ImportSymbolFollower) | @@ -173,28 +173,52 @@ private static BicepCompletionContextKind GetDeclarationTypeFlags(IList name.Span.Length > 0 && offset > name.GetEndPosition() && offset <= type.Span.Position; + bool CheckResourceTypeIsExpected(SyntaxBase name, SyntaxBase type) => name.Span.Length > 0 && type.Span.Length > 0 && offset > type.GetEndPosition() && type is ResourceTypeSyntax resourceType && resourceType.Type is null; + if (SyntaxMatcher.IsTailMatch(matchingNodes, parameter => CheckTypeIsExpected(parameter.Name, parameter.Type)) || - SyntaxMatcher.IsTailMatch(matchingNodes, (_, _, token) => token.Type == TokenType.Identifier)) + SyntaxMatcher.IsTailMatch(matchingNodes, (_, _, token) => token.Type == TokenType.Identifier)) { // the most specific matching node is a parameter declaration // the declaration syntax is "param ..." // the cursor position is on the type if we have an identifier (non-zero length span) and the offset matches the type position // OR - // we are in a token that is inside a TypeSyntax node, which is inside a parameter node + // we are in a token that is inside a SimpleTypeSyntax node, which is inside a parameter node return BicepCompletionContextKind.ParameterType; } + if (SyntaxMatcher.IsTailMatch(matchingNodes, parameter => CheckResourceTypeIsExpected(parameter.Name, parameter.Type)) || + SyntaxMatcher.IsTailMatch(matchingNodes, (_, _, _, token) => token.Type == TokenType.StringComplete)) + { + // the most specific matching node is a parameter declaration with the resource keyword + // the declaration syntax is "param resource ..." + // the cursor position is on the resource type if we have the resource keyword but nothing else + // OR + // we are in a token that is inside a ResourceTypeSyntax node, which is inside a parameter node + return BicepCompletionContextKind.ResourceType; + } + if (SyntaxMatcher.IsTailMatch(matchingNodes, output => CheckTypeIsExpected(output.Name, output.Type)) || - SyntaxMatcher.IsTailMatch(matchingNodes, (_, _, token) => token.Type == TokenType.Identifier)) + SyntaxMatcher.IsTailMatch(matchingNodes, (_, _, token) => token.Type == TokenType.Identifier)) { // the most specific matching node is an output declaration // the declaration syntax is "output ..." // the cursor position is on the type if we have an identifier (non-zero length span) and the offset matches the type position // OR - // we are in a token that is inside a TypeSyntax node, which is inside an output node + // we are in a token that is inside a SimpleTypeSyntax node, which is inside an output node return BicepCompletionContextKind.OutputType; } + if (SyntaxMatcher.IsTailMatch(matchingNodes, output => CheckResourceTypeIsExpected(output.Name, output.Type)) || + SyntaxMatcher.IsTailMatch(matchingNodes, (_, _, _, token) => token.Type == TokenType.StringComplete)) + { + // the most specific matching node is an output declaration with the resource keyword + // the declaration syntax is "output resource ..." + // the cursor position is on the resource type if we have the resource keyword but nothing else + // OR + // we are in a token that is inside a ResourceTypeSyntax node, which is inside an output node + return BicepCompletionContextKind.ResourceType; + } + if (SyntaxMatcher.IsTailMatch(matchingNodes, resource => CheckTypeIsExpected(resource.Name, resource.Type)) || SyntaxMatcher.IsTailMatch(matchingNodes, (_, _, token) => token.Type == TokenType.StringComplete) || SyntaxMatcher.IsTailMatch(matchingNodes, (resource, skipped, token) => resource.Type == skipped && token.Type == TokenType.Identifier)) @@ -711,7 +735,7 @@ TokenType.StringMiddlePiece when IsOffsetImmediatlyAfterNode(offset, token) => f (operatorToken.Type == TokenType.Colon && operatorToken.GetPosition() == offset && ternaryOperation.TrueExpression is not SkippedTriviaSyntax) || (operatorToken.Type == TokenType.Colon && operatorToken.GetEndPosition() == offset && ternaryOperation.FalseExpression is not SkippedTriviaSyntax))); } - + static bool IsOffsetImmediatlyAfterNode(int offset, SyntaxBase node) => node.Span.Position + node.Span.Length == offset; private static Range GetReplacementRange(BicepFile bicepFile, SyntaxBase innermostMatchingNode, int offset) diff --git a/src/Bicep.LangServer/Completions/BicepCompletionProvider.cs b/src/Bicep.LangServer/Completions/BicepCompletionProvider.cs index 311d41d97e0..e961238096e 100644 --- a/src/Bicep.LangServer/Completions/BicepCompletionProvider.cs +++ b/src/Bicep.LangServer/Completions/BicepCompletionProvider.cs @@ -177,12 +177,12 @@ IEnumerable GetPrimitiveTypeCompletions() => if (context.Kind.HasFlag(BicepCompletionContextKind.ParameterType)) { - return GetPrimitiveTypeCompletions().Concat(GetParameterTypeSnippets(compilation, context)); + return GetPrimitiveTypeCompletions().Concat(GetParameterTypeSnippets(compilation, context)).Concat(CreateResourceTypeKeywordCompletion(context.ReplacementRange)); } if (context.Kind.HasFlag(BicepCompletionContextKind.OutputType)) { - return GetPrimitiveTypeCompletions(); + return GetPrimitiveTypeCompletions().Concat(CreateResourceTypeKeywordCompletion(context.ReplacementRange)); } return Enumerable.Empty(); @@ -226,17 +226,35 @@ private IEnumerable GetResourceTypeCompletions(SemanticModel mod return items; } + static string? TryGetFullyQualifiedType(StringSyntax? stringSyntax) + { + if (stringSyntax?.TryGetLiteralValue() is string entered && ResourceTypeReference.IsNamespaceAndTypeSegment(entered)) + { + return entered; + } + + return null; + } + + static string? TryGetFullyQualfiedResourceType(SyntaxBase? enclosingDeclaration) + { + return enclosingDeclaration switch + { + ResourceDeclarationSyntax resourceSyntax => TryGetFullyQualifiedType(resourceSyntax.TypeString), + ParameterDeclarationSyntax parameterSyntax when parameterSyntax.Type is ResourceTypeSyntax resourceType => TryGetFullyQualifiedType(resourceType.TypeString), + OutputDeclarationSyntax outputSyntax when outputSyntax.Type is ResourceTypeSyntax resourceType => TryGetFullyQualifiedType(resourceType.TypeString), + _ => null, + }; + } + // ResourceType completions are divided into 2 parts. // If the current value passes the namespace and type notation ("/") format, we return the fully qualified resource types - if (context.EnclosingDeclaration is ResourceDeclarationSyntax declarationSyntax - && declarationSyntax.Type is StringSyntax stringSyntax - && stringSyntax.TryGetLiteralValue() is string entered - && ResourceTypeReference.IsNamespaceAndTypeSegment(entered)) + if (TryGetFullyQualfiedResourceType(context.EnclosingDeclaration) is string qualified) { // newest api versions should be shown first // strict filtering on type so that we show api versions for only the selected type return model.Binder.NamespaceResolver.GetAvailableResourceTypes() - .Where(rt => StringComparer.OrdinalIgnoreCase.Equals(entered.Split('@')[0], rt.FormatType())) + .Where(rt => StringComparer.OrdinalIgnoreCase.Equals(qualified.Split('@')[0], rt.FormatType())) .OrderBy(rt => rt.FormatType(), StringComparer.OrdinalIgnoreCase) .ThenByDescending(rt => rt.ApiVersion, ApiVersionComparer.Instance) .Select((reference, index) => CreateResourceTypeCompletion(reference, index, context.ReplacementRange, showApiVersion: true)) @@ -1002,6 +1020,13 @@ private static CompletionItem CreateTypeCompletion(TypeSymbol type, Range replac .WithSortText(GetSortText(type.Name, priority)) .Build(); + private static CompletionItem CreateResourceTypeKeywordCompletion(Range replacementRange, CompletionPriority priority= CompletionPriority.Medium) => + CompletionItemBuilder.Create(CompletionItemKind.Class, LanguageConstants.ResourceKeyword) + .WithPlainTextEdit(replacementRange, LanguageConstants.ResourceKeyword) + .WithDetail(LanguageConstants.ResourceKeyword) + .WithSortText(GetSortText(LanguageConstants.ResourceKeyword, priority)) + .Build(); + private static CompletionItem CreateOperatorCompletion(string op, Range replacementRange, bool preselect = false, CompletionPriority priority = CompletionPriority.Medium) => CompletionItemBuilder.Create(CompletionItemKind.Operator, op) .WithPlainTextEdit(replacementRange, op) diff --git a/src/Bicep.LangServer/SemanticTokenVisitor.cs b/src/Bicep.LangServer/SemanticTokenVisitor.cs index 259b47945f1..883e8e2808d 100644 --- a/src/Bicep.LangServer/SemanticTokenVisitor.cs +++ b/src/Bicep.LangServer/SemanticTokenVisitor.cs @@ -259,10 +259,16 @@ public override void VisitSyntaxTrivia(SyntaxTrivia syntaxTrivia) } } - public override void VisitTypeSyntax(TypeSyntax syntax) + public override void VisitResourceTypeSyntax(ResourceTypeSyntax syntax) + { + AddTokenType(syntax.Keyword, SemanticTokenType.Keyword); + base.VisitResourceTypeSyntax(syntax); + } + + public override void VisitSimpleTypeSyntax(SimpleTypeSyntax syntax) { AddTokenType(syntax.Identifier, SemanticTokenType.Type); - base.VisitTypeSyntax(syntax); + base.VisitSimpleTypeSyntax(syntax); } public override void VisitUnaryOperationSyntax(UnaryOperationSyntax syntax) diff --git a/src/Bicep.Wasm/LanguageHelpers/SemanticTokenVisitor.cs b/src/Bicep.Wasm/LanguageHelpers/SemanticTokenVisitor.cs index 2b197bc005b..dc50128952a 100644 --- a/src/Bicep.Wasm/LanguageHelpers/SemanticTokenVisitor.cs +++ b/src/Bicep.Wasm/LanguageHelpers/SemanticTokenVisitor.cs @@ -139,7 +139,7 @@ public override void VisitResourceDeclarationSyntax(ResourceDeclarationSyntax sy { AddTokenType(syntax.Keyword, SemanticTokenType.Keyword); AddTokenType(syntax.Name, SemanticTokenType.Variable); - AddTokenType(syntax.ExistingKeyword, SemanticTokenType.Keyword); + AddTokenType(syntax.ExistingKeyword, SemanticTokenType.Keyword); base.VisitResourceDeclarationSyntax(syntax); } @@ -241,10 +241,16 @@ public override void VisitSyntaxTrivia(SyntaxTrivia syntaxTrivia) } } - public override void VisitTypeSyntax(TypeSyntax syntax) + public override void VisitResourceTypeSyntax(ResourceTypeSyntax syntax) + { + AddTokenType(syntax.Keyword, SemanticTokenType.Keyword); + base.VisitResourceTypeSyntax(syntax); + } + + public override void VisitSimpleTypeSyntax(SimpleTypeSyntax syntax) { AddTokenType(syntax.Identifier, SemanticTokenType.Type); - base.VisitTypeSyntax(syntax); + base.VisitSimpleTypeSyntax(syntax); } public override void VisitUnaryOperationSyntax(UnaryOperationSyntax syntax)