File: ExtractMethod\MethodExtractor.Analyzer.SymbolMapBuilder.cs
Web Access
Project: src\src\Features\Core\Portable\Microsoft.CodeAnalysis.Features.csproj (Microsoft.CodeAnalysis.Features)
// 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.
 
#nullable disable
 
using System.Collections.Generic;
using System.Threading;
using Microsoft.CodeAnalysis.LanguageService;
using Microsoft.CodeAnalysis.Shared.Extensions;
using Microsoft.CodeAnalysis.Text;
using Roslyn.Utilities;
 
namespace Microsoft.CodeAnalysis.ExtractMethod;
 
internal abstract partial class MethodExtractor<TSelectionResult, TStatementSyntax, TExpressionSyntax>
{
    protected abstract partial class Analyzer
    {
        private sealed class SymbolMapBuilder
        {
            private readonly SemanticModel _semanticModel;
            private readonly ISyntaxFactsService _service;
            private readonly TextSpan _span;
            private readonly Dictionary<ISymbol, List<SyntaxToken>> _symbolMap = [];
            private readonly CancellationToken _cancellationToken;
 
            public static Dictionary<ISymbol, List<SyntaxToken>> Build(
                ISyntaxFactsService service,
                SemanticModel semanticModel,
                SyntaxNode root,
                TextSpan span,
                CancellationToken cancellationToken)
            {
                Contract.ThrowIfNull(semanticModel);
                Contract.ThrowIfNull(service);
                Contract.ThrowIfNull(root);
 
                var builder = new SymbolMapBuilder(service, semanticModel, span, cancellationToken);
                builder.Visit(root);
 
                return builder._symbolMap;
            }
 
            private SymbolMapBuilder(
                ISyntaxFactsService service,
                SemanticModel semanticModel,
                TextSpan span,
                CancellationToken cancellationToken)
            {
                _semanticModel = semanticModel;
                _service = service;
                _span = span;
                _cancellationToken = cancellationToken;
            }
 
            private void Visit(SyntaxNode node)
            {
                foreach (var token in node.DescendantTokens())
                {
                    if (token.IsMissing ||
                        token.Width() <= 0 ||
                        !_service.IsIdentifier(token) ||
                        !_span.Contains(token.Span) ||
                        _service.IsNameOfNamedArgument(token.Parent))
                    {
                        continue;
                    }
 
                    var symbolInfo = _semanticModel.GetSymbolInfo(token, _cancellationToken);
                    foreach (var sym in symbolInfo.GetAllSymbols())
                    {
                        // add binding result to map
                        var list = _symbolMap.GetOrAdd(sym, _ => []);
                        list.Add(token);
                    }
                }
            }
        }
    }
}