Skip to content

Commit

Permalink
switch to using FunctionFlags and TypeSymbolValidationFlags
Browse files Browse the repository at this point in the history
  • Loading branch information
miqm committed Mar 7, 2021
1 parent e744ca2 commit 70ccd4a
Show file tree
Hide file tree
Showing 15 changed files with 180 additions and 98 deletions.
67 changes: 62 additions & 5 deletions src/Bicep.Core.IntegrationTests/ScenarioTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -709,7 +709,7 @@ param groupReaderId string
});
}
}

[TestMethod]
public void Test_Issue1364()
{
Expand Down Expand Up @@ -804,14 +804,14 @@ public void Test_Issue1028_1()
var (template, diags, _) = CompilationHelper.Compile(
("main.bicep", @"
resource kv 'Microsoft.KeyVault/vaults@2019-09-01' existing = {
name: 'testkeyvault'
name: 'testkeyvault'
}
module secret 'secret.bicep' = {
name: 'secret'
params: {
mySecret: kv.getSecret('mySecret')
mySecret: kv.getSecret('mySecret')
}
}
"),
Expand Down Expand Up @@ -841,13 +841,13 @@ public void Test_Issue1028_2()
var (template, diags, _) = CompilationHelper.Compile(
("main.bicep", @"
resource kv 'Microsoft.KeyVault/vaults@2019-09-01' existing = {
name: 'testkeyvault'
name: 'testkeyvault'
}
module secret 'secret.bicep' = {
name: 'secret'
params: {
mySecret: kv.getSecret('mySecret','secretversionguid')
mySecret: kv.getSecret('mySecret','secretversionguid')
}
}
"),
Expand All @@ -869,5 +869,62 @@ public void Test_Issue1028_2()
parameterToken.SelectToken("$.reference.secretVersion")!.Should().DeepEqual("secretversionguid");
}
}

[TestMethod]
public void Test_Issue1028_3()
{
var (template, diags, _) = CompilationHelper.Compile(
("main.bicep", @"
resource kv 'Microsoft.KeyVault/vaults@2019-09-01' existing = {
name: 'testkeyvault'
}
output exposed string = kv.getSecret('mySecret','secretversionguid')
"));

diags.Should().NotBeEmpty();
template!.Should().BeNull();
}

[TestMethod]
public void Test_Issue1028_4()
{
var (template, diags, _) = CompilationHelper.Compile(
("main.bicep", @"
resource kv 'Microsoft.KeyVault/vaults@2019-09-01' existing = {
name: 'testkeyvault'
}
var secret = kv.getSecret('mySecret','secretversionguid')
"));

diags.Should().NotBeEmpty();
template!.Should().BeNull();
}


[TestMethod]
public void Test_Issue1028_5()
{
var (template, diags, _) = CompilationHelper.Compile(
("main.bicep", @"
resource kv 'Microsoft.KeyVault/vaults@2019-09-01' existing = {
name: 'testkeyvault'
}
module secret 'secret.bicep' = {
name: 'secret'
params: {
notSecret: kv.getSecret('mySecret','secretversionguid')
}
}
"),
("secret.bicep", @"
param notSecret string
"));

diags.Should().NotBeEmpty();
template!.Should().BeNull();
}
}
}
4 changes: 2 additions & 2 deletions src/Bicep.Core.Samples/Files/AKS_LF/main.symbols.bicep
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,11 @@ param linuxAdminUsername string
param sshRSAPublicKey string
//@[6:21) Parameter sshRSAPublicKey. Type: string. Declaration start char: 0, length: 28
param servcePrincipalClientId string {
//@[6:29) Parameter servcePrincipalClientId. Type: secret | string. Declaration start char: 0, length: 57
//@[6:29) Parameter servcePrincipalClientId. Type: string. Declaration start char: 0, length: 57
secure: true
}
param servicePrincipalClientSecret string {
//@[6:34) Parameter servicePrincipalClientSecret. Type: secret | string. Declaration start char: 0, length: 62
//@[6:34) Parameter servicePrincipalClientSecret. Type: string. Declaration start char: 0, length: 62
secure: true
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -452,7 +452,7 @@ param incompleteDecorators string
// wrong target type
@minValue(20)
param someString string {
//@[6:16) Parameter someString. Type: secret | string. Declaration start char: 0, length: 176
//@[6:16) Parameter someString. Type: string. Declaration start char: 0, length: 176
// using decorators and modifier at the same time
secure: true
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,13 +67,13 @@ param myAlternativeArrayParam array {

// secure string
param password string {
//@[6:14) Parameter password. Type: secret | string. Declaration start char: 0, length: 42
//@[6:14) Parameter password. Type: string. Declaration start char: 0, length: 42
secure: true
}

@secure()
param passwordWithDecorator string
//@[6:27) Parameter passwordWithDecorator. Type: secret | string. Declaration start char: 0, length: 45
//@[6:27) Parameter passwordWithDecorator. Type: string. Declaration start char: 0, length: 45

// non-secure string
param nonSecure string {
Expand Down
4 changes: 2 additions & 2 deletions src/Bicep.Core.Samples/Files/Parameters_LF/main.symbols.bicep
Original file line number Diff line number Diff line change
Expand Up @@ -77,13 +77,13 @@ param myAlternativeArrayParam array {

// secure string
param password string {
//@[6:14) Parameter password. Type: secret | string. Declaration start char: 0, length: 40
//@[6:14) Parameter password. Type: string. Declaration start char: 0, length: 40
secure: true
}

@secure()
param passwordWithDecorator string
//@[6:27) Parameter passwordWithDecorator. Type: secret | string. Declaration start char: 0, length: 44
//@[6:27) Parameter passwordWithDecorator. Type: string. Declaration start char: 0, length: 44

// non-secure string
param nonSecure string {
Expand Down
5 changes: 5 additions & 0 deletions src/Bicep.Core/Diagnostics/DiagnosticBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -864,6 +864,11 @@ public Diagnostic RuntimePropertyNotAllowed(string property, IEnumerable<string>
TextSpan,
"BCP152",
$"Function \"{functionName}\" cannot be used as a decorator.");

public ErrorDiagnostic FunctionOnlyValidInModuleParameterAssignment(string functionName) => new(
TextSpan,
"BCP153",
$"Function \"{functionName}\" is not valid at this location. It can only be used in assigning value to a module parameter.");
}

public static DiagnosticBuilderInternal ForPosition(TextSpan span)
Expand Down
3 changes: 2 additions & 1 deletion src/Bicep.Core/LanguageConstants.cs
Original file line number Diff line number Diff line change
Expand Up @@ -93,12 +93,13 @@ public static class LanguageConstants
public static readonly TypeSymbol String = new PrimitiveType(StringTypeName, TypeSymbolValidationFlags.Default);
// LooseString should be regarded as equal to the 'string' type, but with different validation behavior
public static readonly TypeSymbol LooseString = new PrimitiveType(StringTypeName, TypeSymbolValidationFlags.AllowLooseStringAssignment);
public static readonly TypeSymbol SecureString = new PrimitiveType(StringTypeName, TypeSymbolValidationFlags.AllowLooseStringAssignment | TypeSymbolValidationFlags.AllowKeyVaultSecretReferenceAssignment);
public static readonly TypeSymbol KeyVaultSecretReference = new KeyVaultSecretReferenceType();
public static readonly TypeSymbol Object = new ObjectType("object");
public static readonly TypeSymbol Int = new PrimitiveType("int", TypeSymbolValidationFlags.Default);
public static readonly TypeSymbol Bool = new PrimitiveType("bool", TypeSymbolValidationFlags.Default);
public static readonly TypeSymbol Null = new PrimitiveType(NullKeyword, TypeSymbolValidationFlags.Default);
public static readonly TypeSymbol Array = new ArrayType("array");
public static readonly TypeSymbol Secret = new SecretType();

// declares the description property but also allows any other property of any type
public static readonly TypeSymbol ParameterModifierMetadata = new NamedObjectType(nameof(ParameterModifierMetadata), TypeSymbolValidationFlags.Default, CreateParameterModifierMetadataProperties(), Any, TypePropertyFlags.Constant);
Expand Down
21 changes: 12 additions & 9 deletions src/Bicep.Core/Semantics/SymbolValidator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,9 @@ public static Symbol ResolveNamespaceQualifiedFunction(FunctionFlags allowedFlag
_ => builder.FunctionDoesNotExistInNamespaceWithSuggestion(namespaceSymbol, identifierSyntax.IdentifierName, suggestedName),
});

public static Symbol ResolveObjectQualifiedFunction(Symbol? foundSymbol, IdentifierSyntax identifierSyntax, ObjectType objectType)
public static Symbol ResolveObjectQualifiedFunction(FunctionFlags allowedFlags, Symbol? foundSymbol, IdentifierSyntax identifierSyntax, ObjectType objectType)
=> ResolveSymbolInternal(
FunctionFlags.Default,
allowedFlags,
foundSymbol,
identifierSyntax,
getNameSuggestions: () => objectType.MethodResolver.GetKnownFunctions().Keys,
Expand Down Expand Up @@ -78,21 +78,19 @@ public static Symbol ResolveUnqualifiedSymbol(Symbol? foundSymbol, IdentifierSyn

private static Symbol ResolveSymbolInternal(FunctionFlags allowedFlags, Symbol? foundSymbol, IdentifierSyntax identifierSyntax, GetNameSuggestions getNameSuggestions, GetMissingNameError getMissingNameError)
{
if (foundSymbol == null)
if (foundSymbol is null)
{
var nameCandidates = getNameSuggestions().ToImmutableSortedSet(StringComparer.OrdinalIgnoreCase);
var suggestedName = SpellChecker.GetSpellingSuggestion(identifierSyntax.IdentifierName, nameCandidates);

return new ErrorSymbol(getMissingNameError(DiagnosticBuilder.ForPosition(identifierSyntax), suggestedName));
}

switch (foundSymbol)
return foundSymbol switch
{
case FunctionSymbol functionSymbol:
return ResolveFunctionFlags(allowedFlags, functionSymbol, identifierSyntax);
default:
return foundSymbol;
}
FunctionSymbol functionSymbol => ResolveFunctionFlags(allowedFlags, functionSymbol, identifierSyntax),
_ => foundSymbol,
};
}

private static Symbol ResolveFunctionFlags(FunctionFlags allowedFlags, FunctionSymbol functionSymbol, IPositionable span)
Expand All @@ -109,6 +107,11 @@ private static Symbol ResolveFunctionFlags(FunctionFlags allowedFlags, FunctionS
return new ErrorSymbol(DiagnosticBuilder.ForPosition(span).FunctionOnlyValidInResourceBody(functionSymbol.Name));
}

if (functionFlags.HasFlag(FunctionFlags.ModuleParamsAssignmentOnly) && !allowedFlags.HasFlag(FunctionFlags.ModuleParamsAssignmentOnly))
{
return new ErrorSymbol(DiagnosticBuilder.ForPosition(span).FunctionOnlyValidInModuleParameterAssignment(functionSymbol.Name));
}

if (functionFlags.HasAnyDecoratorFlag() && allowedFlags.HasAllDecoratorFlags())
{
return functionSymbol;
Expand Down
2 changes: 1 addition & 1 deletion src/Bicep.Core/Syntax/ParameterDeclarationSyntax.cs
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ public TypeSymbol GetAssignedType(ITypeManager typeManager, ArraySyntax? allowed
(this.SafeGetDecoaratorByName(LanguageConstants.ParameterModifierSecureName) is not null))
{
//parameter can accept either LooseString (see below) or reference to key vault secret
assignedType = UnionType.Create(LanguageConstants.LooseString, LanguageConstants.Secret);
assignedType = LanguageConstants.SecureString;
}
else
{
Expand Down
4 changes: 2 additions & 2 deletions src/Bicep.Core/TypeSystem/Az/AzResourceTypeProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -144,9 +144,9 @@ private static IEnumerable<FunctionOverload> GetTypeBicepFunctions(string name)
{
case "microsoft.keyvault/vaults":
yield return new FunctionOverloadBuilder("getSecret")
.WithReturnType(LanguageConstants.Secret)
.WithReturnType(LanguageConstants.KeyVaultSecretReference)
.WithDescription("References a secret from this key vault to be binded to a secure string module parameter")
.WithFlags(FunctionFlags.Default)
.WithFlags(FunctionFlags.ModuleParamsAssignmentOnly)
.WithRequiredParameter("secretName", LanguageConstants.String, "Secret Name")
.WithOptionalParameter("secretVersion", LanguageConstants.String, "Secret Version")
.Build();
Expand Down
99 changes: 52 additions & 47 deletions src/Bicep.Core/TypeSystem/FunctionFlags.cs
Original file line number Diff line number Diff line change
@@ -1,53 +1,58 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
using System;

namespace Bicep.Core.TypeSystem
{
/// <summary>
/// Flags that may be placed on functions to modify their behavior.
/// </summary>
[Flags]
public enum FunctionFlags
{
/// <summary>
/// The default, no restrictions
/// </summary>
Default = 0,

/// <summary>
/// The function can only be used in parameter default values.
/// </summary>
ParamDefaultsOnly = 1 << 0,

/// <summary>
/// The function requires inlining.
/// </summary>
RequiresInlining = 1 << 1,

// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
using System;

namespace Bicep.Core.TypeSystem
{
/// <summary>
/// Flags that may be placed on functions to modify their behavior.
/// </summary>
[Flags]
public enum FunctionFlags
{
/// <summary>
/// The default, no restrictions
/// </summary>
Default = 0,

/// <summary>
/// The function can only be used in parameter default values.
/// </summary>
ParamDefaultsOnly = 1 << 0,

/// <summary>
/// The function requires inlining.
/// </summary>
RequiresInlining = 1 << 1,

/// <summary>
/// The function can be used as a parameter decorator.
/// </summary>
ParameterDecorator = 1 << 2,

/// <summary>
/// The function can be used as a parameter decorator.
/// </summary>
VariableDecorator = 1 << 3,

/// </summary>
ParameterDecorator = 1 << 2,

/// <summary>
/// The function can be used as a parameter decorator.
/// </summary>
VariableDecorator = 1 << 3,

/// <summary>
/// The function can be used as a resource decorator.
/// </summary>
ResoureDecorator = 1 << 4,

/// <summary>
/// The function can be used as a module decorator.
/// </summary>
ModuleDecorator = 1 << 5,

/// </summary>
ResoureDecorator = 1 << 4,

/// <summary>
/// The function can be used as a module decorator.
/// </summary>
ModuleDecorator = 1 << 5,

/// <summary>
/// The function can be used as an output decorator.
/// </summary>
OutputDecorator = 1 << 6,
}
}
/// </summary>
OutputDecorator = 1 << 6,

/// <summary>
/// The function can be used as input for module parameter only.
/// </summary>
ModuleParamsAssignmentOnly = 1 << 7,
}
}
Original file line number Diff line number Diff line change
@@ -1,15 +1,11 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

using System;
using System.Collections.Generic;
using System.Text;

namespace Bicep.Core.TypeSystem
{
class SecretType : TypeSymbol
class KeyVaultSecretReferenceType : ObjectType
{
public SecretType() : base("secret")
public KeyVaultSecretReferenceType() : base("keyVaultSecretReference")
{
}

Expand Down
Loading

0 comments on commit 70ccd4a

Please sign in to comment.