Skip to content

Commit

Permalink
WIP nameof function
Browse files Browse the repository at this point in the history
  • Loading branch information
miqm committed Jul 26, 2024
1 parent 3863bf7 commit 6a61d62
Show file tree
Hide file tree
Showing 2 changed files with 128 additions and 0 deletions.
95 changes: 95 additions & 0 deletions src/Bicep.Core.IntegrationTests/Scenarios/NameofFunctionTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Bicep.Core.UnitTests.Assertions;
using Bicep.Core.UnitTests.Utils;
using FluentAssertions.Execution;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace Bicep.Core.IntegrationTests.Scenarios
{
[TestClass]
public class NameofFunctionTests
{
[TestMethod]
public void NameofFunction_OnObjectProperty_ReturnsPropertyName()
{
var result = CompilationHelper.Compile("""
var obj = {
prop: 'value'
}
var name = nameof(obj.prop)
""");

using (new AssertionScope())
{
result.Should().NotHaveAnyCompilationBlockingDiagnostics();
result.Template.Should().HaveValueAtPath("$.variables['name']", "prop");
}
}

[TestMethod]
public void NameofFunction_OnVariable_ReturnsVariableName()
{
var result = CompilationHelper.Compile("""
var obj = {
prop: 'value'
}
var name = nameof(obj)
""");

using (new AssertionScope())
{
result.Should().NotHaveAnyCompilationBlockingDiagnostics();
result.Template.Should().HaveValueAtPath("$.variables['name']", "obj");
}
}

[TestMethod]
public void NameofFunction_OnResource_ReturnsResourceSymbolicName()
{
var result = CompilationHelper.Compile("""
resource myStorage 'Microsoft.Storage/storageAccounts@2019-06-01' = {
name: 'storage123'
}

var name = nameof(myStorage)
""");

using (new AssertionScope())
{
result.Should().NotHaveAnyCompilationBlockingDiagnostics();
result.Template.Should().HaveValueAtPath("$.variables['name']", "myStorage");
}
}

[DataTestMethod]
[DataRow("name", "name")]
[DataRow("type", "type")]
[DataRow("location", "location")]
[DataRow("properties", "properties")]
[DataRow("properties.sku", "sku")]
public void NameofFunction_OnResourceProperty_ReturnsResourcePropertyName(string resourceProperty, string expectedValue)
{
var result = CompilationHelper.Compile($$"""
resource myStorage 'Microsoft.Storage/storageAccounts@2019-06-01' = {
name: 'storage123'
}

var name = nameof(myStorage.{{resourceProperty}})

""");

using (new AssertionScope())
{
result.Should().NotHaveAnyCompilationBlockingDiagnostics();
result.Template.Should().HaveValueAtPath("$.variables['name']", expectedValue);
}
}
}
}
33 changes: 33 additions & 0 deletions src/Bicep.Core/Semantics/Namespaces/SystemNamespaceType.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1053,6 +1053,39 @@ TypeSymbol type when TypeCollapser.TryCollapse(type) is TypeSymbol collapsed =>
return new(LanguageConstants.Object);
}, LanguageConstants.Object)
.Build();

yield return new FunctionOverloadBuilder("nameof")
.WithGenericDescription("Returns the name of the specified parameter, variable, or resource.")
.WithRequiredParameter("symbol", LanguageConstants.Any, "The parameter, variable, or resource to retrieve the name of.")
.WithReturnResultBuilder((model, diagnostics, call, argumentTypes) =>
{
var x = call.Arguments[0].Expression switch
{
VariableAccessSyntax variableAccess => variableAccess.Name.IdentifierName,
PropertyAccessSyntax propertyAccess => propertyAccess.PropertyName.IdentifierName,
ResourceAccessSyntax resourceAccess => resourceAccess.ResourceName.IdentifierName,
ModuleDeclarationSyntax moduleDeclaration => moduleDeclaration.Name.IdentifierName,
_ => null,
};
if (x is null)
{
return new(ErrorType.Create(DiagnosticBuilder.ForPosition(call.Arguments[0]).CompileTimeConstantRequired()));
}
return new(new StringLiteralType(x, TypeSymbolValidationFlags.Default));
}, LanguageConstants.String)
.WithEvaluator(expression =>
{
var x = expression.Parameters[0].SourceSyntax switch
{
VariableAccessSyntax variableAccess => variableAccess.Name.IdentifierName,
PropertyAccessSyntax propertyAccess => propertyAccess.PropertyName.IdentifierName,
ResourceAccessSyntax resourceAccess => resourceAccess.ResourceName.IdentifierName,
ModuleDeclarationSyntax moduleDeclaration => moduleDeclaration.Name.IdentifierName,
_ => string.Empty,
};
return new StringLiteralExpression(expression.Parameters[0].SourceSyntax, x);
})
.Build();
}

static IEnumerable<FunctionOverload> GetParamsFilePermittedOverloads()
Expand Down

0 comments on commit 6a61d62

Please sign in to comment.