| File: Language\DefaultDirectiveSyntaxTreePass.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; using System.Collections.Immutable; using System.Diagnostics.CodeAnalysis; using System.Threading; using Microsoft.AspNetCore.Razor.Language.Extensions; using Microsoft.AspNetCore.Razor.Language.Syntax; namespace Microsoft.AspNetCore.Razor.Language; internal class DefaultDirectiveSyntaxTreePass : RazorEngineFeatureBase, IRazorSyntaxTreePass { public int Order => 75; public RazorSyntaxTree Execute( RazorCodeDocument codeDocument, RazorSyntaxTree syntaxTree, CancellationToken cancellationToken = default) { if (codeDocument.FileKind.IsComponent()) { // Nothing to do here. return syntaxTree; } var sectionVerifier = new NestedSectionVerifier(syntaxTree, cancellationToken); return sectionVerifier.Verify(); } private sealed class NestedSectionVerifier(RazorSyntaxTree syntaxTree, CancellationToken cancellationToken) : SyntaxRewriter { private readonly RazorSyntaxTree _syntaxTree = syntaxTree; private readonly CancellationToken _cancellationToken = cancellationToken; private ImmutableArray<RazorDiagnostic>.Builder? _diagnostics; private int _nestedLevel; public RazorSyntaxTree Verify() { var root = Visit(_syntaxTree.Root); var diagnostics = _diagnostics?.ToImmutableAndClear() ?? _syntaxTree.Diagnostics; return new RazorSyntaxTree(root, _syntaxTree.Source, diagnostics, _syntaxTree.Options); } [return: NotNullIfNotNull(nameof(node))] public override SyntaxNode? Visit(SyntaxNode? node) { _cancellationToken.ThrowIfCancellationRequested(); try { return base.Visit(node); } catch (InsufficientExecutionStackException) { // We're very close to reaching the stack limit. Let's not go any deeper. // It's okay to not show nested section errors in deeply nested cases instead of crashing. _diagnostics ??= _syntaxTree.Diagnostics.ToBuilder(); _diagnostics.Add(RazorDiagnosticFactory.CreateRewriter_InsufficientStack()); return node; } } public override SyntaxNode VisitRazorDirective(RazorDirectiveSyntax node) { _cancellationToken.ThrowIfCancellationRequested(); if (!node.IsDirective(SectionDirective.Directive)) { // We only want to track the nesting of section directives. return base.VisitRazorDirective(node); } _nestedLevel++; var result = (RazorDirectiveSyntax)base.VisitRazorDirective(node); if (_nestedLevel > 1) { var directiveStart = node.Transition.GetSourceLocation(_syntaxTree.Source); var errorLength = /* @ */ 1 + SectionDirective.Directive.Directive.Length; var error = RazorDiagnosticFactory.CreateParsing_SectionsCannotBeNested(new SourceSpan(directiveStart, errorLength)); result = result.AppendDiagnostic(error); } _nestedLevel--; return result; } } }