Fix minimized attributes when using 5.0 SDK with 3.x target (#25307)

* Write minimized attribute values explicitly for older language version

* Add tests

* Add baselines for new tests
This commit is contained in:
Steve Sanderson 2020-08-28 16:37:30 +01:00 committed by GitHub
parent 432f9b8a91
commit ebaaa0f01d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 304 additions and 14 deletions

View File

@ -852,11 +852,20 @@ namespace Microsoft.AspNetCore.Razor.Language.Components
private void WriteAttribute(CodeRenderingContext context, string key, IList<IntermediateToken> value)
{
BeginWriteAttribute(context, key);
if (value.Count > 0)
{
context.CodeWriter.WriteParameterSeparator();
WriteAttributeValue(context, value);
}
else if (!context.Options.OmitMinimizedComponentAttributeValues)
{
// In version 5+, there's no need to supply a value for a minimized attribute.
// But for older language versions, minimized attributes were represented as "true".
context.CodeWriter.WriteParameterSeparator();
context.CodeWriter.WriteBooleanLiteral(true);
}
context.CodeWriter.WriteEndMethodInvocation();
}

View File

@ -1,4 +1,4 @@
// Copyright (c) .NET Foundation. All rights reserved.
// 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.
namespace Microsoft.AspNetCore.Razor.Language
@ -13,7 +13,8 @@ namespace Microsoft.AspNetCore.Razor.Language
bool suppressChecksum,
bool suppressMetadataAttributes,
bool suppressPrimaryMethodBody,
bool suppressNullabilityEnforcement)
bool suppressNullabilityEnforcement,
bool omitMinimizedComponentAttributeValues)
{
IndentWithTabs = indentWithTabs;
IndentSize = indentSize;
@ -23,6 +24,7 @@ namespace Microsoft.AspNetCore.Razor.Language
SuppressMetadataAttributes = suppressMetadataAttributes;
SuppressPrimaryMethodBody = suppressPrimaryMethodBody;
SuppressNullabilityEnforcement = suppressNullabilityEnforcement;
OmitMinimizedComponentAttributeValues = omitMinimizedComponentAttributeValues;
}
public override bool DesignTime { get; }
@ -36,5 +38,7 @@ namespace Microsoft.AspNetCore.Razor.Language
public override bool SuppressChecksum { get; }
public override bool SuppressNullabilityEnforcement { get; }
public override bool OmitMinimizedComponentAttributeValues { get; }
}
}

View File

@ -1,4 +1,4 @@
// Copyright (c) .NET Foundation. All rights reserved.
// 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;
@ -39,6 +39,8 @@ namespace Microsoft.AspNetCore.Razor.Language
public override bool SuppressNullabilityEnforcement { get; set; }
public override bool OmitMinimizedComponentAttributeValues { get; set; }
public override RazorCodeGenerationOptions Build()
{
return new DefaultRazorCodeGenerationOptions(
@ -49,7 +51,8 @@ namespace Microsoft.AspNetCore.Razor.Language
SuppressChecksum,
SuppressMetadataAttributes,
SuppressPrimaryMethodBody,
SuppressNullabilityEnforcement);
SuppressNullabilityEnforcement,
OmitMinimizedComponentAttributeValues);
}
public override void SetDesignTime(bool designTime)

View File

@ -1,4 +1,4 @@
// Copyright (c) .NET Foundation. All rights reserved.
// 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;
@ -17,7 +17,8 @@ namespace Microsoft.AspNetCore.Razor.Language
rootNamespace: null,
suppressMetadataAttributes: false,
suppressPrimaryMethodBody: false,
suppressNullabilityEnforcement: false);
suppressNullabilityEnforcement: false,
omitMinimizedComponentAttributeValues: false);
}
public static RazorCodeGenerationOptions CreateDesignTimeDefault()
@ -30,7 +31,8 @@ namespace Microsoft.AspNetCore.Razor.Language
suppressChecksum: false,
suppressMetadataAttributes: true,
suppressPrimaryMethodBody: false,
suppressNullabilityEnforcement: false);
suppressNullabilityEnforcement: false,
omitMinimizedComponentAttributeValues: false);
}
public static RazorCodeGenerationOptions Create(Action<RazorCodeGenerationOptionsBuilder> configure)
@ -114,5 +116,10 @@ namespace Microsoft.AspNetCore.Razor.Language
/// Gets a value that determines if nullability type enforcement should be suppressed for user code.
/// </summary>
public virtual bool SuppressNullabilityEnforcement { get; }
/// <summary>
/// Gets a value that determines if the components code writer may omit values for minimized attributes.
/// </summary>
public virtual bool OmitMinimizedComponentAttributeValues { get; }
}
}

View File

@ -1,4 +1,4 @@
// Copyright (c) .NET Foundation. All rights reserved.
// 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.
namespace Microsoft.AspNetCore.Razor.Language
@ -59,6 +59,11 @@ namespace Microsoft.AspNetCore.Razor.Language
/// </summary>
public virtual bool SuppressNullabilityEnforcement { get; set; }
/// <summary>
/// Gets or sets a value that determines if the components code writer may omit values for minimized attributes.
/// </summary>
public virtual bool OmitMinimizedComponentAttributeValues { get; set; }
public abstract RazorCodeGenerationOptions Build();
public virtual void SetDesignTime(bool designTime)

View File

@ -9,10 +9,14 @@ namespace Microsoft.AspNetCore.Razor.Language.IntegrationTests
{
public abstract class ComponentCodeGenerationTestBase : RazorBaselineIntegrationTestBase
{
private RazorConfiguration _configuration;
internal override string FileKind => FileKinds.Component;
internal override bool UseTwoPhaseCompilation => true;
internal override RazorConfiguration Configuration => _configuration ?? base.Configuration;
protected ComponentCodeGenerationTestBase()
: base(generateBaselines: null)
{
@ -364,6 +368,38 @@ namespace Test
CompileToAssembly(generated);
}
[Fact]
public void OmitsMinimizedAttributeValueParameter()
{
// Act
var generated = CompileToCSharp(@"
<elem normal-attr=""@(""val"")"" minimized-attr empty-string-atttr=""""></elem>");
// Assert
AssertDocumentNodeMatchesBaseline(generated.CodeDocument);
AssertCSharpDocumentMatchesBaseline(generated.CodeDocument);
CompileToAssembly(generated);
}
[Fact]
public void IncludesMinimizedAttributeValueParameterBeforeLanguageVersion5()
{
// Arrange
_configuration = RazorConfiguration.Create(
RazorLanguageVersion.Version_3_0,
base.Configuration.ConfigurationName,
base.Configuration.Extensions);
// Act
var generated = CompileToCSharp(@"
<elem normal-attr=""@(""val"")"" minimized-attr empty-string-atttr=""""></elem>");
// Assert
AssertDocumentNodeMatchesBaseline(generated.CodeDocument);
AssertCSharpDocumentMatchesBaseline(generated.CodeDocument);
CompileToAssembly(generated);
}
[Fact]
public void Component_WithFullyQualifiedTagNames()
{

View File

@ -0,0 +1,36 @@
// <auto-generated/>
#pragma warning disable 1591
namespace Test
{
#line hidden
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Components;
public partial class TestComponent : Microsoft.AspNetCore.Components.ComponentBase
{
#pragma warning disable 219
private void __RazorDirectiveTokenHelpers__() {
}
#pragma warning restore 219
#pragma warning disable 0414
private static System.Object __o = null;
#pragma warning restore 0414
#pragma warning disable 1998
protected override void BuildRenderTree(Microsoft.AspNetCore.Components.Rendering.RenderTreeBuilder __builder)
{
__o =
#nullable restore
#line 1 "x:\dir\subdir\Test\TestComponent.cshtml"
"val"
#line default
#line hidden
#nullable disable
;
}
#pragma warning restore 1998
}
}
#pragma warning restore 1591

View File

@ -0,0 +1,22 @@
Document -
NamespaceDeclaration - - Test
UsingDirective - (3:1,1 [12] ) - System
UsingDirective - (18:2,1 [32] ) - System.Collections.Generic
UsingDirective - (53:3,1 [17] ) - System.Linq
UsingDirective - (73:4,1 [28] ) - System.Threading.Tasks
UsingDirective - (104:5,1 [37] ) - Microsoft.AspNetCore.Components
ClassDeclaration - - public partial - TestComponent - Microsoft.AspNetCore.Components.ComponentBase -
DesignTimeDirective -
CSharpCode -
IntermediateToken - - CSharp - #pragma warning disable 0414
CSharpCode -
IntermediateToken - - CSharp - private static System.Object __o = null;
CSharpCode -
IntermediateToken - - CSharp - #pragma warning restore 0414
MethodDeclaration - - protected override - void - BuildRenderTree
MarkupElement - (0:0,0 [73] x:\dir\subdir\Test\TestComponent.cshtml) - elem
HtmlAttribute - (5:0,5 [23] x:\dir\subdir\Test\TestComponent.cshtml) - normal-attr=" - "
CSharpExpressionAttributeValue - (19:0,19 [8] x:\dir\subdir\Test\TestComponent.cshtml) -
LazyIntermediateToken - (21:0,21 [5] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - "val"
HtmlAttribute - (28:0,28 [15] x:\dir\subdir\Test\TestComponent.cshtml) - minimized-attr -
HtmlAttribute - (43:0,43 [22] x:\dir\subdir\Test\TestComponent.cshtml) - empty-string-atttr=" - "

View File

@ -0,0 +1,5 @@
Source Location: (21:0,21 [5] x:\dir\subdir\Test\TestComponent.cshtml)
|"val"|
Generated Location: (893:25,21 [5] )
|"val"|

View File

@ -0,0 +1,36 @@
// <auto-generated/>
#pragma warning disable 1591
namespace Test
{
#line hidden
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Components;
public partial class TestComponent : Microsoft.AspNetCore.Components.ComponentBase
{
#pragma warning disable 219
private void __RazorDirectiveTokenHelpers__() {
}
#pragma warning restore 219
#pragma warning disable 0414
private static System.Object __o = null;
#pragma warning restore 0414
#pragma warning disable 1998
protected override void BuildRenderTree(Microsoft.AspNetCore.Components.Rendering.RenderTreeBuilder __builder)
{
__o =
#nullable restore
#line 1 "x:\dir\subdir\Test\TestComponent.cshtml"
"val"
#line default
#line hidden
#nullable disable
;
}
#pragma warning restore 1998
}
}
#pragma warning restore 1591

View File

@ -0,0 +1,22 @@
Document -
NamespaceDeclaration - - Test
UsingDirective - (3:1,1 [12] ) - System
UsingDirective - (18:2,1 [32] ) - System.Collections.Generic
UsingDirective - (53:3,1 [17] ) - System.Linq
UsingDirective - (73:4,1 [28] ) - System.Threading.Tasks
UsingDirective - (104:5,1 [37] ) - Microsoft.AspNetCore.Components
ClassDeclaration - - public partial - TestComponent - Microsoft.AspNetCore.Components.ComponentBase -
DesignTimeDirective -
CSharpCode -
IntermediateToken - - CSharp - #pragma warning disable 0414
CSharpCode -
IntermediateToken - - CSharp - private static System.Object __o = null;
CSharpCode -
IntermediateToken - - CSharp - #pragma warning restore 0414
MethodDeclaration - - protected override - void - BuildRenderTree
MarkupElement - (0:0,0 [73] x:\dir\subdir\Test\TestComponent.cshtml) - elem
HtmlAttribute - (5:0,5 [23] x:\dir\subdir\Test\TestComponent.cshtml) - normal-attr=" - "
CSharpExpressionAttributeValue - (19:0,19 [8] x:\dir\subdir\Test\TestComponent.cshtml) -
LazyIntermediateToken - (21:0,21 [5] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - "val"
HtmlAttribute - (28:0,28 [15] x:\dir\subdir\Test\TestComponent.cshtml) - minimized-attr -
HtmlAttribute - (43:0,43 [22] x:\dir\subdir\Test\TestComponent.cshtml) - empty-string-atttr=" - "

View File

@ -0,0 +1,5 @@
Source Location: (21:0,21 [5] x:\dir\subdir\Test\TestComponent.cshtml)
|"val"|
Generated Location: (893:25,21 [5] )
|"val"|

View File

@ -0,0 +1,33 @@
// <auto-generated/>
#pragma warning disable 1591
namespace Test
{
#line hidden
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Components;
public partial class TestComponent : Microsoft.AspNetCore.Components.ComponentBase
{
#pragma warning disable 1998
protected override void BuildRenderTree(Microsoft.AspNetCore.Components.Rendering.RenderTreeBuilder __builder)
{
__builder.OpenElement(0, "elem");
__builder.AddAttribute(1, "normal-attr",
#nullable restore
#line 1 "x:\dir\subdir\Test\TestComponent.cshtml"
"val"
#line default
#line hidden
#nullable disable
);
__builder.AddAttribute(2, "minimized-attr", true);
__builder.AddAttribute(3, "empty-string-atttr", true);
__builder.CloseElement();
}
#pragma warning restore 1998
}
}
#pragma warning restore 1591

View File

@ -0,0 +1,15 @@
Document -
NamespaceDeclaration - - Test
UsingDirective - (3:1,1 [14] ) - System
UsingDirective - (18:2,1 [34] ) - System.Collections.Generic
UsingDirective - (53:3,1 [19] ) - System.Linq
UsingDirective - (73:4,1 [30] ) - System.Threading.Tasks
UsingDirective - (104:5,1 [39] ) - Microsoft.AspNetCore.Components
ClassDeclaration - - public partial - TestComponent - Microsoft.AspNetCore.Components.ComponentBase -
MethodDeclaration - - protected override - void - BuildRenderTree
MarkupElement - (0:0,0 [73] x:\dir\subdir\Test\TestComponent.cshtml) - elem
HtmlAttribute - (5:0,5 [23] x:\dir\subdir\Test\TestComponent.cshtml) - normal-attr=" - "
CSharpExpressionAttributeValue - (19:0,19 [8] x:\dir\subdir\Test\TestComponent.cshtml) -
LazyIntermediateToken - (21:0,21 [5] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - "val"
HtmlAttribute - (28:0,28 [15] x:\dir\subdir\Test\TestComponent.cshtml) - minimized-attr -
HtmlAttribute - (43:0,43 [22] x:\dir\subdir\Test\TestComponent.cshtml) - empty-string-atttr=" - "

View File

@ -0,0 +1,33 @@
// <auto-generated/>
#pragma warning disable 1591
namespace Test
{
#line hidden
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Components;
public partial class TestComponent : Microsoft.AspNetCore.Components.ComponentBase
{
#pragma warning disable 1998
protected override void BuildRenderTree(Microsoft.AspNetCore.Components.Rendering.RenderTreeBuilder __builder)
{
__builder.OpenElement(0, "elem");
__builder.AddAttribute(1, "normal-attr",
#nullable restore
#line 1 "x:\dir\subdir\Test\TestComponent.cshtml"
"val"
#line default
#line hidden
#nullable disable
);
__builder.AddAttribute(2, "minimized-attr");
__builder.AddAttribute(3, "empty-string-atttr");
__builder.CloseElement();
}
#pragma warning restore 1998
}
}
#pragma warning restore 1591

View File

@ -0,0 +1,15 @@
Document -
NamespaceDeclaration - - Test
UsingDirective - (3:1,1 [14] ) - System
UsingDirective - (18:2,1 [34] ) - System.Collections.Generic
UsingDirective - (53:3,1 [19] ) - System.Linq
UsingDirective - (73:4,1 [30] ) - System.Threading.Tasks
UsingDirective - (104:5,1 [39] ) - Microsoft.AspNetCore.Components
ClassDeclaration - - public partial - TestComponent - Microsoft.AspNetCore.Components.ComponentBase -
MethodDeclaration - - protected override - void - BuildRenderTree
MarkupElement - (0:0,0 [73] x:\dir\subdir\Test\TestComponent.cshtml) - elem
HtmlAttribute - (5:0,5 [23] x:\dir\subdir\Test\TestComponent.cshtml) - normal-attr=" - "
CSharpExpressionAttributeValue - (19:0,19 [8] x:\dir\subdir\Test\TestComponent.cshtml) -
LazyIntermediateToken - (21:0,21 [5] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - "val"
HtmlAttribute - (28:0,28 [15] x:\dir\subdir\Test\TestComponent.cshtml) - minimized-attr -
HtmlAttribute - (43:0,43 [22] x:\dir\subdir\Test\TestComponent.cshtml) - empty-string-atttr=" - "

View File

@ -1,4 +1,4 @@
// Copyright (c) .NET Foundation. All rights reserved.
// 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;
@ -64,10 +64,8 @@ namespace Microsoft.CodeAnalysis.Razor
{
// Prior to 3.0 there were no C# version specific controlled features. Suppress nullability enforcement.
options.SuppressNullabilityEnforcement = true;
return;
}
if (CSharpLanguageVersion < LanguageVersion.CSharp8)
else if (CSharpLanguageVersion < LanguageVersion.CSharp8)
{
// Having nullable flags < C# 8.0 would cause compile errors.
options.SuppressNullabilityEnforcement = true;
@ -85,6 +83,12 @@ namespace Microsoft.CodeAnalysis.Razor
// Roslyn project and acquires the effective C# version at that point.
options.SuppressNullabilityEnforcement = false;
}
if (options.Configuration?.LanguageVersion.Major >= 5)
{
// This is a useful optimization but isn't supported by older framework versions
options.OmitMinimizedComponentAttributeValues = true;
}
}
}
}

View File

@ -189,7 +189,7 @@ namespace Microsoft.AspNetCore.Razor.Language.IntegrationTests
{
// The first phase won't include any metadata references for component discovery. This mirrors
// what the build does.
var projectEngine = CreateProjectEngine(RazorConfiguration.Default, Array.Empty<MetadataReference>());
var projectEngine = CreateProjectEngine(Configuration, Array.Empty<MetadataReference>());
RazorCodeDocument codeDocument;
foreach (var item in AdditionalRazorItems)
@ -218,7 +218,7 @@ namespace Microsoft.AspNetCore.Razor.Language.IntegrationTests
// Add the 'temp' compilation as a metadata reference
var references = BaseCompilation.References.Concat(new[] { tempAssembly.Compilation.ToMetadataReference() }).ToArray();
projectEngine = CreateProjectEngine(RazorConfiguration.Default, references);
projectEngine = CreateProjectEngine(Configuration, references);
// Now update the any additional files
foreach (var item in AdditionalRazorItems)