Exemple #1
0
        private static SyntaxNode Unwrap(ISyntaxFactsService syntaxFacts, SyntaxNode node)
        {
            var invocation = node as TInvocationExpression;

            if (invocation != null)
            {
                return(syntaxFacts.GetExpressionOfInvocationExpression(invocation));
            }

            var memberAccess = node as TMemberAccessExpression;

            if (memberAccess != null)
            {
                return(syntaxFacts.GetExpressionOfMemberAccessExpression(memberAccess));
            }

            var conditionalAccess = node as TConditionalAccessExpression;

            if (conditionalAccess != null)
            {
                return(syntaxFacts.GetExpressionOfConditionalAccessExpression(conditionalAccess));
            }

            var elementAccess = node as TElementAccessExpression;

            if (elementAccess != null)
            {
                return(syntaxFacts.GetExpressionOfElementAccessExpression(elementAccess));
            }

            return(null);
        }
Exemple #2
0
        protected override bool IsViableExtensionMethod(IMethodSymbol method, SyntaxNode expression, SemanticModel semanticModel, ISyntaxFactsService syntaxFacts, CancellationToken cancellationToken)
        {
            var leftExpression = syntaxFacts.GetExpressionOfMemberAccessExpression(expression) ?? syntaxFacts.GetExpressionOfConditionalMemberAccessExpression(expression);

            if (leftExpression == null)
            {
                return(false);
            }

            var semanticInfo       = semanticModel.GetTypeInfo(leftExpression, cancellationToken);
            var leftExpressionType = semanticInfo.Type;

            return(leftExpressionType != null && method.ReduceExtensionMethod(leftExpressionType) != null);
        }
Exemple #3
0
        protected override bool IsViableExtensionMethod(IMethodSymbol method, SyntaxNode expression, SemanticModel semanticModel, ISyntaxFactsService syntaxFacts, CancellationToken cancellationToken)
        {
            var leftExpression = syntaxFacts.GetExpressionOfMemberAccessExpression(expression);

            if (leftExpression == null)
            {
                if (expression.IsKind(SyntaxKind.CollectionInitializerExpression))
                {
                    leftExpression = expression.GetAncestor <ObjectCreationExpressionSyntax>();
                }
                else
                {
                    return(false);
                }
            }

            var semanticInfo       = semanticModel.GetTypeInfo(leftExpression, cancellationToken);
            var leftExpressionType = semanticInfo.Type;

            return(IsViableExtensionMethod(method, leftExpressionType));
        }
        private static SyntaxNode Unwrap(ISyntaxFactsService syntaxFacts, SyntaxNode node)
        {
            if (node is TInvocationExpression invocation)
            {
                return(syntaxFacts.GetExpressionOfInvocationExpression(invocation));
            }

            if (node is TMemberAccessExpression memberAccess)
            {
                return(syntaxFacts.GetExpressionOfMemberAccessExpression(memberAccess));
            }

            if (node is TConditionalAccessExpression conditionalAccess)
            {
                return(syntaxFacts.GetExpressionOfConditionalAccessExpression(conditionalAccess));
            }

            if (node is TElementAccessExpression elementAccess)
            {
                return(syntaxFacts.GetExpressionOfElementAccessExpression(elementAccess));
            }

            return(null);
        }
        internal List <Match <TAssignmentStatementSyntax, TMemberAccessExpressionSyntax, TExpressionSyntax> > Analyze()
        {
            if (_syntaxFacts.GetObjectCreationInitializer(_objectCreationExpression) != null)
            {
                // Don't bother if this already has an initializer.
                return(null);
            }

            _containingStatement = _objectCreationExpression.FirstAncestorOrSelf <TStatementSyntax>();
            if (_containingStatement == null)
            {
                return(null);
            }

            if (!TryInitializeVariableDeclarationCase() &&
                !TryInitializeAssignmentCase())
            {
                return(null);
            }

            var containingBlock = _containingStatement.Parent;
            var foundStatement  = false;

            List <Match <TAssignmentStatementSyntax, TMemberAccessExpressionSyntax, TExpressionSyntax> > matches = null;
            HashSet <string> seenNames = null;

            foreach (var child in containingBlock.ChildNodesAndTokens())
            {
                if (!foundStatement)
                {
                    if (child == _containingStatement)
                    {
                        foundStatement = true;
                    }

                    continue;
                }

                if (child.IsToken)
                {
                    break;
                }

                var statement = child.AsNode() as TAssignmentStatementSyntax;
                if (statement == null)
                {
                    break;
                }

                if (!_syntaxFacts.IsSimpleAssignmentStatement(statement))
                {
                    break;
                }

                SyntaxNode left, right;
                _syntaxFacts.GetPartsOfAssignmentStatement(statement, out left, out right);

                var rightExpression  = right as TExpressionSyntax;
                var leftMemberAccess = left as TMemberAccessExpressionSyntax;
                if (!_syntaxFacts.IsSimpleMemberAccessExpression(leftMemberAccess))
                {
                    break;
                }

                var expression = (TExpressionSyntax)_syntaxFacts.GetExpressionOfMemberAccessExpression(leftMemberAccess);
                if (!ValuePatternMatches(expression))
                {
                    break;
                }

                // found a match!
                seenNames = seenNames ?? new HashSet <string>();
                matches   = matches ?? new List <Match <TAssignmentStatementSyntax, TMemberAccessExpressionSyntax, TExpressionSyntax> >();

                // If we see an assignment to the same property/field, we can't convert it
                // to an initializer.
                var name       = _syntaxFacts.GetNameOfMemberAccessExpression(leftMemberAccess);
                var identifier = _syntaxFacts.GetIdentifierOfSimpleName(name);
                if (!seenNames.Add(identifier.ValueText))
                {
                    break;
                }

                matches.Add(new Match <TAssignmentStatementSyntax, TMemberAccessExpressionSyntax, TExpressionSyntax>(
                                statement, leftMemberAccess, rightExpression));
            }

            return(matches);
        }
Exemple #6
0
        internal ImmutableArray <Match <TExpressionSyntax, TStatementSyntax, TMemberAccessExpressionSyntax, TAssignmentStatementSyntax> >?Analyze()
        {
            if (_syntaxFacts.GetObjectCreationInitializer(_objectCreationExpression) != null)
            {
                // Don't bother if this already has an initializer.
                return(null);
            }

            _containingStatement = _objectCreationExpression.FirstAncestorOrSelf <TStatementSyntax>();
            if (_containingStatement == null)
            {
                return(null);
            }

            if (!TryInitializeVariableDeclarationCase() &&
                !TryInitializeAssignmentCase())
            {
                return(null);
            }

            var containingBlock = _containingStatement.Parent;
            var foundStatement  = false;

            var matches = ArrayBuilder <Match <TExpressionSyntax, TStatementSyntax, TMemberAccessExpressionSyntax, TAssignmentStatementSyntax> > .GetInstance();

            HashSet <string> seenNames = null;

            foreach (var child in containingBlock.ChildNodesAndTokens())
            {
                if (!foundStatement)
                {
                    if (child == _containingStatement)
                    {
                        foundStatement = true;
                        continue;
                    }

                    continue;
                }

                if (child.IsToken)
                {
                    break;
                }

                var statement = child.AsNode() as TAssignmentStatementSyntax;
                if (statement == null)
                {
                    break;
                }

                if (!_syntaxFacts.IsSimpleAssignmentStatement(statement))
                {
                    break;
                }

                _syntaxFacts.GetPartsOfAssignmentStatement(
                    statement, out var left, out var right);

                var rightExpression  = right as TExpressionSyntax;
                var leftMemberAccess = left as TMemberAccessExpressionSyntax;

                if (!_syntaxFacts.IsSimpleMemberAccessExpression(leftMemberAccess))
                {
                    break;
                }

                var expression = (TExpressionSyntax)_syntaxFacts.GetExpressionOfMemberAccessExpression(leftMemberAccess);
                if (!ValuePatternMatches(expression))
                {
                    break;
                }

                // Don't offer this fix if the value we're initializing is itself referenced
                // on the RHS of the assignment.  For example:
                //
                //      var v = new X();
                //      v.Prop = v.Prop.WithSomething();
                //
                // Or with
                //
                //      v = new X();
                //      v.Prop = v.Prop.WithSomething();
                //
                // In the first case, 'v' is being initialized, and so will not be available
                // in the object initializer we create.
                //
                // In the second case we'd change semantics because we'd access the old value
                // before the new value got written.
                if (ExpressionContainsValuePattern(rightExpression))
                {
                    break;
                }

                // If we have code like "x.v = .Length.ToString()"
                // then we don't want to change this into:
                //
                //      var x = new Whatever() With { .v = .Length.ToString() }
                //
                // The problem here is that .Length will change it's meaning to now refer to the
                // object that we're creating in our object-creation expression.
                if (ImplicitMemberAccessWouldBeAffected(rightExpression))
                {
                    break;
                }

                // found a match!
                seenNames = seenNames ?? new HashSet <string>();

                // If we see an assignment to the same property/field, we can't convert it
                // to an initializer.
                var name       = _syntaxFacts.GetNameOfMemberAccessExpression(leftMemberAccess);
                var identifier = _syntaxFacts.GetIdentifierOfSimpleName(name);
                if (!seenNames.Add(identifier.ValueText))
                {
                    break;
                }

                matches.Add(new Match <TExpressionSyntax, TStatementSyntax, TMemberAccessExpressionSyntax, TAssignmentStatementSyntax>(
                                statement, leftMemberAccess, rightExpression));
            }

            return(matches.ToImmutableAndFree());
        }
        private static void RemoveAwaitFromCallerIfPresent(
            SyntaxEditor editor, ISyntaxFactsService syntaxFacts,
            SyntaxNode root, ReferenceLocation referenceLocation,
            CancellationToken cancellationToken)
        {
            if (referenceLocation.IsImplicit)
            {
                return;
            }

            var location = referenceLocation.Location;
            var token    = location.FindToken(cancellationToken);

            var nameNode = token.Parent;

            if (nameNode == null)
            {
                return;
            }

            // Look for the following forms:
            //  await M(...)
            //  await <expr>.M(...)
            //  await M(...).ConfigureAwait(...)
            //  await <expr>.M(...).ConfigureAwait(...)

            var expressionNode = nameNode;

            if (syntaxFacts.IsNameOfMemberAccessExpression(nameNode))
            {
                expressionNode = nameNode.Parent;
            }

            if (!syntaxFacts.IsExpressionOfInvocationExpression(expressionNode))
            {
                return;
            }

            // We now either have M(...) or <expr>.M(...)

            var invocationExpression = expressionNode.Parent;

            Debug.Assert(syntaxFacts.IsInvocationExpression(invocationExpression));

            if (syntaxFacts.IsExpressionOfAwaitExpression(invocationExpression))
            {
                // Handle the case where we're directly awaited.
                var awaitExpression = invocationExpression.Parent;
                editor.ReplaceNode(awaitExpression, (currentAwaitExpression, generator) =>
                                   syntaxFacts.GetExpressionOfAwaitExpression(currentAwaitExpression)
                                   .WithTriviaFrom(currentAwaitExpression));
            }
            else if (syntaxFacts.IsExpressionOfMemberAccessExpression(invocationExpression))
            {
                // Check for the .ConfigureAwait case.
                var parentMemberAccessExpression         = invocationExpression.Parent;
                var parentMemberAccessExpressionNameNode = syntaxFacts.GetNameOfMemberAccessExpression(
                    parentMemberAccessExpression);

                var parentMemberAccessExpressionName = syntaxFacts.GetIdentifierOfSimpleName(parentMemberAccessExpressionNameNode).ValueText;
                if (parentMemberAccessExpressionName == nameof(Task.ConfigureAwait))
                {
                    var parentExpression = parentMemberAccessExpression.Parent;
                    if (syntaxFacts.IsExpressionOfAwaitExpression(parentExpression))
                    {
                        var awaitExpression = parentExpression.Parent;
                        editor.ReplaceNode(awaitExpression, (currentAwaitExpression, generator) =>
                        {
                            var currentConfigureAwaitInvocation = syntaxFacts.GetExpressionOfAwaitExpression(currentAwaitExpression);
                            var currentMemberAccess             = syntaxFacts.GetExpressionOfInvocationExpression(currentConfigureAwaitInvocation);
                            var currentInvocationExpression     = syntaxFacts.GetExpressionOfMemberAccessExpression(currentMemberAccess);
                            return(currentInvocationExpression.WithTriviaFrom(currentAwaitExpression));
                        });
                    }
                }
            }
        }
        protected override bool IsViableExtensionMethod(IMethodSymbol method, SyntaxNode expression, SemanticModel semanticModel, ISyntaxFactsService syntaxFacts, CancellationToken cancellationToken)
        {
            var leftExpression = syntaxFacts.GetExpressionOfMemberAccessExpression(expression) ?? syntaxFacts.GetExpressionOfConditionalMemberAccessExpression(expression);
            if (leftExpression == null)
            {
                if (expression.IsKind(SyntaxKind.CollectionInitializerExpression))
                {
                    leftExpression = expression.GetAncestor<ObjectCreationExpressionSyntax>();
                }
                else
                {
                    return false;
                }
            }

            var semanticInfo = semanticModel.GetTypeInfo(leftExpression, cancellationToken);
            var leftExpressionType = semanticInfo.Type;

            return leftExpressionType != null && method.ReduceExtensionMethod(leftExpressionType) != null;
        }
        private void RemoveAwaitFromCallerIfPresent(
            SyntaxEditor editor, ISyntaxFactsService syntaxFacts, 
            SyntaxNode root, ReferenceLocation referenceLocation,
            CancellationToken cancellationToken)
        {
            if (referenceLocation.IsImplicit)
            {
                return;
            }

            var location = referenceLocation.Location;
            var token = location.FindToken(cancellationToken);

            var nameNode = token.Parent;
            if (nameNode == null)
            {
                return;
            }

            // Look for the following forms:
            //  await M(...)
            //  await <expr>.M(...)
            //  await M(...).ConfigureAwait(...)
            //  await <expr>.M(...).ConfigureAwait(...)

            var expressionNode = nameNode;
            if (syntaxFacts.IsNameOfMemberAccessExpression(nameNode))
            {
                expressionNode = nameNode.Parent;
            }

            if (!syntaxFacts.IsExpressionOfInvocationExpression(expressionNode))
            {
                return;
            }

            // We now either have M(...) or <expr>.M(...)

            var invocationExpression = expressionNode.Parent;
            Debug.Assert(syntaxFacts.IsInvocationExpression(invocationExpression));

            if (syntaxFacts.IsExpressionOfAwaitExpression(invocationExpression))
            {
                // Handle the case where we're directly awaited.  
                var awaitExpression = invocationExpression.Parent;
                editor.ReplaceNode(awaitExpression, (currentAwaitExpression, generator) =>
                    syntaxFacts.GetExpressionOfAwaitExpression(currentAwaitExpression)
                               .WithTriviaFrom(currentAwaitExpression));
            }
            else if (syntaxFacts.IsExpressionOfMemberAccessExpression(invocationExpression))
            {
                // Check for the .ConfigureAwait case.
                var parentMemberAccessExpression = invocationExpression.Parent;
                var parentMemberAccessExpressionNameNode = syntaxFacts.GetNameOfMemberAccessExpression(
                    parentMemberAccessExpression);

                var parentMemberAccessExpressionName = syntaxFacts.GetIdentifierOfSimpleName(parentMemberAccessExpressionNameNode).ValueText;
                if (parentMemberAccessExpressionName == nameof(Task.ConfigureAwait))
                {
                    var parentExpression = parentMemberAccessExpression.Parent;
                    if (syntaxFacts.IsExpressionOfAwaitExpression(parentExpression))
                    {
                        var awaitExpression = parentExpression.Parent;
                        editor.ReplaceNode(awaitExpression, (currentAwaitExpression, generator) =>
                        {
                            var currentConfigureAwaitInvocation = syntaxFacts.GetExpressionOfAwaitExpression(currentAwaitExpression);
                            var currentMemberAccess = syntaxFacts.GetExpressionOfInvocationExpression(currentConfigureAwaitInvocation);
                            var currentInvocationExpression = syntaxFacts.GetExpressionOfMemberAccessExpression(currentMemberAccess);
                            return currentInvocationExpression.WithTriviaFrom(currentAwaitExpression);
                        });
                    }
                }
            }
        }
        protected override bool IsViableExtensionMethod(IMethodSymbol method, SyntaxNode expression, SemanticModel semanticModel, ISyntaxFactsService syntaxFacts, CancellationToken cancellationToken)
        {
            var leftExpression = syntaxFacts.GetExpressionOfMemberAccessExpression(expression) ?? syntaxFacts.GetExpressionOfConditionalMemberAccessExpression(expression);
            if (leftExpression == null)
            {
                return false;
            }

            var semanticInfo = semanticModel.GetTypeInfo(leftExpression, cancellationToken);
            var leftExpressionType = semanticInfo.Type;

            return leftExpressionType != null && method.ReduceExtensionMethod(leftExpressionType) != null;
        }