Пример #1
0
        public static bool CanBeReplacedWithAnyName(this NameSyntax nameSyntax)
        {
            if (nameSyntax.IsParentKind(SyntaxKind.AliasQualifiedName) ||
                nameSyntax.IsParentKind(SyntaxKind.NameColon) ||
                nameSyntax.IsParentKind(SyntaxKind.NameEquals) ||
                nameSyntax.IsParentKind(SyntaxKind.TypeParameterConstraintClause))
            {
                return false;
            }

            if (nameSyntax.CheckParent<QualifiedNameSyntax>(q => q.Right == nameSyntax) ||
                nameSyntax.CheckParent<MemberAccessExpressionSyntax>(m => m.Name == nameSyntax))
            {
                return false;
            }

            // TODO(cyrusn): Add more cases as the language changes.
            return true;
        }
        public static bool CanReplaceWithLValue(
            this ExpressionSyntax expression, SemanticModel semanticModel, CancellationToken cancellationToken)
        {
            if (expression.IsKind(SyntaxKind.StackAllocArrayCreationExpression))
            {
                // Stack alloc is very interesting.  While it appears to be an expression, it is only
                // such so it can appear in a variable decl.  It is not a normal expression that can
                // go anywhere.
                return false;
            }

            if (expression.IsKind(SyntaxKind.BaseExpression) ||
                expression.IsKind(SyntaxKind.CollectionInitializerExpression) ||
                expression.IsKind(SyntaxKind.ObjectInitializerExpression) ||
                expression.IsKind(SyntaxKind.ComplexElementInitializerExpression))
            {
                return false;
            }

            // literal can be always replaced.
            if (expression is LiteralExpressionSyntax && !expression.IsParentKind(SyntaxKind.UnaryMinusExpression))
            {
                return true;
            }

            if (!(expression is ObjectCreationExpressionSyntax) && !(expression is AnonymousObjectCreationExpressionSyntax))
            {
                var symbolInfo = semanticModel.GetSymbolInfo(expression, cancellationToken);
                if (!symbolInfo.GetBestOrAllSymbols().All(CanReplace))
                {
                    // If the expression is actually a reference to a type, then it can't be replaced
                    // with an arbitrary expression.
                    return false;
                }
            }

            // If we are a conditional access expression:
            // case (1) : obj?.Method(), obj1.obj2?.Property
            // case (2) : obj?.GetAnotherObj()?.Length, obj?.AnotherObj?.Length
            // in case (1), the entire expression forms the conditional access expression, which can be replaced with an LValue.
            // in case (2), the nested conditional access expression is ".GetAnotherObj()?.Length" or ".AnotherObj()?.Length"
            // essentially, the first expression (before the operator) in a nested conditional access expression 
            // is some form of member binding expression and they cannot be replaced with an LValue.
            if (expression.IsKind(SyntaxKind.ConditionalAccessExpression))
            {
                return expression.Parent.Kind() != SyntaxKind.ConditionalAccessExpression;
            }

            switch (expression.Parent.Kind())
            {
                case SyntaxKind.InvocationExpression:
                    // Technically, you could introduce an LValue for "Foo" in "Foo()" even if "Foo" binds
                    // to a method.  (i.e. by assigning to a Func<...> type).  However, this is so contrived
                    // and none of the features that use this extension consider this replaceable.
                    if (expression.IsKind(SyntaxKind.IdentifierName) || expression is MemberAccessExpressionSyntax)
                    {
                        // If it looks like a method then we don't allow it to be replaced if it is a
                        // method (or if it doesn't bind).

                        var symbolInfo = semanticModel.GetSymbolInfo(expression, cancellationToken);
                        return symbolInfo.GetBestOrAllSymbols().Any() && !symbolInfo.GetBestOrAllSymbols().Any(s => s is IMethodSymbol);
                    }
                    else
                    {
                        // It doesn't look like a method, we allow this to be replaced.
                        return true;
                    }

                // If the parent is a conditional access expression, we could introduce an LValue
                // for the given expression, unless it is itself a MemberBindingExpression or starts with one.
                // Case (1) : The WhenNotNull clause always starts with a memberbindingexpression.
                //              expression '.Method()' in a?.Method()
                // Case (2) : The Expression clause always starts with a memberbindingexpression if 
                // the grandparent is a conditional access expression.
                //              expression '.Method' in a?.Method()?.Length
                // Case (3) : The child Conditional access expression always starts with a memberbindingexpression if
                // the parent is a conditional access expression. This case is already covered before the parent kind switch
                case SyntaxKind.ConditionalAccessExpression:
                    var parentConditionalAccessExpression = (ConditionalAccessExpressionSyntax)expression.Parent;
                    return expression != parentConditionalAccessExpression.WhenNotNull &&
                            !parentConditionalAccessExpression.Parent.IsKind(SyntaxKind.ConditionalAccessExpression);

                case SyntaxKind.IsExpression:
                case SyntaxKind.AsExpression:
                    // Can't introduce a variable for the type portion of an is/as check.
                    var isOrAsExpression = (BinaryExpressionSyntax)expression.Parent;
                    return expression == isOrAsExpression.Left;
                case SyntaxKind.EqualsValueClause:
                case SyntaxKind.ExpressionStatement:
                case SyntaxKind.ArrayInitializerExpression:
                case SyntaxKind.CollectionInitializerExpression:
                case SyntaxKind.Argument:
                case SyntaxKind.AttributeArgument:
                case SyntaxKind.AnonymousObjectMemberDeclarator:
                case SyntaxKind.ArrowExpressionClause:
                case SyntaxKind.AwaitExpression:
                case SyntaxKind.ReturnStatement:
                case SyntaxKind.YieldReturnStatement:
                case SyntaxKind.ParenthesizedLambdaExpression:
                case SyntaxKind.SimpleLambdaExpression:
                case SyntaxKind.ParenthesizedExpression:
                case SyntaxKind.ArrayRankSpecifier:
                case SyntaxKind.ConditionalExpression:
                case SyntaxKind.IfStatement:
                case SyntaxKind.CatchFilterClause:
                case SyntaxKind.WhileStatement:
                case SyntaxKind.DoStatement:
                case SyntaxKind.ThrowStatement:
                case SyntaxKind.SwitchStatement:
                case SyntaxKind.InterpolatedStringExpression:
                case SyntaxKind.ComplexElementInitializerExpression:
                case SyntaxKind.Interpolation:
                    // Direct parent kind checks.
                    return true;
            }

            if (expression.Parent is PrefixUnaryExpressionSyntax)
            {
                if (!(expression is LiteralExpressionSyntax && expression.IsParentKind(SyntaxKind.UnaryMinusExpression)))
                {
                    return true;
                }
            }

            var parentNonExpression = expression.GetAncestors().SkipWhile(n => n is ExpressionSyntax).FirstOrDefault();
            var topExpression = expression;
            while (topExpression.Parent is TypeSyntax)
            {
                topExpression = (TypeSyntax)topExpression.Parent;
            }

            if (parentNonExpression != null &&
                parentNonExpression.IsKind(SyntaxKind.FromClause) &&
                topExpression != null &&
                ((FromClauseSyntax)parentNonExpression).Type == topExpression)
            {
                return false;
            }

            // Parent type checks.
            if (expression.Parent is PostfixUnaryExpressionSyntax ||
                expression.Parent is BinaryExpressionSyntax ||
                expression.Parent is AssignmentExpressionSyntax ||
                expression.Parent is QueryClauseSyntax ||
                expression.Parent is SelectOrGroupClauseSyntax ||
                expression.Parent is CheckedExpressionSyntax)
            {
                return true;
            }

            // Specific child checks.
            if (expression.CheckParent<ForEachStatementSyntax>(f => f.Expression == expression) ||
                expression.CheckParent<MemberAccessExpressionSyntax>(m => m.Expression == expression) ||
                expression.CheckParent<CastExpressionSyntax>(c => c.Expression == expression))
            {
                return true;
            }

            // Misc checks.
            if ((expression.IsParentKind(SyntaxKind.NameEquals) && expression.Parent.IsParentKind(SyntaxKind.AttributeArgument)) ||
                expression.IsLeftSideOfAnyAssignExpression())
            {
                return true;
            }

            return false;
        }
Пример #3
0
        public static bool CanReplaceWithLValue(
            this ExpressionSyntax expression, SemanticModel semanticModel, CancellationToken cancellationToken)
        {
            if (expression.IsKind(SyntaxKind.StackAllocArrayCreationExpression))
            {
                // Stack alloc is very interesting.  While it appears to be an expression, it is only
                // such so it can appear in a variable decl.  It is not a normal expression that can
                // go anywhere.
                return false;
            }

            if (expression.IsKind(SyntaxKind.BaseExpression) ||
                expression.IsKind(SyntaxKind.CollectionInitializerExpression) ||
                expression.IsKind(SyntaxKind.ObjectInitializerExpression) ||
                expression.IsKind(SyntaxKind.ComplexElementInitializerExpression))
            {
                return false;
            }

            // literal can be always replaced.
            if (expression is LiteralExpressionSyntax && !expression.IsParentKind(SyntaxKind.UnaryMinusExpression))
            {
                return true;
            }

            if (!(expression is ObjectCreationExpressionSyntax) && !(expression is AnonymousObjectCreationExpressionSyntax))
            {
                var symbolInfo = semanticModel.GetSymbolInfo(expression, cancellationToken);
                if (!symbolInfo.GetBestOrAllSymbols().All(CanReplace))
                {
                    // If the expression is actually a reference to a type, then it can't be replaced
                    // with an arbitrary expression.
                    return false;
                }
            }

            // Technically, you could introduce an LValue for "Foo" in "Foo()" even if "Foo" binds
            // to a method.  (i.e. by assigning to a Func<...> type).  However, this is so contrived
            // and none of the features that use this extension consider this replaceable.
            if (expression.Parent is InvocationExpressionSyntax)
            {
                if (expression.IsKind(SyntaxKind.IdentifierName) || expression is MemberAccessExpressionSyntax)
                {
                    // If it looks like a method then we don't allow it to be replaced if it is a
                    // method (or if it doesn't bind).

                    var symbolInfo = semanticModel.GetSymbolInfo(expression, cancellationToken);
                    return symbolInfo.GetBestOrAllSymbols().Any() && !symbolInfo.GetBestOrAllSymbols().Any(s => s is IMethodSymbol);
                }
                else
                {
                    // It doesn't look like a method, we allow this to be replaced.
                    return true;
                }
            }

            // Direct parent kind checks.
            if (expression.IsParentKind(SyntaxKind.ExpressionStatement) ||
                expression.IsParentKind(SyntaxKind.EqualsValueClause) ||
                expression.IsParentKind(SyntaxKind.ArrayInitializerExpression) ||
                expression.IsParentKind(SyntaxKind.CollectionInitializerExpression) ||
                expression.IsParentKind(SyntaxKind.Argument) ||
                expression.IsParentKind(SyntaxKind.AttributeArgument) ||
                expression.IsParentKind(SyntaxKind.AnonymousObjectMemberDeclarator) ||
                expression.IsParentKind(SyntaxKind.ReturnStatement) ||
                expression.IsParentKind(SyntaxKind.YieldReturnStatement) ||
                expression.IsParentKind(SyntaxKind.ParenthesizedLambdaExpression) ||
                expression.IsParentKind(SyntaxKind.SimpleLambdaExpression) ||
                expression.IsParentKind(SyntaxKind.ParenthesizedExpression) ||
                expression.IsParentKind(SyntaxKind.ArrayRankSpecifier) ||
                expression.IsParentKind(SyntaxKind.ConditionalExpression) ||
                expression.IsParentKind(SyntaxKind.IfStatement) ||
                expression.IsParentKind(SyntaxKind.WhileStatement) ||
                expression.IsParentKind(SyntaxKind.DoStatement) ||
                expression.IsParentKind(SyntaxKind.ThrowStatement) ||
                expression.IsParentKind(SyntaxKind.SwitchStatement))
            {
                return true;
            }

            if (expression.IsParentKind(SyntaxKind.IsExpression) ||
                expression.IsParentKind(SyntaxKind.AsExpression))
            {
                // Can't introduce a variable for the type portion of an is/as check.
                var isOrAsExpression = (BinaryExpressionSyntax)expression.Parent;
                return expression == isOrAsExpression.Left;
            }

            if (expression.Parent is PrefixUnaryExpressionSyntax)
            {
                if (!(expression is LiteralExpressionSyntax && expression.IsParentKind(SyntaxKind.UnaryMinusExpression)))
                {
                    return true;
                }
            }

            var parentNonExpression = expression.GetAncestors().SkipWhile(n => n is ExpressionSyntax).FirstOrDefault();
            var topExpression = expression;
            while (topExpression.Parent is TypeSyntax)
            {
                topExpression = (TypeSyntax)topExpression.Parent;
            }

            if (parentNonExpression != null &&
                parentNonExpression.IsKind(SyntaxKind.FromClause) &&
                topExpression != null &&
                ((FromClauseSyntax)parentNonExpression).Type == topExpression)
            {
                return false;
            }

            // Parent type checks.
            if (expression.Parent is PostfixUnaryExpressionSyntax ||
                expression.Parent is BinaryExpressionSyntax ||
                expression.Parent is QueryClauseSyntax ||
                expression.Parent is SelectOrGroupClauseSyntax ||
                expression.Parent is CheckedExpressionSyntax)
            {
                return true;
            }

            // Specific child checks.
            if (expression.CheckParent<ForEachStatementSyntax>(f => f.Expression == expression) ||
                expression.CheckParent<MemberAccessExpressionSyntax>(m => m.Expression == expression) ||
                expression.CheckParent<CastExpressionSyntax>(c => c.Expression == expression))
            {
                return true;
            }

            // Misc checks.
            if ((expression.IsParentKind(SyntaxKind.NameEquals) && expression.Parent.IsParentKind(SyntaxKind.AttributeArgument)) ||
                expression.IsLeftSideOfAnyAssignExpression())
            {
                return true;
            }

            return false;
        }
		//		public bool IsInvocationExpression(SyntaxNode node)
		//		{
		//			return node is InvocationExpressionSyntax;
		//		}
		//
		//		public bool IsAnonymousFunction(SyntaxNode node)
		//		{
		//			return node is ParenthesizedLambdaExpressionSyntax ||
		//				node is SimpleLambdaExpressionSyntax ||
		//				node is AnonymousMethodExpressionSyntax;
		//		}
		//
		//		public bool IsGenericName(SyntaxNode node)
		//		{
		//			return node is GenericNameSyntax;
		//		}

		public static bool IsNamedParameter (this SyntaxNode node)
		{
			return node.CheckParent<NameColonSyntax> (p => p.Name == node);
		}