|
// 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;
using Microsoft.AspNetCore.Analyzers.Infrastructure;
namespace Microsoft.AspNetCore.Analyzers.Infrastructure.EmbeddedSyntax;
internal readonly struct EmbeddedSeparatedSyntaxNodeList<TSyntaxKind, TSyntaxNode, TDerivedNode>
where TSyntaxKind : struct
where TSyntaxNode : EmbeddedSyntaxNode<TSyntaxKind, TSyntaxNode>
where TDerivedNode : TSyntaxNode
{
public ImmutableArray<EmbeddedSyntaxNodeOrToken<TSyntaxKind, TSyntaxNode>> NodesAndTokens { get; }
public int Length { get; }
public int SeparatorLength { get; }
public static readonly EmbeddedSeparatedSyntaxNodeList<TSyntaxKind, TSyntaxNode, TDerivedNode> Empty
= new(ImmutableArray<EmbeddedSyntaxNodeOrToken<TSyntaxKind, TSyntaxNode>>.Empty);
public EmbeddedSeparatedSyntaxNodeList(
ImmutableArray<EmbeddedSyntaxNodeOrToken<TSyntaxKind, TSyntaxNode>> nodesAndTokens)
{
Debug.Assert(!nodesAndTokens.IsDefault);
NodesAndTokens = nodesAndTokens;
var allLength = NodesAndTokens.Length;
Length = (allLength + 1) / 2;
SeparatorLength = allLength / 2;
Verify();
}
[Conditional("DEBUG")]
private void Verify()
{
for (var i = 0; i < NodesAndTokens.Length; i++)
{
if ((i & 1) == 0)
{
// All even values should be TNode
Debug.Assert(NodesAndTokens[i].IsNode);
Debug.Assert(NodesAndTokens[i].Node is EmbeddedSyntaxNode<TSyntaxKind, TSyntaxNode>);
}
else
{
// All odd values should be separator tokens
Debug.Assert(!NodesAndTokens[i].IsNode);
}
}
}
/// <summary>
/// Retrieves only nodes, skipping the separator tokens
/// </summary>
public TDerivedNode this[int index]
{
get
{
if (index < Length && index >= 0)
{
// x2 here to get only even indexed numbers. Follows same logic
// as SeparatedSyntaxList in that the separator tokens are not returned
var nodeOrToken = NodesAndTokens[index * 2];
AnalyzerDebug.Assert(nodeOrToken.IsNode);
AnalyzerDebug.Assert(nodeOrToken.Node != null);
return (TDerivedNode)nodeOrToken.Node;
}
throw new ArgumentOutOfRangeException(nameof(index));
}
}
public Enumerator GetEnumerator() => new(this);
public struct Enumerator
{
private readonly EmbeddedSeparatedSyntaxNodeList<TSyntaxKind, TSyntaxNode, TDerivedNode> _list;
private int _currentIndex;
public Enumerator(EmbeddedSeparatedSyntaxNodeList<TSyntaxKind, TSyntaxNode, TDerivedNode> list)
{
_list = list;
_currentIndex = -1;
Current = null!;
}
public TDerivedNode Current { get; private set; }
public bool MoveNext()
{
_currentIndex++;
if (_currentIndex >= _list.Length)
{
Current = null!;
return false;
}
Current = _list[_currentIndex];
return true;
}
}
}
|