/// <summary> /// Collect all the available cast pairs, format is (target argument expression, potential conversion type) /// </summary> /// <param name="targetArgument"> The argument that need to be cast</param> /// <param name="argumentList"> The argument list that contains the target argument to be cast </param> /// <param name="invocationNode"> The invocation node that is the parent of "argumentList"</param> /// <returns> /// Return all the available cast pairs, format is (target argument expression, potential conversion type) /// </returns> public ImmutableArray <(TExpressionSyntax, ITypeSymbol)> GetPotentialConversionTypes( SemanticModel semanticModel, SyntaxNode root, TArgumentSyntax targetArgument, TArgumentListSyntax argumentList, TInvocationSyntax invocationNode, CancellationToken cancellationToken ) { // Implicit downcast appears on the argument of invocation node, // get all candidate functions and extract potential conversion types var symbolInfo = semanticModel.GetSymbolInfo(invocationNode, cancellationToken); using var _ = ArrayBuilder <ISymbol> .GetInstance(out var candidateSymbols); if (symbolInfo.Symbol != null) // BC42016: the only candidate symbol is symbolInfo.Symbol { candidateSymbols.Add(symbolInfo.Symbol); } else { candidateSymbols.AddRange(symbolInfo.CandidateSymbols); } using var __ = ArrayBuilder <(TExpressionSyntax, ITypeSymbol)> .GetInstance( out var mutablePotentialConversionTypes ); foreach (var candidateSymbol in candidateSymbols.OfType <IMethodSymbol>()) { if ( CanArgumentTypesBeConvertedToParameterTypes( semanticModel, root, argumentList, candidateSymbol.Parameters, targetArgument, cancellationToken, out var targetArgumentConversionType ) && GetExpressionOfArgument(targetArgument) is TExpressionSyntax argumentExpression ) { mutablePotentialConversionTypes.Add( (argumentExpression, targetArgumentConversionType) ); } } // Sort the potential conversion types by inheritance distance, so that // operations are in order and user can choose least specific types(more accurate) mutablePotentialConversionTypes.Sort( new InheritanceDistanceComparer <TExpressionSyntax>(semanticModel) ); return(mutablePotentialConversionTypes.ToImmutable()); }
public bool CanArgumentTypesBeConvertedToParameterTypes( SemanticModel semanticModel, SyntaxNode root, TArgumentListSyntax argumentList, ImmutableArray <IParameterSymbol> parameters, TArgumentSyntax targetArgument, CancellationToken cancellationToken, [NotNullWhen(true)] out ITypeSymbol?targetArgumentConversionType) { targetArgumentConversionType = null; // No conversion happens under this case if (parameters.Length == 0) { return(false); } var syntaxFacts = _provider.SyntaxFacts; var arguments = GetArgumentsOfArgumentList(argumentList); using var _ = ArrayBuilder <TArgumentSyntax> .GetInstance(out var newArguments); for (var i = 0; i < arguments.Count; i++) { // Parameter index cannot out of its range, #arguments is larger than #parameter only if // the last parameter with keyword params var parameterIndex = Math.Min(i, parameters.Length - 1); // If the argument has a name, get the corresponding parameter index if (syntaxFacts.GetNameForArgument(arguments[i]) is string name && name != string.Empty && !FindCorrespondingParameterByName(name, parameters, ref parameterIndex)) { return(false); } // The argument is either in order with parameters, or have a matched name with parameters. var argumentExpression = GetExpressionOfArgument(arguments[i]); if (argumentExpression == null) { // argumentExpression is null when it is an omitted argument in VB .NET newArguments.Add(arguments[i]); continue; } var parameterType = parameters[parameterIndex].Type; if (parameters[parameterIndex].IsParams && parameterType is IArrayTypeSymbol paramsType && _provider.ClassifyConversion(semanticModel, argumentExpression, paramsType.ElementType).Exists) { newArguments.Add(GenerateNewArgument(arguments[i], paramsType.ElementType)); if (arguments[i].Equals(targetArgument)) { targetArgumentConversionType = paramsType.ElementType; } }
protected abstract SymbolInfo GetSpeculativeSymbolInfo( SemanticModel semanticModel, TArgumentListSyntax newArgumentList );
protected abstract SeparatedSyntaxList <TArgumentSyntax> GetArgumentsOfArgumentList( TArgumentListSyntax argumentList );
protected abstract TArgumentListSyntax GenerateNewArgumentList( TArgumentListSyntax oldArgumentList, ArrayBuilder <TArgumentSyntax> newArguments );