Keep complex attribute content (#9553)

* Add a test

* Keep complex attribute content

* Simplify form name codegen

* Keep type check for mixed content

* Add a test

* Verify `@formname` mixed content C# diagnostics

* Add integration test
This commit is contained in:
Jan Jones 2023-11-21 12:22:31 +01:00 коммит произвёл GitHub
Родитель 0e8b3abe98
Коммит 630d8260fc
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
39 изменённых файлов: 677 добавлений и 58 удалений

Просмотреть файл

@ -55,13 +55,11 @@ internal class ComponentComplexAttributeContentPass : ComponentIntermediateNodeP
private static void ProcessAttribute(IntermediateNode parent, IntermediateNode node, string attributeName)
{
var removeNode = false;
var issueDiagnostic = false;
if (node.Children is [HtmlAttributeIntermediateNode { Children.Count: > 1 }])
{
// This case can be hit for a 'string' attribute
removeNode = true;
issueDiagnostic = true;
}
else if (node.Children is [CSharpExpressionIntermediateNode { Children.Count: > 1 } cSharpNode])
@ -78,7 +76,6 @@ internal class ComponentComplexAttributeContentPass : ComponentIntermediateNodeP
}
else
{
removeNode = true;
issueDiagnostic = true;
}
}
@ -86,36 +83,19 @@ internal class ComponentComplexAttributeContentPass : ComponentIntermediateNodeP
{
// This is the case when an attribute contains a code block @{ ... }
// We don't support this.
removeNode = true;
issueDiagnostic = true;
}
else if (node.Children is [CSharpExpressionIntermediateNode, HtmlContentIntermediateNode { Children: [IntermediateToken { Content: "." }] }])
{
// This is the case when an attribute contains something like "@MyEnum."
// We simplify this to remove the "." so that tooling can provide completion on "MyEnum"
// in case the user is in the middle of typing
node.Children.RemoveAt(1);
// We still want to issue a diagnostic, even though we simplified, because ultimately
// we don't support this, so if the user isn't typing, we can't let this through
issueDiagnostic = true;
}
else if (node.Children.Count > 1)
{
// This is the common case for 'mixed' content
removeNode = true;
issueDiagnostic = true;
}
if (issueDiagnostic)
{
parent.Diagnostics.Add(ComponentDiagnosticFactory.Create_UnsupportedComplexContent(
node.Diagnostics.Add(ComponentDiagnosticFactory.Create_UnsupportedComplexContent(
node,
attributeName));
}
if (removeNode)
{
parent.Children.Remove(node);
}
}
}

Просмотреть файл

@ -798,6 +798,12 @@ internal class ComponentDesignTimeNodeWriter : ComponentNodeWriter
private void WriteComponentAttributeInnards(CodeRenderingContext context, ComponentAttributeIntermediateNode node, bool canTypeCheck)
{
if (node.Children.Count > 1)
{
Debug.Assert(node.HasDiagnostics, "We should have reported an error for mixed content.");
// We render the children anyway, so tooling works.
}
// We limit component attributes to simple cases. However there is still a lot of complexity
// to handle here, since there are a few different cases for how an attribute might be structured.
//
@ -807,11 +813,6 @@ internal class ComponentDesignTimeNodeWriter : ComponentNodeWriter
// Minimized attributes always map to 'true'
context.CodeWriter.Write("true");
}
else if (node.Children.Count > 1)
{
// We don't expect this to happen, we just want to know if it can.
throw new InvalidOperationException("Attribute nodes should either be minimized or a single type of content." + string.Join(", ", node.Children));
}
else if (node.Children.Count == 1 && node.Children[0] is HtmlContentIntermediateNode)
{
// We don't actually need the content at designtime, an empty string will do.
@ -1170,27 +1171,20 @@ internal class ComponentDesignTimeNodeWriter : ComponentNodeWriter
public sealed override void WriteFormName(CodeRenderingContext context, FormNameIntermediateNode node)
{
var tokens = node.FindDescendantNodes<IntermediateToken>();
if (tokens.Count == 0)
if (node.Children.Count > 1)
{
return;
Debug.Assert(node.HasDiagnostics, "We should have reported an error for mixed content.");
}
// Either all tokens should be C# or none of them.
if (tokens[0].IsCSharp)
foreach (var token in node.FindDescendantNodes<IntermediateToken>())
{
context.CodeWriter.Write(ComponentsApi.RuntimeHelpers.TypeCheck);
context.CodeWriter.Write("<string>(");
foreach (var token in tokens)
if (token.IsCSharp)
{
Debug.Assert(token.IsCSharp);
context.CodeWriter.Write(ComponentsApi.RuntimeHelpers.TypeCheck);
context.CodeWriter.Write("<string>(");
WriteCSharpToken(context, token);
context.CodeWriter.WriteLine(");");
}
context.CodeWriter.Write(");");
}
else
{
Debug.Assert(!tokens.Any(t => t.IsCSharp));
}
}

Просмотреть файл

@ -1,7 +1,6 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System.Diagnostics;
using Microsoft.AspNetCore.Razor.Language.Intermediate;
namespace Microsoft.AspNetCore.Razor.Language.Components;
@ -23,8 +22,6 @@ internal sealed class ComponentRenderModeLoweringPass : ComponentIntermediateNod
{
if (reference is { Node: TagHelperDirectiveAttributeIntermediateNode node, Parent: IntermediateNode parentNode } && node.TagHelper.IsRenderModeTagHelper())
{
Debug.Assert(node.Diagnostics.Count == 0);
if (parentNode is not ComponentIntermediateNode componentNode)
{
node.Diagnostics.Add(ComponentDiagnosticFactory.CreateAttribute_ValidOnlyOnComponent(node.Source, node.OriginalAttributeName));
@ -38,6 +35,7 @@ internal sealed class ComponentRenderModeLoweringPass : ComponentIntermediateNod
};
var renderModeNode = new RenderModeIntermediateNode() { Source = node.Source, Children = { expression } };
renderModeNode.Diagnostics.AddRange(node.Diagnostics);
if (componentNode.Component.Metadata.ContainsKey(ComponentMetadata.Component.HasRenderModeDirectiveKey))
{

Просмотреть файл

@ -630,16 +630,17 @@ internal class ComponentRuntimeNodeWriter : ComponentNodeWriter
private void WriteComponentAttributeInnards(CodeRenderingContext context, ComponentAttributeIntermediateNode node, bool canTypeCheck)
{
if (node.Children.Count > 1)
{
Debug.Assert(node.HasDiagnostics, "We should have reported an error for mixed content.");
// We render the children anyway, so tooling works.
}
if (node.AttributeStructure == AttributeStructure.Minimized)
{
// Minimized attributes always map to 'true'
context.CodeWriter.Write("true");
}
else if (node.Children.Count > 1)
{
// We don't expect this to happen, we just want to know if it can.
throw new InvalidOperationException("Attribute nodes should either be minimized or a single type of content." + string.Join(", ", node.Children));
}
else if (node.Children.Count == 1 && node.Children[0] is HtmlContentIntermediateNode htmlNode)
{
// This is how string attributes are lowered by default, a single HTML node with a single HTML token.
@ -944,6 +945,11 @@ internal class ComponentRuntimeNodeWriter : ComponentNodeWriter
public sealed override void WriteFormName(CodeRenderingContext context, FormNameIntermediateNode node)
{
if (node.Children.Count > 1)
{
Debug.Assert(node.HasDiagnostics, "We should have reported an error for mixed content.");
}
// string __formName = expression;
context.CodeWriter.Write("string ");
context.CodeWriter.Write(_scopeStack.FormNameVarName);

Просмотреть файл

@ -9897,7 +9897,96 @@ namespace Test
// Assert
AssertDocumentNodeMatchesBaseline(generated.CodeDocument);
AssertCSharpDocumentMatchesBaseline(generated.CodeDocument, verifyLinePragmas: false);
AssertCSharpDocumentMatchesBaseline(generated.CodeDocument);
var result = CompileToAssembly(generated, throwOnFailure: false);
result.Diagnostics.Verify(
// x:\dir\subdir\Test\TestComponent.cshtml(1,31): error CS0119: 'TestComponent.MyEnum' is a type, which is not valid in the given context
// MyEnum
Diagnostic(ErrorCode.ERR_BadSKunknown, "MyEnum").WithArguments("Test.TestComponent.MyEnum", "type").WithLocation(1, 31));
Assert.NotEmpty(generated.Diagnostics);
}
[IntegrationTestFact, WorkItem("https://github.com/dotnet/razor/issues/9346")]
public void Component_ComplexContentInAttribute_02()
{
// Arrange
AdditionalSyntaxTrees.Add(Parse("""
using Microsoft.AspNetCore.Components;
namespace Test
{
public class MyComponent : ComponentBase
{
[Parameter] public string StringProperty { get; set; }
}
}
"""));
// Act
var generated = CompileToCSharp("""
<MyComponent StringProperty="@MyEnum+" />
@code {
public enum MyEnum
{
One,
Two
}
}
""");
// Assert
AssertDocumentNodeMatchesBaseline(generated.CodeDocument);
AssertCSharpDocumentMatchesBaseline(generated.CodeDocument);
var result = CompileToAssembly(generated, throwOnFailure: false);
result.Diagnostics.Verify(
// x:\dir\subdir\Test\TestComponent.cshtml(1,31): error CS0119: 'TestComponent.MyEnum' is a type, which is not valid in the given context
// MyEnum
Diagnostic(ErrorCode.ERR_BadSKunknown, "MyEnum").WithArguments("Test.TestComponent.MyEnum", "type").WithLocation(1, 31));
Assert.NotEmpty(generated.Diagnostics);
}
[IntegrationTestFact, WorkItem("https://github.com/dotnet/razor/issues/9346")]
public void Component_ComplexContentInAttribute_03()
{
// Arrange
AdditionalSyntaxTrees.Add(Parse("""
using Microsoft.AspNetCore.Components;
namespace Test
{
public class MyComponent : ComponentBase
{
[Parameter] public string StringProperty { get; set; }
}
}
"""));
// Act
var generated = CompileToCSharp("""
<MyComponent StringProperty="@x html @("string")" />
@code {
int x = 1;
}
""");
// Assert
AssertDocumentNodeMatchesBaseline(generated.CodeDocument);
AssertCSharpDocumentMatchesBaseline(generated.CodeDocument);
var result = CompileToAssembly(generated, throwOnFailure: false);
result.Diagnostics.Verify(
// x:\dir\subdir\Test\TestComponent.cshtml(1,32): error CS1003: Syntax error, ',' expected
// x
Diagnostic(ErrorCode.ERR_SyntaxError, "").WithArguments(",").WithLocation(1, 32),
DesignTime
// (23,91): error CS1501: No overload for method 'TypeCheck' takes 2 arguments
// __o = global::Microsoft.AspNetCore.Components.CompilerServices.RuntimeHelpers.TypeCheck<global::System.String>(
? Diagnostic(ErrorCode.ERR_BadArgCount, "TypeCheck<global::System.String>").WithArguments("TypeCheck", "2").WithLocation(23, 91)
// (17,138): error CS1501: No overload for method 'TypeCheck' takes 2 arguments
// __builder.AddComponentParameter(1, "StringProperty", global::Microsoft.AspNetCore.Components.CompilerServices.RuntimeHelpers.TypeCheck<global::System.String>(
: Diagnostic(ErrorCode.ERR_BadArgCount, "TypeCheck<global::System.String>").WithArguments("TypeCheck", "2").WithLocation(17, 138));
Assert.NotEmpty(generated.Diagnostics);
}
[IntegrationTestFact]
@ -10502,7 +10591,20 @@ Time: @DateTime.Now
// Assert
AssertDocumentNodeMatchesBaseline(generated.CodeDocument);
AssertCSharpDocumentMatchesBaseline(generated.CodeDocument, verifyLinePragmas: false);
AssertCSharpDocumentMatchesBaseline(generated.CodeDocument);
var result = CompileToAssembly(generated, throwOnFailure: false);
if (DesignTime)
{
result.Diagnostics.Verify(
// x:\dir\subdir\Test\TestComponent.cshtml(2,74): error CS1503: Argument 1: cannot convert from 'int' to 'string'
// x
Diagnostic(ErrorCode.ERR_BadArgType, "x").WithArguments("1", "int", "string").WithLocation(2, 74));
}
else
{
result.Diagnostics.Verify();
}
Assert.NotEmpty(generated.Diagnostics);
}
[IntegrationTestFact, WorkItem("https://github.com/dotnet/razor/issues/9077")]
@ -10555,6 +10657,14 @@ Time: @DateTime.Now
// Assert
AssertDocumentNodeMatchesBaseline(generated.CodeDocument);
AssertCSharpDocumentMatchesBaseline(generated.CodeDocument);
var result = CompileToAssembly(generated, throwOnFailure: false);
result.Diagnostics.Verify(DesignTime
// (39,85): error CS7036: There is no argument given that corresponds to the required parameter 'value' of 'RuntimeHelpers.TypeCheck<T>(T)'
// global::Microsoft.AspNetCore.Components.CompilerServices.RuntimeHelpers.TypeCheck<string>();
? Diagnostic(ErrorCode.ERR_NoCorrespondingArgument, "TypeCheck<string>").WithArguments("value", "Microsoft.AspNetCore.Components.CompilerServices.RuntimeHelpers.TypeCheck<T>(T)").WithLocation(39, 85)
// (34,105): error CS7036: There is no argument given that corresponds to the required parameter 'value' of 'RuntimeHelpers.TypeCheck<T>(T)'
// string __formName = global::Microsoft.AspNetCore.Components.CompilerServices.RuntimeHelpers.TypeCheck<string>();
: Diagnostic(ErrorCode.ERR_NoCorrespondingArgument, "TypeCheck<string>").WithArguments("value", "Microsoft.AspNetCore.Components.CompilerServices.RuntimeHelpers.TypeCheck<T>(T)").WithLocation(34, 105));
}
[IntegrationTestFact, WorkItem("https://github.com/dotnet/razor/issues/9077")]

Просмотреть файл

@ -1 +1 @@
x:\dir\subdir\Test\TestComponent.cshtml(1,30): Error RZ9986: Component attributes do not support complex content (mixed C# and markup). Attribute: 'StringProperty', text: 'MyEnum'
x:\dir\subdir\Test\TestComponent.cshtml(1,30): Error RZ9986: Component attributes do not support complex content (mixed C# and markup). Attribute: 'StringProperty', text: 'MyEnum.'

Просмотреть файл

@ -18,6 +18,8 @@
ComponentAttribute - (29:0,29 [8] x:\dir\subdir\Test\TestComponent.cshtml) - StringProperty - StringProperty - AttributeStructure.DoubleQuotes
CSharpExpression - (30:0,30 [6] x:\dir\subdir\Test\TestComponent.cshtml)
LazyIntermediateToken - (30:0,30 [6] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - MyEnum
HtmlContent - (36:0,36 [1] x:\dir\subdir\Test\TestComponent.cshtml)
LazyIntermediateToken - (36:0,36 [1] x:\dir\subdir\Test\TestComponent.cshtml) - Html - .
HtmlContent - (41:0,41 [4] x:\dir\subdir\Test\TestComponent.cshtml)
LazyIntermediateToken - (41:0,41 [4] x:\dir\subdir\Test\TestComponent.cshtml) - Html - \n\n
CSharpCode - (52:2,7 [67] x:\dir\subdir\Test\TestComponent.cshtml)

Просмотреть файл

@ -0,0 +1,69 @@
// <auto-generated/>
#pragma warning disable 1591
namespace Test
{
#line hidden
using global::System;
using global::System.Collections.Generic;
using global::System.Linq;
using global::System.Threading.Tasks;
using global::Microsoft.AspNetCore.Components;
public partial class TestComponent : global::Microsoft.AspNetCore.Components.ComponentBase
{
#pragma warning disable 219
private void __RazorDirectiveTokenHelpers__() {
}
#pragma warning restore 219
#pragma warning disable 0414
private static object __o = null;
#pragma warning restore 0414
#pragma warning disable 1998
protected override void BuildRenderTree(global::Microsoft.AspNetCore.Components.Rendering.RenderTreeBuilder __builder)
{
__o = global::Microsoft.AspNetCore.Components.CompilerServices.RuntimeHelpers.TypeCheck<global::System.String>(
#nullable restore
#line 1 "x:\dir\subdir\Test\TestComponent.cshtml"
MyEnum
#line default
#line hidden
#nullable disable
);
__builder.AddAttribute(-1, "ChildContent", (global::Microsoft.AspNetCore.Components.RenderFragment)((__builder2) => {
}
));
#pragma warning disable BL0005
((global::Test.MyComponent)default).
#nullable restore
#line 1 "x:\dir\subdir\Test\TestComponent.cshtml"
StringProperty
#line default
#line hidden
#nullable disable
= default;
#pragma warning restore BL0005
#nullable restore
#line 1 "x:\dir\subdir\Test\TestComponent.cshtml"
__o = typeof(global::Test.MyComponent);
#line default
#line hidden
#nullable disable
}
#pragma warning restore 1998
#nullable restore
#line 3 "x:\dir\subdir\Test\TestComponent.cshtml"
public enum MyEnum
{
One,
Two
}
#line default
#line hidden
#nullable disable
}
}
#pragma warning restore 1591

Просмотреть файл

@ -0,0 +1 @@
x:\dir\subdir\Test\TestComponent.cshtml(1,30): Error RZ9986: Component attributes do not support complex content (mixed C# and markup). Attribute: 'StringProperty', text: 'MyEnum+'

Просмотреть файл

@ -0,0 +1,26 @@
Document -
NamespaceDeclaration - - Test
UsingDirective - (3:1,1 [20] ) - global::System
UsingDirective - (26:2,1 [40] ) - global::System.Collections.Generic
UsingDirective - (69:3,1 [25] ) - global::System.Linq
UsingDirective - (97:4,1 [36] ) - global::System.Threading.Tasks
UsingDirective - (136:5,1 [45] ) - global::Microsoft.AspNetCore.Components
ClassDeclaration - - public partial - TestComponent - global::Microsoft.AspNetCore.Components.ComponentBase -
DesignTimeDirective -
CSharpCode -
IntermediateToken - - CSharp - #pragma warning disable 0414
CSharpCode -
IntermediateToken - - CSharp - private static object __o = null;
CSharpCode -
IntermediateToken - - CSharp - #pragma warning restore 0414
MethodDeclaration - - protected override - void - BuildRenderTree
Component - (0:0,0 [41] x:\dir\subdir\Test\TestComponent.cshtml) - MyComponent
ComponentAttribute - (29:0,29 [8] x:\dir\subdir\Test\TestComponent.cshtml) - StringProperty - StringProperty - AttributeStructure.DoubleQuotes
CSharpExpression - (30:0,30 [6] x:\dir\subdir\Test\TestComponent.cshtml)
LazyIntermediateToken - (30:0,30 [6] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - MyEnum
HtmlContent - (36:0,36 [1] x:\dir\subdir\Test\TestComponent.cshtml)
LazyIntermediateToken - (36:0,36 [1] x:\dir\subdir\Test\TestComponent.cshtml) - Html - +
HtmlContent - (41:0,41 [4] x:\dir\subdir\Test\TestComponent.cshtml)
LazyIntermediateToken - (41:0,41 [4] x:\dir\subdir\Test\TestComponent.cshtml) - Html - \n\n
CSharpCode - (52:2,7 [67] x:\dir\subdir\Test\TestComponent.cshtml)
LazyIntermediateToken - (52:2,7 [67] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - \n public enum MyEnum\n {\n One,\n Two\n }\n

Просмотреть файл

@ -0,0 +1,27 @@
Source Location: (30:0,30 [6] x:\dir\subdir\Test\TestComponent.cshtml)
|MyEnum|
Generated Location: (1056:25,30 [6] )
|MyEnum|
Source Location: (13:0,13 [14] x:\dir\subdir\Test\TestComponent.cshtml)
|StringProperty|
Generated Location: (1470:38,13 [14] )
|StringProperty|
Source Location: (52:2,7 [67] x:\dir\subdir\Test\TestComponent.cshtml)
|
public enum MyEnum
{
One,
Two
}
|
Generated Location: (1892:56,7 [67] )
|
public enum MyEnum
{
One,
Two
}
|

Просмотреть файл

@ -0,0 +1,72 @@
// <auto-generated/>
#pragma warning disable 1591
namespace Test
{
#line hidden
using global::System;
using global::System.Collections.Generic;
using global::System.Linq;
using global::System.Threading.Tasks;
using global::Microsoft.AspNetCore.Components;
public partial class TestComponent : global::Microsoft.AspNetCore.Components.ComponentBase
{
#pragma warning disable 219
private void __RazorDirectiveTokenHelpers__() {
}
#pragma warning restore 219
#pragma warning disable 0414
private static object __o = null;
#pragma warning restore 0414
#pragma warning disable 1998
protected override void BuildRenderTree(global::Microsoft.AspNetCore.Components.Rendering.RenderTreeBuilder __builder)
{
__o = global::Microsoft.AspNetCore.Components.CompilerServices.RuntimeHelpers.TypeCheck<global::System.String>(
#nullable restore
#line 1 "x:\dir\subdir\Test\TestComponent.cshtml"
x
#line default
#line hidden
#nullable disable
#nullable restore
#line 1 "x:\dir\subdir\Test\TestComponent.cshtml"
"string"
#line default
#line hidden
#nullable disable
);
__builder.AddAttribute(-1, "ChildContent", (global::Microsoft.AspNetCore.Components.RenderFragment)((__builder2) => {
}
));
#pragma warning disable BL0005
((global::Test.MyComponent)default).
#nullable restore
#line 1 "x:\dir\subdir\Test\TestComponent.cshtml"
StringProperty
#line default
#line hidden
#nullable disable
= default;
#pragma warning restore BL0005
#nullable restore
#line 1 "x:\dir\subdir\Test\TestComponent.cshtml"
__o = typeof(global::Test.MyComponent);
#line default
#line hidden
#nullable disable
}
#pragma warning restore 1998
#nullable restore
#line 3 "x:\dir\subdir\Test\TestComponent.cshtml"
int x = 1;
#line default
#line hidden
#nullable disable
}
}
#pragma warning restore 1591

Просмотреть файл

@ -0,0 +1 @@
x:\dir\subdir\Test\TestComponent.cshtml(1,30): Error RZ9986: Component attributes do not support complex content (mixed C# and markup). Attribute: 'StringProperty', text: 'x html "string"'

Просмотреть файл

@ -0,0 +1,29 @@
Document -
NamespaceDeclaration - - Test
UsingDirective - (3:1,1 [20] ) - global::System
UsingDirective - (26:2,1 [40] ) - global::System.Collections.Generic
UsingDirective - (69:3,1 [25] ) - global::System.Linq
UsingDirective - (97:4,1 [36] ) - global::System.Threading.Tasks
UsingDirective - (136:5,1 [45] ) - global::Microsoft.AspNetCore.Components
ClassDeclaration - - public partial - TestComponent - global::Microsoft.AspNetCore.Components.ComponentBase -
DesignTimeDirective -
CSharpCode -
IntermediateToken - - CSharp - #pragma warning disable 0414
CSharpCode -
IntermediateToken - - CSharp - private static object __o = null;
CSharpCode -
IntermediateToken - - CSharp - #pragma warning restore 0414
MethodDeclaration - - protected override - void - BuildRenderTree
Component - (0:0,0 [52] x:\dir\subdir\Test\TestComponent.cshtml) - MyComponent
ComponentAttribute - (29:0,29 [19] x:\dir\subdir\Test\TestComponent.cshtml) - StringProperty - StringProperty - AttributeStructure.DoubleQuotes
CSharpExpression - (30:0,30 [1] x:\dir\subdir\Test\TestComponent.cshtml)
LazyIntermediateToken - (30:0,30 [1] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - x
HtmlContent - (31:0,31 [6] x:\dir\subdir\Test\TestComponent.cshtml)
LazyIntermediateToken - (31:0,31 [5] x:\dir\subdir\Test\TestComponent.cshtml) - Html - html
LazyIntermediateToken - (36:0,36 [1] x:\dir\subdir\Test\TestComponent.cshtml) - Html -
CSharpExpression - (39:0,39 [8] x:\dir\subdir\Test\TestComponent.cshtml)
LazyIntermediateToken - (39:0,39 [8] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - "string"
HtmlContent - (52:0,52 [4] x:\dir\subdir\Test\TestComponent.cshtml)
LazyIntermediateToken - (52:0,52 [4] x:\dir\subdir\Test\TestComponent.cshtml) - Html - \n\n
CSharpCode - (63:2,7 [18] x:\dir\subdir\Test\TestComponent.cshtml)
LazyIntermediateToken - (63:2,7 [18] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - \n int x = 1;\n

Просмотреть файл

@ -0,0 +1,24 @@
Source Location: (30:0,30 [1] x:\dir\subdir\Test\TestComponent.cshtml)
|x|
Generated Location: (1056:25,30 [1] )
|x|
Source Location: (39:0,39 [8] x:\dir\subdir\Test\TestComponent.cshtml)
|"string"|
Generated Location: (1218:32,39 [8] )
|"string"|
Source Location: (13:0,13 [14] x:\dir\subdir\Test\TestComponent.cshtml)
|StringProperty|
Generated Location: (1634:45,13 [14] )
|StringProperty|
Source Location: (63:2,7 [18] x:\dir\subdir\Test\TestComponent.cshtml)
|
int x = 1;
|
Generated Location: (2056:63,7 [18] )
|
int x = 1;
|

Просмотреть файл

@ -32,6 +32,24 @@ using Microsoft.AspNetCore.Components.Web;
#line 2 "x:\dir\subdir\Test\TestComponent.cshtml"
() => { }
#line default
#line hidden
#nullable disable
);
global::Microsoft.AspNetCore.Components.CompilerServices.RuntimeHelpers.TypeCheck<string>(
#nullable restore
#line 2 "x:\dir\subdir\Test\TestComponent.cshtml"
"literal"
#line default
#line hidden
#nullable disable
);
global::Microsoft.AspNetCore.Components.CompilerServices.RuntimeHelpers.TypeCheck<string>(
#nullable restore
#line 2 "x:\dir\subdir\Test\TestComponent.cshtml"
x
#line default
#line hidden
#nullable disable

Просмотреть файл

@ -26,6 +26,18 @@
IntermediateToken - - CSharp - global::Microsoft.AspNetCore.Components.EventCallback.Factory.Create<global::System.EventArgs>(this,
LazyIntermediateToken - (75:1,31 [9] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - () => { }
IntermediateToken - - CSharp - )
FormName - (97:1,53 [25] x:\dir\subdir\Test\TestComponent.cshtml)
HtmlContent - (97:1,53 [6] x:\dir\subdir\Test\TestComponent.cshtml)
LazyIntermediateToken - (97:1,53 [5] x:\dir\subdir\Test\TestComponent.cshtml) - Html - start
LazyIntermediateToken - (102:1,58 [1] x:\dir\subdir\Test\TestComponent.cshtml) - Html -
CSharpExpression - (105:1,61 [9] x:\dir\subdir\Test\TestComponent.cshtml)
LazyIntermediateToken - (105:1,61 [9] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - "literal"
HtmlContent - (115:1,71 [1] x:\dir\subdir\Test\TestComponent.cshtml)
LazyIntermediateToken - (115:1,71 [1] x:\dir\subdir\Test\TestComponent.cshtml) - Html -
CSharpExpression - (117:1,73 [1] x:\dir\subdir\Test\TestComponent.cshtml)
LazyIntermediateToken - (117:1,73 [1] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - x
HtmlContent - (118:1,74 [4] x:\dir\subdir\Test\TestComponent.cshtml)
LazyIntermediateToken - (118:1,74 [4] x:\dir\subdir\Test\TestComponent.cshtml) - Html - end
HtmlContent - (131:1,87 [2] x:\dir\subdir\Test\TestComponent.cshtml)
LazyIntermediateToken - (131:1,87 [2] x:\dir\subdir\Test\TestComponent.cshtml) - Html - \n
CSharpCode - (140:2,7 [18] x:\dir\subdir\Test\TestComponent.cshtml)

Просмотреть файл

@ -8,11 +8,21 @@ Source Location: (75:1,31 [9] x:\dir\subdir\Test\TestComponent.cshtml)
Generated Location: (1217:32,31 [9] )
|() => { }|
Source Location: (105:1,61 [9] x:\dir\subdir\Test\TestComponent.cshtml)
|"literal"|
Generated Location: (1529:41,61 [9] )
|"literal"|
Source Location: (117:1,73 [1] x:\dir\subdir\Test\TestComponent.cshtml)
|x|
Generated Location: (1853:50,73 [1] )
|x|
Source Location: (140:2,7 [18] x:\dir\subdir\Test\TestComponent.cshtml)
|
int x = 1;
|
Generated Location: (1420:42,7 [18] )
Generated Location: (2048:60,7 [18] )
|
int x = 1;
|

Просмотреть файл

@ -44,7 +44,8 @@ using Microsoft.AspNetCore.Components.Web;
#line default
#line hidden
#nullable disable
);__o = global::Microsoft.AspNetCore.Components.EventCallback.Factory.Create<global::System.EventArgs>(this,
);
__o = global::Microsoft.AspNetCore.Components.EventCallback.Factory.Create<global::System.EventArgs>(this,
#nullable restore
#line 3 "x:\dir\subdir\Test\TestComponent.cshtml"
() => { }

Просмотреть файл

@ -15,12 +15,12 @@ Generated Location: (1522:41,54 [1] )
Source Location: (141:2,31 [9] x:\dir\subdir\Test\TestComponent.cshtml)
|() => { }|
Generated Location: (1799:49,31 [9] )
Generated Location: (1813:50,31 [9] )
|() => { }|
Source Location: (164:2,54 [1] x:\dir\subdir\Test\TestComponent.cshtml)
|y|
Generated Location: (2104:58,54 [1] )
Generated Location: (2118:59,54 [1] )
|y|
Source Location: (183:3,7 [44] x:\dir\subdir\Test\TestComponent.cshtml)
@ -28,7 +28,7 @@ Source Location: (183:3,7 [44] x:\dir\subdir\Test\TestComponent.cshtml)
string x = "a";
string y = "b";
|
Generated Location: (2299:68,7 [44] )
Generated Location: (2313:69,7 [44] )
|
string x = "a";
string y = "b";

Просмотреть файл

@ -36,6 +36,7 @@ using Microsoft.AspNetCore.Components.Web;
#line hidden
#nullable disable
);
global::Microsoft.AspNetCore.Components.CompilerServices.RuntimeHelpers.TypeCheck<string>();
}
#pragma warning restore 1998
}

Просмотреть файл

@ -26,3 +26,6 @@
IntermediateToken - - CSharp - global::Microsoft.AspNetCore.Components.EventCallback.Factory.Create<global::System.EventArgs>(this,
LazyIntermediateToken - (75:1,31 [9] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - () => { }
IntermediateToken - - CSharp - )
FormName - (97:1,53 [4] x:\dir\subdir\Test\TestComponent.cshtml)
CSharpCode - (99:1,55 [1] x:\dir\subdir\Test\TestComponent.cshtml)
LazyIntermediateToken - (99:1,55 [1] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp -

Просмотреть файл

@ -1 +1 @@
x:\dir\subdir\Test\TestComponent.cshtml(1,30): Error RZ9986: Component attributes do not support complex content (mixed C# and markup). Attribute: 'StringProperty', text: 'MyEnum'
x:\dir\subdir\Test\TestComponent.cshtml(1,30): Error RZ9986: Component attributes do not support complex content (mixed C# and markup). Attribute: 'StringProperty', text: 'MyEnum.'

Просмотреть файл

@ -11,5 +11,7 @@
ComponentAttribute - (29:0,29 [8] x:\dir\subdir\Test\TestComponent.cshtml) - StringProperty - StringProperty - AttributeStructure.DoubleQuotes
CSharpExpression - (30:0,30 [6] x:\dir\subdir\Test\TestComponent.cshtml)
LazyIntermediateToken - (30:0,30 [6] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - MyEnum
HtmlContent - (36:0,36 [1] x:\dir\subdir\Test\TestComponent.cshtml)
LazyIntermediateToken - (36:0,36 [1] x:\dir\subdir\Test\TestComponent.cshtml) - Html - .
CSharpCode - (52:2,7 [67] x:\dir\subdir\Test\TestComponent.cshtml)
LazyIntermediateToken - (52:2,7 [67] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - \n public enum MyEnum\n {\n One,\n Two\n }\n

Просмотреть файл

@ -0,0 +1,43 @@
// <auto-generated/>
#pragma warning disable 1591
namespace Test
{
#line hidden
using global::System;
using global::System.Collections.Generic;
using global::System.Linq;
using global::System.Threading.Tasks;
using global::Microsoft.AspNetCore.Components;
public partial class TestComponent : global::Microsoft.AspNetCore.Components.ComponentBase
{
#pragma warning disable 1998
protected override void BuildRenderTree(global::Microsoft.AspNetCore.Components.Rendering.RenderTreeBuilder __builder)
{
__builder.OpenComponent<global::Test.MyComponent>(0);
__builder.AddComponentParameter(1, "StringProperty", global::Microsoft.AspNetCore.Components.CompilerServices.RuntimeHelpers.TypeCheck<global::System.String>(
#nullable restore
#line 1 "x:\dir\subdir\Test\TestComponent.cshtml"
MyEnum
#line default
#line hidden
#nullable disable
));
__builder.CloseComponent();
}
#pragma warning restore 1998
#nullable restore
#line 3 "x:\dir\subdir\Test\TestComponent.cshtml"
public enum MyEnum
{
One,
Two
}
#line default
#line hidden
#nullable disable
}
}
#pragma warning restore 1591

Просмотреть файл

@ -0,0 +1 @@
x:\dir\subdir\Test\TestComponent.cshtml(1,30): Error RZ9986: Component attributes do not support complex content (mixed C# and markup). Attribute: 'StringProperty', text: 'MyEnum+'

Просмотреть файл

@ -0,0 +1,17 @@
Document -
NamespaceDeclaration - - Test
UsingDirective - (3:1,1 [22] ) - global::System
UsingDirective - (26:2,1 [42] ) - global::System.Collections.Generic
UsingDirective - (69:3,1 [27] ) - global::System.Linq
UsingDirective - (97:4,1 [38] ) - global::System.Threading.Tasks
UsingDirective - (136:5,1 [47] ) - global::Microsoft.AspNetCore.Components
ClassDeclaration - - public partial - TestComponent - global::Microsoft.AspNetCore.Components.ComponentBase -
MethodDeclaration - - protected override - void - BuildRenderTree
Component - (0:0,0 [41] x:\dir\subdir\Test\TestComponent.cshtml) - MyComponent
ComponentAttribute - (29:0,29 [8] x:\dir\subdir\Test\TestComponent.cshtml) - StringProperty - StringProperty - AttributeStructure.DoubleQuotes
CSharpExpression - (30:0,30 [6] x:\dir\subdir\Test\TestComponent.cshtml)
LazyIntermediateToken - (30:0,30 [6] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - MyEnum
HtmlContent - (36:0,36 [1] x:\dir\subdir\Test\TestComponent.cshtml)
LazyIntermediateToken - (36:0,36 [1] x:\dir\subdir\Test\TestComponent.cshtml) - Html - +
CSharpCode - (52:2,7 [67] x:\dir\subdir\Test\TestComponent.cshtml)
LazyIntermediateToken - (52:2,7 [67] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - \n public enum MyEnum\n {\n One,\n Two\n }\n

Просмотреть файл

@ -0,0 +1,17 @@
Source Location: (52:2,7 [67] x:\dir\subdir\Test\TestComponent.cshtml)
|
public enum MyEnum
{
One,
Two
}
|
Generated Location: (1151:30,7 [67] )
|
public enum MyEnum
{
One,
Two
}
|

Просмотреть файл

@ -0,0 +1,46 @@
// <auto-generated/>
#pragma warning disable 1591
namespace Test
{
#line hidden
using global::System;
using global::System.Collections.Generic;
using global::System.Linq;
using global::System.Threading.Tasks;
using global::Microsoft.AspNetCore.Components;
public partial class TestComponent : global::Microsoft.AspNetCore.Components.ComponentBase
{
#pragma warning disable 1998
protected override void BuildRenderTree(global::Microsoft.AspNetCore.Components.Rendering.RenderTreeBuilder __builder)
{
__builder.OpenComponent<global::Test.MyComponent>(0);
__builder.AddComponentParameter(1, "StringProperty", global::Microsoft.AspNetCore.Components.CompilerServices.RuntimeHelpers.TypeCheck<global::System.String>(
#nullable restore
#line 1 "x:\dir\subdir\Test\TestComponent.cshtml"
x
#line default
#line hidden
#nullable disable
#nullable restore
#line 1 "x:\dir\subdir\Test\TestComponent.cshtml"
"string"
#line default
#line hidden
#nullable disable
));
__builder.CloseComponent();
}
#pragma warning restore 1998
#nullable restore
#line 3 "x:\dir\subdir\Test\TestComponent.cshtml"
int x = 1;
#line default
#line hidden
#nullable disable
}
}
#pragma warning restore 1591

Просмотреть файл

@ -0,0 +1 @@
x:\dir\subdir\Test\TestComponent.cshtml(1,30): Error RZ9986: Component attributes do not support complex content (mixed C# and markup). Attribute: 'StringProperty', text: 'x html "string"'

Просмотреть файл

@ -0,0 +1,20 @@
Document -
NamespaceDeclaration - - Test
UsingDirective - (3:1,1 [22] ) - global::System
UsingDirective - (26:2,1 [42] ) - global::System.Collections.Generic
UsingDirective - (69:3,1 [27] ) - global::System.Linq
UsingDirective - (97:4,1 [38] ) - global::System.Threading.Tasks
UsingDirective - (136:5,1 [47] ) - global::Microsoft.AspNetCore.Components
ClassDeclaration - - public partial - TestComponent - global::Microsoft.AspNetCore.Components.ComponentBase -
MethodDeclaration - - protected override - void - BuildRenderTree
Component - (0:0,0 [52] x:\dir\subdir\Test\TestComponent.cshtml) - MyComponent
ComponentAttribute - (29:0,29 [19] x:\dir\subdir\Test\TestComponent.cshtml) - StringProperty - StringProperty - AttributeStructure.DoubleQuotes
CSharpExpression - (30:0,30 [1] x:\dir\subdir\Test\TestComponent.cshtml)
LazyIntermediateToken - (30:0,30 [1] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - x
HtmlContent - (31:0,31 [6] x:\dir\subdir\Test\TestComponent.cshtml)
LazyIntermediateToken - (31:0,31 [5] x:\dir\subdir\Test\TestComponent.cshtml) - Html - html
LazyIntermediateToken - (36:0,36 [1] x:\dir\subdir\Test\TestComponent.cshtml) - Html -
CSharpExpression - (39:0,39 [8] x:\dir\subdir\Test\TestComponent.cshtml)
LazyIntermediateToken - (39:0,39 [8] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - "string"
CSharpCode - (63:2,7 [18] x:\dir\subdir\Test\TestComponent.cshtml)
LazyIntermediateToken - (63:2,7 [18] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - \n int x = 1;\n

Просмотреть файл

@ -0,0 +1,9 @@
Source Location: (63:2,7 [18] x:\dir\subdir\Test\TestComponent.cshtml)
|
int x = 1;
|
Generated Location: (1315:37,7 [18] )
|
int x = 1;
|

Просмотреть файл

@ -31,6 +31,24 @@ using Microsoft.AspNetCore.Components.Web;
#line hidden
#nullable disable
));
string __formName = global::Microsoft.AspNetCore.Components.CompilerServices.RuntimeHelpers.TypeCheck<string>("start" + " " + (
#nullable restore
#line 2 "x:\dir\subdir\Test\TestComponent.cshtml"
"literal"
#line default
#line hidden
#nullable disable
) + " " + (
#nullable restore
#line 2 "x:\dir\subdir\Test\TestComponent.cshtml"
x
#line default
#line hidden
#nullable disable
) + " end");
__builder.AddNamedEvent("onsubmit", __formName);
__builder.CloseElement();
}
#pragma warning restore 1998

Просмотреть файл

@ -17,5 +17,17 @@
IntermediateToken - - CSharp - global::Microsoft.AspNetCore.Components.EventCallback.Factory.Create<global::System.EventArgs>(this,
LazyIntermediateToken - (75:1,31 [9] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - () => { }
IntermediateToken - - CSharp - )
FormName - (97:1,53 [25] x:\dir\subdir\Test\TestComponent.cshtml)
HtmlContent - (97:1,53 [6] x:\dir\subdir\Test\TestComponent.cshtml)
LazyIntermediateToken - (97:1,53 [5] x:\dir\subdir\Test\TestComponent.cshtml) - Html - start
LazyIntermediateToken - (102:1,58 [1] x:\dir\subdir\Test\TestComponent.cshtml) - Html -
CSharpExpression - (105:1,61 [9] x:\dir\subdir\Test\TestComponent.cshtml)
LazyIntermediateToken - (105:1,61 [9] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - "literal"
HtmlContent - (115:1,71 [1] x:\dir\subdir\Test\TestComponent.cshtml)
LazyIntermediateToken - (115:1,71 [1] x:\dir\subdir\Test\TestComponent.cshtml) - Html -
CSharpExpression - (117:1,73 [1] x:\dir\subdir\Test\TestComponent.cshtml)
LazyIntermediateToken - (117:1,73 [1] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - x
HtmlContent - (118:1,74 [4] x:\dir\subdir\Test\TestComponent.cshtml)
LazyIntermediateToken - (118:1,74 [4] x:\dir\subdir\Test\TestComponent.cshtml) - Html - end
CSharpCode - (140:2,7 [18] x:\dir\subdir\Test\TestComponent.cshtml)
LazyIntermediateToken - (140:2,7 [18] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - \n int x = 1;\n

Просмотреть файл

@ -2,7 +2,7 @@
|
int x = 1;
|
Generated Location: (1336:38,7 [18] )
Generated Location: (1978:56,7 [18] )
|
int x = 1;
|

Просмотреть файл

@ -31,6 +31,8 @@ using Microsoft.AspNetCore.Components.Web;
#line hidden
#nullable disable
));
string __formName = global::Microsoft.AspNetCore.Components.CompilerServices.RuntimeHelpers.TypeCheck<string>();
__builder.AddNamedEvent("onsubmit", __formName);
__builder.CloseElement();
}
#pragma warning restore 1998

Просмотреть файл

@ -17,3 +17,6 @@
IntermediateToken - - CSharp - global::Microsoft.AspNetCore.Components.EventCallback.Factory.Create<global::System.EventArgs>(this,
LazyIntermediateToken - (75:1,31 [9] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp - () => { }
IntermediateToken - - CSharp - )
FormName - (97:1,53 [4] x:\dir\subdir\Test\TestComponent.cshtml)
CSharpCode - (99:1,55 [1] x:\dir\subdir\Test\TestComponent.cshtml)
LazyIntermediateToken - (99:1,55 [1] x:\dir\subdir\Test\TestComponent.cshtml) - CSharp -

Просмотреть файл

@ -144,6 +144,46 @@ public class CompletionIntegrationTests(ITestOutputHelper testOutputHelper) : Ab
Assert.Null(completionSession);
}
[IdeFact, WorkItem("https://github.com/dotnet/razor/issues/9346")]
public async Task Completion_EnumDot()
{
await TestServices.SolutionExplorer.AddFileAsync(
RazorProjectConstants.BlazorProjectName,
"Test.razor",
"""
<Test Param="@MyEnum." />
@code {
[Parameter] public string Param { get; set; }
public enum MyEnum
{
One
}
}
""",
open: true,
ControlledHangMitigatingCancellationToken);
await TestServices.Editor.WaitForComponentClassificationAsync(ControlledHangMitigatingCancellationToken);
await TestServices.Editor.PlaceCaretAsync("@MyEnum.", charsOffset: 1, ControlledHangMitigatingCancellationToken);
TestServices.Input.Send("O");
await CommitCompletionAndVerifyAsync("""
<Test Param="@MyEnum.One" />
@code {
[Parameter] public string Param { get; set; }
public enum MyEnum
{
One
}
}
""");
}
private async Task CommitCompletionAndVerifyAsync(string expected)
{
var textView = await TestServices.Editor.GetActiveTextViewAsync(HangMitigatingCancellationToken);

Просмотреть файл

@ -9,13 +9,17 @@ namespace Microsoft.CodeAnalysis;
public enum ErrorCode
{
ERR_NameNotInContext = 103,
ERR_BadSKunknown = 119,
ERR_ObjectRequired = 120,
WRN_UnreferencedField = 169,
ERR_SingleTypeNameNotFound = 246,
ERR_CantInferMethTypeArgs = 411,
WRN_UnreferencedFieldAssg = 414,
ERR_SyntaxError = 1003,
ERR_BadArgCount = 1501,
ERR_BadArgType = 1503,
WRN_AsyncLacksAwaits = 1998,
ERR_NoCorrespondingArgument = 7036,
WRN_NullReferenceReceiver = 8602,
WRN_UninitializedNonNullableField = 8618,
}