| File: Syntax\InternalSyntax\SyntaxDiagnosticInfoList.cs | Web Access |
| Project: src\roslyn\src\Compilers\Core\Portable\Microsoft.CodeAnalysis.csproj (Microsoft.CodeAnalysis) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. using System; using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Syntax.InternalSyntax { // Avoid implementing IEnumerable so we do not get any unintentional boxing. internal readonly struct SyntaxDiagnosticInfoList { private readonly GreenNode _node; internal SyntaxDiagnosticInfoList(GreenNode node) { _node = node; } public Enumerator GetEnumerator() { return new Enumerator(_node); } internal bool Any(Func<DiagnosticInfo, bool> predicate) { var enumerator = GetEnumerator(); while (enumerator.MoveNext()) { if (predicate(enumerator.Current)) return true; } return false; } public struct Enumerator { private struct NodeIteration { internal readonly GreenNode Node; internal int DiagnosticIndex; internal int SlotIndex; internal NodeIteration(GreenNode node) { this.Node = node; this.SlotIndex = -1; this.DiagnosticIndex = -1; } } private NodeIteration[]? _stack; private int _count; public DiagnosticInfo Current { get; private set; } internal Enumerator(GreenNode node) { Current = null!; _stack = null; _count = 0; if (node != null && node.ContainsDiagnostics) { _stack = new NodeIteration[8]; this.PushNodeOrToken(node); } } public bool MoveNext() { while (_count > 0) { var diagIndex = _stack![_count - 1].DiagnosticIndex; var node = _stack[_count - 1].Node; var diags = node.GetDiagnostics(); if (diagIndex < diags.Length - 1) { diagIndex++; Current = diags[diagIndex]; _stack[_count - 1].DiagnosticIndex = diagIndex; return true; } var slotIndex = _stack[_count - 1].SlotIndex; tryAgain: if (slotIndex < node.SlotCount - 1) { slotIndex++; var child = node.GetSlot(slotIndex); if (child == null || !child.ContainsDiagnostics) { goto tryAgain; } _stack[_count - 1].SlotIndex = slotIndex; this.PushNodeOrToken(child); } else { this.Pop(); } } return false; } private void PushNodeOrToken(GreenNode node) { if (node.IsToken) { this.PushToken(node); } else { this.Push(node); } } private void PushToken(GreenNode token) { var trailing = token.GetTrailingTriviaCore(); if (trailing != null) { this.Push(trailing); } this.Push(token); var leading = token.GetLeadingTriviaCore(); if (leading != null) { this.Push(leading); } } private void Push(GreenNode node) { RoslynDebug.Assert(_stack is object); if (_count >= _stack.Length) { var tmp = new NodeIteration[_stack.Length * 2]; Array.Copy(_stack, tmp, _stack.Length); _stack = tmp; } _stack[_count] = new NodeIteration(node); _count++; } private void Pop() { _count--; } } } }