| File: Mvc.Version2_X\InstrumentationPass.cs | Web Access |
| Project: src\roslyn\src\Razor\src\Compiler\Microsoft.CodeAnalysis.Razor.Compiler\src\Microsoft.CodeAnalysis.Razor.Compiler.csproj (Microsoft.CodeAnalysis.Razor.Compiler) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System.Collections.Generic; using System.Globalization; using System.Threading; using Microsoft.AspNetCore.Razor.Language; using Microsoft.AspNetCore.Razor.Language.Extensions; using Microsoft.AspNetCore.Razor.Language.Intermediate; namespace Microsoft.AspNetCore.Mvc.Razor.Extensions.Version2_X; public sealed class InstrumentationPass : IntermediateNodePassBase, IRazorOptimizationPass { public override int Order => DefaultFeatureOrder; protected override void ExecuteCore( RazorCodeDocument codeDocument, DocumentIntermediateNode documentNode, CancellationToken cancellationToken) { var walker = new Visitor(); walker.VisitDocument(documentNode); for (var i = 0; i < walker.Items.Count; i++) { var node = walker.Items[i]; AddInstrumentation(node); } } private static void AddInstrumentation(InstrumentationItem item) { var beginContextMethodName = "BeginContext"; // ORIGINAL: BeginContextMethodName var endContextMethodName = "EndContext"; // ORIGINAL: EndContextMethodName var beginNode = new CSharpCodeIntermediateNode(); var absoluteIndex = item.Source.AbsoluteIndex.ToString(CultureInfo.InvariantCulture); var length = item.Source.Length.ToString(CultureInfo.InvariantCulture); var isLiteral = item.IsLiteral ? "true" : "false"; beginNode.Children.Add( IntermediateNodeFactory.CSharpToken($"{beginContextMethodName}({absoluteIndex}, {length}, {isLiteral});")); var endNode = new CSharpCodeIntermediateNode(); endNode.Children.Add(IntermediateNodeFactory.CSharpToken($"{endContextMethodName}();")); var nodeIndex = item.Parent.Children.IndexOf(item.Node); item.Parent.Children.Insert(nodeIndex, beginNode); item.Parent.Children.Insert(nodeIndex + 2, endNode); } private struct InstrumentationItem { public InstrumentationItem(IntermediateNode node, IntermediateNode parent, bool isLiteral, SourceSpan source) { Node = node; Parent = parent; IsLiteral = isLiteral; Source = source; } public IntermediateNode Node { get; } public IntermediateNode Parent { get; } public bool IsLiteral { get; } public SourceSpan Source { get; } } private class Visitor : IntermediateNodeWalker { public List<InstrumentationItem> Items { get; } = new List<InstrumentationItem>(); public override void VisitHtml(HtmlContentIntermediateNode node) { if (node.Source != null) { Items.Add(new InstrumentationItem(node, Parent!, isLiteral: true, source: node.Source.Value)); } VisitDefault(node); } public override void VisitCSharpExpression(CSharpExpressionIntermediateNode node) { if (node.Source != null) { Items.Add(new InstrumentationItem(node, Parent!, isLiteral: false, source: node.Source.Value)); } VisitDefault(node); } public override void VisitTagHelper(TagHelperIntermediateNode node) { if (node.Source != null) { Items.Add(new InstrumentationItem(node, Parent!, isLiteral: false, source: node.Source.Value)); } // Inside a tag helper we only want to visit inside of the body (skip all of the attributes and properties). for (var i = 0; i < node.Children.Count; i++) { var child = node.Children[i]; if (child is TagHelperBodyIntermediateNode || child is DefaultTagHelperBodyIntermediateNode) { VisitDefault(child); } } } } }