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); } } }
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>(); }