public static async Task ComputeRefactoringsAsync(RefactoringContext context, InitializerExpressionSyntax initializer)
        {
            if (initializer.IsKind(SyntaxKind.ComplexElementInitializerExpression) &&
                initializer.IsParentKind(SyntaxKind.CollectionInitializerExpression))
            {
                initializer = (InitializerExpressionSyntax)initializer.Parent;
            }

            if (context.Span.IsEmptyAndContainedInSpanOrBetweenSpans(initializer) ||
                context.Span.IsEmptyAndContainedInSpanOrBetweenSpans(initializer.Expressions))
            {
                SeparatedSyntaxList <ExpressionSyntax> expressions = initializer.Expressions;

                if (context.IsRefactoringEnabled(RefactoringIdentifiers.FormatInitializer) &&
                    expressions.Any() &&
                    !initializer.IsKind(SyntaxKind.ComplexElementInitializerExpression) &&
                    initializer.IsParentKind(
                        SyntaxKind.ArrayCreationExpression,
                        SyntaxKind.ImplicitArrayCreationExpression,
                        SyntaxKind.ObjectCreationExpression,
                        SyntaxKind.CollectionInitializerExpression))
                {
                    if (initializer.IsSingleLine(includeExteriorTrivia: false))
                    {
                        context.RegisterRefactoring(
                            "Format initializer on multiple lines",
                            cancellationToken => SyntaxFormatter.ToMultiLineAsync(
                                context.Document,
                                initializer,
                                cancellationToken),
                            RefactoringIdentifiers.FormatInitializer);
                    }
                    else if (expressions.All(expression => expression.IsSingleLine()) &&
                             initializer.DescendantTrivia(initializer.Span).All(f => f.IsWhitespaceOrEndOfLineTrivia()))
                    {
                        context.RegisterRefactoring(
                            "Format initializer on a single line",
                            cancellationToken => SyntaxFormatter.ToSingleLineAsync(
                                context.Document,
                                initializer,
                                cancellationToken),
                            RefactoringIdentifiers.FormatInitializer);
                    }
                }

                if (context.IsRefactoringEnabled(RefactoringIdentifiers.ExpandInitializer))
                {
                    await ExpandInitializerRefactoring.ComputeRefactoringsAsync(context, initializer).ConfigureAwait(false);
                }

                if (context.IsRefactoringEnabled(RefactoringIdentifiers.UseCSharp6DictionaryInitializer) &&
                    context.SupportsCSharp6)
                {
                    await UseCSharp6DictionaryInitializerRefactoring.ComputeRefactoringAsync(context, initializer).ConfigureAwait(false);
                }
            }
        }
Beispiel #2
0
        public static async Task ComputeRefactoringsAsync(RefactoringContext context, InitializerExpressionSyntax initializer)
        {
            if (initializer.IsKind(SyntaxKind.ComplexElementInitializerExpression) &&
                initializer.IsParentKind(SyntaxKind.CollectionInitializerExpression))
            {
                initializer = (InitializerExpressionSyntax)initializer.Parent;
            }

            if (context.Span.IsEmptyAndContainedInSpanOrBetweenSpans(initializer) ||
                context.Span.IsEmptyAndContainedInSpanOrBetweenSpans(initializer.Expressions))
            {
                SeparatedSyntaxList <ExpressionSyntax> expressions = initializer.Expressions;

                if (context.IsRefactoringEnabled(RefactoringDescriptors.WrapInitializerExpressions) &&
                    expressions.Any() &&
                    !initializer.IsKind(SyntaxKind.ComplexElementInitializerExpression) &&
                    initializer.IsParentKind(
                        SyntaxKind.ArrayCreationExpression,
                        SyntaxKind.ImplicitArrayCreationExpression,
                        SyntaxKind.ObjectCreationExpression,
                        SyntaxKind.CollectionInitializerExpression,
                        SyntaxKind.WithExpression))
                {
                    if (initializer.IsSingleLine(includeExteriorTrivia: false))
                    {
                        context.RegisterRefactoring(
                            "Wrap initializer expression",
                            ct => SyntaxFormatter.ToMultiLineAsync(context.Document, initializer, ct),
                            RefactoringDescriptors.WrapInitializerExpressions);
                    }
                    else if (expressions.All(expression => expression.IsSingleLine()) &&
                             initializer.DescendantTrivia(initializer.Span).All(f => f.IsWhitespaceOrEndOfLineTrivia()))
                    {
                        context.RegisterRefactoring(
                            "Unwrap initializer expressions",
                            ct => SyntaxFormatter.ToSingleLineAsync(
                                context.Document,
                                initializer.Parent,
                                TextSpan.FromBounds(initializer.OpenBraceToken.GetPreviousToken().Span.End, initializer.CloseBraceToken.Span.End),
                                ct),
                            RefactoringDescriptors.WrapInitializerExpressions);
                    }
                }

                if (context.IsRefactoringEnabled(RefactoringDescriptors.AddAllPropertiesToInitializer) &&
                    initializer.IsKind(SyntaxKind.ObjectInitializerExpression, SyntaxKind.WithInitializerExpression) &&
                    AddAllPropertiesToInitializerRefactoring.IsApplicableSpan(initializer, context.Span))
                {
                    SemanticModel semanticModdel = await context.GetSemanticModelAsync().ConfigureAwait(false);

                    AddAllPropertiesToInitializerRefactoring.ComputeRefactorings(context, initializer, semanticModdel);
                }

                await ExpandInitializerRefactoring.ComputeRefactoringsAsync(context, initializer).ConfigureAwait(false);

                if (context.IsRefactoringEnabled(RefactoringDescriptors.UseIndexInitializer) &&
                    context.SupportsCSharp6)
                {
                    await UseIndexInitializerRefactoring.ComputeRefactoringAsync(context, initializer).ConfigureAwait(false);
                }
            }
        }
            private IEnumerable<ITypeSymbol> InferTypeInInitializerExpression(
                InitializerExpressionSyntax initializerExpression,
                ExpressionSyntax expressionOpt = null,
                SyntaxToken? previousToken = null)
            {
                if (initializerExpression.IsParentKind(SyntaxKind.ImplicitArrayCreationExpression))
                {
                    // First, try to infer the type that the array should be.  If we can infer an
                    // appropriate array type, then use the element type of the array.  Otherwise,
                    // look at the siblings of this expression and use their type instead.

                    var arrayTypes = this.InferTypes((ExpressionSyntax)initializerExpression.Parent);
                    var elementTypes = arrayTypes.OfType<IArrayTypeSymbol>().Select(a => a.ElementType).Where(e => !IsUnusableType(e));

                    if (elementTypes.Any())
                    {
                        return elementTypes;
                    }

                    // { foo(), |
                    if (previousToken.HasValue && previousToken.Value.CSharpKind() == SyntaxKind.CommaToken)
                    {
                        var sibling = initializerExpression.Expressions.FirstOrDefault(e => e.SpanStart < previousToken.Value.SpanStart);
                        if (sibling != null)
                        {
                            var types = GetTypes(sibling);
                            if (types.Any())
                            {
                                return types;
                            }
                        }
                    }

                    foreach (var sibling in initializerExpression.Expressions)
                    {
                        if (sibling != expressionOpt)
                        {
                            var types = GetTypes(sibling);
                            if (types.Any())
                            {
                                return types;
                            }
                        }
                    }
                }
                else if (initializerExpression.IsParentKind(SyntaxKind.EqualsValueClause))
                {
                    // = { Foo() }
                    var equalsValueClause = (EqualsValueClauseSyntax)initializerExpression.Parent;
                    IEnumerable<ITypeSymbol> types = InferTypeInEqualsValueClause(equalsValueClause);

                    if (types.Any(t => t is IArrayTypeSymbol))
                    {
                        return types.OfType<IArrayTypeSymbol>().Select(t => t.ElementType);
                    }
                }
                else if (initializerExpression.IsParentKind(SyntaxKind.ArrayCreationExpression))
                {
                    // new int[] { Foo() } 
                    var arrayCreation = (ArrayCreationExpressionSyntax)initializerExpression.Parent;
                    IEnumerable<ITypeSymbol> types = GetTypes(arrayCreation);

                    if (types.Any(t => t is IArrayTypeSymbol))
                    {
                        return types.OfType<IArrayTypeSymbol>().Select(t => t.ElementType);
                    }
                }
                else if (initializerExpression.IsParentKind(SyntaxKind.ObjectCreationExpression))
                {
                    // new List<T> { Foo() } 
                    var objectCreation = (ObjectCreationExpressionSyntax)initializerExpression.Parent;

                    IEnumerable<ITypeSymbol> types = GetTypes(objectCreation);
                    if (types.Any(t => t is INamedTypeSymbol))
                    {
                        return types.OfType<INamedTypeSymbol>().SelectMany(t => 
                            GetCollectionElementType(t, parameterIndex: 0, parameterCount: 1));
                    }
                }
                else if (
                    initializerExpression.IsParentKind(SyntaxKind.ComplexElementInitializerExpression) &&
                    initializerExpression.Parent.IsParentKind(SyntaxKind.ObjectCreationExpression))
                {
                    // new Dictionary<K,V> { { Foo(), ... } }
                    var objectCreation = (ObjectCreationExpressionSyntax)initializerExpression.Parent.Parent;

                    IEnumerable<ITypeSymbol> types = GetTypes(objectCreation);

                    if (types.Any(t => t is INamedTypeSymbol))
                    {
                        var parameterIndex = previousToken.HasValue
                            ? initializerExpression.Expressions.GetWithSeparators().IndexOf(previousToken.Value) + 1
                            : initializerExpression.Expressions.IndexOf(expressionOpt);

                        return types.OfType<INamedTypeSymbol>().SelectMany(t =>
                            GetCollectionElementType(t,
                                parameterIndex: parameterIndex,
                                parameterCount: initializerExpression.Expressions.Count));
                    }
                }
                else if (initializerExpression.IsParentKind(SyntaxKind.SimpleAssignmentExpression))
                {
                    // new Foo { a = { Foo() } }
                    var assignExpression = (BinaryExpressionSyntax)initializerExpression.Parent;
                    IEnumerable<ITypeSymbol> types = GetTypes(assignExpression.Left);

                    if (types.Any(t => t is INamedTypeSymbol))
                    {
                        var parameterIndex = previousToken.HasValue
                            ? initializerExpression.Expressions.GetWithSeparators().IndexOf(previousToken.Value) + 1
                            : initializerExpression.Expressions.IndexOf(expressionOpt);

                        return types.OfType<INamedTypeSymbol>().SelectMany(t =>
                            GetCollectionElementType(t,
                                parameterIndex: parameterIndex,
                                parameterCount: initializerExpression.Expressions.Count));
                    }
                }

                return SpecializedCollections.EmptyEnumerable<ITypeSymbol>();
            }
            private IEnumerable<ITypeSymbol> InferTypeInInitializerExpression(
                InitializerExpressionSyntax initializerExpression,
                ExpressionSyntax expressionOpt = null,
                SyntaxToken? previousToken = null)
            {
                if (initializerExpression.IsKind(SyntaxKind.ComplexElementInitializerExpression))
                {
                    // new Dictionary<K,V> { { x, ... } }
                    // new C { Prop = { { x, ... } } }
                    var parameterIndex = previousToken.HasValue
                            ? initializerExpression.Expressions.GetSeparators().ToList().IndexOf(previousToken.Value) + 1
                            : initializerExpression.Expressions.IndexOf(expressionOpt);

                    var addMethodSymbols = SemanticModel.GetCollectionInitializerSymbolInfo(initializerExpression).GetAllSymbols();
                    var addMethodParameterTypes = addMethodSymbols
                        .Cast<IMethodSymbol>()
                        .Where(a => a.Parameters.Length == initializerExpression.Expressions.Count)
                        .Select(a => a.Parameters.ElementAtOrDefault(parameterIndex)?.Type)
                        .WhereNotNull();

                    if (addMethodParameterTypes.Any())
                    {
                        return addMethodParameterTypes;
                    }
                }
                else if (initializerExpression.IsKind(SyntaxKind.CollectionInitializerExpression))
                {
                    if (expressionOpt != null)
                    {
                        // new List<T> { x, ... }
                        // new C { Prop = { x, ... } }
                        var addMethodSymbols = SemanticModel.GetCollectionInitializerSymbolInfo(expressionOpt).GetAllSymbols();
                        var addMethodParameterTypes = addMethodSymbols
                            .Cast<IMethodSymbol>()
                            .Where(a => a.Parameters.Length == 1)
                            .Select(a => a.Parameters[0].Type).WhereNotNull();
                        if (addMethodParameterTypes.Any())
                        {
                            return addMethodParameterTypes;
                        }
                    }
                    else
                    {
                        // new List<T> { x,
                        // new C { Prop = { x,

                        foreach (var sibling in initializerExpression.Expressions.Where(e => e.Kind() != SyntaxKind.ComplexElementInitializerExpression))
                        {
                            var types = GetTypes(sibling);
                            if (types.Any())
                            {
                                return types;
                            }
                        }
                    }
                }

                if (initializerExpression.IsParentKind(SyntaxKind.ImplicitArrayCreationExpression))
                {
                    // new[] { 1, x }

                    // First, try to infer the type that the array should be.  If we can infer an
                    // appropriate array type, then use the element type of the array.  Otherwise,
                    // look at the siblings of this expression and use their type instead.

                    var arrayTypes = this.InferTypes((ExpressionSyntax)initializerExpression.Parent);
                    var elementTypes = arrayTypes.OfType<IArrayTypeSymbol>().Select(a => a.ElementType).Where(IsUsableTypeFunc);

                    if (elementTypes.Any())
                    {
                        return elementTypes;
                    }

                    foreach (var sibling in initializerExpression.Expressions)
                    {
                        if (sibling != expressionOpt)
                        {
                            var types = GetTypes(sibling);
                            if (types.Any())
                            {
                                return types;
                            }
                        }
                    }
                }
                else if (initializerExpression.IsParentKind(SyntaxKind.EqualsValueClause))
                {
                    // = { Foo() }
                    var equalsValueClause = (EqualsValueClauseSyntax)initializerExpression.Parent;
                    IEnumerable<ITypeSymbol> types = InferTypeInEqualsValueClause(equalsValueClause);

                    if (types.Any(t => t is IArrayTypeSymbol))
                    {
                        return types.OfType<IArrayTypeSymbol>().Select(t => t.ElementType);
                    }
                }
                else if (initializerExpression.IsParentKind(SyntaxKind.ArrayCreationExpression))
                {
                    // new int[] { Foo() } 
                    var arrayCreation = (ArrayCreationExpressionSyntax)initializerExpression.Parent;
                    IEnumerable<ITypeSymbol> types = GetTypes(arrayCreation);

                    if (types.Any(t => t is IArrayTypeSymbol))
                    {
                        return types.OfType<IArrayTypeSymbol>().Select(t => t.ElementType);
                    }
                }
                else if (initializerExpression.IsParentKind(SyntaxKind.ObjectCreationExpression))
                {
                    // new List<T> { Foo() } 

                    var objectCreation = (ObjectCreationExpressionSyntax)initializerExpression.Parent;

                    IEnumerable<ITypeSymbol> types = GetTypes(objectCreation);
                    if (types.Any(t => t is INamedTypeSymbol))
                    {
                        return types.OfType<INamedTypeSymbol>().SelectMany(t =>
                            GetCollectionElementType(t, parameterIndex: 0));
                    }
                }
                else if (initializerExpression.IsParentKind(SyntaxKind.SimpleAssignmentExpression))
                {
                    // new Foo { a = { Foo() } }

                    if (expressionOpt != null)
                    {
                        var addMethodSymbols = SemanticModel.GetCollectionInitializerSymbolInfo(expressionOpt).GetAllSymbols();
                        var addMethodParameterTypes = addMethodSymbols.Select(a => ((IMethodSymbol)a).Parameters[0].Type).WhereNotNull();
                        if (addMethodParameterTypes.Any())
                        {
                            return addMethodParameterTypes;
                        }
                    }

                    var assignExpression = (AssignmentExpressionSyntax)initializerExpression.Parent;
                    IEnumerable<ITypeSymbol> types = GetTypes(assignExpression.Left);

                    if (types.Any(t => t is INamedTypeSymbol))
                    {
                        // new Foo { a = { Foo() } }
                        var parameterIndex = previousToken.HasValue
                                ? initializerExpression.Expressions.GetSeparators().ToList().IndexOf(previousToken.Value) + 1
                                : initializerExpression.Expressions.IndexOf(expressionOpt);

                        return types.OfType<INamedTypeSymbol>().SelectMany(t =>
                            GetCollectionElementType(t, 0));
                    }
                }

                return SpecializedCollections.EmptyEnumerable<ITypeSymbol>();
            }
            private IEnumerable<ITypeSymbol> InferTypeInInitializerExpression(
                InitializerExpressionSyntax initializerExpression,
                ExpressionSyntax expressionOpt = null,
                SyntaxToken? previousToken = null)
            {
                if (initializerExpression.IsParentKind(SyntaxKind.ImplicitArrayCreationExpression))
                {
                    // First, try to infer the type that the array should be.  If we can infer an
                    // appropriate array type, then use the element type of the array.  Otherwise,
                    // look at the siblings of this expression and use their type instead.

                    var arrayTypes = this.InferTypes((ExpressionSyntax)initializerExpression.Parent);
                    var elementTypes = arrayTypes.OfType<IArrayTypeSymbol>().Select(a => a.ElementType).Where(e => !IsUnusableType(e));

                    if (elementTypes.Any())
                    {
                        return elementTypes;
                    }

                    // { foo(), |
                    if (previousToken.HasValue && previousToken.Value.CSharpKind() == SyntaxKind.CommaToken)
                    {
                        var sibling = initializerExpression.Expressions.FirstOrDefault(e => e.SpanStart < previousToken.Value.SpanStart);
                        if (sibling != null)
                        {
                            var types = GetTypes(sibling);
                            if (types.Any())
                            {
                                return types;
                            }
                        }
                    }

                    foreach (var sibling in initializerExpression.Expressions)
                    {
                        if (sibling != expressionOpt)
                        {
                            var types = GetTypes(sibling);
                            if (types.Any())
                            {
                                return types;
                            }
                        }
                    }
                }
                else if (initializerExpression.IsParentKind(SyntaxKind.ArrayCreationExpression))
                {
                    // new int[] { Foo() } 
                    var arrayCreation = (ArrayCreationExpressionSyntax)initializerExpression.Parent;
                    IEnumerable<ITypeSymbol> type = GetTypes(arrayCreation);

                    // BUG: (vladres) Is it a correct type check? 
                    // BUG: Is there a type that implements both IEnumerable<ITypeSymbol> and IArrayTypeSymbol?
                    // BUG: Or it was intended to be:
                    // BUG:   type.FirstOrDefault() as IArrayTypeSymbol
                    // BUG: or
                    // BUG:   type.OfType<IArrayTypeSymbol>().FirstOrDefault() ?
                    // BUG: (see other similar problems below)
                    if (type is IArrayTypeSymbol)
                    {
                        return SpecializedCollections.SingletonEnumerable(((IArrayTypeSymbol)type).ElementType);
                    }
                }
                else if (initializerExpression.IsParentKind(SyntaxKind.ObjectCreationExpression))
                {
                    // new List<T> { Foo() } 
                    var objectCreation = (ObjectCreationExpressionSyntax)initializerExpression.Parent;

                    // BUG: (vladres) Is it a correct type check? 
                    // BUG: Is there a type that implements both IEnumerable<ITypeSymbol> and INamedTypeSymbol?
                    // BUG: (see other similar problems below)
                    var type = GetTypes(objectCreation) as INamedTypeSymbol;
                    return GetCollectionElementType(type, parameterIndex: 0, parameterCount: 1);
                }
                else if (
                    initializerExpression.IsParentKind(SyntaxKind.ComplexElementInitializerExpression) &&
                    initializerExpression.Parent.IsParentKind(SyntaxKind.ObjectCreationExpression))
                {
                    // new Dictionary<K,V> { { Foo(), ... } }
                    var objectCreation = (ObjectCreationExpressionSyntax)initializerExpression.Parent.Parent;

                    // BUG: (vladres) Is it a correct type check? 
                    // BUG: Is there a type that implements both IEnumerable<ITypeSymbol> and INamedTypeSymbol?
                    // BUG: (see other similar problems below)
                    var type = GetTypes(objectCreation) as INamedTypeSymbol;

                    var parameterIndex = previousToken.HasValue
                        ? initializerExpression.Expressions.GetWithSeparators().IndexOf(previousToken.Value) + 1
                        : initializerExpression.Expressions.IndexOf(expressionOpt);

                    return GetCollectionElementType(type,
                            parameterIndex: parameterIndex,
                            parameterCount: initializerExpression.Expressions.Count);
                }
                else if (initializerExpression.IsParentKind(SyntaxKind.SimpleAssignmentExpression))
                {
                    // new Foo { a = { Foo() } }
                    var assignExpression = (BinaryExpressionSyntax)initializerExpression.Parent;

                    // BUG: (vladres) Is it a correct type check? 
                    // BUG: Is there a type that implements both IEnumerable<ITypeSymbol> and INamedTypeSymbol?
                    var type = GetTypes(assignExpression.Left) as INamedTypeSymbol;

                    var parameterIndex = previousToken.HasValue
                        ? initializerExpression.Expressions.GetWithSeparators().IndexOf(previousToken.Value) + 1
                        : initializerExpression.Expressions.IndexOf(expressionOpt);

                    return GetCollectionElementType(type,
                                parameterIndex: parameterIndex,
                                parameterCount: initializerExpression.Expressions.Count);
                }

                return SpecializedCollections.EmptyEnumerable<ITypeSymbol>();
            }