Fix for #453
This fix adds missing line mappings for the Blazor runtime code generation. We had the correct line mappings for design time code, but they were missing in this case for runtime code - where they are used for error messages and debugging (not yet supported). Once this fix is is in the error window and output log will report the file/line/column of the original source in .cshtml. It looks like jumping to the code from the error window is currently not working correctly in VS. It works from the output window. I'm going to follow up on the VS issue in the Razor repo, since the fix won't come from the Blazor side.
This commit is contained in:
parent
d097190824
commit
0c942ccc76
|
|
@ -50,6 +50,16 @@ namespace Microsoft.AspNetCore.Blazor.Razor
|
|||
|
||||
public override void WriteCSharpCode(CodeRenderingContext context, CSharpCodeIntermediateNode node)
|
||||
{
|
||||
if (context == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(context));
|
||||
}
|
||||
|
||||
if (node == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(node));
|
||||
}
|
||||
|
||||
var isWhitespaceStatement = true;
|
||||
for (var i = 0; i < node.Children.Count; i++)
|
||||
{
|
||||
|
|
@ -63,14 +73,25 @@ namespace Microsoft.AspNetCore.Blazor.Razor
|
|||
|
||||
if (isWhitespaceStatement)
|
||||
{
|
||||
// The runtime and design time code differ in their handling of whitespace-only
|
||||
// statements. At runtime we can discard them completely. At design time we need
|
||||
// to keep them for the editor.
|
||||
return;
|
||||
}
|
||||
|
||||
IDisposable linePragmaScope = null;
|
||||
if (node.Source != null)
|
||||
{
|
||||
linePragmaScope = context.CodeWriter.BuildLinePragma(node.Source.Value);
|
||||
context.CodeWriter.WritePadding(0, node.Source.Value, context);
|
||||
}
|
||||
|
||||
for (var i = 0; i < node.Children.Count; i++)
|
||||
{
|
||||
if (node.Children[i] is IntermediateToken token && token.IsCSharp)
|
||||
{
|
||||
_scopeStack.IncrementCurrentScopeChildCount(context);
|
||||
context.AddSourceMappingFor(token);
|
||||
context.CodeWriter.Write(token.Content);
|
||||
}
|
||||
else
|
||||
|
|
@ -79,6 +100,15 @@ namespace Microsoft.AspNetCore.Blazor.Razor
|
|||
context.RenderNode(node.Children[i]);
|
||||
}
|
||||
}
|
||||
|
||||
if (linePragmaScope != null)
|
||||
{
|
||||
linePragmaScope.Dispose();
|
||||
}
|
||||
else
|
||||
{
|
||||
context.CodeWriter.WriteLine();
|
||||
}
|
||||
}
|
||||
|
||||
public override void WriteCSharpCodeAttributeValue(CodeRenderingContext context, CSharpCodeAttributeValueIntermediateNode node)
|
||||
|
|
|
|||
|
|
@ -100,6 +100,62 @@ namespace Microsoft.AspNetCore.Blazor.Build.Test
|
|||
Assert.Empty(frames);
|
||||
}
|
||||
|
||||
[Fact] // Regression test for https://github.com/aspnet/Blazor/issues/453
|
||||
public void DeclarationConfiguration_FunctionsBlockHasLineMappings_MappingsApplyToError()
|
||||
{
|
||||
// Arrange & Act 1
|
||||
var generated = CompileToCSharp(@"
|
||||
@functions {
|
||||
public StringBuilder Builder { get; set; }
|
||||
}
|
||||
");
|
||||
|
||||
// Assert 1
|
||||
AssertSourceEquals(@"
|
||||
// <auto-generated/>
|
||||
#pragma warning disable 1591
|
||||
#pragma warning disable 0414
|
||||
#pragma warning disable 0649
|
||||
#pragma warning disable 0169
|
||||
|
||||
namespace Test
|
||||
{
|
||||
#line hidden
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
public class TestComponent : Microsoft.AspNetCore.Blazor.Components.BlazorComponent
|
||||
{
|
||||
#pragma warning disable 1998
|
||||
protected override void BuildRenderTree(Microsoft.AspNetCore.Blazor.RenderTree.RenderTreeBuilder builder)
|
||||
{
|
||||
}
|
||||
#pragma warning restore 1998
|
||||
#line 1 ""x:\dir\subdir\Test\TestComponent.cshtml""
|
||||
|
||||
public StringBuilder Builder { get; set; }
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
}
|
||||
}
|
||||
#pragma warning restore 1591
|
||||
", generated);
|
||||
|
||||
// Act 2
|
||||
var assembly = CompileToAssembly(generated, throwOnFailure: false);
|
||||
|
||||
// Assert 2
|
||||
var diagnostic = Assert.Single(assembly.Diagnostics);
|
||||
|
||||
// This error should map to line 2 of the generated file, the test
|
||||
// says 1 because Roslyn's line/column data structures are 0-based.
|
||||
var position = diagnostic.Location.GetMappedLineSpan();
|
||||
Assert.EndsWith(".cshtml", position.Path);
|
||||
Assert.Equal(1, position.StartLinePosition.Line);
|
||||
}
|
||||
|
||||
public class BaseClass : BlazorComponent
|
||||
{
|
||||
}
|
||||
|
|
|
|||
|
|
@ -208,7 +208,7 @@ namespace Microsoft.AspNetCore.Blazor.Build.Test
|
|||
return CompileToAssembly(cSharpResult);
|
||||
}
|
||||
|
||||
protected CompileToAssemblyResult CompileToAssembly(CompileToCSharpResult cSharpResult)
|
||||
protected CompileToAssemblyResult CompileToAssembly(CompileToCSharpResult cSharpResult, bool throwOnFailure = true)
|
||||
{
|
||||
if (cSharpResult.Diagnostics.Any())
|
||||
{
|
||||
|
|
@ -227,10 +227,18 @@ namespace Microsoft.AspNetCore.Blazor.Build.Test
|
|||
.GetDiagnostics()
|
||||
.Where(d => d.Severity != DiagnosticSeverity.Hidden);
|
||||
|
||||
if (diagnostics.Any())
|
||||
if (diagnostics.Any() && throwOnFailure)
|
||||
{
|
||||
throw new CompilationFailedException(compilation);
|
||||
}
|
||||
else if (diagnostics.Any())
|
||||
{
|
||||
return new CompileToAssemblyResult
|
||||
{
|
||||
Compilation = compilation,
|
||||
Diagnostics = diagnostics,
|
||||
};
|
||||
}
|
||||
|
||||
using (var peStream = new MemoryStream())
|
||||
{
|
||||
|
|
|
|||
|
|
@ -49,6 +49,7 @@ namespace Test
|
|||
protected override void BuildRenderTree(Microsoft.AspNetCore.Blazor.RenderTree.RenderTreeBuilder builder)
|
||||
{
|
||||
base.BuildRenderTree(builder);
|
||||
|
||||
builder.OpenComponent<Test.MyComponent>(0);
|
||||
builder.CloseComponent();
|
||||
}
|
||||
|
|
@ -110,6 +111,7 @@ namespace Test
|
|||
protected override void BuildRenderTree(Microsoft.AspNetCore.Blazor.RenderTree.RenderTreeBuilder builder)
|
||||
{
|
||||
base.BuildRenderTree(builder);
|
||||
|
||||
builder.OpenComponent<Test.MyComponent>(0);
|
||||
builder.AddAttribute(1, ""IntProperty"", 123);
|
||||
builder.AddAttribute(2, ""BoolProperty"", true);
|
||||
|
|
@ -164,6 +166,7 @@ namespace Test
|
|||
protected override void BuildRenderTree(Microsoft.AspNetCore.Blazor.RenderTree.RenderTreeBuilder builder)
|
||||
{
|
||||
base.BuildRenderTree(builder);
|
||||
|
||||
builder.OpenComponent<Test.MyComponent>(0);
|
||||
builder.AddAttribute(1, ""StringProperty"", 42.ToString());
|
||||
builder.CloseComponent();
|
||||
|
|
@ -214,6 +217,7 @@ namespace Test
|
|||
protected override void BuildRenderTree(Microsoft.AspNetCore.Blazor.RenderTree.RenderTreeBuilder builder)
|
||||
{
|
||||
base.BuildRenderTree(builder);
|
||||
|
||||
builder.OpenComponent<Test.MyComponent>(0);
|
||||
builder.AddAttribute(1, ""some-attribute"", ""foo"");
|
||||
builder.AddAttribute(2, ""another-attribute"", 43.ToString());
|
||||
|
|
@ -276,20 +280,26 @@ namespace Test
|
|||
protected override void BuildRenderTree(Microsoft.AspNetCore.Blazor.RenderTree.RenderTreeBuilder builder)
|
||||
{
|
||||
base.BuildRenderTree(builder);
|
||||
|
||||
builder.OpenComponent<Test.MyComponent>(0);
|
||||
builder.AddAttribute(1, ""OnClick"", new Microsoft.AspNetCore.Blazor.UIEventHandler(e => { Increment(); }));
|
||||
builder.CloseComponent();
|
||||
builder.AddContent(2, ""\n\n"");
|
||||
}
|
||||
#pragma warning restore 1998
|
||||
|
||||
#line 4 ""x:\dir\subdir\Test\TestComponent.cshtml""
|
||||
|
||||
private int counter;
|
||||
private void Increment() {
|
||||
counter++;
|
||||
}
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
}
|
||||
}
|
||||
#pragma warning restore 1591
|
||||
|
||||
", generated);
|
||||
}
|
||||
|
||||
|
|
@ -344,20 +354,26 @@ namespace Test
|
|||
protected override void BuildRenderTree(Microsoft.AspNetCore.Blazor.RenderTree.RenderTreeBuilder builder)
|
||||
{
|
||||
base.BuildRenderTree(builder);
|
||||
|
||||
builder.OpenComponent<Test.MyComponent>(0);
|
||||
builder.AddAttribute(1, ""OnClick"", new Microsoft.AspNetCore.Blazor.UIEventHandler(Increment));
|
||||
builder.CloseComponent();
|
||||
builder.AddContent(2, ""\n\n"");
|
||||
}
|
||||
#pragma warning restore 1998
|
||||
|
||||
#line 5 ""x:\dir\subdir\Test\TestComponent.cshtml""
|
||||
|
||||
private int counter;
|
||||
private void Increment(UIEventArgs e) {
|
||||
counter++;
|
||||
}
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
}
|
||||
}
|
||||
#pragma warning restore 1591
|
||||
|
||||
", generated);
|
||||
}
|
||||
|
||||
|
|
@ -404,6 +420,7 @@ namespace Test
|
|||
protected override void BuildRenderTree(Microsoft.AspNetCore.Blazor.RenderTree.RenderTreeBuilder builder)
|
||||
{
|
||||
base.BuildRenderTree(builder);
|
||||
|
||||
builder.OpenComponent<Test.MyComponent>(0);
|
||||
builder.AddAttribute(1, ""MyAttr"", ""abc"");
|
||||
builder.AddAttribute(2, ""ChildContent"", (Microsoft.AspNetCore.Blazor.RenderFragment)((builder2) => {
|
||||
|
|
@ -466,6 +483,7 @@ namespace Test
|
|||
protected override void BuildRenderTree(Microsoft.AspNetCore.Blazor.RenderTree.RenderTreeBuilder builder)
|
||||
{
|
||||
base.BuildRenderTree(builder);
|
||||
|
||||
builder.OpenComponent<Test.MyComponent>(0);
|
||||
builder.CloseComponent();
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue