| File: Operations\OperationMapBuilder.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.Collections.Generic; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using Microsoft.CodeAnalysis.Operations; using Roslyn.Utilities; namespace Microsoft.CodeAnalysis { internal static class OperationMapBuilder { /// <summary> /// Populates a empty dictionary of SyntaxNode->IOperation, where every key corresponds to an explicit IOperation node. /// If there is a SyntaxNode with more than one explicit IOperation, this will throw. /// </summary> internal static void AddToMap(IOperation root, Dictionary<SyntaxNode, IOperation> dictionary) { Debug.Assert(dictionary.Count == 0); Walker.Instance.Visit(root, dictionary); } private sealed class Walker : OperationWalker<Dictionary<SyntaxNode, IOperation>> { internal static readonly Walker Instance = new Walker(); public override object? DefaultVisit(IOperation operation, Dictionary<SyntaxNode, IOperation> argument) { RecordOperation(operation, argument); return base.DefaultVisit(operation, argument); } public override object? VisitBinaryOperator([DisallowNull] IBinaryOperation? operation, Dictionary<SyntaxNode, IOperation> argument) { // In order to handle very large nested operators, we implement manual iteration here. Our operations are not order sensitive, // so we don't need to maintain a stack, just iterate through every level. while (true) { RecordOperation(operation, argument); Visit(operation.RightOperand, argument); if (operation.LeftOperand is IBinaryOperation nested) { operation = nested; } else { Visit(operation.LeftOperand, argument); break; } } return null; } public override object? VisitConditional(IConditionalOperation operation, Dictionary<SyntaxNode, IOperation> argument) { while (true) { RecordOperation(operation, argument); Visit(operation.Condition, argument); Visit(operation.WhenTrue, argument); if (operation.WhenFalse is IConditionalOperation nested) { operation = nested; } else { Visit(operation.WhenFalse, argument); break; } } return null; } public override object? VisitBinaryPattern(IBinaryPatternOperation operation, Dictionary<SyntaxNode, IOperation> argument) { // In order to handle very large nested patterns, we implement manual iteration here. Our operations are not order sensitive, // so we don't need to maintain a stack, just iterate through every level. while (true) { RecordOperation(operation, argument); Visit(operation.RightPattern, argument); if (operation.LeftPattern is IBinaryPatternOperation nested) { operation = nested; } else { Visit(operation.LeftPattern, argument); break; } } return null; } internal override object? VisitNoneOperation(IOperation operation, Dictionary<SyntaxNode, IOperation> argument) { // OperationWalker skips these nodes by default, to avoid having public consumers deal with NoneOperation. // we need to deal with it here, however, so delegate to DefaultVisit. return DefaultVisit(operation, argument); } private static void RecordOperation(IOperation operation, Dictionary<SyntaxNode, IOperation> argument) { if (!operation.IsImplicit) { // IOperation invariant is that all there is at most 1 non-implicit node per syntax node. RoslynDebug.Assert( !argument.ContainsKey(operation.Syntax), $"Duplicate operation node for {operation.Syntax}. Existing node is {(argument.TryGetValue(operation.Syntax, out var original) ? (OperationKind?)original.Kind : null)}, new node is {operation.Kind}."); argument.Add(operation.Syntax, operation); } } } } }