| File: StackTraceExplorer\AbstractStackTraceSymbolResolver.cs | Web Access |
| Project: src\roslyn\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. using System.Collections.Generic; using System.Collections.Immutable; using System.Linq; using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.EmbeddedLanguages.StackFrame; namespace Microsoft.CodeAnalysis.StackTraceExplorer; internal abstract class AbstractStackTraceSymbolResolver { public abstract Task<IMethodSymbol?> TryGetBestMatchAsync( Project project, INamedTypeSymbol type, StackFrameSimpleNameNode methodNode, StackFrameParameterList methodArguments, StackFrameTypeArgumentList? methodTypeArguments, CancellationToken cancellationToken); protected static bool MatchTypeArguments(ImmutableArray<ITypeSymbol> typeArguments, StackFrameTypeArgumentList? stackFrameTypeArgumentList) { if (stackFrameTypeArgumentList is null) { return typeArguments.IsEmpty; } if (typeArguments.IsEmpty) { return false; } var stackFrameTypeArguments = stackFrameTypeArgumentList.TypeArguments; return typeArguments.Length == stackFrameTypeArguments.Length; } protected static bool MatchType(ITypeSymbol type, StackFrameTypeNode stackFrameType) { if (type is IArrayTypeSymbol arrayType) { if (stackFrameType is not StackFrameArrayTypeNode arrayTypeNode) { return false; } ITypeSymbol currentType = arrayType; // Iterate through each array expression and make sure the dimensions // match the element types in an array. // Ex: string[,][] // [,] is a 2 dimension array with element type string[] // [] is a 1 dimension array with element type string foreach (var arrayExpression in arrayTypeNode.ArrayRankSpecifiers) { if (currentType is not IArrayTypeSymbol currentArrayType) { return false; } if (currentArrayType.Rank != arrayExpression.CommaTokens.Length + 1) { return false; } currentType = currentArrayType.ElementType; } // All array types have been exchausted from the // stackframe identifier and the type is still an array if (currentType is IArrayTypeSymbol) { return false; } return MatchType(currentType, arrayTypeNode.TypeIdentifier); } return type.Name == stackFrameType.ToString(); } protected static bool MatchParameters(ImmutableArray<IParameterSymbol> parameters, StackFrameParameterList stackFrameParameters) { if (parameters.Length != stackFrameParameters.Parameters.Length) { return false; } for (var i = 0; i < stackFrameParameters.Parameters.Length; i++) { var stackFrameParameter = stackFrameParameters.Parameters[i]; var paramSymbol = parameters[i]; if (paramSymbol.Name != stackFrameParameter.Identifier.ToString()) { return false; } if (!MatchType(paramSymbol.Type, stackFrameParameter.Type)) { return false; } } return true; } protected static IMethodSymbol? TryGetBestMatch( IEnumerable<IMethodSymbol> candidateFunctions, StackFrameTypeArgumentList? methodTypeArguments, StackFrameParameterList methodArguments) => candidateFunctions .Where(m => MatchTypeArguments(m.TypeArguments, methodTypeArguments)) .FirstOrDefault(m => MatchParameters(m.Parameters, methodArguments)); }