CSharpTypeInferenceService.TypeInferrer.cs 110.3 KB
Newer Older
1
// Copyright (c) Microsoft.  All Rights Reserved.  Licensed under the Apache License, Version 2.0.  See License.txt in the project root for license information.
P
Pilchie 已提交
2

3
using System;
P
Pilchie 已提交
4 5
using System.Collections.Generic;
using System.Collections.Immutable;
6
using System.Diagnostics;
P
Pilchie 已提交
7 8
using System.Linq;
using System.Threading;
C
CyrusNajmabadi 已提交
9
using System.Threading.Tasks;
P
Pilchie 已提交
10 11
using Microsoft.CodeAnalysis.CSharp.Extensions;
using Microsoft.CodeAnalysis.CSharp.Syntax;
12
using Microsoft.CodeAnalysis.LanguageServices;
T
Tomas Matousek 已提交
13
using Microsoft.CodeAnalysis.PooledObjects;
P
Pilchie 已提交
14 15 16 17 18 19 20
using Microsoft.CodeAnalysis.Shared.Extensions;
using Roslyn.Utilities;

namespace Microsoft.CodeAnalysis.CSharp
{
    internal partial class CSharpTypeInferenceService
    {
21
        private class TypeInferrer : AbstractTypeInferrer
P
Pilchie 已提交
22 23 24
        {
            internal TypeInferrer(
                SemanticModel semanticModel,
25
                CancellationToken cancellationToken) : base(semanticModel, cancellationToken)
P
Pilchie 已提交
26 27
            {
            }
28

29
            protected override bool IsUnusableType(ITypeSymbol otherSideType)
P
Pilchie 已提交
30 31 32 33 34
            {
                return otherSideType.IsErrorType() &&
                    (otherSideType.Name == string.Empty || otherSideType.Name == "var");
            }

35
            protected override IEnumerable<TypeInferenceInfo> GetTypes_DoNotCallDirectly(ExpressionSyntax expression, bool objectAsDefault)
36
            {
C
Cyrus Najmabadi 已提交
37 38
                var types = GetTypesSimple(expression).Where(IsUsableTypeFunc);
                if (types.Any())
39 40
                {
                    return types;
P
Pilchie 已提交
41 42
                }

C
Cyrus Najmabadi 已提交
43
                return GetTypesComplex(expression).Where(IsUsableTypeFunc);
P
Pilchie 已提交
44 45
            }

46
            private static bool DecomposeBinaryOrAssignmentExpression(ExpressionSyntax expression, out SyntaxToken operatorToken, out ExpressionSyntax left, out ExpressionSyntax right)
P
Pilchie 已提交
47
            {
C
CyrusNajmabadi 已提交
48
                if (expression is BinaryExpressionSyntax binaryExpression)
P
Pilchie 已提交
49
                {
50 51 52 53 54 55
                    operatorToken = binaryExpression.OperatorToken;
                    left = binaryExpression.Left;
                    right = binaryExpression.Right;
                    return true;
                }

C
CyrusNajmabadi 已提交
56
                if (expression is AssignmentExpressionSyntax assignmentExpression)
57 58 59 60 61 62 63
                {
                    operatorToken = assignmentExpression.OperatorToken;
                    left = assignmentExpression.Left;
                    right = assignmentExpression.Right;
                    return true;
                }

C
CyrusNajmabadi 已提交
64
                operatorToken = default;
65 66 67 68
                left = right = null;
                return false;
            }

69
            private IEnumerable<TypeInferenceInfo> GetTypesComplex(ExpressionSyntax expression)
70
            {
C
CyrusNajmabadi 已提交
71 72
                if (DecomposeBinaryOrAssignmentExpression(expression,
                        out var operatorToken, out var left, out var right))
73
                {
C
Cyrus Najmabadi 已提交
74
                    var types = InferTypeInBinaryOrAssignmentExpression(expression, operatorToken, left, right, left).Where(IsUsableTypeFunc);
P
Pilchie 已提交
75 76
                    if (types.IsEmpty())
                    {
C
Cyrus Najmabadi 已提交
77
                        types = InferTypeInBinaryOrAssignmentExpression(expression, operatorToken, left, right, right).Where(IsUsableTypeFunc);
P
Pilchie 已提交
78 79 80 81 82 83
                    }

                    return types;
                }

                // TODO(cyrusn): More cases if necessary.
84
                return SpecializedCollections.EmptyEnumerable<TypeInferenceInfo>();
P
Pilchie 已提交
85 86
            }

87
            private IEnumerable<TypeInferenceInfo> GetTypesSimple(ExpressionSyntax expression)
P
Pilchie 已提交
88
            {
89 90 91 92 93
                if (expression is RefTypeSyntax refType)
                {
                    return GetTypes(refType.Type);
                }
                else if (expression != null)
P
Pilchie 已提交
94
                {
95 96
                    var typeInfo = SemanticModel.GetTypeInfo(expression, CancellationToken);
                    var symbolInfo = SemanticModel.GetSymbolInfo(expression, CancellationToken);
P
Pilchie 已提交
97 98 99

                    if (symbolInfo.CandidateReason != CandidateReason.WrongArity)
                    {
R
Ravi Chande 已提交
100
                        var typeInferenceInfo = new TypeInferenceInfo(typeInfo.Type);
P
Pilchie 已提交
101 102

                        // If it bound to a method, try to get the Action/Func form of that method.
103
                        if (typeInferenceInfo.InferredType == null)
P
Pilchie 已提交
104
                        {
105 106 107 108 109 110 111
                            var allSymbols = symbolInfo.GetAllSymbols();
                            if (allSymbols.Length == 1 &&
                                allSymbols[0].Kind == SymbolKind.Method)
                            {
                                var method = allSymbols[0];
                                typeInferenceInfo = new TypeInferenceInfo(method.ConvertToType(this.Compilation));
                            }
P
Pilchie 已提交
112 113
                        }

R
Ravi Chande 已提交
114
                        if (IsUsableTypeFunc(typeInferenceInfo))
P
Pilchie 已提交
115
                        {
R
Ravi Chande 已提交
116
                            return SpecializedCollections.SingletonEnumerable(typeInferenceInfo);
P
Pilchie 已提交
117 118 119 120
                        }
                    }
                }

121
                return SpecializedCollections.EmptyEnumerable<TypeInferenceInfo>();
P
Pilchie 已提交
122 123
            }

124
            protected override IEnumerable<TypeInferenceInfo> InferTypesWorker_DoNotCallDirectly(
125
                ExpressionSyntax expression)
P
Pilchie 已提交
126 127 128 129
            {
                expression = expression.WalkUpParentheses();
                var parent = expression.Parent;

C
CyrusNajmabadi 已提交
130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159
                switch (parent)
                {
                    case AnonymousObjectMemberDeclaratorSyntax memberDeclarator: return InferTypeInMemberDeclarator(memberDeclarator);
                    case ArgumentSyntax argument: return InferTypeInArgument(argument);
                    case ArrayCreationExpressionSyntax arrayCreationExpression: return InferTypeInArrayCreationExpression(arrayCreationExpression);
                    case ArrayRankSpecifierSyntax arrayRankSpecifier: return InferTypeInArrayRankSpecifier(arrayRankSpecifier);
                    case ArrayTypeSyntax arrayType: return InferTypeInArrayType(arrayType);
                    case ArrowExpressionClauseSyntax arrowClause: return InferTypeInArrowExpressionClause(arrowClause);
                    case AssignmentExpressionSyntax assignmentExpression: return InferTypeInBinaryOrAssignmentExpression(assignmentExpression, assignmentExpression.OperatorToken, assignmentExpression.Left, assignmentExpression.Right, expression);
                    case AttributeArgumentSyntax attribute: return InferTypeInAttributeArgument(attribute);
                    case AttributeSyntax attribute: return InferTypeInAttribute(attribute);
                    case AwaitExpressionSyntax awaitExpression: return InferTypeInAwaitExpression(awaitExpression);
                    case BinaryExpressionSyntax binaryExpression: return InferTypeInBinaryOrAssignmentExpression(binaryExpression, binaryExpression.OperatorToken, binaryExpression.Left, binaryExpression.Right, expression);
                    case CastExpressionSyntax castExpression: return InferTypeInCastExpression(castExpression, expression);
                    case CatchDeclarationSyntax catchDeclaration: return InferTypeInCatchDeclaration(catchDeclaration);
                    case CatchFilterClauseSyntax catchFilterClause: return InferTypeInCatchFilterClause(catchFilterClause);
                    case CheckedExpressionSyntax checkedExpression: return InferTypes(checkedExpression);
                    case ConditionalAccessExpressionSyntax conditionalAccessExpression: return InferTypeInConditionalAccessExpression(conditionalAccessExpression);
                    case ConditionalExpressionSyntax conditionalExpression: return InferTypeInConditionalExpression(conditionalExpression, expression);
                    case DoStatementSyntax doStatement: return InferTypeInDoStatement(doStatement);
                    case EqualsValueClauseSyntax equalsValue: return InferTypeInEqualsValueClause(equalsValue);
                    case ExpressionStatementSyntax expressionStatement: return InferTypeInExpressionStatement(expressionStatement);
                    case ForEachStatementSyntax forEachStatement: return InferTypeInForEachStatement(forEachStatement, expression);
                    case ForStatementSyntax forStatement: return InferTypeInForStatement(forStatement, expression);
                    case IfStatementSyntax ifStatement: return InferTypeInIfStatement(ifStatement);
                    case InitializerExpressionSyntax initializerExpression: return InferTypeInInitializerExpression(initializerExpression, expression);
                    case IsPatternExpressionSyntax isPatternExpression: return InferTypeInIsPatternExpression(isPatternExpression, expression);
                    case LockStatementSyntax lockStatement: return InferTypeInLockStatement(lockStatement);
                    case MemberAccessExpressionSyntax memberAccessExpression: return InferTypeInMemberAccessExpression(memberAccessExpression, expression);
                    case NameEqualsSyntax nameEquals: return InferTypeInNameEquals(nameEquals);
160
                    case LambdaExpressionSyntax lambdaExpression: return InferTypeInLambdaExpression(lambdaExpression);
C
CyrusNajmabadi 已提交
161 162
                    case PostfixUnaryExpressionSyntax postfixUnary: return InferTypeInPostfixUnaryExpression(postfixUnary);
                    case PrefixUnaryExpressionSyntax prefixUnary: return InferTypeInPrefixUnaryExpression(prefixUnary);
163
                    case RefExpressionSyntax refExpression: return InferTypeInRefExpression(refExpression);
C
CyrusNajmabadi 已提交
164 165 166
                    case ReturnStatementSyntax returnStatement: return InferTypeForReturnStatement(returnStatement);
                    case SwitchLabelSyntax switchLabel: return InferTypeInSwitchLabel(switchLabel);
                    case SwitchStatementSyntax switchStatement: return InferTypeInSwitchStatement(switchStatement);
167
                    case ThrowExpressionSyntax throwExpression: return InferTypeInThrowExpression(throwExpression);
C
CyrusNajmabadi 已提交
168 169
                    case ThrowStatementSyntax throwStatement: return InferTypeInThrowStatement(throwStatement);
                    case UsingStatementSyntax usingStatement: return InferTypeInUsingStatement(usingStatement);
170
                    case WhenClauseSyntax whenClause: return InferTypeInWhenClause(whenClause);
C
CyrusNajmabadi 已提交
171 172 173 174
                    case WhileStatementSyntax whileStatement: return InferTypeInWhileStatement(whileStatement);
                    case YieldStatementSyntax yieldStatement: return InferTypeInYieldStatement(yieldStatement);
                    default: return SpecializedCollections.EmptyEnumerable<TypeInferenceInfo>();
                }
P
Pilchie 已提交
175 176
            }

177
            protected override IEnumerable<TypeInferenceInfo> InferTypesWorker_DoNotCallDirectly(int position)
P
Pilchie 已提交
178
            {
179 180
                var syntaxTree = SemanticModel.SyntaxTree;
                var token = syntaxTree.FindTokenOnLeftOfPosition(position, CancellationToken);
P
Pilchie 已提交
181
                token = token.GetPreviousTokenIfTouchingWord(position);
182

C
Cyrus Najmabadi 已提交
183 184
                var parent = token.Parent;

C
CyrusNajmabadi 已提交
185 186
                switch (parent)
                {
187
                    case AnonymousObjectCreationExpressionSyntax anonymousObjectCreation: return InferTypeInAnonymousObjectCreation(anonymousObjectCreation, token);
C
CyrusNajmabadi 已提交
188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214
                    case AnonymousObjectMemberDeclaratorSyntax memberDeclarator: return InferTypeInMemberDeclarator(memberDeclarator, token);
                    case ArgumentListSyntax argument: return InferTypeInArgumentList(argument, token);
                    case ArgumentSyntax argument: return InferTypeInArgument(argument, token);
                    case ArrayCreationExpressionSyntax arrayCreationExpression: return InferTypeInArrayCreationExpression(arrayCreationExpression, token);
                    case ArrayRankSpecifierSyntax arrayRankSpecifier: return InferTypeInArrayRankSpecifier(arrayRankSpecifier, token);
                    case ArrayTypeSyntax arrayType: return InferTypeInArrayType(arrayType, token);
                    case ArrowExpressionClauseSyntax arrowClause: return InferTypeInArrowExpressionClause(arrowClause);
                    case AssignmentExpressionSyntax assignmentExpression: return InferTypeInBinaryOrAssignmentExpression(assignmentExpression, assignmentExpression.OperatorToken, assignmentExpression.Left, assignmentExpression.Right, previousToken: token);
                    case AttributeArgumentListSyntax attributeArgumentList: return InferTypeInAttributeArgumentList(attributeArgumentList, token);
                    case AttributeArgumentSyntax argument: return InferTypeInAttributeArgument(argument, token);
                    case AttributeListSyntax attributeDeclaration: return InferTypeInAttributeDeclaration(attributeDeclaration, token);
                    case AttributeTargetSpecifierSyntax attributeTargetSpecifier: return InferTypeInAttributeTargetSpecifier(attributeTargetSpecifier, token);
                    case AwaitExpressionSyntax awaitExpression: return InferTypeInAwaitExpression(awaitExpression, token);
                    case BinaryExpressionSyntax binaryExpression: return InferTypeInBinaryOrAssignmentExpression(binaryExpression, binaryExpression.OperatorToken, binaryExpression.Left, binaryExpression.Right, previousToken: token);
                    case BracketedArgumentListSyntax bracketedArgumentList: return InferTypeInBracketedArgumentList(bracketedArgumentList, token);
                    case CastExpressionSyntax castExpression: return InferTypeInCastExpression(castExpression, previousToken: token);
                    case CatchDeclarationSyntax catchDeclaration: return InferTypeInCatchDeclaration(catchDeclaration, token);
                    case CatchFilterClauseSyntax catchFilterClause: return InferTypeInCatchFilterClause(catchFilterClause, token);
                    case CheckedExpressionSyntax checkedExpression: return InferTypes(checkedExpression);
                    case ConditionalExpressionSyntax conditionalExpression: return InferTypeInConditionalExpression(conditionalExpression, previousToken: token);
                    case DefaultExpressionSyntax defaultExpression: return InferTypeInDefaultExpression(defaultExpression);
                    case DoStatementSyntax doStatement: return InferTypeInDoStatement(doStatement, token);
                    case EqualsValueClauseSyntax equalsValue: return InferTypeInEqualsValueClause(equalsValue, token);
                    case ExpressionStatementSyntax expressionStatement: return InferTypeInExpressionStatement(expressionStatement, token);
                    case ForEachStatementSyntax forEachStatement: return InferTypeInForEachStatement(forEachStatement, previousToken: token);
                    case ForStatementSyntax forStatement: return InferTypeInForStatement(forStatement, previousToken: token);
                    case IfStatementSyntax ifStatement: return InferTypeInIfStatement(ifStatement, token);
215
                    case ImplicitArrayCreationExpressionSyntax implicitArray: return InferTypeInImplicitArrayCreation(implicitArray, token);
C
CyrusNajmabadi 已提交
216 217 218 219 220 221
                    case InitializerExpressionSyntax initializerExpression: return InferTypeInInitializerExpression(initializerExpression, previousToken: token);
                    case LockStatementSyntax lockStatement: return InferTypeInLockStatement(lockStatement, token);
                    case MemberAccessExpressionSyntax memberAccessExpression: return InferTypeInMemberAccessExpression(memberAccessExpression, previousToken: token);
                    case NameColonSyntax nameColon: return InferTypeInNameColon(nameColon, token);
                    case NameEqualsSyntax nameEquals: return InferTypeInNameEquals(nameEquals, token);
                    case ObjectCreationExpressionSyntax objectCreation: return InferTypeInObjectCreationExpression(objectCreation, token);
222
                    case LambdaExpressionSyntax lambdaExpression: return InferTypeInLambdaExpression(lambdaExpression, token);
C
CyrusNajmabadi 已提交
223 224 225 226 227 228 229
                    case PostfixUnaryExpressionSyntax postfixUnary: return InferTypeInPostfixUnaryExpression(postfixUnary, token);
                    case PrefixUnaryExpressionSyntax prefixUnary: return InferTypeInPrefixUnaryExpression(prefixUnary, token);
                    case ReturnStatementSyntax returnStatement: return InferTypeForReturnStatement(returnStatement, token);
                    case SwitchLabelSyntax switchLabel: return InferTypeInSwitchLabel(switchLabel, token);
                    case SwitchStatementSyntax switchStatement: return InferTypeInSwitchStatement(switchStatement, token);
                    case ThrowStatementSyntax throwStatement: return InferTypeInThrowStatement(throwStatement, token);
                    case UsingStatementSyntax usingStatement: return InferTypeInUsingStatement(usingStatement, token);
230
                    case WhenClauseSyntax whenClause: return InferTypeInWhenClause(whenClause, token);
C
CyrusNajmabadi 已提交
231 232 233 234
                    case WhileStatementSyntax whileStatement: return InferTypeInWhileStatement(whileStatement, token);
                    case YieldStatementSyntax yieldStatement: return InferTypeInYieldStatement(yieldStatement, token);
                    default: return SpecializedCollections.EmptyEnumerable<TypeInferenceInfo>();
                }
P
Pilchie 已提交
235 236
            }

237 238 239 240 241 242 243 244 245
            private IEnumerable<TypeInferenceInfo> InferTypeInAnonymousObjectCreation(AnonymousObjectCreationExpressionSyntax expression, SyntaxToken previousToken)
            {
                if (previousToken == expression.NewKeyword)
                {
                    return InferTypes(expression.SpanStart);
                }

                return SpecializedCollections.EmptyEnumerable<TypeInferenceInfo>();
            }
246

247
            private IEnumerable<TypeInferenceInfo> InferTypeInArgument(
248
                ArgumentSyntax argument, SyntaxToken? previousToken = null)
P
Pilchie 已提交
249 250 251 252 253 254
            {
                if (previousToken.HasValue)
                {
                    // If we have a position, then it must be after the colon in a named argument.
                    if (argument.NameColon == null || argument.NameColon.ColonToken != previousToken)
                    {
255
                        return SpecializedCollections.EmptyEnumerable<TypeInferenceInfo>();
P
Pilchie 已提交
256 257 258 259 260
                    }
                }

                if (argument.Parent != null)
                {
C
CyrusNajmabadi 已提交
261
                    if (argument.Parent.Parent is ConstructorInitializerSyntax initializer)
P
Pilchie 已提交
262 263 264 265 266 267 268 269 270 271 272 273 274 275 276
                    {
                        var index = initializer.ArgumentList.Arguments.IndexOf(argument);
                        return InferTypeInConstructorInitializer(initializer, index, argument);
                    }

                    if (argument.Parent.IsParentKind(SyntaxKind.InvocationExpression))
                    {
                        var invocation = argument.Parent.Parent as InvocationExpressionSyntax;
                        var index = invocation.ArgumentList.Arguments.IndexOf(argument);

                        return InferTypeInInvocationExpression(invocation, index, argument);
                    }

                    if (argument.Parent.IsParentKind(SyntaxKind.ObjectCreationExpression))
                    {
277
                        // new Outer(Goo());
P
Pilchie 已提交
278
                        //
279
                        // new Outer(a: Goo());
P
Pilchie 已提交
280 281 282 283 284 285 286 287 288 289
                        //
                        // etc.
                        var creation = argument.Parent.Parent as ObjectCreationExpressionSyntax;
                        var index = creation.ArgumentList.Arguments.IndexOf(argument);

                        return InferTypeInObjectCreationExpression(creation, index, argument);
                    }

                    if (argument.Parent.IsParentKind(SyntaxKind.ElementAccessExpression))
                    {
290
                        // Outer[Goo()];
P
Pilchie 已提交
291
                        //
292
                        // Outer[a: Goo()];
P
Pilchie 已提交
293 294 295 296 297 298 299
                        //
                        // etc.
                        var elementAccess = argument.Parent.Parent as ElementAccessExpressionSyntax;
                        var index = elementAccess.ArgumentList.Arguments.IndexOf(argument);

                        return InferTypeInElementAccessExpression(elementAccess, index, argument);
                    }
300 301 302 303 304

                    if (argument.IsParentKind(SyntaxKind.TupleExpression))
                    {
                        return InferTypeInTupleExpression((TupleExpressionSyntax)argument.Parent, argument);
                    }
P
Pilchie 已提交
305 306
                }

307 308 309 310 311 312
                if (argument.Parent.IsParentKind(SyntaxKind.ImplicitElementAccess) &&
                    argument.Parent.Parent.IsParentKind(SyntaxKind.SimpleAssignmentExpression) &&
                    argument.Parent.Parent.Parent.IsParentKind(SyntaxKind.ObjectInitializerExpression) &&
                    argument.Parent.Parent.Parent.Parent.IsParentKind(SyntaxKind.ObjectCreationExpression))
                {
                    var objectCreation = (ObjectCreationExpressionSyntax)argument.Parent.Parent.Parent.Parent.Parent;
313
                    var types = GetTypes(objectCreation).Select(t => t.InferredType);
314

315
                    if (types.Any(t => t is INamedTypeSymbol))
316 317 318 319 320 321 322
                    {
                        return types.OfType<INamedTypeSymbol>().SelectMany(t =>
                            GetCollectionElementType(t,
                                parameterIndex: 0));
                    }
                }

323
                return SpecializedCollections.EmptyEnumerable<TypeInferenceInfo>();
P
Pilchie 已提交
324 325
            }

326
            private IEnumerable<TypeInferenceInfo> InferTypeInTupleExpression(
327
                TupleExpressionSyntax tupleExpression, ArgumentSyntax argument)
328
            {
329 330
                var index = tupleExpression.Arguments.IndexOf(argument);
                var parentTypes = InferTypes(tupleExpression);
331 332 333 334 335 336 337

                return parentTypes.Select(typeInfo => typeInfo.InferredType)
                                  .OfType<INamedTypeSymbol>()
                                  .Where(namedType => namedType.IsTupleType && index < namedType.TupleElements.Length)
                                  .Select(tupleType => new TypeInferenceInfo(tupleType.TupleElements[index].Type));
            }

338
            private IEnumerable<TypeInferenceInfo> InferTypeInAttributeArgument(AttributeArgumentSyntax argument, SyntaxToken? previousToken = null, ArgumentSyntax argumentOpt = null)
P
Pilchie 已提交
339 340 341 342 343 344
            {
                if (previousToken.HasValue)
                {
                    // If we have a position, then it must be after the colon or equals in an argument.
                    if (argument.NameColon == null || argument.NameColon.ColonToken != previousToken || argument.NameEquals.EqualsToken != previousToken)
                    {
345
                        return SpecializedCollections.EmptyEnumerable<TypeInferenceInfo>();
P
Pilchie 已提交
346 347 348 349 350
                    }
                }

                if (argument.Parent != null)
                {
C
CyrusNajmabadi 已提交
351
                    if (argument.Parent.Parent is AttributeSyntax attribute)
P
Pilchie 已提交
352 353 354 355 356 357
                    {
                        var index = attribute.ArgumentList.Arguments.IndexOf(argument);
                        return InferTypeInAttribute(attribute, index, argument);
                    }
                }

358
                return SpecializedCollections.EmptyEnumerable<TypeInferenceInfo>();
P
Pilchie 已提交
359 360
            }

361
            private IEnumerable<TypeInferenceInfo> InferTypeInConstructorInitializer(ConstructorInitializerSyntax initializer, int index, ArgumentSyntax argument = null)
P
Pilchie 已提交
362
            {
363
                var info = SemanticModel.GetSymbolInfo(initializer, CancellationToken);
P
Pilchie 已提交
364 365 366 367
                var methods = info.GetBestOrAllSymbols().OfType<IMethodSymbol>();
                return InferTypeInArgument(index, methods, argument);
            }

368
            private IEnumerable<TypeInferenceInfo> InferTypeInObjectCreationExpression(ObjectCreationExpressionSyntax expression, SyntaxToken previousToken)
369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389
            {
                // A couple of broken code scenarios where the new keyword in objectcreationexpression
                // appears to be a part of a subsequent assignment.  For example:
                //
                //       new Form
                //       {
                //           Location = new $$
                //           StartPosition = FormStartPosition.CenterParent
                //       };
                //  The 'new' token is part of an assignment of the assignment to StartPosition,
                //  but the user is really trying to assign to Location.
                //
                // Similarly:
                //      bool b;
                //      Task task = new $$
                //      b = false;
                // The 'new' token is part of an assignment of the assignment to b, but the user 
                // is really trying to assign to task.
                //
                // In both these cases, we simply back up before the 'new' if it follows an equals
                // and start the inference again.
390 391 392 393 394 395 396 397 398
                //
                // Analogously, but in a method call:
                //      Test(new $$
                //      o = s
                // or:
                //      Test(1, new $$
                //      o = s
                // The new is part of the assignment to o but the user is really trying to 
                // add a parameter to the method call.
399
                if (previousToken.Kind() == SyntaxKind.NewKeyword &&
400
                    previousToken.GetPreviousToken().IsKind(SyntaxKind.EqualsToken, SyntaxKind.OpenParenToken, SyntaxKind.CommaToken))
401 402 403 404 405 406 407
                {
                    return InferTypes(previousToken.SpanStart);
                }

                return InferTypes(expression);
            }

408
            private IEnumerable<TypeInferenceInfo> InferTypeInObjectCreationExpression(ObjectCreationExpressionSyntax creation, int index, ArgumentSyntax argumentOpt = null)
P
Pilchie 已提交
409
            {
410
                var info = SemanticModel.GetSymbolInfo(creation.Type, CancellationToken);
P
Pilchie 已提交
411 412 413 414
                var type = info.Symbol as INamedTypeSymbol;

                if (type == null)
                {
415
                    return SpecializedCollections.EmptyEnumerable<TypeInferenceInfo>();
P
Pilchie 已提交
416 417 418 419 420 421 422 423
                }

                if (type.TypeKind == TypeKind.Delegate)
                {
                    // new SomeDelegateType( here );
                    //
                    // They're actually instantiating a delegate, so the delegate type is
                    // that type.
424
                    return SpecializedCollections.SingletonEnumerable(new TypeInferenceInfo(type));
P
Pilchie 已提交
425 426 427 428 429 430
                }

                var constructors = type.InstanceConstructors.Where(m => m.Parameters.Length > index);
                return InferTypeInArgument(index, constructors, argumentOpt);
            }

431
            private IEnumerable<TypeInferenceInfo> InferTypeInInvocationExpression(
P
Pilchie 已提交
432 433 434 435 436 437
                InvocationExpressionSyntax invocation, int index, ArgumentSyntax argumentOpt = null)
            {
                // Check all the methods that have at least enough arguments to support
                // being called with argument at this position.  Note: if they're calling an
                // extension method then it will need one more argument in order for us to
                // call it.
438
                var info = SemanticModel.GetSymbolInfo(invocation, CancellationToken);
439
                var methods = info.GetBestOrAllSymbols().OfType<IMethodSymbol>();
P
Pilchie 已提交
440 441 442 443

                // Overload resolution (see DevDiv 611477) in certain extension method cases
                // can result in GetSymbolInfo returning nothing. In this case, get the 
                // method group info, which is what signature help already does.
444
                if (info.Symbol == null)
P
Pilchie 已提交
445
                {
446 447 448 449 450
                    var memberGroupMethods = 
                        SemanticModel.GetMemberGroup(invocation.Expression, CancellationToken)
                                     .OfType<IMethodSymbol>();

                    methods = methods.Concat(memberGroupMethods).Distinct();
P
Pilchie 已提交
451 452 453 454 455
                }

                return InferTypeInArgument(index, methods, argumentOpt);
            }

456
            private IEnumerable<TypeInferenceInfo> InferTypeInArgumentList(ArgumentListSyntax argumentList, SyntaxToken previousToken)
P
Pilchie 已提交
457 458
            {
                // Has to follow the ( or a ,
459
                if (previousToken != argumentList.OpenParenToken && previousToken.Kind() != SyntaxKind.CommaToken)
P
Pilchie 已提交
460
                {
461
                    return SpecializedCollections.EmptyEnumerable<TypeInferenceInfo>();
P
Pilchie 已提交
462 463
                }

C
CyrusNajmabadi 已提交
464
                switch (argumentList.Parent)
P
Pilchie 已提交
465
                {
C
CyrusNajmabadi 已提交
466 467 468 469 470
                    case InvocationExpressionSyntax invocation:
                        {
                            var index = this.GetArgumentListIndex(argumentList, previousToken);
                            return InferTypeInInvocationExpression(invocation, index);
                        }
P
Pilchie 已提交
471

C
CyrusNajmabadi 已提交
472 473 474 475 476
                    case ObjectCreationExpressionSyntax objectCreation:
                        {
                            var index = this.GetArgumentListIndex(argumentList, previousToken);
                            return InferTypeInObjectCreationExpression(objectCreation, index);
                        }
P
Pilchie 已提交
477

C
CyrusNajmabadi 已提交
478 479 480 481 482
                    case ConstructorInitializerSyntax constructorInitializer:
                        {
                            var index = this.GetArgumentListIndex(argumentList, previousToken);
                            return InferTypeInConstructorInitializer(constructorInitializer, index);
                        }
P
Pilchie 已提交
483 484
                }

485
                return SpecializedCollections.EmptyEnumerable<TypeInferenceInfo>();
P
Pilchie 已提交
486 487
            }

488
            private IEnumerable<TypeInferenceInfo> InferTypeInAttributeArgumentList(AttributeArgumentListSyntax attributeArgumentList, SyntaxToken previousToken)
P
Pilchie 已提交
489 490
            {
                // Has to follow the ( or a ,
491
                if (previousToken != attributeArgumentList.OpenParenToken && previousToken.Kind() != SyntaxKind.CommaToken)
P
Pilchie 已提交
492
                {
493
                    return SpecializedCollections.EmptyEnumerable<TypeInferenceInfo>();
P
Pilchie 已提交
494 495
                }

C
CyrusNajmabadi 已提交
496
                if (attributeArgumentList.Parent is AttributeSyntax attribute)
P
Pilchie 已提交
497 498 499 500 501
                {
                    var index = this.GetArgumentListIndex(attributeArgumentList, previousToken);
                    return InferTypeInAttribute(attribute, index);
                }

502
                return SpecializedCollections.EmptyEnumerable<TypeInferenceInfo>();
P
Pilchie 已提交
503 504
            }

505
            private IEnumerable<TypeInferenceInfo> InferTypeInAttribute(AttributeSyntax attribute, int index, AttributeArgumentSyntax argumentOpt = null)
P
Pilchie 已提交
506
            {
507
                var info = SemanticModel.GetSymbolInfo(attribute, CancellationToken);
P
Pilchie 已提交
508 509 510 511
                var methods = info.GetBestOrAllSymbols().OfType<IMethodSymbol>();
                return InferTypeInAttributeArgument(index, methods, argumentOpt);
            }

512
            private IEnumerable<TypeInferenceInfo> InferTypeInElementAccessExpression(
P
Pilchie 已提交
513 514
                ElementAccessExpressionSyntax elementAccess, int index, ArgumentSyntax argumentOpt = null)
            {
515
                var info = SemanticModel.GetTypeInfo(elementAccess.Expression, CancellationToken);
C
CyrusNajmabadi 已提交
516
                if (info.Type is INamedTypeSymbol type)
P
Pilchie 已提交
517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533
                {
                    var indexers = type.GetMembers().OfType<IPropertySymbol>()
                                                   .Where(p => p.IsIndexer && p.Parameters.Length > index);

                    if (indexers.Any())
                    {
                        return indexers.SelectMany(i =>
                            InferTypeInArgument(index, SpecializedCollections.SingletonEnumerable(i.Parameters), argumentOpt));
                    }
                }

                // For everything else, assume it's an integer.  Note: this won't be correct for
                // type parameters that implement some interface, but that seems like a major
                // corner case for now.
                // 
                // This does, however, cover the more common cases of
                // arrays/pointers/errors/dynamic.
534
                return SpecializedCollections.SingletonEnumerable(new TypeInferenceInfo(this.Compilation.GetSpecialType(SpecialType.System_Int32)));
P
Pilchie 已提交
535 536
            }

537
            private IEnumerable<TypeInferenceInfo> InferTypeInAttributeArgument(int index, IEnumerable<IMethodSymbol> methods, AttributeArgumentSyntax argumentOpt = null)
P
Pilchie 已提交
538 539 540 541
            {
                return InferTypeInAttributeArgument(index, methods.Select(m => m.Parameters), argumentOpt);
            }

542
            private IEnumerable<TypeInferenceInfo> InferTypeInArgument(int index, IEnumerable<IMethodSymbol> methods, ArgumentSyntax argumentOpt)
P
Pilchie 已提交
543
            {
544 545
                if (argumentOpt != null)
                {
C
CyrusNajmabadi 已提交
546
                    if (argumentOpt?.Parent?.Parent is InvocationExpressionSyntax invocation)
547 548 549 550 551
                    {
                        // We're trying to figure out the signature of a method we're an argument to. 
                        // That method may be generic, and we might end up using one of its generic
                        // type parameters in the type we infer.  First, let's see if we can instantiate
                        // the methods so that the type can be inferred better.
552
                        var invocationTypes = this.InferTypes(invocation).Select(t => t.InferredType).ToList();
553
                        var instantiatedMethods = methods.Select(m => Instantiate(m, invocationTypes)).ToList();
C
Cyrus Najmabadi 已提交
554 555 556 557

                        // Now that we've instantiated the methods, filter down to the ones that 
                        // will actually return a viable type given where this invocation expression
                        // is.
558 559
                        var filteredMethods = instantiatedMethods.Where(m =>
                            invocationTypes.Any(t => Compilation.ClassifyConversion(m.ReturnType, t).IsImplicit)).ToList();
C
Cyrus Najmabadi 已提交
560 561 562

                        // If we filtered down to nothing, then just fall back to the instantiated list.
                        // this is a best effort after all.
563 564 565 566
                        methods = filteredMethods.Any() ? filteredMethods : instantiatedMethods;
                    }
                }

P
Pilchie 已提交
567 568 569
                return InferTypeInArgument(index, methods.Select(m => m.Parameters), argumentOpt);
            }

570 571 572 573 574 575 576 577 578
            private IMethodSymbol Instantiate(IMethodSymbol method, IList<ITypeSymbol> invocationTypes)
            {
                // No need to instantiate if this isn't a generic method.
                if (method.TypeArguments.Length == 0)
                {
                    return method;
                }

                // Can't infer the type parameters if this method doesn't have a return type.
C
CyrusNajmabadi 已提交
579 580 581
                // Note: this is because this code path is specifically flowing type information
                // backward through the return type.  Type information is already flowed forward
                // through arguments by the compiler when we get the initial set of methods.
582 583 584 585 586 587 588
                if (method.ReturnsVoid)
                {
                    return method;
                }

                // If the method has already been constructed poorly (i.e. with error types for type 
                // arguments), then unconstruct it.
589
                if (method.TypeArguments.Any(t => t.Kind == SymbolKind.ErrorType))
590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611
                {
                    method = method.ConstructedFrom;
                }

                IDictionary<ITypeParameterSymbol, ITypeSymbol> bestMap = null;
                foreach (var type in invocationTypes)
                {
                    // Ok.  We inferred a type for this location, and we have the return type of this 
                    // method.  See if we can then assign any values for type parameters.
                    var map = DetermineTypeParameterMapping(type, method.ReturnType);
                    if (map.Count > 0 && (bestMap == null || map.Count > bestMap.Count))
                    {
                        bestMap = map;
                    }
                }

                if (bestMap == null)
                {
                    return method;
                }

                var typeArguments = method.ConstructedFrom.TypeParameters.Select(tp => bestMap.GetValueOrDefault(tp) ?? tp).ToArray();
612
                return method.ConstructedFrom.Construct(typeArguments);
613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666
            }

            private Dictionary<ITypeParameterSymbol, ITypeSymbol> DetermineTypeParameterMapping(ITypeSymbol inferredType, ITypeSymbol returnType)
            {
                var result = new Dictionary<ITypeParameterSymbol, ITypeSymbol>();
                DetermineTypeParameterMapping(inferredType, returnType, result);
                return result;
            }

            private void DetermineTypeParameterMapping(ITypeSymbol inferredType, ITypeSymbol returnType, Dictionary<ITypeParameterSymbol, ITypeSymbol> result)
            {
                if (inferredType == null || returnType == null)
                {
                    return;
                }

                if (returnType.Kind == SymbolKind.TypeParameter)
                {
                    if (inferredType.Kind != SymbolKind.TypeParameter)
                    {
                        var returnTypeParameter = (ITypeParameterSymbol)returnType;
                        if (!result.ContainsKey(returnTypeParameter))
                        {
                            result[returnTypeParameter] = inferredType;
                        }
                        return;
                    }
                }

                if (inferredType.Kind != returnType.Kind)
                {
                    return;
                }

                switch (inferredType.Kind)
                {
                    case SymbolKind.ArrayType:
                        DetermineTypeParameterMapping(((IArrayTypeSymbol)inferredType).ElementType, ((IArrayTypeSymbol)returnType).ElementType, result);
                        return;
                    case SymbolKind.PointerType:
                        DetermineTypeParameterMapping(((IPointerTypeSymbol)inferredType).PointedAtType, ((IPointerTypeSymbol)returnType).PointedAtType, result);
                        return;
                    case SymbolKind.NamedType:
                        var inferredNamedType = (INamedTypeSymbol)inferredType;
                        var returnNamedType = (INamedTypeSymbol)returnType;
                        if (inferredNamedType.TypeArguments.Length == returnNamedType.TypeArguments.Length)
                        {
                            for (int i = 0, n = inferredNamedType.TypeArguments.Length; i < n; i++)
                            {
                                DetermineTypeParameterMapping(inferredNamedType.TypeArguments[i], returnNamedType.TypeArguments[i], result);
                            }
                        }
                        return;
                }
667
            }
668

669
            private IEnumerable<TypeInferenceInfo> InferTypeInAttributeArgument(
P
Pilchie 已提交
670 671 672 673 674 675 676 677 678 679 680 681
                int index,
                IEnumerable<ImmutableArray<IParameterSymbol>> parameterizedSymbols,
                AttributeArgumentSyntax argumentOpt = null)
            {
                if (argumentOpt != null && argumentOpt.NameEquals != null)
                {
                    // [MyAttribute(Prop = ...

                    return InferTypeInNameEquals(argumentOpt.NameEquals, argumentOpt.NameEquals.EqualsToken);
                }

                var name = argumentOpt != null && argumentOpt.NameColon != null ? argumentOpt.NameColon.Name.Identifier.ValueText : null;
682
                return InferTypeInArgument(index, parameterizedSymbols, name, RefKind.None);
P
Pilchie 已提交
683 684
            }

685
            private IEnumerable<TypeInferenceInfo> InferTypeInArgument(
P
Pilchie 已提交
686 687 688 689 690
                int index,
                IEnumerable<ImmutableArray<IParameterSymbol>> parameterizedSymbols,
                ArgumentSyntax argumentOpt)
            {
                var name = argumentOpt != null && argumentOpt.NameColon != null ? argumentOpt.NameColon.Name.Identifier.ValueText : null;
691 692
                var refKind = argumentOpt.GetRefKind();
                return InferTypeInArgument(index, parameterizedSymbols, name, refKind);
P
Pilchie 已提交
693 694
            }

695
            private IEnumerable<TypeInferenceInfo> InferTypeInArgument(
P
Pilchie 已提交
696 697
                int index,
                IEnumerable<ImmutableArray<IParameterSymbol>> parameterizedSymbols,
698 699
                string name,
                RefKind refKind)
P
Pilchie 已提交
700 701 702 703 704
            {
                // If the callsite has a named argument, then try to find a method overload that has a
                // parameter with that name.  If we can find one, then return the type of that one.
                if (name != null)
                {
705 706 707 708 709 710 711 712 713 714 715 716
                    var matchingNameParameters = parameterizedSymbols.SelectMany(m => m)
                                                                     .Where(p => p.Name == name)
                                                                     .Select(p => new TypeInferenceInfo(p.Type, p.IsParams));

                    return matchingNameParameters;
                }

                var allParameters = ArrayBuilder<TypeInferenceInfo>.GetInstance();
                var matchingRefParameters = ArrayBuilder<TypeInferenceInfo>.GetInstance();
                try
                {
                    foreach (var parameterSet in parameterizedSymbols)
P
Pilchie 已提交
717
                    {
718 719 720 721 722 723 724 725 726 727 728
                        if (index < parameterSet.Length)
                        {
                            var parameter = parameterSet[index];
                            var info = new TypeInferenceInfo(parameter.Type, parameter.IsParams);
                            allParameters.Add(info);

                            if (parameter.RefKind == refKind)
                            {
                                matchingRefParameters.Add(info);
                            }
                        }
P
Pilchie 已提交
729
                    }
730 731 732 733

                    return matchingRefParameters.Count > 0
                        ? matchingRefParameters.ToImmutable()
                        : allParameters.ToImmutable();
P
Pilchie 已提交
734
                }
735
                finally
P
Pilchie 已提交
736
                {
737 738
                    allParameters.Free();
                    matchingRefParameters.Free();
P
Pilchie 已提交
739 740 741
                }
            }

742
            private IEnumerable<TypeInferenceInfo> InferTypeInArrayCreationExpression(
P
Pilchie 已提交
743 744 745 746 747
                ArrayCreationExpressionSyntax arrayCreationExpression, SyntaxToken? previousToken = null)
            {
                if (previousToken.HasValue && previousToken.Value != arrayCreationExpression.NewKeyword)
                {
                    // Has to follow the 'new' keyword. 
748
                    return SpecializedCollections.EmptyEnumerable<TypeInferenceInfo>();
P
Pilchie 已提交
749 750
                }

R
Ravi Chande 已提交
751
                if (previousToken.HasValue && previousToken.Value.GetPreviousToken().Kind() == SyntaxKind.EqualsToken)
R
Ravi Chande 已提交
752 753 754 755 756 757 758 759 760 761 762 763 764 765
                {
                    // We parsed an array creation but the token before `new` is `=`.
                    // This could be a case like:
                    //
                    // int[] array;
                    // Program p = new |
                    // array[4] = 4;
                    //
                    // This is similar to the cases described in `InferTypeInObjectCreationExpression`.
                    // Again, all we have to do is back up to before `new`.

                    return InferTypes(previousToken.Value.SpanStart);
                }

P
Pilchie 已提交
766
                var outerTypes = InferTypes(arrayCreationExpression);
R
Ravi Chande 已提交
767
                return outerTypes.Where(o => o.InferredType is IArrayTypeSymbol);
P
Pilchie 已提交
768 769
            }

770
            private IEnumerable<TypeInferenceInfo> InferTypeInArrayRankSpecifier(ArrayRankSpecifierSyntax arrayRankSpecifier, SyntaxToken? previousToken = null)
P
Pilchie 已提交
771 772 773 774 775
            {
                // If we have a token, and it's not the open bracket or one of the commas, then no
                // inference.
                if (previousToken == arrayRankSpecifier.CloseBracketToken)
                {
776
                    return SpecializedCollections.EmptyEnumerable<TypeInferenceInfo>();
P
Pilchie 已提交
777 778
                }

779
                return SpecializedCollections.SingletonEnumerable(new TypeInferenceInfo(this.Compilation.GetSpecialType(SpecialType.System_Int32)));
P
Pilchie 已提交
780 781
            }

782
            private IEnumerable<TypeInferenceInfo> InferTypeInArrayType(ArrayTypeSyntax arrayType, SyntaxToken? previousToken = null)
P
Pilchie 已提交
783 784 785 786
            {
                if (previousToken.HasValue)
                {
                    // TODO(cyrusn): NYI.  Handle this appropriately if we need to.
787
                    return SpecializedCollections.EmptyEnumerable<TypeInferenceInfo>();
P
Pilchie 已提交
788 789 790 791 792 793 794
                }

                // Bind the array type, then unwrap whatever we get back based on the number of rank
                // specifiers we see.
                var currentTypes = InferTypes(arrayType);
                for (var i = 0; i < arrayType.RankSpecifiers.Count; i++)
                {
795 796
                    currentTypes = currentTypes.WhereAsArray(c => c.InferredType is IArrayTypeSymbol)
                                               .SelectAsArray(c => new TypeInferenceInfo(((IArrayTypeSymbol)c.InferredType).ElementType));
P
Pilchie 已提交
797 798 799 800
                }
                return currentTypes;
            }

801
            private IEnumerable<TypeInferenceInfo> InferTypeInAttribute(AttributeSyntax attribute)
P
Pilchie 已提交
802
            {
803
                return SpecializedCollections.SingletonEnumerable(new TypeInferenceInfo(this.Compilation.AttributeType()));
P
Pilchie 已提交
804 805
            }

806
            private IEnumerable<TypeInferenceInfo> InferTypeInAttributeDeclaration(AttributeListSyntax attributeDeclaration, SyntaxToken? previousToken)
P
Pilchie 已提交
807 808 809 810
            {
                // If we have a position, then it has to be after the open bracket.
                if (previousToken.HasValue && previousToken.Value != attributeDeclaration.OpenBracketToken)
                {
811
                    return SpecializedCollections.EmptyEnumerable<TypeInferenceInfo>();
P
Pilchie 已提交
812 813
                }

814
                return SpecializedCollections.SingletonEnumerable(new TypeInferenceInfo(this.Compilation.AttributeType()));
P
Pilchie 已提交
815 816
            }

817
            private IEnumerable<TypeInferenceInfo> InferTypeInAttributeTargetSpecifier(
P
Pilchie 已提交
818 819 820 821 822 823
                AttributeTargetSpecifierSyntax attributeTargetSpecifier,
                SyntaxToken? previousToken)
            {
                // If we have a position, then it has to be after the colon.
                if (previousToken.HasValue && previousToken.Value != attributeTargetSpecifier.ColonToken)
                {
824
                    return SpecializedCollections.EmptyEnumerable<TypeInferenceInfo>();
P
Pilchie 已提交
825 826
                }

827
                return SpecializedCollections.SingletonEnumerable(new TypeInferenceInfo(this.Compilation.AttributeType()));
P
Pilchie 已提交
828 829
            }

830
            private IEnumerable<TypeInferenceInfo> InferTypeInBracketedArgumentList(BracketedArgumentListSyntax bracketedArgumentList, SyntaxToken previousToken)
P
Pilchie 已提交
831 832
            {
                // Has to follow the [ or a ,
833
                if (previousToken != bracketedArgumentList.OpenBracketToken && previousToken.Kind() != SyntaxKind.CommaToken)
P
Pilchie 已提交
834
                {
835
                    return SpecializedCollections.EmptyEnumerable<TypeInferenceInfo>();
P
Pilchie 已提交
836 837
                }

C
CyrusNajmabadi 已提交
838
                if (bracketedArgumentList.Parent is ElementAccessExpressionSyntax elementAccess)
P
Pilchie 已提交
839 840 841 842 843 844
                {
                    var index = GetArgumentListIndex(bracketedArgumentList, previousToken);
                    return InferTypeInElementAccessExpression(
                        elementAccess, index);
                }

845
                return SpecializedCollections.EmptyEnumerable<TypeInferenceInfo>();
P
Pilchie 已提交
846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885
            }

            private int GetArgumentListIndex(BaseArgumentListSyntax argumentList, SyntaxToken previousToken)
            {
                if (previousToken == argumentList.GetOpenToken())
                {
                    return 0;
                }

                ////    ( node0 , node1 , node2 , node3 ,
                //
                // Tokidx   0   1   2   3   4   5   6   7
                //
                // index        1       2       3
                //
                // index = (Tokidx + 1) / 2

                var tokenIndex = argumentList.Arguments.GetWithSeparators().IndexOf(previousToken);
                return (tokenIndex + 1) / 2;
            }

            private int GetArgumentListIndex(AttributeArgumentListSyntax attributeArgumentList, SyntaxToken previousToken)
            {
                if (previousToken == attributeArgumentList.OpenParenToken)
                {
                    return 0;
                }

                ////    ( node0 , node1 , node2 , node3 ,
                //
                // Tokidx   0   1   2   3   4   5   6   7
                //
                // index        1       2       3
                //
                // index = (Tokidx + 1) / 2

                var tokenIndex = attributeArgumentList.Arguments.GetWithSeparators().IndexOf(previousToken);
                return (tokenIndex + 1) / 2;
            }

886
            private IEnumerable<TypeInferenceInfo> InferTypeInBinaryOrAssignmentExpression(ExpressionSyntax binop, SyntaxToken operatorToken, ExpressionSyntax left, ExpressionSyntax right, ExpressionSyntax expressionOpt = null, SyntaxToken? previousToken = null)
P
Pilchie 已提交
887 888 889
            {
                // If we got here through a token, then it must have actually been the binary
                // operator's token.
890
                Contract.ThrowIfTrue(previousToken.HasValue && previousToken.Value != operatorToken);
P
Pilchie 已提交
891

892
                if (binop.Kind() == SyntaxKind.CoalesceExpression)
P
Pilchie 已提交
893
                {
894
                    return InferTypeInCoalesceExpression((BinaryExpressionSyntax)binop, expressionOpt, previousToken);
P
Pilchie 已提交
895 896
                }

897
                var onRightOfToken = right == expressionOpt || previousToken.HasValue;
898
                switch (operatorToken.Kind())
P
Pilchie 已提交
899
                {
900 901 902 903
                    case SyntaxKind.LessThanLessThanToken:
                    case SyntaxKind.GreaterThanGreaterThanToken:
                    case SyntaxKind.LessThanLessThanEqualsToken:
                    case SyntaxKind.GreaterThanGreaterThanEqualsToken:
P
Pilchie 已提交
904

905 906
                        if (onRightOfToken)
                        {
907
                            // x << Goo(), x >> Goo(), x <<= Goo(), x >>= Goo()
908
                            return SpecializedCollections.SingletonEnumerable(new TypeInferenceInfo(this.Compilation.GetSpecialType(SpecialType.System_Int32)));
909
                        }
P
Pilchie 已提交
910

911
                        break;
P
Pilchie 已提交
912 913 914
                }

                // Infer operands of && and || as bool regardless of the other operand.
915 916
                if (operatorToken.Kind() == SyntaxKind.AmpersandAmpersandToken ||
                    operatorToken.Kind() == SyntaxKind.BarBarToken)
P
Pilchie 已提交
917
                {
918
                    return SpecializedCollections.SingletonEnumerable(new TypeInferenceInfo(this.Compilation.GetSpecialType(SpecialType.System_Boolean)));
P
Pilchie 已提交
919 920
                }

921 922 923 924 925 926 927
                // Infer type for deconstruction
                if (binop.Kind() == SyntaxKind.SimpleAssignmentExpression &&
                    ((AssignmentExpressionSyntax)binop).IsDeconstruction())
                {
                    return InferTypeInVariableComponentAssignment(left);
                }

P
Pilchie 已提交
928 929 930 931
                // Try to figure out what's on the other side of the binop.  If we can, then just that
                // type.  This is often a reasonable heuristics to use for most operators.  NOTE(cyrusn):
                // we could try to bind the token to see what overloaded operators it corresponds to.
                // But the gain is pretty marginal IMO.
932
                var otherSide = onRightOfToken ? left : right;
P
Pilchie 已提交
933 934 935 936

                var otherSideTypes = GetTypes(otherSide);
                if (otherSideTypes.Any())
                {
937
                    // Don't infer delegate types except in assignments. They're unlikely to be what the
938 939 940
                    // user needs and can cause lambda suggestion mode while
                    // typing type arguments:
                    // https://github.com/dotnet/roslyn/issues/14492
941 942 943 944 945 946
                    if (!(binop is AssignmentExpressionSyntax))
                    {
                        otherSideTypes = otherSideTypes.Where(t => !t.InferredType.IsDelegateType());
                    }

                    return otherSideTypes;
P
Pilchie 已提交
947 948 949 950
                }

                // For &, &=, |, |=, ^, and ^=, since we couldn't infer the type of either side, 
                // try to infer the type of the entire binary expression.
951 952 953 954 955 956
                if (operatorToken.Kind() == SyntaxKind.AmpersandToken ||
                    operatorToken.Kind() == SyntaxKind.AmpersandEqualsToken ||
                    operatorToken.Kind() == SyntaxKind.BarToken ||
                    operatorToken.Kind() == SyntaxKind.BarEqualsToken ||
                    operatorToken.Kind() == SyntaxKind.CaretToken ||
                    operatorToken.Kind() == SyntaxKind.CaretEqualsToken)
P
Pilchie 已提交
957 958 959 960 961 962 963 964 965 966
                {
                    var parentTypes = InferTypes(binop);
                    if (parentTypes.Any())
                    {
                        return parentTypes;
                    }
                }

                // If it's a plus operator, then do some smarts in case it might be a string or
                // delegate.
967
                if (operatorToken.Kind() == SyntaxKind.PlusToken)
P
Pilchie 已提交
968 969 970 971 972
                {
                    // See Bug 6045.  Note: we've already checked the other side of the operator.  So this
                    // is the case where the other side was also unknown.  So we walk one higher and if
                    // we get a delegate or a string type, then use that type here.
                    var parentTypes = InferTypes(binop);
973
                    if (parentTypes.Any(parentType => parentType.InferredType.SpecialType == SpecialType.System_String || parentType.InferredType.TypeKind == TypeKind.Delegate))
P
Pilchie 已提交
974
                    {
975
                        return parentTypes.Where(parentType => parentType.InferredType.SpecialType == SpecialType.System_String || parentType.InferredType.TypeKind == TypeKind.Delegate);
P
Pilchie 已提交
976 977 978 979
                    }
                }

                // Otherwise pick some sane defaults for certain common cases.
980
                switch (operatorToken.Kind())
P
Pilchie 已提交
981
                {
982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003
                    case SyntaxKind.BarToken:
                    case SyntaxKind.CaretToken:
                    case SyntaxKind.AmpersandToken:
                    case SyntaxKind.LessThanToken:
                    case SyntaxKind.LessThanEqualsToken:
                    case SyntaxKind.GreaterThanToken:
                    case SyntaxKind.GreaterThanEqualsToken:
                    case SyntaxKind.PlusToken:
                    case SyntaxKind.MinusToken:
                    case SyntaxKind.AsteriskToken:
                    case SyntaxKind.SlashToken:
                    case SyntaxKind.PercentToken:
                    case SyntaxKind.CaretEqualsToken:
                    case SyntaxKind.PlusEqualsToken:
                    case SyntaxKind.MinusEqualsToken:
                    case SyntaxKind.AsteriskEqualsToken:
                    case SyntaxKind.SlashEqualsToken:
                    case SyntaxKind.PercentEqualsToken:
                    case SyntaxKind.LessThanLessThanToken:
                    case SyntaxKind.GreaterThanGreaterThanToken:
                    case SyntaxKind.LessThanLessThanEqualsToken:
                    case SyntaxKind.GreaterThanGreaterThanEqualsToken:
1004
                        return SpecializedCollections.SingletonEnumerable(new TypeInferenceInfo(this.Compilation.GetSpecialType(SpecialType.System_Int32)));
1005 1006 1007 1008 1009

                    case SyntaxKind.BarEqualsToken:
                    case SyntaxKind.AmpersandEqualsToken:
                        // NOTE(cyrusn): |= and &= can be used for both ints and bools  However, in the
                        // case where there isn't enough information to determine which the user wanted,
1010
                        // I'm just defaulting to bool based on personal preference.
1011
                        return SpecializedCollections.SingletonEnumerable(new TypeInferenceInfo(this.Compilation.GetSpecialType(SpecialType.System_Boolean)));
P
Pilchie 已提交
1012 1013
                }

1014
                return SpecializedCollections.EmptyEnumerable<TypeInferenceInfo>();
P
Pilchie 已提交
1015 1016
            }

1017
            private IEnumerable<TypeInferenceInfo> InferTypeInCastExpression(CastExpressionSyntax castExpression, ExpressionSyntax expressionOpt = null, SyntaxToken? previousToken = null)
P
Pilchie 已提交
1018 1019 1020
            {
                if (expressionOpt != null && castExpression.Expression != expressionOpt)
                {
1021
                    return SpecializedCollections.EmptyEnumerable<TypeInferenceInfo>();
P
Pilchie 已提交
1022 1023 1024 1025 1026
                }

                // If we have a position, then it has to be after the close paren.
                if (previousToken.HasValue && previousToken.Value != castExpression.CloseParenToken)
                {
1027
                    return SpecializedCollections.EmptyEnumerable<TypeInferenceInfo>();
P
Pilchie 已提交
1028 1029 1030 1031 1032
                }

                return this.GetTypes(castExpression.Type);
            }

1033
            private IEnumerable<TypeInferenceInfo> InferTypeInCatchDeclaration(CatchDeclarationSyntax catchDeclaration, SyntaxToken? previousToken = null)
P
Pilchie 已提交
1034
            {
1035
                // If we have a position, it has to be after "catch("
P
Pilchie 已提交
1036 1037
                if (previousToken.HasValue && previousToken.Value != catchDeclaration.OpenParenToken)
                {
1038
                    return SpecializedCollections.EmptyEnumerable<TypeInferenceInfo>();
P
Pilchie 已提交
1039 1040
                }

1041
                return SpecializedCollections.SingletonEnumerable(new TypeInferenceInfo(this.Compilation.ExceptionType()));
P
Pilchie 已提交
1042 1043
            }

1044
            private IEnumerable<TypeInferenceInfo> InferTypeInCatchFilterClause(CatchFilterClauseSyntax catchFilterClause, SyntaxToken? previousToken = null)
1045 1046 1047 1048
            {
                // If we have a position, it has to be after "if ("
                if (previousToken.HasValue && previousToken.Value != catchFilterClause.OpenParenToken)
                {
1049
                    return SpecializedCollections.EmptyEnumerable<TypeInferenceInfo>();
1050 1051
                }

1052
                return SpecializedCollections.SingletonEnumerable(new TypeInferenceInfo(this.Compilation.GetSpecialType(SpecialType.System_Boolean)));
1053 1054
            }

1055
            private IEnumerable<TypeInferenceInfo> InferTypeInCoalesceExpression(
P
Pilchie 已提交
1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068
                BinaryExpressionSyntax coalesceExpression,
                ExpressionSyntax expressionOpt = null,
                SyntaxToken? previousToken = null)
            {
                // If we got here through a token, then it must have actually been the binary
                // operator's token.
                Contract.ThrowIfTrue(previousToken.HasValue && previousToken.Value != coalesceExpression.OperatorToken);

                var onRightSide = coalesceExpression.Right == expressionOpt || previousToken.HasValue;
                if (onRightSide)
                {
                    var leftTypes = GetTypes(coalesceExpression.Left);
                    return leftTypes
1069
                        .Select(x => x.InferredType.IsNullable()
1070 1071
                            ? new TypeInferenceInfo(((INamedTypeSymbol)x.InferredType).TypeArguments[0]) // nullableExpr ?? Goo()
                            : x); // normalExpr ?? Goo() 
P
Pilchie 已提交
1072 1073 1074 1075 1076
                }

                var rightTypes = GetTypes(coalesceExpression.Right);
                if (!rightTypes.Any())
                {
1077
                    return SpecializedCollections.SingletonEnumerable(new TypeInferenceInfo(Compilation.GetSpecialType(SpecialType.System_Object)));
P
Pilchie 已提交
1078 1079 1080
                }

                return rightTypes
1081
                    .Select(x => x.InferredType.IsValueType
1082 1083
                                     ? new TypeInferenceInfo(this.Compilation.GetSpecialType(SpecialType.System_Nullable_T).Construct(x.InferredType)) // Goo() ?? 0
                                     : x); // Goo() ?? ""
P
Pilchie 已提交
1084 1085
            }

1086
            private IEnumerable<TypeInferenceInfo> InferTypeInConditionalAccessExpression(ConditionalAccessExpressionSyntax expression)
1087 1088 1089 1090
            {
                return InferTypes(expression);
            }

1091
            private IEnumerable<TypeInferenceInfo> InferTypeInConditionalExpression(ConditionalExpressionSyntax conditional, ExpressionSyntax expressionOpt = null, SyntaxToken? previousToken = null)
P
Pilchie 已提交
1092 1093 1094
            {
                if (expressionOpt != null && conditional.Condition == expressionOpt)
                {
1095
                    // Goo() ? a : b
1096
                    return SpecializedCollections.SingletonEnumerable(new TypeInferenceInfo(this.Compilation.GetSpecialType(SpecialType.System_Boolean)));
P
Pilchie 已提交
1097 1098
                }

1099
                // a ? Goo() : b
P
Pilchie 已提交
1100
                //
1101
                // a ? b : Goo()
P
Pilchie 已提交
1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113
                var inTrueClause =
                    (conditional.WhenTrue == expressionOpt) ||
                    (previousToken == conditional.QuestionToken);

                var inFalseClause =
                    (conditional.WhenFalse == expressionOpt) ||
                    (previousToken == conditional.ColonToken);

                var otherTypes = inTrueClause
                                     ? GetTypes(conditional.WhenFalse)
                                     : inFalseClause
                                           ? GetTypes(conditional.WhenTrue)
1114
                                           : SpecializedCollections.EmptyEnumerable<TypeInferenceInfo>();
P
Pilchie 已提交
1115 1116 1117 1118 1119 1120

                return otherTypes.IsEmpty()
                           ? InferTypes(conditional)
                           : otherTypes;
            }

1121
            private IEnumerable<TypeInferenceInfo> InferTypeInDefaultExpression(DefaultExpressionSyntax defaultExpression)
R
Ravi Chande 已提交
1122 1123 1124 1125
            {
                return InferTypes(defaultExpression);
            }

1126
            private IEnumerable<TypeInferenceInfo> InferTypeInDoStatement(DoStatementSyntax doStatement, SyntaxToken? previousToken = null)
P
Pilchie 已提交
1127 1128 1129 1130
            {
                // If we have a position, we need to be after "do { } while("
                if (previousToken.HasValue && previousToken.Value != doStatement.OpenParenToken)
                {
1131
                    return SpecializedCollections.EmptyEnumerable<TypeInferenceInfo>();
P
Pilchie 已提交
1132 1133
                }

1134
                return SpecializedCollections.SingletonEnumerable(new TypeInferenceInfo(this.Compilation.GetSpecialType(SpecialType.System_Boolean)));
P
Pilchie 已提交
1135 1136
            }

1137
            private IEnumerable<TypeInferenceInfo> InferTypeInEqualsValueClause(EqualsValueClauseSyntax equalsValue, SyntaxToken? previousToken = null)
P
Pilchie 已提交
1138 1139 1140 1141
            {
                // If we have a position, it has to be after the =
                if (previousToken.HasValue && previousToken.Value != equalsValue.EqualsToken)
                {
1142
                    return SpecializedCollections.EmptyEnumerable<TypeInferenceInfo>();
P
Pilchie 已提交
1143 1144 1145 1146 1147 1148 1149
                }

                if (equalsValue.IsParentKind(SyntaxKind.VariableDeclarator))
                {
                    return InferTypeInVariableDeclarator((VariableDeclaratorSyntax)equalsValue.Parent);
                }

1150 1151 1152 1153 1154
                if (equalsValue.IsParentKind(SyntaxKind.PropertyDeclaration))
                {
                    return InferTypeInPropertyDeclaration((PropertyDeclarationSyntax)equalsValue.Parent);
                }

P
Pilchie 已提交
1155 1156
                if (equalsValue.IsParentKind(SyntaxKind.Parameter))
                {
C
CyrusNajmabadi 已提交
1157
                    if (SemanticModel.GetDeclaredSymbol(equalsValue.Parent, CancellationToken) is IParameterSymbol parameter)
P
Pilchie 已提交
1158
                    {
1159
                        return SpecializedCollections.SingletonEnumerable(new TypeInferenceInfo(parameter.Type));
P
Pilchie 已提交
1160 1161 1162
                    }
                }

1163
                return SpecializedCollections.EmptyEnumerable<TypeInferenceInfo>();
P
Pilchie 已提交
1164 1165
            }

1166
            private IEnumerable<TypeInferenceInfo> InferTypeInPropertyDeclaration(PropertyDeclarationSyntax propertyDeclaration)
1167
            {
1168
                Debug.Assert(propertyDeclaration?.Type != null, "Property type should never be null");
1169

1170
                var typeInfo = SemanticModel.GetTypeInfo(propertyDeclaration.Type);
1171
                return typeInfo.Type != null
1172 1173
                    ? SpecializedCollections.SingletonEnumerable(new TypeInferenceInfo(typeInfo.Type))
                    : SpecializedCollections.EmptyEnumerable<TypeInferenceInfo>();
1174 1175
            }

1176
            private IEnumerable<TypeInferenceInfo> InferTypeInExpressionStatement(ExpressionStatementSyntax expressionStatement, SyntaxToken? previousToken = null)
P
Pilchie 已提交
1177 1178 1179 1180 1181
            {
                // If we're position based, then that means we're after the semicolon.  In this case
                // we don't have any sort of type to infer.
                if (previousToken.HasValue)
                {
1182
                    return SpecializedCollections.EmptyEnumerable<TypeInferenceInfo>();
P
Pilchie 已提交
1183 1184
                }

1185
                return SpecializedCollections.SingletonEnumerable(new TypeInferenceInfo(this.Compilation.GetSpecialType(SpecialType.System_Void)));
P
Pilchie 已提交
1186 1187
            }

1188
            private IEnumerable<TypeInferenceInfo> InferTypeInForEachStatement(ForEachStatementSyntax forEachStatementSyntax, ExpressionSyntax expressionOpt = null, SyntaxToken? previousToken = null)
P
Pilchie 已提交
1189 1190 1191 1192
            {
                // If we have a position, then we have to be after "foreach(... in"
                if (previousToken.HasValue && previousToken.Value != forEachStatementSyntax.InKeyword)
                {
1193
                    return SpecializedCollections.EmptyEnumerable<TypeInferenceInfo>();
P
Pilchie 已提交
1194 1195 1196 1197
                }

                if (expressionOpt != null && expressionOpt != forEachStatementSyntax.Expression)
                {
1198
                    return SpecializedCollections.EmptyEnumerable<TypeInferenceInfo>();
P
Pilchie 已提交
1199 1200
                }

1201
                // foreach (int v = Goo())
P
Pilchie 已提交
1202 1203 1204
                var variableTypes = GetTypes(forEachStatementSyntax.Type);
                if (!variableTypes.Any())
                {
1205
                    return SpecializedCollections.SingletonEnumerable(new TypeInferenceInfo(
P
Pilchie 已提交
1206
                        this.Compilation.GetSpecialType(SpecialType.System_Collections_Generic_IEnumerable_T)
1207
                        .Construct(Compilation.GetSpecialType(SpecialType.System_Object))));
P
Pilchie 已提交
1208 1209 1210
                }

                var type = this.Compilation.GetSpecialType(SpecialType.System_Collections_Generic_IEnumerable_T);
1211
                return variableTypes.Select(v => new TypeInferenceInfo(type.Construct(v.InferredType)));
P
Pilchie 已提交
1212 1213
            }

1214
            private IEnumerable<TypeInferenceInfo> InferTypeInForStatement(ForStatementSyntax forStatement, ExpressionSyntax expressionOpt = null, SyntaxToken? previousToken = null)
P
Pilchie 已提交
1215 1216 1217 1218
            {
                // If we have a position, it has to be after "for(...;"
                if (previousToken.HasValue && previousToken.Value != forStatement.FirstSemicolonToken)
                {
1219
                    return SpecializedCollections.EmptyEnumerable<TypeInferenceInfo>();
P
Pilchie 已提交
1220 1221 1222 1223
                }

                if (expressionOpt != null && forStatement.Condition != expressionOpt)
                {
1224
                    return SpecializedCollections.EmptyEnumerable<TypeInferenceInfo>();
P
Pilchie 已提交
1225 1226
                }

1227
                return SpecializedCollections.SingletonEnumerable(new TypeInferenceInfo(this.Compilation.GetSpecialType(SpecialType.System_Boolean)));
P
Pilchie 已提交
1228 1229
            }

1230
            private IEnumerable<TypeInferenceInfo> InferTypeInIfStatement(IfStatementSyntax ifStatement, SyntaxToken? previousToken = null)
P
Pilchie 已提交
1231 1232 1233 1234
            {
                // If we have a position, we have to be after the "if("
                if (previousToken.HasValue && previousToken.Value != ifStatement.OpenParenToken)
                {
1235
                    return SpecializedCollections.EmptyEnumerable<TypeInferenceInfo>();
P
Pilchie 已提交
1236 1237
                }

1238
                return SpecializedCollections.SingletonEnumerable(new TypeInferenceInfo(this.Compilation.GetSpecialType(SpecialType.System_Boolean)));
P
Pilchie 已提交
1239 1240
            }

R
Ravi Chande 已提交
1241
            private IEnumerable<TypeInferenceInfo> InferTypeInImplicitArrayCreation(ImplicitArrayCreationExpressionSyntax implicitArray, SyntaxToken previousToken)
1242 1243 1244 1245
            {
                return InferTypes(implicitArray.SpanStart);
            }

1246
            private IEnumerable<TypeInferenceInfo> InferTypeInInitializerExpression(
P
Pilchie 已提交
1247 1248 1249 1250
                InitializerExpressionSyntax initializerExpression,
                ExpressionSyntax expressionOpt = null,
                SyntaxToken? previousToken = null)
            {
1251
                if (initializerExpression.IsKind(SyntaxKind.ComplexElementInitializerExpression))
P
Pilchie 已提交
1252
                {
1253 1254 1255 1256 1257
                    // 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);
P
Pilchie 已提交
1258

1259
                    var addMethodSymbols = SemanticModel.GetCollectionInitializerSymbolInfo(initializerExpression).GetAllSymbols();
1260 1261 1262
                    var addMethodParameterTypes = addMethodSymbols
                        .Cast<IMethodSymbol>()
                        .Where(a => a.Parameters.Length == initializerExpression.Expressions.Count)
R
Ravi Chande 已提交
1263 1264
                        .Select(a => new TypeInferenceInfo(a.Parameters.ElementAtOrDefault(parameterIndex)?.Type))
                        .Where(t => t.InferredType != null);
P
Pilchie 已提交
1265

1266
                    if (addMethodParameterTypes.Any())
P
Pilchie 已提交
1267
                    {
1268
                        return addMethodParameterTypes;
P
Pilchie 已提交
1269
                    }
1270 1271 1272 1273
                }
                else if (initializerExpression.IsKind(SyntaxKind.CollectionInitializerExpression))
                {
                    if (expressionOpt != null)
P
Pilchie 已提交
1274
                    {
1275 1276
                        // new List<T> { x, ... }
                        // new C { Prop = { x, ... } }
1277
                        var addMethodSymbols = SemanticModel.GetCollectionInitializerSymbolInfo(expressionOpt).GetAllSymbols();
1278 1279 1280
                        var addMethodParameterTypes = addMethodSymbols
                            .Cast<IMethodSymbol>()
                            .Where(a => a.Parameters.Length == 1)
1281 1282
                            .Select(a => new TypeInferenceInfo(a.Parameters[0].Type));

1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293
                        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))
P
Pilchie 已提交
1294 1295 1296 1297 1298 1299 1300 1301
                        {
                            var types = GetTypes(sibling);
                            if (types.Any())
                            {
                                return types;
                            }
                        }
                    }
1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312
                }

                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);
1313
                    var elementTypes = arrayTypes.OfType<IArrayTypeSymbol>().Select(a => new TypeInferenceInfo(a.ElementType)).Where(IsUsableTypeFunc);
1314 1315 1316 1317 1318

                    if (elementTypes.Any())
                    {
                        return elementTypes;
                    }
P
Pilchie 已提交
1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331

                    foreach (var sibling in initializerExpression.Expressions)
                    {
                        if (sibling != expressionOpt)
                        {
                            var types = GetTypes(sibling);
                            if (types.Any())
                            {
                                return types;
                            }
                        }
                    }
                }
1332 1333
                else if (initializerExpression.IsParentKind(SyntaxKind.EqualsValueClause))
                {
1334
                    // = { Goo() }
1335
                    var equalsValueClause = (EqualsValueClauseSyntax)initializerExpression.Parent;
1336
                    IEnumerable<ITypeSymbol> types = InferTypeInEqualsValueClause(equalsValueClause).Select(t => t.InferredType);
1337

1338
                    if (types.Any(t => t is IArrayTypeSymbol))
1339
                    {
1340
                        return types.OfType<IArrayTypeSymbol>().Select(t => new TypeInferenceInfo(t.ElementType));
1341 1342
                    }
                }
P
Pilchie 已提交
1343 1344
                else if (initializerExpression.IsParentKind(SyntaxKind.ArrayCreationExpression))
                {
1345
                    // new int[] { Goo() } 
P
Pilchie 已提交
1346
                    var arrayCreation = (ArrayCreationExpressionSyntax)initializerExpression.Parent;
1347
                    IEnumerable<ITypeSymbol> types = GetTypes(arrayCreation).Select(t => t.InferredType);
B
BalajiKris 已提交
1348

1349
                    if (types.Any(t => t is IArrayTypeSymbol))
P
Pilchie 已提交
1350
                    {
1351
                        return types.OfType<IArrayTypeSymbol>().Select(t => new TypeInferenceInfo(t.ElementType));
P
Pilchie 已提交
1352 1353 1354 1355
                    }
                }
                else if (initializerExpression.IsParentKind(SyntaxKind.ObjectCreationExpression))
                {
1356
                    // new List<T> { Goo() } 
1357

P
Pilchie 已提交
1358 1359
                    var objectCreation = (ObjectCreationExpressionSyntax)initializerExpression.Parent;

1360 1361
                    IEnumerable<ITypeSymbol> types = GetTypes(objectCreation).Select(t => t.InferredType);
                    if (types.Any(t => t is INamedTypeSymbol))
B
BalajiKris 已提交
1362
                    {
1363
                        return types.OfType<INamedTypeSymbol>().SelectMany(t =>
1364
                            GetCollectionElementType(t, parameterIndex: 0));
B
BalajiKris 已提交
1365
                    }
P
Pilchie 已提交
1366 1367 1368
                }
                else if (initializerExpression.IsParentKind(SyntaxKind.SimpleAssignmentExpression))
                {
1369
                    // new Goo { a = { Goo() } }
1370

1371
                    if (expressionOpt != null)
1372
                    {
1373
                        var addMethodSymbols = SemanticModel.GetCollectionInitializerSymbolInfo(expressionOpt).GetAllSymbols();
1374
                        var addMethodParameterTypes = addMethodSymbols.Select(a => new TypeInferenceInfo(((IMethodSymbol)a).Parameters[0].Type));
1375 1376 1377 1378
                        if (addMethodParameterTypes.Any())
                        {
                            return addMethodParameterTypes;
                        }
1379 1380
                    }

1381
                    var assignExpression = (AssignmentExpressionSyntax)initializerExpression.Parent;
1382
                    IEnumerable<ITypeSymbol> types = GetTypes(assignExpression.Left).Select(t => t.InferredType);
P
Pilchie 已提交
1383

1384
                    if (types.Any(t => t is INamedTypeSymbol))
B
BalajiKris 已提交
1385
                    {
1386
                        // new Goo { a = { Goo() } }
B
BalajiKris 已提交
1387
                        var parameterIndex = previousToken.HasValue
1388 1389
                                ? initializerExpression.Expressions.GetSeparators().ToList().IndexOf(previousToken.Value) + 1
                                : initializerExpression.Expressions.IndexOf(expressionOpt);
P
Pilchie 已提交
1390

1391
                        return types.OfType<INamedTypeSymbol>().SelectMany(t =>
1392
                            GetCollectionElementType(t, 0));
B
BalajiKris 已提交
1393
                    }
P
Pilchie 已提交
1394 1395
                }

1396
                return SpecializedCollections.EmptyEnumerable<TypeInferenceInfo>();
P
Pilchie 已提交
1397 1398
            }

1399
            private IEnumerable<TypeInferenceInfo> InferTypeInIsPatternExpression(
1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410
                IsPatternExpressionSyntax isPatternExpression,
                ExpressionSyntax expression)
            {
                if (expression == isPatternExpression.Expression)
                {
                    return GetPatternTypes(isPatternExpression.Pattern);
                }

                return null;
            }

1411
            private IEnumerable<TypeInferenceInfo> GetPatternTypes(PatternSyntax pattern)
1412
            {
C
CyrusNajmabadi 已提交
1413 1414 1415 1416 1417 1418
                switch (pattern)
                {
                    case DeclarationPatternSyntax declarationPattern: return GetTypes(declarationPattern.Type);
                    case ConstantPatternSyntax constantPattern: return GetTypes(constantPattern.Expression);
                    default: return null;
                }
1419 1420
            }

1421
            private IEnumerable<TypeInferenceInfo> InferTypeInLockStatement(LockStatementSyntax lockStatement, SyntaxToken? previousToken = null)
P
Pilchie 已提交
1422 1423 1424 1425
            {
                // If we're position based, then we have to be after the "lock("
                if (previousToken.HasValue && previousToken.Value != lockStatement.OpenParenToken)
                {
1426
                    return SpecializedCollections.EmptyEnumerable<TypeInferenceInfo>();
P
Pilchie 已提交
1427 1428
                }

1429
                return SpecializedCollections.SingletonEnumerable(new TypeInferenceInfo(this.Compilation.GetSpecialType(SpecialType.System_Object)));
P
Pilchie 已提交
1430 1431
            }

1432
            private IEnumerable<TypeInferenceInfo> InferTypeInLambdaExpression(LambdaExpressionSyntax lambdaExpression, SyntaxToken? previousToken = null)
P
Pilchie 已提交
1433 1434 1435 1436
            {
                // If we have a position, it has to be after the lambda arrow.
                if (previousToken.HasValue && previousToken.Value != lambdaExpression.ArrowToken)
                {
1437
                    return SpecializedCollections.EmptyEnumerable<TypeInferenceInfo>();
P
Pilchie 已提交
1438 1439
                }

1440
                return InferTypeInAnonymousFunctionExpression(lambdaExpression);
P
Pilchie 已提交
1441 1442
            }

1443
            private IEnumerable<TypeInferenceInfo> InferTypeInAnonymousFunctionExpression(AnonymousFunctionExpressionSyntax anonymousFunction)
P
Pilchie 已提交
1444
            {
1445
                // Func<int,string> = i => Goo();
1446 1447
                // Func<int,string> = delegate (int i) { return Goo(); };
                var types = InferTypes(anonymousFunction);
1448
                var type = types.FirstOrDefault().InferredType.GetDelegateType(this.Compilation);
P
Pilchie 已提交
1449 1450 1451 1452 1453 1454

                if (type != null)
                {
                    var invoke = type.DelegateInvokeMethod;
                    if (invoke != null)
                    {
1455 1456 1457
                        var isAsync = anonymousFunction.AsyncKeyword.Kind() != SyntaxKind.None;
                        return SpecializedCollections.SingletonEnumerable(
                            new TypeInferenceInfo(UnwrapTaskLike(invoke.ReturnType, isAsync)));
P
Pilchie 已提交
1458 1459 1460
                    }
                }

1461
                return SpecializedCollections.EmptyEnumerable<TypeInferenceInfo>();
P
Pilchie 已提交
1462 1463
            }

1464
            private IEnumerable<TypeInferenceInfo> InferTypeInMemberDeclarator(AnonymousObjectMemberDeclaratorSyntax memberDeclarator, SyntaxToken? previousTokenOpt = null)
P
Pilchie 已提交
1465 1466 1467 1468 1469 1470
            {
                if (memberDeclarator.NameEquals != null && memberDeclarator.Parent is AnonymousObjectCreationExpressionSyntax)
                {
                    // If we're position based, then we have to be after the = 
                    if (previousTokenOpt.HasValue && previousTokenOpt.Value != memberDeclarator.NameEquals.EqualsToken)
                    {
1471
                        return SpecializedCollections.EmptyEnumerable<TypeInferenceInfo>();
P
Pilchie 已提交
1472 1473 1474 1475
                    }

                    var types = InferTypes((AnonymousObjectCreationExpressionSyntax)memberDeclarator.Parent);

1476 1477
                    return types.Where(t => t.InferredType.IsAnonymousType())
                        .SelectMany(t => t.InferredType.GetValidAnonymousTypeProperties()
P
Pilchie 已提交
1478
                            .Where(p => p.Name == memberDeclarator.NameEquals.Name.Identifier.ValueText)
1479
                            .Select(p => new TypeInferenceInfo(p.Type)));
P
Pilchie 已提交
1480 1481
                }

1482
                return SpecializedCollections.EmptyEnumerable<TypeInferenceInfo>();
P
Pilchie 已提交
1483 1484
            }

1485
            private IEnumerable<TypeInferenceInfo> InferTypeInNameColon(NameColonSyntax nameColon, SyntaxToken previousToken)
P
Pilchie 已提交
1486 1487 1488 1489
            {
                if (previousToken != nameColon.ColonToken)
                {
                    // Must follow the colon token.
1490
                    return SpecializedCollections.EmptyEnumerable<TypeInferenceInfo>();
P
Pilchie 已提交
1491 1492
                }

C
CyrusNajmabadi 已提交
1493
                if (nameColon.Parent is ArgumentSyntax argumentSyntax)
P
Pilchie 已提交
1494 1495 1496 1497
                {
                    return InferTypeInArgument(argumentSyntax);
                }

1498
                return SpecializedCollections.EmptyEnumerable<TypeInferenceInfo>();
P
Pilchie 已提交
1499 1500
            }

1501
            private IEnumerable<TypeInferenceInfo> InferTypeInMemberAccessExpression(
1502
                MemberAccessExpressionSyntax memberAccessExpression,
1503
                ExpressionSyntax expressionOpt = null,
1504
                SyntaxToken? previousToken = null)
1505
            {
C
CyrusNajmabadi 已提交
1506
                // We need to be on the right of the dot to infer an appropriate type for
1507
                // the member access expression.  i.e. if we have "Goo.Bar" then we can 
C
CyrusNajmabadi 已提交
1508
                // def infer what the type of 'Bar' should be (it's whatever type we infer
1509
                // for 'Goo.Bar' itself.  However, if we're on 'Goo' then we can't figure
C
CyrusNajmabadi 已提交
1510
                // out anything about its type.
1511 1512 1513 1514
                if (previousToken != null)
                {
                    if (previousToken.Value != memberAccessExpression.OperatorToken)
                    {
1515
                        return SpecializedCollections.EmptyEnumerable<TypeInferenceInfo>();
1516 1517
                    }

1518 1519
                    // We're right after the dot in "Goo.Bar".  The type for "Bar" should be
                    // whatever type we'd infer for "Goo.Bar" itself.
C
CyrusNajmabadi 已提交
1520
                    return InferTypes(memberAccessExpression);
1521 1522
                }
                else
1523
                {
1524
                    Debug.Assert(expressionOpt != null);
C
CyrusNajmabadi 已提交
1525
                    if (expressionOpt == memberAccessExpression.Expression)
1526
                    {
C
CyrusNajmabadi 已提交
1527 1528 1529
                        return InferTypeForExpressionOfMemberAccessExpression(memberAccessExpression);
                    }

1530 1531
                    // We're right after the dot in "Goo.Bar".  The type for "Bar" should be
                    // whatever type we'd infer for "Goo.Bar" itself.
C
CyrusNajmabadi 已提交
1532 1533 1534 1535
                    return InferTypes(memberAccessExpression);
                }
            }

1536
            private IEnumerable<TypeInferenceInfo> InferTypeForExpressionOfMemberAccessExpression(
C
CyrusNajmabadi 已提交
1537 1538 1539 1540 1541
                MemberAccessExpressionSyntax memberAccessExpression)
            {
                // If we're on the left side of a dot, it's possible in a few cases
                // to figure out what type we should be.  Specifically, if we have
                //
1542
                //      await goo.ConfigureAwait()
C
CyrusNajmabadi 已提交
1543
                //
1544
                // then we can figure out what 'goo' should be based on teh await
C
CyrusNajmabadi 已提交
1545 1546 1547 1548 1549 1550 1551 1552 1553 1554
                // context.
                var name = memberAccessExpression.Name.Identifier.Value;
                if (name.Equals(nameof(Task<int>.ConfigureAwait)) &&
                    memberAccessExpression.IsParentKind(SyntaxKind.InvocationExpression) &&
                    memberAccessExpression.Parent.IsParentKind(SyntaxKind.AwaitExpression))
                {
                    return InferTypes((ExpressionSyntax)memberAccessExpression.Parent);
                }
                else if (name.Equals(nameof(Task<int>.ContinueWith)))
                {
1555
                    // goo.ContinueWith(...)
C
CyrusNajmabadi 已提交
1556 1557 1558 1559 1560 1561 1562
                    // We want to infer Task<T>.  For now, we'll just do Task<object>,
                    // in the future it would be nice to figure out the actual result
                    // type based on the argument to ContinueWith.
                    var taskOfT = this.Compilation.TaskOfTType();
                    if (taskOfT != null)
                    {
                        return SpecializedCollections.SingletonEnumerable(
1563
                            new TypeInferenceInfo(taskOfT.Construct(this.Compilation.ObjectType)));
C
CyrusNajmabadi 已提交
1564 1565 1566 1567 1568 1569 1570
                    }
                }
                else if (name.Equals(nameof(Enumerable.Select)) ||
                         name.Equals(nameof(Enumerable.Where)))
                {
                    var ienumerableType = this.Compilation.IEnumerableOfTType();

1571
                    // goo.Select
C
CyrusNajmabadi 已提交
1572 1573 1574 1575 1576 1577
                    // We want to infer IEnumerable<T>.  We can try to figure out what 
                    // T if we get a delegate as the first argument to Select/Where.
                    if (ienumerableType != null && memberAccessExpression.IsParentKind(SyntaxKind.InvocationExpression))
                    {
                        var invocation = (InvocationExpressionSyntax)memberAccessExpression.Parent;
                        if (invocation.ArgumentList.Arguments.Count > 0)
1578
                        {
C
CyrusNajmabadi 已提交
1579 1580
                            var argumentExpression = invocation.ArgumentList.Arguments[0].Expression;

1581
                            if (argumentExpression != null)
1582
                            {
1583
                                var argumentTypes = GetTypes(argumentExpression);
1584
                                var delegateType = argumentTypes.FirstOrDefault().InferredType.GetDelegateType(this.Compilation);
1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595
                                var typeArg = delegateType?.TypeArguments.Length > 0
                                    ? delegateType.TypeArguments[0]
                                    : this.Compilation.ObjectType;

                                if (IsUnusableType(typeArg) && argumentExpression is LambdaExpressionSyntax)
                                {
                                    typeArg = InferTypeForFirstParameterOfLambda((LambdaExpressionSyntax)argumentExpression) ??
                                        this.Compilation.ObjectType;
                                }

                                return SpecializedCollections.SingletonEnumerable(
1596
                                    new TypeInferenceInfo(ienumerableType.Construct(typeArg)));
1597 1598
                            }
                        }
1599
                    }
1600
                }
C
CyrusNajmabadi 已提交
1601

1602
                return SpecializedCollections.EmptyEnumerable<TypeInferenceInfo>();
1603 1604
            }

1605 1606 1607
            private ITypeSymbol InferTypeForFirstParameterOfLambda(
                LambdaExpressionSyntax lambdaExpression)
            {
C
CyrusNajmabadi 已提交
1608
                if (lambdaExpression is ParenthesizedLambdaExpressionSyntax parenLambda)
1609
                {
C
CyrusNajmabadi 已提交
1610
                    return InferTypeForFirstParameterOfParenthesizedLambda(parenLambda);
1611
                }
C
CyrusNajmabadi 已提交
1612
                else if (lambdaExpression is SimpleLambdaExpressionSyntax simpleLambda)
1613
                {
C
CyrusNajmabadi 已提交
1614
                    return InferTypeForFirstParameterOfSimpleLambda(simpleLambda);
1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649
                }

                return null;
            }

            private ITypeSymbol InferTypeForFirstParameterOfParenthesizedLambda(
                ParenthesizedLambdaExpressionSyntax lambdaExpression)
            {
                return lambdaExpression.ParameterList.Parameters.Count == 0
                    ? null
                    : InferTypeForFirstParameterOfLambda(
                        lambdaExpression, lambdaExpression.ParameterList.Parameters[0]);
            }

            private ITypeSymbol InferTypeForFirstParameterOfSimpleLambda(
                SimpleLambdaExpressionSyntax lambdaExpression)
            {
                return InferTypeForFirstParameterOfLambda(
                    lambdaExpression, lambdaExpression.Parameter);
            }

            private ITypeSymbol InferTypeForFirstParameterOfLambda(
                LambdaExpressionSyntax lambdaExpression, ParameterSyntax parameter)
            {
                return InferTypeForFirstParameterOfLambda(
                    parameter.Identifier.ValueText, lambdaExpression.Body);
            }

            private ITypeSymbol InferTypeForFirstParameterOfLambda(
                string parameterName,
                SyntaxNode node)
            {
                if (node.IsKind(SyntaxKind.IdentifierName))
                {
                    var identifierName = (IdentifierNameSyntax)node;
1650 1651
                    if (identifierName.Identifier.ValueText.Equals(parameterName) &&
                        SemanticModel.GetSymbolInfo(identifierName.Identifier).Symbol?.Kind == SymbolKind.Parameter)
1652
                    {
1653
                        return InferTypes(identifierName).FirstOrDefault().InferredType;
1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673
                    }
                }
                else
                {
                    foreach (var child in node.ChildNodesAndTokens())
                    {
                        if (child.IsNode)
                        {
                            var type = InferTypeForFirstParameterOfLambda(parameterName, child.AsNode());
                            if (type != null)
                            {
                                return type;
                            }
                        }
                    }
                }

                return null;
            }

1674
            private IEnumerable<TypeInferenceInfo> InferTypeInNameEquals(NameEqualsSyntax nameEquals, SyntaxToken? previousToken = null)
P
Pilchie 已提交
1675 1676 1677 1678 1679 1680 1681 1682
            {
                if (previousToken == nameEquals.EqualsToken)
                {
                    // we're on the right of the equals.  Try to bind the left name to see if it
                    // gives us anything useful.
                    return GetTypes(nameEquals.Name);
                }

C
CyrusNajmabadi 已提交
1683
                if (nameEquals.Parent is AttributeArgumentSyntax attributeArgumentSyntax)
P
Pilchie 已提交
1684 1685 1686 1687 1688
                {
                    var argumentExpression = attributeArgumentSyntax.Expression;
                    return this.GetTypes(argumentExpression);
                }

1689
                return SpecializedCollections.EmptyEnumerable<TypeInferenceInfo>();
P
Pilchie 已提交
1690 1691
            }

1692
            private IEnumerable<TypeInferenceInfo> InferTypeInPostfixUnaryExpression(PostfixUnaryExpressionSyntax postfixUnaryExpressionSyntax, SyntaxToken? previousToken = null)
P
Pilchie 已提交
1693 1694 1695 1696
            {
                // If we're after a postfix ++ or -- then we can't infer anything.
                if (previousToken.HasValue)
                {
1697
                    return SpecializedCollections.EmptyEnumerable<TypeInferenceInfo>();
P
Pilchie 已提交
1698 1699
                }

1700
                switch (postfixUnaryExpressionSyntax.Kind())
P
Pilchie 已提交
1701
                {
1702 1703
                    case SyntaxKind.PostDecrementExpression:
                    case SyntaxKind.PostIncrementExpression:
1704
                        return SpecializedCollections.SingletonEnumerable(new TypeInferenceInfo(this.Compilation.GetSpecialType(SpecialType.System_Int32)));
P
Pilchie 已提交
1705 1706
                }

1707
                return SpecializedCollections.EmptyEnumerable<TypeInferenceInfo>();
P
Pilchie 已提交
1708 1709
            }

1710
            private IEnumerable<TypeInferenceInfo> InferTypeInPrefixUnaryExpression(PrefixUnaryExpressionSyntax prefixUnaryExpression, SyntaxToken? previousToken = null)
P
Pilchie 已提交
1711 1712 1713 1714
            {
                // If we have a position, then we must be after the prefix token.
                Contract.ThrowIfTrue(previousToken.HasValue && previousToken.Value != prefixUnaryExpression.OperatorToken);

1715
                switch (prefixUnaryExpression.Kind())
P
Pilchie 已提交
1716
                {
1717 1718 1719 1720
                    case SyntaxKind.PreDecrementExpression:
                    case SyntaxKind.PreIncrementExpression:
                    case SyntaxKind.UnaryPlusExpression:
                    case SyntaxKind.UnaryMinusExpression:
1721
                        // ++, --, +Goo(), -Goo();
1722
                        return SpecializedCollections.SingletonEnumerable(new TypeInferenceInfo(this.Compilation.GetSpecialType(SpecialType.System_Int32)));
P
Pilchie 已提交
1723

B
Brandon 已提交
1724
                    case SyntaxKind.BitwiseNotExpression:
1725
                        // ~Goo()
1726
                        var types = InferTypes(prefixUnaryExpression);
B
Brandon 已提交
1727 1728
                        if (!types.Any())
                        {
1729
                            return SpecializedCollections.SingletonEnumerable(new TypeInferenceInfo(this.Compilation.GetSpecialType(SpecialType.System_Int32)));
B
Brandon 已提交
1730 1731 1732 1733 1734 1735
                        }
                        else
                        {
                            return types;
                        }

1736
                    case SyntaxKind.LogicalNotExpression:
1737
                        // !Goo()
1738
                        return SpecializedCollections.SingletonEnumerable(new TypeInferenceInfo(this.Compilation.GetSpecialType(SpecialType.System_Boolean)));
P
Pilchie 已提交
1739 1740
                }

1741
                return SpecializedCollections.EmptyEnumerable<TypeInferenceInfo>();
P
Pilchie 已提交
1742 1743
            }

1744
            private IEnumerable<TypeInferenceInfo> InferTypeInAwaitExpression(AwaitExpressionSyntax awaitExpression, SyntaxToken? previousToken = null)
1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756
            {
                // If we have a position, then we must be after the prefix token.
                Contract.ThrowIfTrue(previousToken.HasValue && previousToken.Value != awaitExpression.AwaitKeyword);

                // await <expression>
                var types = InferTypes(awaitExpression);

                var task = this.Compilation.TaskType();
                var taskOfT = this.Compilation.TaskOfTType();

                if (task == null || taskOfT == null)
                {
1757
                    return SpecializedCollections.EmptyEnumerable<TypeInferenceInfo>();
1758 1759 1760 1761
                }

                if (!types.Any())
                {
1762
                    return SpecializedCollections.SingletonEnumerable(new TypeInferenceInfo(task));
1763 1764
                }

1765
                return types.Select(t => t.InferredType.SpecialType == SpecialType.System_Void ? new TypeInferenceInfo(task) : new TypeInferenceInfo(taskOfT.Construct(t.InferredType)));
1766 1767
            }

1768
            private IEnumerable<TypeInferenceInfo> InferTypeInYieldStatement(YieldStatementSyntax yieldStatement, SyntaxToken? previousToken = null)
P
Pilchie 已提交
1769 1770 1771 1772
            {
                // If we are position based, then we have to be after the return keyword
                if (previousToken.HasValue && (previousToken.Value != yieldStatement.ReturnOrBreakKeyword || yieldStatement.ReturnOrBreakKeyword.IsKind(SyntaxKind.BreakKeyword)))
                {
1773
                    return SpecializedCollections.EmptyEnumerable<TypeInferenceInfo>();
P
Pilchie 已提交
1774 1775
                }

Š
Šimon Koníček 已提交
1776
                var declaration = yieldStatement.FirstAncestorOrSelf<SyntaxNode>(n => n.IsReturnableConstruct());
1777
                var memberSymbol = GetDeclaredMemberSymbolFromOriginalSemanticModel(declaration);
P
Pilchie 已提交
1778

1779
                var memberType = GetMemberType(memberSymbol, out _);
P
Pilchie 已提交
1780

C
CyrusNajmabadi 已提交
1781
                if (memberType is INamedTypeSymbol namedType)
P
Pilchie 已提交
1782 1783 1784 1785
                {
                    if (memberType.OriginalDefinition.SpecialType == SpecialType.System_Collections_Generic_IEnumerable_T ||
                        memberType.OriginalDefinition.SpecialType == SpecialType.System_Collections_Generic_IEnumerator_T)
                    {
C
CyrusNajmabadi 已提交
1786
                        return SpecializedCollections.SingletonEnumerable(new TypeInferenceInfo(namedType.TypeArguments[0]));
P
Pilchie 已提交
1787 1788 1789
                    }
                }

1790
                return SpecializedCollections.EmptyEnumerable<TypeInferenceInfo>();
P
Pilchie 已提交
1791 1792
            }

1793
            private static ITypeSymbol GetMemberType(ISymbol memberSymbol, out bool isAsync)
C
CyrusNajmabadi 已提交
1794
            {
1795 1796
                isAsync = false;

C
CyrusNajmabadi 已提交
1797 1798
                switch (memberSymbol)
                {
1799 1800 1801 1802 1803 1804 1805
                    case IMethodSymbol method:
                        isAsync = method.IsAsync;
                        return method.ReturnType;
                    case IPropertySymbol property:
                        return property.Type;
                    case IFieldSymbol field:
                        return field.Type;
C
CyrusNajmabadi 已提交
1806 1807 1808 1809 1810
                }

                return null;
            }

1811 1812 1813
            private IEnumerable<TypeInferenceInfo> InferTypeInRefExpression(RefExpressionSyntax refExpression)
                => InferTypes(refExpression);

1814
            private ITypeSymbol UnwrapTaskLike(ITypeSymbol type, bool isAsync)
P
Pilchie 已提交
1815
            {
1816
                if (isAsync)
1817
                {
1818 1819 1820 1821 1822 1823 1824 1825 1826
                    if (type.OriginalDefinition.Equals(this.Compilation.TaskOfTType()))
                    {
                        return ((INamedTypeSymbol)type).TypeArguments[0];
                    }

                    if (type.OriginalDefinition.Equals(this.Compilation.TaskType()))
                    {
                        return this.Compilation.GetSpecialType(SpecialType.System_Void);
                    }
1827 1828
                }

1829
                return type;
1830 1831
            }

1832 1833
            private IEnumerable<TypeInferenceInfo> InferTypeForReturnStatement(
                ReturnStatementSyntax returnStatement, SyntaxToken? previousToken = null)
1834
            {
P
Pilchie 已提交
1835 1836 1837
                // If we are position based, then we have to be after the return statement.
                if (previousToken.HasValue && previousToken.Value != returnStatement.ReturnKeyword)
                {
1838
                    return SpecializedCollections.EmptyEnumerable<TypeInferenceInfo>();
P
Pilchie 已提交
1839 1840
                }

Š
Šimon Koníček 已提交
1841
                var ancestor = returnStatement.FirstAncestorOrSelf<SyntaxNode>(n => n.IsReturnableConstruct());
B
Basoundr_ms 已提交
1842

1843 1844
                return ancestor is AnonymousFunctionExpressionSyntax anonymousFunction
                    ? InferTypeInAnonymousFunctionExpression(anonymousFunction)
Š
Šimon Koníček 已提交
1845
                    : InferTypeInMethodLikeDeclaration(ancestor);
1846
            }
1847

1848
            private IEnumerable<TypeInferenceInfo> InferTypeInArrowExpressionClause(ArrowExpressionClauseSyntax arrowClause)
Š
Šimon Koníček 已提交
1849
                => InferTypeInMethodLikeDeclaration(arrowClause.Parent);
1850

Š
Šimon Koníček 已提交
1851
            private IEnumerable<TypeInferenceInfo> InferTypeInMethodLikeDeclaration(SyntaxNode declaration)
1852
            {
Š
Šimon Koníček 已提交
1853 1854
                // `declaration` can be a base-method member, property, accessor or local function

1855
                var symbol = GetDeclaredMemberSymbolFromOriginalSemanticModel(declaration);
1856 1857 1858 1859 1860
                var type = GetMemberType(symbol, out var isAsync);

                return type != null
                    ? SpecializedCollections.SingletonEnumerable(new TypeInferenceInfo(UnwrapTaskLike(type, isAsync)))
                    : SpecializedCollections.EmptyEnumerable<TypeInferenceInfo>();
P
Pilchie 已提交
1861 1862
            }

1863
            private ISymbol GetDeclaredMemberSymbolFromOriginalSemanticModel(SyntaxNode declarationInCurrentTree)
P
Pilchie 已提交
1864
            {
1865
                var currentSemanticModel = SemanticModel;
P
Pilchie 已提交
1866 1867
                var originalSemanticModel = currentSemanticModel.GetOriginalSemanticModel();

1868 1869
                if (declarationInCurrentTree is MemberDeclarationSyntax &&
                    currentSemanticModel.IsSpeculativeSemanticModel)
P
Pilchie 已提交
1870
                {
1871
                    var tokenInOriginalTree = originalSemanticModel.SyntaxTree.GetRoot(CancellationToken).FindToken(currentSemanticModel.OriginalPositionForSpeculation);
1872 1873
                    var declaration = tokenInOriginalTree.GetAncestor<MemberDeclarationSyntax>();
                    return originalSemanticModel.GetDeclaredSymbol(declaration, CancellationToken);
P
Pilchie 已提交
1874 1875
                }

1876 1877 1878
                return declarationInCurrentTree != null
                    ? currentSemanticModel.GetDeclaredSymbol(declarationInCurrentTree, CancellationToken)
                    : null;
P
Pilchie 已提交
1879 1880
            }

1881
            private IEnumerable<TypeInferenceInfo> InferTypeInSwitchLabel(
P
Pilchie 已提交
1882 1883 1884 1885
                SwitchLabelSyntax switchLabel, SyntaxToken? previousToken = null)
            {
                if (previousToken.HasValue)
                {
1886
                    if (previousToken.Value != switchLabel.Keyword ||
1887
                        switchLabel.Kind() != SyntaxKind.CaseSwitchLabel)
P
Pilchie 已提交
1888
                    {
1889
                        return SpecializedCollections.EmptyEnumerable<TypeInferenceInfo>();
P
Pilchie 已提交
1890 1891 1892 1893 1894 1895 1896
                    }
                }

                var switchStatement = (SwitchStatementSyntax)switchLabel.Parent.Parent;
                return GetTypes(switchStatement.Expression);
            }

1897
            private IEnumerable<TypeInferenceInfo> InferTypeInSwitchStatement(
P
Pilchie 已提交
1898 1899 1900 1901 1902
                SwitchStatementSyntax switchStatement, SyntaxToken? previousToken = null)
            {
                // If we have a position, then it has to be after "switch("
                if (previousToken.HasValue && previousToken.Value != switchStatement.OpenParenToken)
                {
1903
                    return SpecializedCollections.EmptyEnumerable<TypeInferenceInfo>();
P
Pilchie 已提交
1904 1905 1906
                }

                // Use the first case label to determine the return type.
C
CyrusNajmabadi 已提交
1907 1908
                if (switchStatement.Sections.SelectMany(ss => ss.Labels)
                                                  .FirstOrDefault(label => label.Kind() == SyntaxKind.CaseSwitchLabel) is CaseSwitchLabelSyntax firstCase)
P
Pilchie 已提交
1909 1910 1911 1912 1913 1914 1915 1916
                {
                    var result = GetTypes(firstCase.Value);
                    if (result.Any())
                    {
                        return result;
                    }
                }

1917
                return SpecializedCollections.SingletonEnumerable(new TypeInferenceInfo(this.Compilation.GetSpecialType(SpecialType.System_Int32)));
P
Pilchie 已提交
1918 1919
            }

1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930
            private IEnumerable<TypeInferenceInfo> InferTypeInThrowExpression(ThrowExpressionSyntax throwExpression, SyntaxToken? previousToken = null)
            {
                // If we have a position, it has to be after the 'throw' keyword.
                if (previousToken.HasValue && previousToken.Value != throwExpression.ThrowKeyword)
                {
                    return SpecializedCollections.EmptyEnumerable<TypeInferenceInfo>();
                }

                return SpecializedCollections.SingletonEnumerable(new TypeInferenceInfo(this.Compilation.ExceptionType()));
            }

1931
            private IEnumerable<TypeInferenceInfo> InferTypeInThrowStatement(ThrowStatementSyntax throwStatement, SyntaxToken? previousToken = null)
P
Pilchie 已提交
1932 1933 1934 1935
            {
                // If we have a position, it has to be after the 'throw' keyword.
                if (previousToken.HasValue && previousToken.Value != throwStatement.ThrowKeyword)
                {
1936
                    return SpecializedCollections.EmptyEnumerable<TypeInferenceInfo>();
P
Pilchie 已提交
1937 1938
                }

1939
                return SpecializedCollections.SingletonEnumerable(new TypeInferenceInfo(this.Compilation.ExceptionType()));
P
Pilchie 已提交
1940 1941
            }

1942
            private IEnumerable<TypeInferenceInfo> InferTypeInUsingStatement(UsingStatementSyntax usingStatement, SyntaxToken? previousToken = null)
P
Pilchie 已提交
1943 1944 1945 1946
            {
                // If we have a position, it has to be after "using("
                if (previousToken.HasValue && previousToken.Value != usingStatement.OpenParenToken)
                {
1947
                    return SpecializedCollections.EmptyEnumerable<TypeInferenceInfo>();
P
Pilchie 已提交
1948 1949
                }

1950
                return SpecializedCollections.SingletonEnumerable(new TypeInferenceInfo(this.Compilation.GetSpecialType(SpecialType.System_IDisposable)));
P
Pilchie 已提交
1951 1952
            }

1953
            private IEnumerable<TypeInferenceInfo> InferTypeInVariableDeclarator(VariableDeclaratorSyntax variableDeclarator)
P
Pilchie 已提交
1954 1955
            {
                var variableType = variableDeclarator.GetVariableType();
1956 1957
                if (variableType == null)
                {
1958
                    return SpecializedCollections.EmptyEnumerable<TypeInferenceInfo>();
1959 1960
                }

C
Cyrus Najmabadi 已提交
1961
                var types = GetTypes(variableType).Where(IsUsableTypeFunc);
P
Pilchie 已提交
1962 1963 1964

                if (variableType.IsVar)
                {
C
CyrusNajmabadi 已提交
1965
                    if (variableDeclarator.Parent is VariableDeclarationSyntax variableDeclaration)
P
Pilchie 已提交
1966 1967 1968
                    {
                        if (variableDeclaration.IsParentKind(SyntaxKind.UsingStatement))
                        {
1969
                            // using (var v = Goo())
1970
                            return SpecializedCollections.SingletonEnumerable(new TypeInferenceInfo(this.Compilation.GetSpecialType(SpecialType.System_IDisposable)));
P
Pilchie 已提交
1971 1972 1973 1974
                        }

                        if (variableDeclaration.IsParentKind(SyntaxKind.ForStatement))
                        {
1975
                            // for (var v = Goo(); ..
1976
                            return SpecializedCollections.SingletonEnumerable(new TypeInferenceInfo(this.Compilation.GetSpecialType(SpecialType.System_Int32)));
P
Pilchie 已提交
1977 1978 1979
                        }

                        // Return the types here if they actually bound to a type called 'var'.
1980
                        return types.Where(t => t.InferredType.Name == "var");
P
Pilchie 已提交
1981 1982 1983 1984 1985 1986
                    }
                }

                return types;
            }

1987
            private IEnumerable<TypeInferenceInfo> InferTypeInVariableComponentAssignment(ExpressionSyntax left)
1988
            {
1989
                if (left.IsKind(SyntaxKind.DeclarationExpression))
1990
                {
1991 1992 1993 1994 1995 1996 1997 1998 1999 2000
                    return GetTypes(((DeclarationExpressionSyntax)left).Type);
                }
                else if (left.IsKind(SyntaxKind.TupleExpression))
                {
                    // We have something of the form:
                    //   (int a, int b) = ...
                    //
                    // This is a deconstruction, and a decent deconstructable type we can infer here
                    // is ValueTuple<int,int>.
                    var tupleType = GetTupleType((TupleExpressionSyntax)left);
2001

2002 2003 2004
                    if (tupleType != null)
                    {
                        return SpecializedCollections.SingletonEnumerable(new TypeInferenceInfo(tupleType));
2005 2006 2007 2008 2009 2010 2011
                    }
                }

                return SpecializedCollections.EmptyEnumerable<TypeInferenceInfo>();
            }

            private ITypeSymbol GetTupleType(
2012
                TupleExpressionSyntax tuple)
2013
            {
C
CyrusNajmabadi 已提交
2014
                if (!TryGetTupleTypesAndNames(tuple.Arguments, out var elementTypes, out var elementNames))
2015 2016 2017 2018 2019 2020 2021 2022
                {
                    return null;
                }

                return Compilation.CreateTupleTypeSymbol(elementTypes, elementNames);
            }

            private bool TryGetTupleTypesAndNames(
2023
                SeparatedSyntaxList<ArgumentSyntax> arguments,
2024 2025 2026
                out ImmutableArray<ITypeSymbol> elementTypes,
                out ImmutableArray<string> elementNames)
            {
C
CyrusNajmabadi 已提交
2027 2028
                elementTypes = default;
                elementNames = default;
2029 2030 2031 2032 2033

                var elementTypesBuilder = ArrayBuilder<ITypeSymbol>.GetInstance();
                var elementNamesBuilder = ArrayBuilder<string>.GetInstance();
                try
                {
2034
                    foreach (var arg in arguments)
2035
                    {
2036 2037
                        var expr = arg.Expression;
                        if (expr.IsKind(SyntaxKind.DeclarationExpression))
2038
                        {
2039
                            AddTypeAndName((DeclarationExpressionSyntax)expr, elementTypesBuilder, elementNamesBuilder);
2040
                        }
2041
                        else if (expr.IsKind(SyntaxKind.TupleExpression))
2042
                        {
2043
                            AddTypeAndName((TupleExpressionSyntax)expr, elementTypesBuilder, elementNamesBuilder);
2044
                        }
2045
                        else if (expr is IdentifierNameSyntax name)
2046
                        {
2047 2048
                            elementNamesBuilder.Add(name.Identifier.ValueText == "" ? null : 
                                name.Identifier.ValueText);
2049 2050
                            elementTypesBuilder.Add(GetTypes(expr).FirstOrDefault().InferredType ?? this.Compilation.ObjectType);
                        }
2051 2052 2053 2054
                        else
                        {
                            return false;
                        }
2055 2056
                    }

2057
                    if (elementTypesBuilder.Contains(null) || elementTypesBuilder.Count != arguments.Count)
2058 2059 2060 2061 2062 2063 2064 2065 2066 2067 2068 2069 2070 2071 2072 2073
                    {
                        return false;
                    }

                    elementTypes = elementTypesBuilder.ToImmutable();
                    elementNames = elementNamesBuilder.ToImmutable();
                    return true;
                }
                finally
                {
                    elementTypesBuilder.Free();
                    elementNamesBuilder.Free();
                }
            }

            private void AddTypeAndName(
2074 2075
                DeclarationExpressionSyntax declaration,
                ArrayBuilder<ITypeSymbol> elementTypesBuilder,
2076 2077
                ArrayBuilder<string> elementNamesBuilder)
            {
2078
                elementTypesBuilder.Add(GetTypes(declaration.Type).FirstOrDefault().InferredType);
2079

2080
                var designation = declaration.Designation;
2081 2082 2083
                if (designation.IsKind(SyntaxKind.SingleVariableDesignation))
                {
                    var singleVariable = (SingleVariableDesignationSyntax)designation;
2084 2085 2086 2087 2088 2089 2090
                    var name = singleVariable.Identifier.ValueText;

                    if (name != string.Empty)
                    {
                        elementNamesBuilder.Add(name);
                        return;
                    }
2091
                }
2092 2093

                elementNamesBuilder.Add(null);
2094 2095 2096
            }

            private void AddTypeAndName(
2097 2098
                TupleExpressionSyntax tuple,
                ArrayBuilder<ITypeSymbol> elementTypesBuilder,
2099 2100
                ArrayBuilder<string> elementNamesBuilder)
            {
2101
                var tupleType = GetTupleType(tuple);
2102 2103 2104 2105
                elementTypesBuilder.Add(tupleType);
                elementNamesBuilder.Add(null);
            }

2106 2107 2108 2109 2110 2111 2112 2113 2114 2115 2116
            private IEnumerable<TypeInferenceInfo> InferTypeInWhenClause(WhenClauseSyntax whenClause, SyntaxToken? previousToken = null)
            {
                // If we have a position, we have to be after the "when"
                if (previousToken.HasValue && previousToken.Value != whenClause.WhenKeyword)
                {
                    return SpecializedCollections.EmptyEnumerable<TypeInferenceInfo>();
                }

                return SpecializedCollections.SingletonEnumerable(new TypeInferenceInfo(Compilation.GetSpecialType(SpecialType.System_Boolean)));
            }

2117
            private IEnumerable<TypeInferenceInfo> InferTypeInWhileStatement(WhileStatementSyntax whileStatement, SyntaxToken? previousToken = null)
P
Pilchie 已提交
2118 2119 2120 2121
            {
                // If we're position based, then we have to be after the "while("
                if (previousToken.HasValue && previousToken.Value != whileStatement.OpenParenToken)
                {
2122
                    return SpecializedCollections.EmptyEnumerable<TypeInferenceInfo>();
P
Pilchie 已提交
2123 2124
                }

2125
                return SpecializedCollections.SingletonEnumerable(new TypeInferenceInfo(this.Compilation.GetSpecialType(SpecialType.System_Boolean)));
P
Pilchie 已提交
2126 2127
            }

2128
            private IEnumerable<TypeInferenceInfo> GetCollectionElementType(INamedTypeSymbol type, int parameterIndex)
P
Pilchie 已提交
2129 2130 2131
            {
                if (type != null)
                {
2132 2133 2134 2135 2136
                    var parameters = type.GetAllTypeArguments();

                    var elementType = parameters.ElementAtOrDefault(parameterIndex);
                    if (elementType != null)
                    {
2137
                        return SpecializedCollections.SingletonCollection(new TypeInferenceInfo(elementType));
2138
                    }
P
Pilchie 已提交
2139 2140
                }

2141
                return SpecializedCollections.EmptyEnumerable<TypeInferenceInfo>();
P
Pilchie 已提交
2142 2143 2144 2145
            }
        }
    }
}