Add indexer null-check for preallocated tag helper attributes

This commit is contained in:
Ajay Bhargav Baaskaran 2017-06-09 16:25:21 -07:00
parent e3287ae672
commit 27ac5da6d5
4 changed files with 70 additions and 7 deletions

View File

@ -1,6 +1,7 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using Microsoft.AspNetCore.Razor.Language.Intermediate;
using Microsoft.AspNetCore.Razor.Language.Legacy;
@ -18,6 +19,8 @@ namespace Microsoft.AspNetCore.Razor.Language.CodeGeneration
public string ExecutionContextAddTagHelperAttributeMethodName { get; set; } = "AddTagHelperAttribute";
public string FormatInvalidIndexerAssignmentMethodName { get; set; } = "InvalidTagHelperIndexerAssignment";
public void WriteDeclarePreallocatedTagHelperHtmlAttribute(CSharpRenderingContext context, DeclarePreallocatedTagHelperHtmlAttributeIRNode node)
{
context.Writer
@ -74,8 +77,39 @@ namespace Microsoft.AspNetCore.Razor.Language.CodeGeneration
public void WriteSetPreallocatedTagHelperProperty(CSharpRenderingContext context, SetPreallocatedTagHelperPropertyIRNode node)
{
var tagHelperVariableName = GetTagHelperVariableName(node.TagHelperTypeName);
var propertyName = node.Descriptor.GetPropertyName();
var propertyValueAccessor = GetTagHelperPropertyAccessor(node.IsIndexerNameMatch, tagHelperVariableName, node.AttributeName, node.Descriptor);
var attributeValueAccessor = $"{node.VariableName}.Value" /* ORIGINAL: TagHelperAttributeValuePropertyName */;
// Ensure that the property we're trying to set has initialized its dictionary bound properties.
if (node.IsIndexerNameMatch &&
context.TagHelperRenderingContext.VerifiedPropertyDictionaries.Add($"{node.TagHelperTypeName}.{propertyName}"))
{
// Throw a reasonable Exception at runtime if the dictionary property is null.
context.Writer
.Write("if (")
.Write(tagHelperVariableName)
.Write(".")
.Write(propertyName)
.WriteLine(" == null)");
using (context.Writer.BuildScope())
{
// System is in Host.NamespaceImports for all MVC scenarios. No need to generate FullName
// of InvalidOperationException type.
context.Writer
.Write("throw ")
.WriteStartNewObject(nameof(InvalidOperationException))
.WriteStartMethodInvocation(FormatInvalidIndexerAssignmentMethodName)
.WriteStringLiteral(node.AttributeName)
.WriteParameterSeparator()
.WriteStringLiteral(node.TagHelperTypeName)
.WriteParameterSeparator()
.WriteStringLiteral(propertyName)
.WriteEndMethodInvocation(endLine: false) // End of method call
.WriteEndMethodInvocation(); // End of new expression / throw statement
}
}
context.Writer
.WriteStartAssignment(propertyValueAccessor)
.Write("(string)")

View File

@ -324,7 +324,7 @@ namespace Microsoft.AspNetCore.Razor.Language.CodeGeneration
// Ensure that the property we're trying to set has initialized its dictionary bound properties.
if (node.IsIndexerNameMatch &&
tagHelperRenderingContext.VerifiedPropertyDictionaries.Add(propertyName))
tagHelperRenderingContext.VerifiedPropertyDictionaries.Add($"{node.TagHelperTypeName}.{propertyName}"))
{
// Throw a reasonable Exception at runtime if the dictionary property is null.
context.Writer

View File

@ -171,7 +171,8 @@ __tagHelperExecutionContext.AddTagHelperAttribute(_tagHelper1);
var extension = new PreallocatedAttributeTargetExtension();
var context = new CSharpRenderingContext()
{
Writer = new CSharpCodeWriter()
Writer = new CSharpCodeWriter(),
TagHelperRenderingContext = new TagHelperRenderingContext()
};
var descriptor = BoundAttributeDescriptorBuilder
@ -197,7 +198,11 @@ __tagHelperExecutionContext.AddTagHelperAttribute(_tagHelper1);
// Assert
var csharp = context.Writer.Builder.ToString();
Assert.Equal(
@"__FooTagHelper.FooProp[""Foo""] = (string)_tagHelper1.Value;
@"if (__FooTagHelper.FooProp == null)
{
throw new InvalidOperationException(InvalidTagHelperIndexerAssignment(""pre-Foo"", ""FooTagHelper"", ""FooProp""));
}
__FooTagHelper.FooProp[""Foo""] = (string)_tagHelper1.Value;
__tagHelperExecutionContext.AddTagHelperAttribute(_tagHelper1);
",
csharp,

View File

@ -105,6 +105,10 @@ __TestNamespace_InputTagHelper1.IntDictionaryProperty["garlic"] = 37;
#line default
#line hidden
__tagHelperExecutionContext.AddTagHelperAttribute("int-prefix-garlic", __TestNamespace_InputTagHelper1.IntDictionaryProperty["garlic"], global::Microsoft.AspNetCore.Razor.TagHelpers.HtmlAttributeValueStyle.DoubleQuotes);
if (__TestNamespace_InputTagHelper2.IntDictionaryProperty == null)
{
throw new InvalidOperationException(InvalidTagHelperIndexerAssignment("int-prefix-garlic", "TestNamespace.InputTagHelper2", "IntDictionaryProperty"));
}
__TestNamespace_InputTagHelper2.IntDictionaryProperty["garlic"] = __TestNamespace_InputTagHelper1.IntDictionaryProperty["garlic"];
#line 17 "TestFiles/IntegrationTests/CodeGenerationIntegrationTest/PrefixedAttributeTagHelpers.cshtml"
__TestNamespace_InputTagHelper1.IntProperty = 42;
@ -140,6 +144,10 @@ __TestNamespace_InputTagHelper1.IntProperty = 42;
throw new InvalidOperationException(InvalidTagHelperIndexerAssignment("int-prefix-grabber", "TestNamespace.InputTagHelper2", "IntDictionaryProperty"));
}
__TestNamespace_InputTagHelper2.IntDictionaryProperty["grabber"] = __TestNamespace_InputTagHelper1.IntProperty;
if (__TestNamespace_InputTagHelper1.IntDictionaryProperty == null)
{
throw new InvalidOperationException(InvalidTagHelperIndexerAssignment("int-prefix-salt", "TestNamespace.InputTagHelper1", "IntDictionaryProperty"));
}
#line 19 "TestFiles/IntegrationTests/CodeGenerationIntegrationTest/PrefixedAttributeTagHelpers.cshtml"
__TestNamespace_InputTagHelper1.IntDictionaryProperty["salt"] = 37;
@ -157,16 +165,20 @@ __TestNamespace_InputTagHelper1.IntDictionaryProperty["pepper"] = 98;
__tagHelperExecutionContext.AddHtmlAttribute(__tagHelperAttribute_3);
__TestNamespace_InputTagHelper1.StringProperty = (string)__tagHelperAttribute_4.Value;
__tagHelperExecutionContext.AddTagHelperAttribute(__tagHelperAttribute_4);
if (__TestNamespace_InputTagHelper2.StringDictionaryProperty == null)
{
throw new InvalidOperationException(InvalidTagHelperIndexerAssignment("string-prefix-grabber", "TestNamespace.InputTagHelper2", "StringDictionaryProperty"));
}
__TestNamespace_InputTagHelper2.StringDictionaryProperty["grabber"] = (string)__tagHelperAttribute_4.Value;
__tagHelperExecutionContext.AddTagHelperAttribute(__tagHelperAttribute_4);
if (__TestNamespace_InputTagHelper1.StringDictionaryProperty == null)
{
throw new InvalidOperationException(InvalidTagHelperIndexerAssignment("string-prefix-paprika", "TestNamespace.InputTagHelper1", "StringDictionaryProperty"));
}
__TestNamespace_InputTagHelper1.StringDictionaryProperty["paprika"] = (string)__tagHelperAttribute_5.Value;
__tagHelperExecutionContext.AddTagHelperAttribute(__tagHelperAttribute_5);
__TestNamespace_InputTagHelper2.StringDictionaryProperty["paprika"] = (string)__tagHelperAttribute_5.Value;
__tagHelperExecutionContext.AddTagHelperAttribute(__tagHelperAttribute_5);
if (__TestNamespace_InputTagHelper1.StringDictionaryProperty == null)
{
throw new InvalidOperationException(InvalidTagHelperIndexerAssignment("string-prefix-cumin", "TestNamespace.InputTagHelper1", "StringDictionaryProperty"));
}
BeginWriteTagHelperAttribute();
WriteLiteral("literate ");
#line 21 "TestFiles/IntegrationTests/CodeGenerationIntegrationTest/PrefixedAttributeTagHelpers.cshtml"
@ -204,9 +216,21 @@ __TestNamespace_InputTagHelper1.IntDictionaryProperty["value"] = 37;
#line default
#line hidden
__tagHelperExecutionContext.AddTagHelperAttribute("int-prefix-value", __TestNamespace_InputTagHelper1.IntDictionaryProperty["value"], global::Microsoft.AspNetCore.Razor.TagHelpers.HtmlAttributeValueStyle.DoubleQuotes);
if (__TestNamespace_InputTagHelper2.IntDictionaryProperty == null)
{
throw new InvalidOperationException(InvalidTagHelperIndexerAssignment("int-prefix-value", "TestNamespace.InputTagHelper2", "IntDictionaryProperty"));
}
__TestNamespace_InputTagHelper2.IntDictionaryProperty["value"] = __TestNamespace_InputTagHelper1.IntDictionaryProperty["value"];
if (__TestNamespace_InputTagHelper1.StringDictionaryProperty == null)
{
throw new InvalidOperationException(InvalidTagHelperIndexerAssignment("string-prefix-thyme", "TestNamespace.InputTagHelper1", "StringDictionaryProperty"));
}
__TestNamespace_InputTagHelper1.StringDictionaryProperty["thyme"] = (string)__tagHelperAttribute_6.Value;
__tagHelperExecutionContext.AddTagHelperAttribute(__tagHelperAttribute_6);
if (__TestNamespace_InputTagHelper2.StringDictionaryProperty == null)
{
throw new InvalidOperationException(InvalidTagHelperIndexerAssignment("string-prefix-thyme", "TestNamespace.InputTagHelper2", "StringDictionaryProperty"));
}
__TestNamespace_InputTagHelper2.StringDictionaryProperty["thyme"] = (string)__tagHelperAttribute_6.Value;
__tagHelperExecutionContext.AddTagHelperAttribute(__tagHelperAttribute_6);
await __tagHelperRunner.RunAsync(__tagHelperExecutionContext);