Clean up and enable nullability for CodeRenderingContext and DefaultDocumentWriter

This commit is contained in:
Dustin Campbell 2024-08-14 14:37:56 -07:00
Родитель 7a9f32ea37
Коммит 6593264ac6
4 изменённых файлов: 95 добавлений и 113 удалений

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

@ -4,7 +4,6 @@
using System;
using System.Collections.Immutable;
using System.Globalization;
using System.Text;
using Microsoft.AspNetCore.Razor.PooledObjects;
namespace Microsoft.AspNetCore.Razor.Language;

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

@ -1,8 +1,6 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
#nullable disable
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
@ -28,6 +26,9 @@ public sealed class CodeRenderingContext : IDisposable
private readonly ImmutableArray<SourceMapping>.Builder _sourceMappings;
private readonly ImmutableArray<LinePragma>.Builder _linePragmas;
private IntermediateNodeVisitor? _visitor;
public IntermediateNodeVisitor Visitor => _visitor.AssumeNotNull();
public string DocumentKind => _documentNode.DocumentKind;
public CodeRenderingContext(
@ -74,12 +75,16 @@ public sealed class CodeRenderingContext : IDisposable
CodeWriter.Dispose();
}
// This will be initialized by the document writer when the context is 'live'.
public IntermediateNodeVisitor Visitor { get; set; }
// This will be called by the document writer when the context is 'live'.
public void SetVisitor(IntermediateNodeVisitor visitor)
{
_visitor = visitor;
}
public IntermediateNodeWriter NodeWriter => _scopeStack.Peek().Writer;
public IntermediateNode Parent => _ancestorStack.Count == 0 ? null : _ancestorStack.Peek();
public IntermediateNode? Parent
=> _ancestorStack.Count == 0 ? null : _ancestorStack.Peek();
public void AddDiagnostic(RazorDiagnostic diagnostic)
{

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

@ -1,8 +1,6 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
#nullable disable
using System;
using System.Linq;
using System.Security.Cryptography;
@ -10,16 +8,10 @@ using Microsoft.AspNetCore.Razor.Language.Intermediate;
namespace Microsoft.AspNetCore.Razor.Language.CodeGeneration;
internal class DefaultDocumentWriter : DocumentWriter
internal class DefaultDocumentWriter(CodeTarget codeTarget, RazorCodeGenerationOptions options) : DocumentWriter
{
private readonly CodeTarget _codeTarget;
private readonly RazorCodeGenerationOptions _options;
public DefaultDocumentWriter(CodeTarget codeTarget, RazorCodeGenerationOptions options)
{
_codeTarget = codeTarget;
_options = options;
}
private readonly CodeTarget _codeTarget = codeTarget;
private readonly RazorCodeGenerationOptions _options = options;
public override RazorCSharpDocument WriteDocument(RazorCodeDocument codeDocument, DocumentIntermediateNode documentNode)
{
@ -32,37 +24,35 @@ internal class DefaultDocumentWriter : DocumentWriter
documentNode,
_options);
context.Visitor = new Visitor(_codeTarget, context);
context.SetVisitor(new Visitor(_codeTarget, context));
context.Visitor.VisitDocument(documentNode);
var csharp = context.CodeWriter.GenerateCode();
var generatedCode = context.CodeWriter.GenerateCode();
return new RazorCSharpDocument(
codeDocument,
csharp,
generatedCode,
_options,
context.GetDiagnostics(),
context.GetSourceMappings(),
context.GetLinePragmas());
}
private class Visitor : IntermediateNodeVisitor
private sealed class Visitor(CodeTarget codeTarget, CodeRenderingContext context) : IntermediateNodeVisitor
{
private readonly CodeRenderingContext _context;
private readonly CodeTarget _target;
private readonly CodeRenderingContext _context = context;
private readonly CodeTarget _codeTarget = codeTarget;
public Visitor(CodeTarget target, CodeRenderingContext context)
{
_target = target;
_context = context;
}
private CodeRenderingContext Context => _context;
private CodeWriter CodeWriter => _context.CodeWriter;
private IntermediateNodeWriter NodeWriter => _context.NodeWriter;
private RazorCodeGenerationOptions Options => _context.Options;
public override void VisitDocument(DocumentIntermediateNode node)
{
if (!Context.Options.SuppressChecksum)
var codeWriter = CodeWriter;
if (!Options.SuppressChecksum)
{
// See http://msdn.microsoft.com/en-us/library/system.codedom.codechecksumpragma.checksumalgorithmid.aspx
// And https://github.com/dotnet/roslyn/blob/614299ff83da9959fa07131c6d0ffbc58873b6ae/src/Compilers/Core/Portable/PEWriter/DebugSourceDocument.cs#L67
@ -70,7 +60,7 @@ internal class DefaultDocumentWriter : DocumentWriter
// We only support algorithms that the debugger understands, which is currently SHA1 and SHA256.
string algorithmId;
var algorithm = Context.SourceDocument.Text.ChecksumAlgorithm;
var algorithm = _context.SourceDocument.Text.ChecksumAlgorithm;
if (algorithm == CodeAnalysis.Text.SourceHashAlgorithm.Sha256)
{
algorithmId = "{8829d00f-11b8-4213-878b-770e8597ac16}";
@ -81,80 +71,75 @@ internal class DefaultDocumentWriter : DocumentWriter
}
else
{
var supportedAlgorithms = string.Join(" ", new string[]
{
HashAlgorithmName.SHA1.Name,
HashAlgorithmName.SHA256.Name
});
string?[] supportedAlgorithms = [HashAlgorithmName.SHA1.Name, HashAlgorithmName.SHA256.Name];
var message = Resources.FormatUnsupportedChecksumAlgorithm(
algorithm,
supportedAlgorithms,
nameof(RazorCodeGenerationOptions) + "." + nameof(RazorCodeGenerationOptions.SuppressChecksum),
string.Join(" ", supportedAlgorithms),
$"{nameof(RazorCodeGenerationOptions)}.{nameof(RazorCodeGenerationOptions.SuppressChecksum)}",
bool.TrueString);
throw new InvalidOperationException(message);
}
var sourceDocument = Context.SourceDocument;
var sourceDocument = _context.SourceDocument;
var checksum = ChecksumUtilities.BytesToString(sourceDocument.Text.GetChecksum());
if (!string.IsNullOrEmpty(checksum))
var filePath = sourceDocument.FilePath.AssumeNotNull();
if (checksum.Length > 0)
{
Context.CodeWriter
.Write("#pragma checksum \"")
.Write(sourceDocument.FilePath)
.Write("\" \"")
.Write(algorithmId)
.Write("\" \"")
.Write(checksum)
.WriteLine("\"");
codeWriter.WriteLine($"#pragma checksum \"{filePath}\" \"{algorithmId}\" \"{checksum}\"");
}
}
Context.CodeWriter
codeWriter
.WriteLine("// <auto-generated/>")
.WriteLine("#pragma warning disable 1591");
VisitDefault(node);
Context.CodeWriter.WriteLine("#pragma warning restore 1591");
codeWriter.WriteLine("#pragma warning restore 1591");
}
public override void VisitUsingDirective(UsingDirectiveIntermediateNode node)
{
Context.NodeWriter.WriteUsingDirective(Context, node);
NodeWriter.WriteUsingDirective(_context, node);
}
public override void VisitNamespaceDeclaration(NamespaceDeclarationIntermediateNode node)
{
using (Context.CodeWriter.BuildNamespace(node.Content, node.Source, Context))
var codeWriter = CodeWriter;
using (codeWriter.BuildNamespace(node.Content, node.Source, _context))
{
if (node.Children.OfType<UsingDirectiveIntermediateNode>().Any())
{
// Tooling needs at least one line directive before using directives, otherwise Roslyn will
// not offer to create a new one. The last using in the group will output a hidden line
// directive after itself.
Context.CodeWriter.WriteLine("#line default");
codeWriter.WriteLine("#line default");
}
else
{
// If there are no using directives, we output the hidden directive here.
Context.CodeWriter.WriteLine("#line hidden");
codeWriter.WriteLine("#line hidden");
}
VisitDefault(node);
}
}
public override void VisitClassDeclaration(ClassDeclarationIntermediateNode node)
{
using (Context.CodeWriter.BuildClassDeclaration(
using (CodeWriter.BuildClassDeclaration(
node.Modifiers,
node.ClassName,
node.BaseType,
node.Interfaces,
node.TypeParameters,
Context,
useNullableContext: !Context.Options.SuppressNullabilityEnforcement && node.Annotations[CommonAnnotations.NullableContext] is not null))
_context,
useNullableContext: !Options.SuppressNullabilityEnforcement && node.Annotations[CommonAnnotations.NullableContext] is not null))
{
VisitDefault(node);
}
@ -162,100 +147,99 @@ internal class DefaultDocumentWriter : DocumentWriter
public override void VisitMethodDeclaration(MethodDeclarationIntermediateNode node)
{
Context.CodeWriter.WriteLine("#pragma warning disable 1998");
var codeWriter = CodeWriter;
codeWriter.WriteLine("#pragma warning disable 1998");
for (var i = 0; i < node.Modifiers.Count; i++)
{
Context.CodeWriter.Write(node.Modifiers[i]);
Context.CodeWriter.Write(" ");
codeWriter.Write($"{node.Modifiers[i]} ");
}
Context.CodeWriter.Write(node.ReturnType);
Context.CodeWriter.Write(" ");
codeWriter.Write($"{node.ReturnType} ");
codeWriter.Write($"{node.MethodName}(");
Context.CodeWriter.Write(node.MethodName);
Context.CodeWriter.Write("(");
var isFirst = true;
for (var i = 0; i < node.Parameters.Count; i++)
{
var parameter = node.Parameters[i];
if (isFirst)
{
isFirst = false;
}
else
{
codeWriter.Write(", ");
}
for (var j = 0; j < parameter.Modifiers.Count; j++)
{
Context.CodeWriter.Write(parameter.Modifiers[j]);
Context.CodeWriter.Write(" ");
codeWriter.Write($"{parameter.Modifiers[j]} ");
}
Context.CodeWriter.Write(parameter.TypeName);
Context.CodeWriter.Write(" ");
Context.CodeWriter.Write(parameter.ParameterName);
if (i < node.Parameters.Count - 1)
{
Context.CodeWriter.Write(", ");
}
codeWriter.Write($"{parameter.TypeName} {parameter.ParameterName}");
}
Context.CodeWriter.Write(")");
Context.CodeWriter.WriteLine();
codeWriter.WriteLine(")");
using (Context.CodeWriter.BuildScope())
using (codeWriter.BuildScope())
{
VisitDefault(node);
}
Context.CodeWriter.WriteLine("#pragma warning restore 1998");
codeWriter.WriteLine("#pragma warning restore 1998");
}
public override void VisitFieldDeclaration(FieldDeclarationIntermediateNode node)
{
Context.CodeWriter.WriteField(node.SuppressWarnings, node.Modifiers, node.FieldType, node.FieldName);
CodeWriter.WriteField(node.SuppressWarnings, node.Modifiers, node.FieldType, node.FieldName);
}
public override void VisitPropertyDeclaration(PropertyDeclarationIntermediateNode node)
{
Context.CodeWriter.WriteAutoPropertyDeclaration(node.Modifiers, node.PropertyType, node.PropertyName);
CodeWriter.WriteAutoPropertyDeclaration(node.Modifiers, node.PropertyType, node.PropertyName);
}
public override void VisitExtension(ExtensionIntermediateNode node)
{
node.WriteNode(_target, Context);
node.WriteNode(_codeTarget, _context);
}
public override void VisitCSharpExpression(CSharpExpressionIntermediateNode node)
{
Context.NodeWriter.WriteCSharpExpression(Context, node);
NodeWriter.WriteCSharpExpression(_context, node);
}
public override void VisitCSharpCode(CSharpCodeIntermediateNode node)
{
Context.NodeWriter.WriteCSharpCode(Context, node);
NodeWriter.WriteCSharpCode(_context, node);
}
public override void VisitHtmlAttribute(HtmlAttributeIntermediateNode node)
{
Context.NodeWriter.WriteHtmlAttribute(Context, node);
NodeWriter.WriteHtmlAttribute(_context, node);
}
public override void VisitHtmlAttributeValue(HtmlAttributeValueIntermediateNode node)
{
Context.NodeWriter.WriteHtmlAttributeValue(Context, node);
NodeWriter.WriteHtmlAttributeValue(_context, node);
}
public override void VisitCSharpExpressionAttributeValue(CSharpExpressionAttributeValueIntermediateNode node)
{
Context.NodeWriter.WriteCSharpExpressionAttributeValue(Context, node);
NodeWriter.WriteCSharpExpressionAttributeValue(_context, node);
}
public override void VisitCSharpCodeAttributeValue(CSharpCodeAttributeValueIntermediateNode node)
{
Context.NodeWriter.WriteCSharpCodeAttributeValue(Context, node);
NodeWriter.WriteCSharpCodeAttributeValue(_context, node);
}
public override void VisitHtml(HtmlContentIntermediateNode node)
{
Context.NodeWriter.WriteHtmlContent(Context, node);
NodeWriter.WriteHtmlContent(_context, node);
}
public override void VisitTagHelper(TagHelperIntermediateNode node)
@ -265,67 +249,67 @@ internal class DefaultDocumentWriter : DocumentWriter
public override void VisitComponent(ComponentIntermediateNode node)
{
Context.NodeWriter.WriteComponent(Context, node);
NodeWriter.WriteComponent(_context, node);
}
public override void VisitComponentAttribute(ComponentAttributeIntermediateNode node)
{
Context.NodeWriter.WriteComponentAttribute(Context, node);
NodeWriter.WriteComponentAttribute(_context, node);
}
public override void VisitComponentChildContent(ComponentChildContentIntermediateNode node)
{
Context.NodeWriter.WriteComponentChildContent(Context, node);
NodeWriter.WriteComponentChildContent(_context, node);
}
public override void VisitComponentTypeArgument(ComponentTypeArgumentIntermediateNode node)
{
Context.NodeWriter.WriteComponentTypeArgument(Context, node);
NodeWriter.WriteComponentTypeArgument(_context, node);
}
public override void VisitComponentTypeInferenceMethod(ComponentTypeInferenceMethodIntermediateNode node)
{
Context.NodeWriter.WriteComponentTypeInferenceMethod(Context, node);
NodeWriter.WriteComponentTypeInferenceMethod(_context, node);
}
public override void VisitMarkupElement(MarkupElementIntermediateNode node)
{
Context.NodeWriter.WriteMarkupElement(Context, node);
NodeWriter.WriteMarkupElement(_context, node);
}
public override void VisitMarkupBlock(MarkupBlockIntermediateNode node)
{
Context.NodeWriter.WriteMarkupBlock(Context, node);
NodeWriter.WriteMarkupBlock(_context, node);
}
public override void VisitReferenceCapture(ReferenceCaptureIntermediateNode node)
{
Context.NodeWriter.WriteReferenceCapture(Context, node);
NodeWriter.WriteReferenceCapture(_context, node);
}
public override void VisitSetKey(SetKeyIntermediateNode node)
{
Context.NodeWriter.WriteSetKey(Context, node);
NodeWriter.WriteSetKey(_context, node);
}
public override void VisitSplat(SplatIntermediateNode node)
{
Context.NodeWriter.WriteSplat(Context, node);
NodeWriter.WriteSplat(_context, node);
}
public override void VisitRenderMode(RenderModeIntermediateNode node)
{
Context.NodeWriter.WriteRenderMode(Context, node);
NodeWriter.WriteRenderMode(_context, node);
}
public override void VisitFormName(FormNameIntermediateNode node)
{
Context.NodeWriter.WriteFormName(Context, node);
NodeWriter.WriteFormName(_context, node);
}
public override void VisitDefault(IntermediateNode node)
{
Context.RenderChildren(node);
_context.RenderChildren(node);
}
}
}

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

@ -22,7 +22,7 @@ public static class TestCodeRenderingContext
var options = ConfigureOptions(RazorCodeGenerationOptions.DesignTimeDefault, newLineString, suppressUniqueIds);
var context = new CodeRenderingContext(nodeWriter, source, documentNode, options);
context.Visitor = new RenderChildrenVisitor(context);
context.SetVisitor(new RenderChildrenVisitor(context.CodeWriter));
return context;
}
@ -40,7 +40,7 @@ public static class TestCodeRenderingContext
var options = ConfigureOptions(RazorCodeGenerationOptions.Default, newLineString, suppressUniqueIds);
var context = new CodeRenderingContext(nodeWriter, source, documentNode, options);
context.Visitor = new RenderChildrenVisitor(context);
context.SetVisitor(new RenderChildrenVisitor(context.CodeWriter));
return context;
}
@ -67,17 +67,11 @@ public static class TestCodeRenderingContext
return builder.Build();
}
private class RenderChildrenVisitor : IntermediateNodeVisitor
private class RenderChildrenVisitor(CodeWriter writer) : IntermediateNodeVisitor
{
private readonly CodeRenderingContext _context;
public RenderChildrenVisitor(CodeRenderingContext context)
{
_context = context;
}
public override void VisitDefault(IntermediateNode node)
{
_context.CodeWriter.WriteLine("Render Children");
writer.WriteLine("Render Children");
}
}
}