예제 #1
0
    private async Task <CSharpSyntaxNode> ConvertToFunctionDeclarationOrNullAsync(VBSyntax.LambdaExpressionSyntax vbNode,
                                                                                  ParameterListSyntax param, BlockSyntax block,
                                                                                  ArrowExpressionClauseSyntax arrow)
    {
        if (!(_semanticModel.GetOperation(vbNode) is IAnonymousFunctionOperation anonFuncOp) || anonFuncOp.GetParentIgnoringConversions() is IDelegateCreationOperation dco && !dco.IsImplicit)
        {
            return(null);
        }

        var potentialAncestorDeclarationOperation = anonFuncOp.GetParentIgnoringConversions().GetParentIgnoringConversions();
        // Could do: See if we can improve upon returning "object" for pretty much everything (which is what the symbols say)
        // I believe that in general, special VB functions such as MultiplyObject are designed to work the same as integer when given two integers for example.
        // If all callers currently pass an integer, perhaps it'd be more idiomatic in C# to specify "int", than to have Operators
        var paramsWithTypes = anonFuncOp.Symbol.Parameters.Select(p => CommonConversions.CsSyntaxGenerator.ParameterDeclaration(p));

        var paramListWithTypes = param.WithParameters(SyntaxFactory.SeparatedList(paramsWithTypes));

        if (potentialAncestorDeclarationOperation is IFieldInitializerOperation fieldInit)
        {
            var fieldSymbol = fieldInit.InitializedFields.Single();
            if (fieldSymbol.GetResultantVisibility() != SymbolVisibility.Public && !fieldSymbol.Type.IsDelegateReferencableByName() && await _solution.IsNeverWrittenAsync(fieldSymbol))
            {
                return(CreateMethodDeclaration(anonFuncOp, fieldSymbol, block, arrow));
            }
        }

        if (potentialAncestorDeclarationOperation is IVariableInitializerOperation vio)
        {
            if (vio.GetParentIgnoringConversions().GetParentIgnoringConversions() is IVariableDeclarationGroupOperation go)
            {
                potentialAncestorDeclarationOperation = go.Declarations.First(d => d.Syntax.FullSpan.Contains(vbNode.FullSpan));
            }
            else
            {
                potentialAncestorDeclarationOperation = vio.Parent;
            }

            if (potentialAncestorDeclarationOperation is IVariableDeclarationOperation variableDeclaration)
            {
                var variableDeclaratorOperation = variableDeclaration.Declarators.Single();
                if (!variableDeclaratorOperation.Symbol.Type.IsDelegateReferencableByName() &&
                    await _solution.IsNeverWrittenAsync(variableDeclaratorOperation.Symbol))
                {
                    //Should do: Check no (other) write usages exist: SymbolFinder.FindReferencesAsync + checking if they're an assignment LHS or out parameter
                    return(CreateLocalFunction(anonFuncOp, variableDeclaratorOperation, paramListWithTypes, block,
                                               arrow));
                }
            }
        }

        return(null);
    }
예제 #2
0
    public async Task <CSharpSyntaxNode> ConvertAsync(VBSyntax.LambdaExpressionSyntax vbNode,
                                                      ParameterListSyntax param, IReadOnlyCollection <StatementSyntax> convertedStatements)
    {
        BlockSyntax                 block          = null;
        ExpressionSyntax            expressionBody = null;
        ArrowExpressionClauseSyntax arrow          = null;

        if (!convertedStatements.TryUnpackSingleStatement(out StatementSyntax singleStatement))
        {
            convertedStatements = convertedStatements.Select(l => l.WithTrailingTrivia(SyntaxFactory.ElasticCarriageReturnLineFeed)).ToList();
            block = SyntaxFactory.Block(convertedStatements);
        }
        else if (singleStatement.TryUnpackSingleExpressionFromStatement(out expressionBody))
        {
            arrow = SyntaxFactory.ArrowExpressionClause(expressionBody);
        }
        else
        {
            block = SyntaxFactory.Block(singleStatement);
        }

        var functionStatement = await ConvertToFunctionDeclarationOrNullAsync(vbNode, param, block, arrow);

        if (functionStatement != null)
        {
            return(functionStatement);
        }

        var body        = (CSharpSyntaxNode)block ?? expressionBody;
        var isAnonAsync = _semanticModel.GetOperation(vbNode) is IAnonymousFunctionOperation a && a.Symbol.IsAsync;

        var asyncKeyword = SyntaxFactory.Token(SyntaxKind.AsyncKeyword);
        LambdaExpressionSyntax lambda;

        if (param.Parameters.Count == 1 && param.Parameters.Single().Type == null)
        {
            var l = SyntaxFactory.SimpleLambdaExpression(param.Parameters[0], body);
            lambda = isAnonAsync ? l.WithAsyncKeyword(asyncKeyword) : l;
        }
        else
        {
            var l = SyntaxFactory.ParenthesizedLambdaExpression(param, body);
            lambda = isAnonAsync ? l.WithAsyncKeyword(asyncKeyword) : l;
        }

        return(lambda);
    }