CSharpTypeInferenceService.TypeInferrer.cs 108.7 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 12 13
using Microsoft.CodeAnalysis.CSharp.Extensions;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Shared.Extensions;
using Roslyn.Utilities;
14
using Microsoft.CodeAnalysis.LanguageServices;
P
Pilchie 已提交
15 16 17 18 19

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

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

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

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

45
            private static bool DecomposeBinaryOrAssignmentExpression(ExpressionSyntax expression, out SyntaxToken operatorToken, out ExpressionSyntax left, out ExpressionSyntax right)
P
Pilchie 已提交
46 47 48 49
            {
                var binaryExpression = expression as BinaryExpressionSyntax;
                if (binaryExpression != null)
                {
50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69
                    operatorToken = binaryExpression.OperatorToken;
                    left = binaryExpression.Left;
                    right = binaryExpression.Right;
                    return true;
                }

                var assignmentExpression = expression as AssignmentExpressionSyntax;
                if (assignmentExpression != null)
                {
                    operatorToken = assignmentExpression.OperatorToken;
                    left = assignmentExpression.Left;
                    right = assignmentExpression.Right;
                    return true;
                }

                operatorToken = default(SyntaxToken);
                left = right = null;
                return false;
            }

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

                    return types;
                }

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

89
            private IEnumerable<TypeInferenceInfo> GetTypesSimple(ExpressionSyntax expression)
P
Pilchie 已提交
90 91 92
            {
                if (expression != null)
                {
93 94
                    var typeInfo = SemanticModel.GetTypeInfo(expression, CancellationToken);
                    var symbolInfo = SemanticModel.GetSymbolInfo(expression, CancellationToken);
P
Pilchie 已提交
95 96 97

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

                        // If it bound to a method, try to get the Action/Func form of that method.
R
Ravi Chande 已提交
101
                        if (typeInferenceInfo.InferredType == null &&
P
Pilchie 已提交
102 103 104 105
                            symbolInfo.GetAllSymbols().Count() == 1 &&
                            symbolInfo.GetAllSymbols().First().Kind == SymbolKind.Method)
                        {
                            var method = symbolInfo.GetAllSymbols().First();
R
Ravi Chande 已提交
106
                            typeInferenceInfo = new TypeInferenceInfo(method.ConvertToType(this.Compilation));
P
Pilchie 已提交
107 108
                        }

R
Ravi Chande 已提交
109
                        if (IsUsableTypeFunc(typeInferenceInfo))
P
Pilchie 已提交
110
                        {
R
Ravi Chande 已提交
111
                            return SpecializedCollections.SingletonEnumerable(typeInferenceInfo);
P
Pilchie 已提交
112 113 114 115
                        }
                    }
                }

116
                return SpecializedCollections.EmptyEnumerable<TypeInferenceInfo>();
P
Pilchie 已提交
117 118
            }

119
            protected override IEnumerable<TypeInferenceInfo> InferTypesWorker_DoNotCallDirectly(
120
                ExpressionSyntax expression)
P
Pilchie 已提交
121 122 123 124
            {
                expression = expression.WalkUpParentheses();
                var parent = expression.Parent;

C
CyrusNajmabadi 已提交
125 126 127 128 129 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 160 161 162 163 164 165 166 167
                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);
                    case ParenthesizedLambdaExpressionSyntax parenthesizedLambdaExpression: return InferTypeInParenthesizedLambdaExpression(parenthesizedLambdaExpression);
                    case PostfixUnaryExpressionSyntax postfixUnary: return InferTypeInPostfixUnaryExpression(postfixUnary);
                    case PrefixUnaryExpressionSyntax prefixUnary: return InferTypeInPrefixUnaryExpression(prefixUnary);
                    case ReturnStatementSyntax returnStatement: return InferTypeForReturnStatement(returnStatement);
                    case SimpleLambdaExpressionSyntax simpleLambdaExpression: return InferTypeInSimpleLambdaExpression(simpleLambdaExpression);
                    case SwitchLabelSyntax switchLabel: return InferTypeInSwitchLabel(switchLabel);
                    case SwitchStatementSyntax switchStatement: return InferTypeInSwitchStatement(switchStatement);
                    case ThrowStatementSyntax throwStatement: return InferTypeInThrowStatement(throwStatement);
                    case UsingStatementSyntax usingStatement: return InferTypeInUsingStatement(usingStatement);
                    case WhileStatementSyntax whileStatement: return InferTypeInWhileStatement(whileStatement);
                    case YieldStatementSyntax yieldStatement: return InferTypeInYieldStatement(yieldStatement);
                    default: return SpecializedCollections.EmptyEnumerable<TypeInferenceInfo>();
                }
P
Pilchie 已提交
168 169
            }

170
            private IEnumerable<TypeInferenceInfo> InferTypeInArrowExpressionClause(ArrowExpressionClauseSyntax arrowClause)
171 172 173 174 175 176 177 178 179 180 181
            {
                if (arrowClause.IsParentKind(SyntaxKind.PropertyDeclaration))
                {
                    return InferTypeInPropertyDeclaration(arrowClause.Parent as PropertyDeclarationSyntax);
                }

                if (arrowClause.Parent is BaseMethodDeclarationSyntax)
                {
                    return InferTypeInBaseMethodDeclaration(arrowClause.Parent as BaseMethodDeclarationSyntax);
                }

182
                return SpecializedCollections.EmptyEnumerable<TypeInferenceInfo>();
183 184
            }

185
            protected override IEnumerable<TypeInferenceInfo> InferTypesWorker_DoNotCallDirectly(int position)
P
Pilchie 已提交
186
            {
187 188
                var syntaxTree = SemanticModel.SyntaxTree;
                var token = syntaxTree.FindTokenOnLeftOfPosition(position, CancellationToken);
P
Pilchie 已提交
189
                token = token.GetPreviousTokenIfTouchingWord(position);
190

C
Cyrus Najmabadi 已提交
191 192
                var parent = token.Parent;

C
CyrusNajmabadi 已提交
193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240
                switch (parent)
                {
                    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);
                    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);
                    case ParenthesizedLambdaExpressionSyntax parenthesizedLambdaExpression: return InferTypeInParenthesizedLambdaExpression(parenthesizedLambdaExpression, token);
                    case PostfixUnaryExpressionSyntax postfixUnary: return InferTypeInPostfixUnaryExpression(postfixUnary, token);
                    case PrefixUnaryExpressionSyntax prefixUnary: return InferTypeInPrefixUnaryExpression(prefixUnary, token);
                    case ReturnStatementSyntax returnStatement: return InferTypeForReturnStatement(returnStatement, token);
                    case SimpleLambdaExpressionSyntax simpleLambdaExpression: return InferTypeInSimpleLambdaExpression(simpleLambdaExpression, 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);
                    case WhileStatementSyntax whileStatement: return InferTypeInWhileStatement(whileStatement, token);
                    case YieldStatementSyntax yieldStatement: return InferTypeInYieldStatement(yieldStatement, token);
                    default: return SpecializedCollections.EmptyEnumerable<TypeInferenceInfo>();
                }
P
Pilchie 已提交
241 242
            }

243
            private IEnumerable<TypeInferenceInfo> InferTypeInArgument(
244
                ArgumentSyntax argument, SyntaxToken? previousToken = null)
P
Pilchie 已提交
245 246 247 248 249 250
            {
                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)
                    {
251
                        return SpecializedCollections.EmptyEnumerable<TypeInferenceInfo>();
P
Pilchie 已提交
252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298
                    }
                }

                if (argument.Parent != null)
                {
                    var initializer = argument.Parent.Parent as ConstructorInitializerSyntax;
                    if (initializer != null)
                    {
                        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))
                    {
                        // new Outer(Foo());
                        //
                        // new Outer(a: Foo());
                        //
                        // 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))
                    {
                        // Outer[Foo()];
                        //
                        // Outer[a: Foo()];
                        //
                        // etc.
                        var elementAccess = argument.Parent.Parent as ElementAccessExpressionSyntax;
                        var index = elementAccess.ArgumentList.Arguments.IndexOf(argument);

                        return InferTypeInElementAccessExpression(elementAccess, index, argument);
                    }
                }

299 300 301 302 303 304
                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;
305
                    var types = GetTypes(objectCreation).Select(t => t.InferredType);
306

307
                    if (types.Any(t => t is INamedTypeSymbol))
308 309 310 311 312 313 314
                    {
                        return types.OfType<INamedTypeSymbol>().SelectMany(t =>
                            GetCollectionElementType(t,
                                parameterIndex: 0));
                    }
                }

315
                return SpecializedCollections.EmptyEnumerable<TypeInferenceInfo>();
P
Pilchie 已提交
316 317
            }

318
            private IEnumerable<TypeInferenceInfo> InferTypeInAttributeArgument(AttributeArgumentSyntax argument, SyntaxToken? previousToken = null, ArgumentSyntax argumentOpt = null)
P
Pilchie 已提交
319 320 321 322 323 324
            {
                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)
                    {
325
                        return SpecializedCollections.EmptyEnumerable<TypeInferenceInfo>();
P
Pilchie 已提交
326 327 328 329 330 331 332 333 334 335 336 337 338
                    }
                }

                if (argument.Parent != null)
                {
                    var attribute = argument.Parent.Parent as AttributeSyntax;
                    if (attribute != null)
                    {
                        var index = attribute.ArgumentList.Arguments.IndexOf(argument);
                        return InferTypeInAttribute(attribute, index, argument);
                    }
                }

339
                return SpecializedCollections.EmptyEnumerable<TypeInferenceInfo>();
P
Pilchie 已提交
340 341
            }

342
            private IEnumerable<TypeInferenceInfo> InferTypeInConstructorInitializer(ConstructorInitializerSyntax initializer, int index, ArgumentSyntax argument = null)
P
Pilchie 已提交
343
            {
344
                var info = SemanticModel.GetSymbolInfo(initializer, CancellationToken);
P
Pilchie 已提交
345 346 347 348
                var methods = info.GetBestOrAllSymbols().OfType<IMethodSymbol>();
                return InferTypeInArgument(index, methods, argument);
            }

349
            private IEnumerable<TypeInferenceInfo> InferTypeInObjectCreationExpression(ObjectCreationExpressionSyntax expression, SyntaxToken previousToken)
350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379
            {
                // 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.
                if (previousToken.Kind() == SyntaxKind.NewKeyword &&
                    previousToken.GetPreviousToken().Kind() == SyntaxKind.EqualsToken)
                {
                    return InferTypes(previousToken.SpanStart);
                }

                return InferTypes(expression);
            }

380
            private IEnumerable<TypeInferenceInfo> InferTypeInObjectCreationExpression(ObjectCreationExpressionSyntax creation, int index, ArgumentSyntax argumentOpt = null)
P
Pilchie 已提交
381
            {
382
                var info = SemanticModel.GetSymbolInfo(creation.Type, CancellationToken);
P
Pilchie 已提交
383 384 385 386
                var type = info.Symbol as INamedTypeSymbol;

                if (type == null)
                {
387
                    return SpecializedCollections.EmptyEnumerable<TypeInferenceInfo>();
P
Pilchie 已提交
388 389 390 391 392 393 394 395
                }

                if (type.TypeKind == TypeKind.Delegate)
                {
                    // new SomeDelegateType( here );
                    //
                    // They're actually instantiating a delegate, so the delegate type is
                    // that type.
396
                    return SpecializedCollections.SingletonEnumerable(new TypeInferenceInfo(type));
P
Pilchie 已提交
397 398 399 400 401 402
                }

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

403
            private IEnumerable<TypeInferenceInfo> InferTypeInInvocationExpression(
P
Pilchie 已提交
404 405 406 407 408 409
                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.
410
                var info = SemanticModel.GetSymbolInfo(invocation, CancellationToken);
P
Pilchie 已提交
411 412 413 414 415 416 417
                IEnumerable<IMethodSymbol> methods = null;

                // 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.
                if (info.CandidateReason == CandidateReason.None)
                {
418
                    methods = SemanticModel.GetMemberGroup(invocation.Expression, CancellationToken)
P
Pilchie 已提交
419 420 421 422 423 424 425 426 427 428
                                                            .OfType<IMethodSymbol>();
                }
                else
                {
                    methods = info.GetBestOrAllSymbols().OfType<IMethodSymbol>();
                }

                return InferTypeInArgument(index, methods, argumentOpt);
            }

429
            private IEnumerable<TypeInferenceInfo> InferTypeInArgumentList(ArgumentListSyntax argumentList, SyntaxToken previousToken)
P
Pilchie 已提交
430 431
            {
                // Has to follow the ( or a ,
432
                if (previousToken != argumentList.OpenParenToken && previousToken.Kind() != SyntaxKind.CommaToken)
P
Pilchie 已提交
433
                {
434
                    return SpecializedCollections.EmptyEnumerable<TypeInferenceInfo>();
P
Pilchie 已提交
435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457
                }

                var invocation = argumentList.Parent as InvocationExpressionSyntax;
                if (invocation != null)
                {
                    var index = this.GetArgumentListIndex(argumentList, previousToken);
                    return InferTypeInInvocationExpression(invocation, index);
                }

                var objectCreation = argumentList.Parent as ObjectCreationExpressionSyntax;
                if (objectCreation != null)
                {
                    var index = this.GetArgumentListIndex(argumentList, previousToken);
                    return InferTypeInObjectCreationExpression(objectCreation, index);
                }

                var constructorInitializer = argumentList.Parent as ConstructorInitializerSyntax;
                if (constructorInitializer != null)
                {
                    var index = this.GetArgumentListIndex(argumentList, previousToken);
                    return InferTypeInConstructorInitializer(constructorInitializer, index);
                }

458
                return SpecializedCollections.EmptyEnumerable<TypeInferenceInfo>();
P
Pilchie 已提交
459 460
            }

461
            private IEnumerable<TypeInferenceInfo> InferTypeInAttributeArgumentList(AttributeArgumentListSyntax attributeArgumentList, SyntaxToken previousToken)
P
Pilchie 已提交
462 463
            {
                // Has to follow the ( or a ,
464
                if (previousToken != attributeArgumentList.OpenParenToken && previousToken.Kind() != SyntaxKind.CommaToken)
P
Pilchie 已提交
465
                {
466
                    return SpecializedCollections.EmptyEnumerable<TypeInferenceInfo>();
P
Pilchie 已提交
467 468 469 470 471 472 473 474 475
                }

                var attribute = attributeArgumentList.Parent as AttributeSyntax;
                if (attribute != null)
                {
                    var index = this.GetArgumentListIndex(attributeArgumentList, previousToken);
                    return InferTypeInAttribute(attribute, index);
                }

476
                return SpecializedCollections.EmptyEnumerable<TypeInferenceInfo>();
P
Pilchie 已提交
477 478
            }

479
            private IEnumerable<TypeInferenceInfo> InferTypeInAttribute(AttributeSyntax attribute, int index, AttributeArgumentSyntax argumentOpt = null)
P
Pilchie 已提交
480
            {
481
                var info = SemanticModel.GetSymbolInfo(attribute, CancellationToken);
P
Pilchie 已提交
482 483 484 485
                var methods = info.GetBestOrAllSymbols().OfType<IMethodSymbol>();
                return InferTypeInAttributeArgument(index, methods, argumentOpt);
            }

486
            private IEnumerable<TypeInferenceInfo> InferTypeInElementAccessExpression(
P
Pilchie 已提交
487 488
                ElementAccessExpressionSyntax elementAccess, int index, ArgumentSyntax argumentOpt = null)
            {
489
                var info = SemanticModel.GetTypeInfo(elementAccess.Expression, CancellationToken);
P
Pilchie 已提交
490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508
                var type = info.Type as INamedTypeSymbol;
                if (type != null)
                {
                    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.
509
                return SpecializedCollections.SingletonEnumerable(new TypeInferenceInfo(this.Compilation.GetSpecialType(SpecialType.System_Int32)));
P
Pilchie 已提交
510 511
            }

512
            private IEnumerable<TypeInferenceInfo> InferTypeInAttributeArgument(int index, IEnumerable<IMethodSymbol> methods, AttributeArgumentSyntax argumentOpt = null)
P
Pilchie 已提交
513 514 515 516
            {
                return InferTypeInAttributeArgument(index, methods.Select(m => m.Parameters), argumentOpt);
            }

517
            private IEnumerable<TypeInferenceInfo> InferTypeInArgument(int index, IEnumerable<IMethodSymbol> methods, ArgumentSyntax argumentOpt)
P
Pilchie 已提交
518
            {
519 520 521 522 523 524 525 526 527
                if (argumentOpt != null)
                {
                    var invocation = argumentOpt?.Parent?.Parent as InvocationExpressionSyntax;
                    if (invocation != null)
                    {
                        // 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.
528
                        var invocationTypes = this.InferTypes(invocation).Select(t => t.InferredType).ToList();
529
                        var instantiatedMethods = methods.Select(m => Instantiate(m, invocationTypes)).ToList();
C
Cyrus Najmabadi 已提交
530 531 532 533

                        // 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.
534 535
                        var filteredMethods = instantiatedMethods.Where(m =>
                            invocationTypes.Any(t => Compilation.ClassifyConversion(m.ReturnType, t).IsImplicit)).ToList();
C
Cyrus Najmabadi 已提交
536 537 538

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

P
Pilchie 已提交
543 544 545
                return InferTypeInArgument(index, methods.Select(m => m.Parameters), argumentOpt);
            }

546 547 548 549 550 551 552 553 554
            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 已提交
555 556 557
                // 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.
558 559 560 561 562 563 564
                if (method.ReturnsVoid)
                {
                    return method;
                }

                // If the method has already been constructed poorly (i.e. with error types for type 
                // arguments), then unconstruct it.
565
                if (method.TypeArguments.Any(t => t.Kind == SymbolKind.ErrorType))
566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587
                {
                    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();
588
                return method.ConstructedFrom.Construct(typeArguments);
589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 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
            }

            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;
                }
643
            }
644

645
            private IEnumerable<TypeInferenceInfo> InferTypeInAttributeArgument(
P
Pilchie 已提交
646 647 648 649 650 651 652 653 654 655 656 657 658 659 660
                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;
                return InferTypeInArgument(index, parameterizedSymbols, name);
            }

661
            private IEnumerable<TypeInferenceInfo> InferTypeInArgument(
P
Pilchie 已提交
662 663 664 665 666 667 668 669
                int index,
                IEnumerable<ImmutableArray<IParameterSymbol>> parameterizedSymbols,
                ArgumentSyntax argumentOpt)
            {
                var name = argumentOpt != null && argumentOpt.NameColon != null ? argumentOpt.NameColon.Name.Identifier.ValueText : null;
                return InferTypeInArgument(index, parameterizedSymbols, name);
            }

670
            private IEnumerable<TypeInferenceInfo> InferTypeInArgument(
P
Pilchie 已提交
671 672 673 674 675 676 677 678 679 680
                int index,
                IEnumerable<ImmutableArray<IParameterSymbol>> parameterizedSymbols,
                string name)
            {
                // 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)
                {
                    var parameters = parameterizedSymbols.SelectMany(m => m)
                                                        .Where(p => p.Name == name)
681
                                                        .Select(p => new TypeInferenceInfo(p.Type, p.IsParams));
P
Pilchie 已提交
682 683 684 685 686 687 688 689 690 691 692
                    if (parameters.Any())
                    {
                        return parameters;
                    }
                }
                else
                {
                    // Otherwise, just take the first overload and pick what type this parameter is
                    // based on index.
                    var q = from parameterSet in parameterizedSymbols
                            where index < parameterSet.Length
693 694
                            let param = parameterSet[index]
                            select new TypeInferenceInfo(param.Type, param.IsParams);
P
Pilchie 已提交
695 696 697 698

                    return q;
                }

699
                return SpecializedCollections.EmptyEnumerable<TypeInferenceInfo>();
P
Pilchie 已提交
700 701
            }

702
            private IEnumerable<TypeInferenceInfo> InferTypeInArrayCreationExpression(
P
Pilchie 已提交
703 704 705 706 707
                ArrayCreationExpressionSyntax arrayCreationExpression, SyntaxToken? previousToken = null)
            {
                if (previousToken.HasValue && previousToken.Value != arrayCreationExpression.NewKeyword)
                {
                    // Has to follow the 'new' keyword. 
708
                    return SpecializedCollections.EmptyEnumerable<TypeInferenceInfo>();
P
Pilchie 已提交
709 710
                }

R
Ravi Chande 已提交
711
                if (previousToken.HasValue && previousToken.Value.GetPreviousToken().Kind() == SyntaxKind.EqualsToken)
R
Ravi Chande 已提交
712 713 714 715 716 717 718 719 720 721 722 723 724 725
                {
                    // 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 已提交
726
                var outerTypes = InferTypes(arrayCreationExpression);
R
Ravi Chande 已提交
727
                return outerTypes.Where(o => o.InferredType is IArrayTypeSymbol);
P
Pilchie 已提交
728 729
            }

730
            private IEnumerable<TypeInferenceInfo> InferTypeInArrayRankSpecifier(ArrayRankSpecifierSyntax arrayRankSpecifier, SyntaxToken? previousToken = null)
P
Pilchie 已提交
731 732 733 734 735
            {
                // If we have a token, and it's not the open bracket or one of the commas, then no
                // inference.
                if (previousToken == arrayRankSpecifier.CloseBracketToken)
                {
736
                    return SpecializedCollections.EmptyEnumerable<TypeInferenceInfo>();
P
Pilchie 已提交
737 738
                }

739
                return SpecializedCollections.SingletonEnumerable(new TypeInferenceInfo(this.Compilation.GetSpecialType(SpecialType.System_Int32)));
P
Pilchie 已提交
740 741
            }

742
            private IEnumerable<TypeInferenceInfo> InferTypeInArrayType(ArrayTypeSyntax arrayType, SyntaxToken? previousToken = null)
P
Pilchie 已提交
743 744 745 746
            {
                if (previousToken.HasValue)
                {
                    // TODO(cyrusn): NYI.  Handle this appropriately if we need to.
747
                    return SpecializedCollections.EmptyEnumerable<TypeInferenceInfo>();
P
Pilchie 已提交
748 749 750 751 752 753 754
                }

                // 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++)
                {
755 756
                    currentTypes = currentTypes.Where(c => c.InferredType is IArrayTypeSymbol)
                        .Select(c => new TypeInferenceInfo(((IArrayTypeSymbol)c.InferredType).ElementType));
P
Pilchie 已提交
757 758 759 760
                }
                return currentTypes;
            }

761
            private IEnumerable<TypeInferenceInfo> InferTypeInAttribute(AttributeSyntax attribute)
P
Pilchie 已提交
762
            {
763
                return SpecializedCollections.SingletonEnumerable(new TypeInferenceInfo(this.Compilation.AttributeType()));
P
Pilchie 已提交
764 765
            }

766
            private IEnumerable<TypeInferenceInfo> InferTypeInAttributeDeclaration(AttributeListSyntax attributeDeclaration, SyntaxToken? previousToken)
P
Pilchie 已提交
767 768 769 770
            {
                // If we have a position, then it has to be after the open bracket.
                if (previousToken.HasValue && previousToken.Value != attributeDeclaration.OpenBracketToken)
                {
771
                    return SpecializedCollections.EmptyEnumerable<TypeInferenceInfo>();
P
Pilchie 已提交
772 773
                }

774
                return SpecializedCollections.SingletonEnumerable(new TypeInferenceInfo(this.Compilation.AttributeType()));
P
Pilchie 已提交
775 776
            }

777
            private IEnumerable<TypeInferenceInfo> InferTypeInAttributeTargetSpecifier(
P
Pilchie 已提交
778 779 780 781 782 783
                AttributeTargetSpecifierSyntax attributeTargetSpecifier,
                SyntaxToken? previousToken)
            {
                // If we have a position, then it has to be after the colon.
                if (previousToken.HasValue && previousToken.Value != attributeTargetSpecifier.ColonToken)
                {
784
                    return SpecializedCollections.EmptyEnumerable<TypeInferenceInfo>();
P
Pilchie 已提交
785 786
                }

787
                return SpecializedCollections.SingletonEnumerable(new TypeInferenceInfo(this.Compilation.AttributeType()));
P
Pilchie 已提交
788 789
            }

790
            private IEnumerable<TypeInferenceInfo> InferTypeInBracketedArgumentList(BracketedArgumentListSyntax bracketedArgumentList, SyntaxToken previousToken)
P
Pilchie 已提交
791 792
            {
                // Has to follow the [ or a ,
793
                if (previousToken != bracketedArgumentList.OpenBracketToken && previousToken.Kind() != SyntaxKind.CommaToken)
P
Pilchie 已提交
794
                {
795
                    return SpecializedCollections.EmptyEnumerable<TypeInferenceInfo>();
P
Pilchie 已提交
796 797 798 799 800 801 802 803 804 805
                }

                var elementAccess = bracketedArgumentList.Parent as ElementAccessExpressionSyntax;
                if (elementAccess != null)
                {
                    var index = GetArgumentListIndex(bracketedArgumentList, previousToken);
                    return InferTypeInElementAccessExpression(
                        elementAccess, index);
                }

806
                return SpecializedCollections.EmptyEnumerable<TypeInferenceInfo>();
P
Pilchie 已提交
807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846
            }

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

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

853
                if (binop.Kind() == SyntaxKind.CoalesceExpression)
P
Pilchie 已提交
854
                {
855
                    return InferTypeInCoalesceExpression((BinaryExpressionSyntax)binop, expressionOpt, previousToken);
P
Pilchie 已提交
856 857
                }

858
                var onRightOfToken = right == expressionOpt || previousToken.HasValue;
859
                switch (operatorToken.Kind())
P
Pilchie 已提交
860
                {
861 862 863 864
                    case SyntaxKind.LessThanLessThanToken:
                    case SyntaxKind.GreaterThanGreaterThanToken:
                    case SyntaxKind.LessThanLessThanEqualsToken:
                    case SyntaxKind.GreaterThanGreaterThanEqualsToken:
P
Pilchie 已提交
865

866 867 868
                        if (onRightOfToken)
                        {
                            // x << Foo(), x >> Foo(), x <<= Foo(), x >>= Foo()
869
                            return SpecializedCollections.SingletonEnumerable(new TypeInferenceInfo(this.Compilation.GetSpecialType(SpecialType.System_Int32)));
870
                        }
P
Pilchie 已提交
871

872
                        break;
P
Pilchie 已提交
873 874 875
                }

                // Infer operands of && and || as bool regardless of the other operand.
876 877
                if (operatorToken.Kind() == SyntaxKind.AmpersandAmpersandToken ||
                    operatorToken.Kind() == SyntaxKind.BarBarToken)
P
Pilchie 已提交
878
                {
879
                    return SpecializedCollections.SingletonEnumerable(new TypeInferenceInfo(this.Compilation.GetSpecialType(SpecialType.System_Boolean)));
P
Pilchie 已提交
880 881
                }

882 883 884 885 886 887 888
                // Infer type for deconstruction
                if (binop.Kind() == SyntaxKind.SimpleAssignmentExpression &&
                    ((AssignmentExpressionSyntax)binop).IsDeconstruction())
                {
                    return InferTypeInVariableComponentAssignment(left);
                }

P
Pilchie 已提交
889 890 891 892
                // 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.
893
                var otherSide = onRightOfToken ? left : right;
P
Pilchie 已提交
894 895 896 897 898 899 900 901 902

                var otherSideTypes = GetTypes(otherSide);
                if (otherSideTypes.Any())
                {
                    return otherSideTypes;
                }

                // For &, &=, |, |=, ^, and ^=, since we couldn't infer the type of either side, 
                // try to infer the type of the entire binary expression.
903 904 905 906 907 908
                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 已提交
909 910 911 912 913 914 915 916 917 918
                {
                    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.
919
                if (operatorToken.Kind() == SyntaxKind.PlusToken)
P
Pilchie 已提交
920 921 922 923 924
                {
                    // 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);
925
                    if (parentTypes.Any(parentType => parentType.InferredType.SpecialType == SpecialType.System_String || parentType.InferredType.TypeKind == TypeKind.Delegate))
P
Pilchie 已提交
926
                    {
927
                        return parentTypes.Where(parentType => parentType.InferredType.SpecialType == SpecialType.System_String || parentType.InferredType.TypeKind == TypeKind.Delegate);
P
Pilchie 已提交
928 929 930 931
                    }
                }

                // Otherwise pick some sane defaults for certain common cases.
932
                switch (operatorToken.Kind())
P
Pilchie 已提交
933
                {
934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955
                    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:
956
                        return SpecializedCollections.SingletonEnumerable(new TypeInferenceInfo(this.Compilation.GetSpecialType(SpecialType.System_Int32)));
957 958 959 960 961

                    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,
962
                        // I'm just defaulting to bool based on personal preference.
963
                        return SpecializedCollections.SingletonEnumerable(new TypeInferenceInfo(this.Compilation.GetSpecialType(SpecialType.System_Boolean)));
P
Pilchie 已提交
964 965
                }

966
                return SpecializedCollections.EmptyEnumerable<TypeInferenceInfo>();
P
Pilchie 已提交
967 968
            }

969
            private IEnumerable<TypeInferenceInfo> InferTypeInCastExpression(CastExpressionSyntax castExpression, ExpressionSyntax expressionOpt = null, SyntaxToken? previousToken = null)
P
Pilchie 已提交
970 971 972
            {
                if (expressionOpt != null && castExpression.Expression != expressionOpt)
                {
973
                    return SpecializedCollections.EmptyEnumerable<TypeInferenceInfo>();
P
Pilchie 已提交
974 975 976 977 978
                }

                // If we have a position, then it has to be after the close paren.
                if (previousToken.HasValue && previousToken.Value != castExpression.CloseParenToken)
                {
979
                    return SpecializedCollections.EmptyEnumerable<TypeInferenceInfo>();
P
Pilchie 已提交
980 981 982 983 984
                }

                return this.GetTypes(castExpression.Type);
            }

985
            private IEnumerable<TypeInferenceInfo> InferTypeInCatchDeclaration(CatchDeclarationSyntax catchDeclaration, SyntaxToken? previousToken = null)
P
Pilchie 已提交
986
            {
987
                // If we have a position, it has to be after "catch("
P
Pilchie 已提交
988 989
                if (previousToken.HasValue && previousToken.Value != catchDeclaration.OpenParenToken)
                {
990
                    return SpecializedCollections.EmptyEnumerable<TypeInferenceInfo>();
P
Pilchie 已提交
991 992
                }

993
                return SpecializedCollections.SingletonEnumerable(new TypeInferenceInfo(this.Compilation.ExceptionType()));
P
Pilchie 已提交
994 995
            }

996
            private IEnumerable<TypeInferenceInfo> InferTypeInCatchFilterClause(CatchFilterClauseSyntax catchFilterClause, SyntaxToken? previousToken = null)
997 998 999 1000
            {
                // If we have a position, it has to be after "if ("
                if (previousToken.HasValue && previousToken.Value != catchFilterClause.OpenParenToken)
                {
1001
                    return SpecializedCollections.EmptyEnumerable<TypeInferenceInfo>();
1002 1003
                }

1004
                return SpecializedCollections.SingletonEnumerable(new TypeInferenceInfo(this.Compilation.GetSpecialType(SpecialType.System_Boolean)));
1005 1006
            }

1007
            private IEnumerable<TypeInferenceInfo> InferTypeInCoalesceExpression(
P
Pilchie 已提交
1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020
                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
1021 1022
                        .Select(x => x.InferredType.IsNullable()
                            ? new TypeInferenceInfo(((INamedTypeSymbol)x.InferredType).TypeArguments[0]) // nullableExpr ?? Foo()
1023
                            : x); // normalExpr ?? Foo() 
P
Pilchie 已提交
1024 1025 1026 1027 1028
                }

                var rightTypes = GetTypes(coalesceExpression.Right);
                if (!rightTypes.Any())
                {
1029
                    return SpecializedCollections.SingletonEnumerable(new TypeInferenceInfo(Compilation.GetSpecialType(SpecialType.System_Object)));
P
Pilchie 已提交
1030 1031 1032
                }

                return rightTypes
1033 1034
                    .Select(x => x.InferredType.IsValueType
                                     ? new TypeInferenceInfo(this.Compilation.GetSpecialType(SpecialType.System_Nullable_T).Construct(x.InferredType)) // Foo() ?? 0
P
Pilchie 已提交
1035 1036 1037
                                     : x); // Foo() ?? ""
            }

1038
            private IEnumerable<TypeInferenceInfo> InferTypeInConditionalAccessExpression(ConditionalAccessExpressionSyntax expression)
1039 1040 1041 1042
            {
                return InferTypes(expression);
            }

1043
            private IEnumerable<TypeInferenceInfo> InferTypeInConditionalExpression(ConditionalExpressionSyntax conditional, ExpressionSyntax expressionOpt = null, SyntaxToken? previousToken = null)
P
Pilchie 已提交
1044 1045 1046 1047
            {
                if (expressionOpt != null && conditional.Condition == expressionOpt)
                {
                    // Foo() ? a : b
1048
                    return SpecializedCollections.SingletonEnumerable(new TypeInferenceInfo(this.Compilation.GetSpecialType(SpecialType.System_Boolean)));
P
Pilchie 已提交
1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065
                }

                // a ? Foo() : b
                //
                // a ? b : Foo()
                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)
1066
                                           : SpecializedCollections.EmptyEnumerable<TypeInferenceInfo>();
P
Pilchie 已提交
1067 1068 1069 1070 1071 1072

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

1073
            private IEnumerable<TypeInferenceInfo> InferTypeInDefaultExpression(DefaultExpressionSyntax defaultExpression)
R
Ravi Chande 已提交
1074 1075 1076 1077
            {
                return InferTypes(defaultExpression);
            }

1078
            private IEnumerable<TypeInferenceInfo> InferTypeInDoStatement(DoStatementSyntax doStatement, SyntaxToken? previousToken = null)
P
Pilchie 已提交
1079 1080 1081 1082
            {
                // If we have a position, we need to be after "do { } while("
                if (previousToken.HasValue && previousToken.Value != doStatement.OpenParenToken)
                {
1083
                    return SpecializedCollections.EmptyEnumerable<TypeInferenceInfo>();
P
Pilchie 已提交
1084 1085
                }

1086
                return SpecializedCollections.SingletonEnumerable(new TypeInferenceInfo(this.Compilation.GetSpecialType(SpecialType.System_Boolean)));
P
Pilchie 已提交
1087 1088
            }

1089
            private IEnumerable<TypeInferenceInfo> InferTypeInEqualsValueClause(EqualsValueClauseSyntax equalsValue, SyntaxToken? previousToken = null)
P
Pilchie 已提交
1090 1091 1092 1093
            {
                // If we have a position, it has to be after the =
                if (previousToken.HasValue && previousToken.Value != equalsValue.EqualsToken)
                {
1094
                    return SpecializedCollections.EmptyEnumerable<TypeInferenceInfo>();
P
Pilchie 已提交
1095 1096 1097 1098 1099 1100 1101
                }

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

1102 1103 1104 1105 1106
                if (equalsValue.IsParentKind(SyntaxKind.PropertyDeclaration))
                {
                    return InferTypeInPropertyDeclaration((PropertyDeclarationSyntax)equalsValue.Parent);
                }

P
Pilchie 已提交
1107 1108
                if (equalsValue.IsParentKind(SyntaxKind.Parameter))
                {
1109
                    var parameter = SemanticModel.GetDeclaredSymbol(equalsValue.Parent, CancellationToken) as IParameterSymbol;
P
Pilchie 已提交
1110 1111
                    if (parameter != null)
                    {
1112
                        return SpecializedCollections.SingletonEnumerable(new TypeInferenceInfo(parameter.Type));
P
Pilchie 已提交
1113 1114 1115
                    }
                }

1116
                return SpecializedCollections.EmptyEnumerable<TypeInferenceInfo>();
P
Pilchie 已提交
1117 1118
            }

1119
            private IEnumerable<TypeInferenceInfo> InferTypeInPropertyDeclaration(PropertyDeclarationSyntax propertyDeclaration)
1120
            {
1121
                Contract.Assert(propertyDeclaration?.Type != null, "Property type should never be null");
1122

1123
                var typeInfo = SemanticModel.GetTypeInfo(propertyDeclaration.Type);
1124
                return typeInfo.Type != null
1125 1126
                    ? SpecializedCollections.SingletonEnumerable(new TypeInferenceInfo(typeInfo.Type))
                    : SpecializedCollections.EmptyEnumerable<TypeInferenceInfo>();
1127 1128
            }

1129
            private IEnumerable<TypeInferenceInfo> InferTypeInBaseMethodDeclaration(BaseMethodDeclarationSyntax declaration)
1130
            {
1131
                var methodSymbol = SemanticModel.GetDeclaredSymbol(declaration);
1132
                return methodSymbol?.ReturnType != null
1133 1134
                    ? SpecializedCollections.SingletonEnumerable(new TypeInferenceInfo(methodSymbol.ReturnType))
                    : SpecializedCollections.EmptyEnumerable<TypeInferenceInfo>();
1135 1136
            }

1137
            private IEnumerable<TypeInferenceInfo> InferTypeInExpressionStatement(ExpressionStatementSyntax expressionStatement, SyntaxToken? previousToken = null)
P
Pilchie 已提交
1138 1139 1140 1141 1142
            {
                // 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)
                {
1143
                    return SpecializedCollections.EmptyEnumerable<TypeInferenceInfo>();
P
Pilchie 已提交
1144 1145
                }

1146
                return SpecializedCollections.SingletonEnumerable(new TypeInferenceInfo(this.Compilation.GetSpecialType(SpecialType.System_Void)));
P
Pilchie 已提交
1147 1148
            }

1149
            private IEnumerable<TypeInferenceInfo> InferTypeInForEachStatement(ForEachStatementSyntax forEachStatementSyntax, ExpressionSyntax expressionOpt = null, SyntaxToken? previousToken = null)
P
Pilchie 已提交
1150 1151 1152 1153
            {
                // If we have a position, then we have to be after "foreach(... in"
                if (previousToken.HasValue && previousToken.Value != forEachStatementSyntax.InKeyword)
                {
1154
                    return SpecializedCollections.EmptyEnumerable<TypeInferenceInfo>();
P
Pilchie 已提交
1155 1156 1157 1158
                }

                if (expressionOpt != null && expressionOpt != forEachStatementSyntax.Expression)
                {
1159
                    return SpecializedCollections.EmptyEnumerable<TypeInferenceInfo>();
P
Pilchie 已提交
1160 1161 1162 1163 1164 1165
                }

                // foreach (int v = Foo())
                var variableTypes = GetTypes(forEachStatementSyntax.Type);
                if (!variableTypes.Any())
                {
1166
                    return SpecializedCollections.SingletonEnumerable(new TypeInferenceInfo(
P
Pilchie 已提交
1167
                        this.Compilation.GetSpecialType(SpecialType.System_Collections_Generic_IEnumerable_T)
1168
                        .Construct(Compilation.GetSpecialType(SpecialType.System_Object))));
P
Pilchie 已提交
1169 1170 1171
                }

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

1175
            private IEnumerable<TypeInferenceInfo> InferTypeInForStatement(ForStatementSyntax forStatement, ExpressionSyntax expressionOpt = null, SyntaxToken? previousToken = null)
P
Pilchie 已提交
1176 1177 1178 1179
            {
                // If we have a position, it has to be after "for(...;"
                if (previousToken.HasValue && previousToken.Value != forStatement.FirstSemicolonToken)
                {
1180
                    return SpecializedCollections.EmptyEnumerable<TypeInferenceInfo>();
P
Pilchie 已提交
1181 1182 1183 1184
                }

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

1188
                return SpecializedCollections.SingletonEnumerable(new TypeInferenceInfo(this.Compilation.GetSpecialType(SpecialType.System_Boolean)));
P
Pilchie 已提交
1189 1190
            }

1191
            private IEnumerable<TypeInferenceInfo> InferTypeInIfStatement(IfStatementSyntax ifStatement, SyntaxToken? previousToken = null)
P
Pilchie 已提交
1192 1193 1194 1195
            {
                // If we have a position, we have to be after the "if("
                if (previousToken.HasValue && previousToken.Value != ifStatement.OpenParenToken)
                {
1196
                    return SpecializedCollections.EmptyEnumerable<TypeInferenceInfo>();
P
Pilchie 已提交
1197 1198
                }

1199
                return SpecializedCollections.SingletonEnumerable(new TypeInferenceInfo(this.Compilation.GetSpecialType(SpecialType.System_Boolean)));
P
Pilchie 已提交
1200 1201
            }

1202
            private IEnumerable<TypeInferenceInfo> InferTypeInInitializerExpression(
P
Pilchie 已提交
1203 1204 1205 1206
                InitializerExpressionSyntax initializerExpression,
                ExpressionSyntax expressionOpt = null,
                SyntaxToken? previousToken = null)
            {
1207
                if (initializerExpression.IsKind(SyntaxKind.ComplexElementInitializerExpression))
P
Pilchie 已提交
1208
                {
1209 1210 1211 1212 1213
                    // 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 已提交
1214

1215
                    var addMethodSymbols = SemanticModel.GetCollectionInitializerSymbolInfo(initializerExpression).GetAllSymbols();
1216 1217 1218
                    var addMethodParameterTypes = addMethodSymbols
                        .Cast<IMethodSymbol>()
                        .Where(a => a.Parameters.Length == initializerExpression.Expressions.Count)
R
Ravi Chande 已提交
1219 1220
                        .Select(a => new TypeInferenceInfo(a.Parameters.ElementAtOrDefault(parameterIndex)?.Type))
                        .Where(t => t.InferredType != null);
P
Pilchie 已提交
1221

1222
                    if (addMethodParameterTypes.Any())
P
Pilchie 已提交
1223
                    {
1224
                        return addMethodParameterTypes;
P
Pilchie 已提交
1225
                    }
1226 1227 1228 1229
                }
                else if (initializerExpression.IsKind(SyntaxKind.CollectionInitializerExpression))
                {
                    if (expressionOpt != null)
P
Pilchie 已提交
1230
                    {
1231 1232
                        // new List<T> { x, ... }
                        // new C { Prop = { x, ... } }
1233
                        var addMethodSymbols = SemanticModel.GetCollectionInitializerSymbolInfo(expressionOpt).GetAllSymbols();
1234 1235 1236
                        var addMethodParameterTypes = addMethodSymbols
                            .Cast<IMethodSymbol>()
                            .Where(a => a.Parameters.Length == 1)
1237 1238
                            .Select(a => new TypeInferenceInfo(a.Parameters[0].Type));

1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249
                        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 已提交
1250 1251 1252 1253 1254 1255 1256 1257
                        {
                            var types = GetTypes(sibling);
                            if (types.Any())
                            {
                                return types;
                            }
                        }
                    }
1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268
                }

                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);
1269
                    var elementTypes = arrayTypes.OfType<IArrayTypeSymbol>().Select(a => new TypeInferenceInfo(a.ElementType)).Where(IsUsableTypeFunc);
1270 1271 1272 1273 1274

                    if (elementTypes.Any())
                    {
                        return elementTypes;
                    }
P
Pilchie 已提交
1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287

                    foreach (var sibling in initializerExpression.Expressions)
                    {
                        if (sibling != expressionOpt)
                        {
                            var types = GetTypes(sibling);
                            if (types.Any())
                            {
                                return types;
                            }
                        }
                    }
                }
1288 1289 1290 1291
                else if (initializerExpression.IsParentKind(SyntaxKind.EqualsValueClause))
                {
                    // = { Foo() }
                    var equalsValueClause = (EqualsValueClauseSyntax)initializerExpression.Parent;
1292
                    IEnumerable<ITypeSymbol> types = InferTypeInEqualsValueClause(equalsValueClause).Select(t => t.InferredType);
1293

1294
                    if (types.Any(t => t is IArrayTypeSymbol))
1295
                    {
1296
                        return types.OfType<IArrayTypeSymbol>().Select(t => new TypeInferenceInfo(t.ElementType));
1297 1298
                    }
                }
P
Pilchie 已提交
1299 1300 1301 1302
                else if (initializerExpression.IsParentKind(SyntaxKind.ArrayCreationExpression))
                {
                    // new int[] { Foo() } 
                    var arrayCreation = (ArrayCreationExpressionSyntax)initializerExpression.Parent;
1303
                    IEnumerable<ITypeSymbol> types = GetTypes(arrayCreation).Select(t => t.InferredType);
B
BalajiKris 已提交
1304

1305
                    if (types.Any(t => t is IArrayTypeSymbol))
P
Pilchie 已提交
1306
                    {
1307
                        return types.OfType<IArrayTypeSymbol>().Select(t => new TypeInferenceInfo(t.ElementType));
P
Pilchie 已提交
1308 1309 1310 1311 1312
                    }
                }
                else if (initializerExpression.IsParentKind(SyntaxKind.ObjectCreationExpression))
                {
                    // new List<T> { Foo() } 
1313

P
Pilchie 已提交
1314 1315
                    var objectCreation = (ObjectCreationExpressionSyntax)initializerExpression.Parent;

1316 1317
                    IEnumerable<ITypeSymbol> types = GetTypes(objectCreation).Select(t => t.InferredType);
                    if (types.Any(t => t is INamedTypeSymbol))
B
BalajiKris 已提交
1318
                    {
1319
                        return types.OfType<INamedTypeSymbol>().SelectMany(t =>
1320
                            GetCollectionElementType(t, parameterIndex: 0));
B
BalajiKris 已提交
1321
                    }
P
Pilchie 已提交
1322 1323 1324 1325
                }
                else if (initializerExpression.IsParentKind(SyntaxKind.SimpleAssignmentExpression))
                {
                    // new Foo { a = { Foo() } }
1326

1327
                    if (expressionOpt != null)
1328
                    {
1329
                        var addMethodSymbols = SemanticModel.GetCollectionInitializerSymbolInfo(expressionOpt).GetAllSymbols();
1330
                        var addMethodParameterTypes = addMethodSymbols.Select(a => new TypeInferenceInfo(((IMethodSymbol)a).Parameters[0].Type));
1331 1332 1333 1334
                        if (addMethodParameterTypes.Any())
                        {
                            return addMethodParameterTypes;
                        }
1335 1336
                    }

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

1340
                    if (types.Any(t => t is INamedTypeSymbol))
B
BalajiKris 已提交
1341
                    {
1342
                        // new Foo { a = { Foo() } }
B
BalajiKris 已提交
1343
                        var parameterIndex = previousToken.HasValue
1344 1345
                                ? initializerExpression.Expressions.GetSeparators().ToList().IndexOf(previousToken.Value) + 1
                                : initializerExpression.Expressions.IndexOf(expressionOpt);
P
Pilchie 已提交
1346

1347
                        return types.OfType<INamedTypeSymbol>().SelectMany(t =>
1348
                            GetCollectionElementType(t, 0));
B
BalajiKris 已提交
1349
                    }
P
Pilchie 已提交
1350 1351
                }

1352
                return SpecializedCollections.EmptyEnumerable<TypeInferenceInfo>();
P
Pilchie 已提交
1353 1354
            }

1355
            private IEnumerable<TypeInferenceInfo> InferTypeInIsPatternExpression(
1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366
                IsPatternExpressionSyntax isPatternExpression,
                ExpressionSyntax expression)
            {
                if (expression == isPatternExpression.Expression)
                {
                    return GetPatternTypes(isPatternExpression.Pattern);
                }

                return null;
            }

1367
            private IEnumerable<TypeInferenceInfo> GetPatternTypes(PatternSyntax pattern)
1368
            {
C
CyrusNajmabadi 已提交
1369 1370 1371 1372 1373 1374
                switch (pattern)
                {
                    case DeclarationPatternSyntax declarationPattern: return GetTypes(declarationPattern.Type);
                    case ConstantPatternSyntax constantPattern: return GetTypes(constantPattern.Expression);
                    default: return null;
                }
1375 1376
            }

1377
            private IEnumerable<TypeInferenceInfo> InferTypeInLockStatement(LockStatementSyntax lockStatement, SyntaxToken? previousToken = null)
P
Pilchie 已提交
1378 1379 1380 1381
            {
                // If we're position based, then we have to be after the "lock("
                if (previousToken.HasValue && previousToken.Value != lockStatement.OpenParenToken)
                {
1382
                    return SpecializedCollections.EmptyEnumerable<TypeInferenceInfo>();
P
Pilchie 已提交
1383 1384
                }

1385
                return SpecializedCollections.SingletonEnumerable(new TypeInferenceInfo(this.Compilation.GetSpecialType(SpecialType.System_Object)));
P
Pilchie 已提交
1386 1387
            }

1388
            private IEnumerable<TypeInferenceInfo> InferTypeInParenthesizedLambdaExpression(ParenthesizedLambdaExpressionSyntax lambdaExpression, SyntaxToken? previousToken = null)
P
Pilchie 已提交
1389 1390 1391 1392
            {
                // If we have a position, it has to be after the lambda arrow.
                if (previousToken.HasValue && previousToken.Value != lambdaExpression.ArrowToken)
                {
1393
                    return SpecializedCollections.EmptyEnumerable<TypeInferenceInfo>();
P
Pilchie 已提交
1394 1395 1396 1397 1398
                }

                return InferTypeInLambdaExpression(lambdaExpression);
            }

1399
            private IEnumerable<TypeInferenceInfo> InferTypeInSimpleLambdaExpression(SimpleLambdaExpressionSyntax lambdaExpression, SyntaxToken? previousToken = null)
P
Pilchie 已提交
1400 1401 1402 1403
            {
                // If we have a position, it has to be after the lambda arrow.
                if (previousToken.HasValue && previousToken.Value != lambdaExpression.ArrowToken)
                {
1404
                    return SpecializedCollections.EmptyEnumerable<TypeInferenceInfo>();
P
Pilchie 已提交
1405 1406 1407 1408 1409
                }

                return InferTypeInLambdaExpression(lambdaExpression);
            }

1410
            private IEnumerable<TypeInferenceInfo> InferTypeInLambdaExpression(ExpressionSyntax lambdaExpression)
P
Pilchie 已提交
1411 1412 1413
            {
                // Func<int,string> = i => Foo();
                var types = InferTypes(lambdaExpression);
1414
                var type = types.FirstOrDefault().InferredType.GetDelegateType(this.Compilation);
P
Pilchie 已提交
1415 1416 1417 1418 1419 1420

                if (type != null)
                {
                    var invoke = type.DelegateInvokeMethod;
                    if (invoke != null)
                    {
1421
                        return SpecializedCollections.SingletonEnumerable(new TypeInferenceInfo(invoke.ReturnType));
P
Pilchie 已提交
1422 1423 1424
                    }
                }

1425
                return SpecializedCollections.EmptyEnumerable<TypeInferenceInfo>();
P
Pilchie 已提交
1426 1427
            }

1428
            private IEnumerable<TypeInferenceInfo> InferTypeInMemberDeclarator(AnonymousObjectMemberDeclaratorSyntax memberDeclarator, SyntaxToken? previousTokenOpt = null)
P
Pilchie 已提交
1429 1430 1431 1432 1433 1434
            {
                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)
                    {
1435
                        return SpecializedCollections.EmptyEnumerable<TypeInferenceInfo>();
P
Pilchie 已提交
1436 1437 1438 1439
                    }

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

1440 1441
                    return types.Where(t => t.InferredType.IsAnonymousType())
                        .SelectMany(t => t.InferredType.GetValidAnonymousTypeProperties()
P
Pilchie 已提交
1442
                            .Where(p => p.Name == memberDeclarator.NameEquals.Name.Identifier.ValueText)
1443
                            .Select(p => new TypeInferenceInfo(p.Type)));
P
Pilchie 已提交
1444 1445
                }

1446
                return SpecializedCollections.EmptyEnumerable<TypeInferenceInfo>();
P
Pilchie 已提交
1447 1448
            }

1449
            private IEnumerable<TypeInferenceInfo> InferTypeInNameColon(NameColonSyntax nameColon, SyntaxToken previousToken)
P
Pilchie 已提交
1450 1451 1452 1453
            {
                if (previousToken != nameColon.ColonToken)
                {
                    // Must follow the colon token.
1454
                    return SpecializedCollections.EmptyEnumerable<TypeInferenceInfo>();
P
Pilchie 已提交
1455 1456 1457 1458 1459 1460 1461 1462
                }

                var argumentSyntax = nameColon.Parent as ArgumentSyntax;
                if (argumentSyntax != null)
                {
                    return InferTypeInArgument(argumentSyntax);
                }

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

1466
            private IEnumerable<TypeInferenceInfo> InferTypeInMemberAccessExpression(
1467
                MemberAccessExpressionSyntax memberAccessExpression,
1468
                ExpressionSyntax expressionOpt = null,
1469
                SyntaxToken? previousToken = null)
1470
            {
C
CyrusNajmabadi 已提交
1471 1472 1473 1474 1475
                // We need to be on the right of the dot to infer an appropriate type for
                // the member access expression.  i.e. if we have "Foo.Bar" then we can 
                // def infer what the type of 'Bar' should be (it's whatever type we infer
                // for 'Foo.Bar' itself.  However, if we're on 'Foo' then we can't figure
                // out anything about its type.
1476 1477 1478 1479
                if (previousToken != null)
                {
                    if (previousToken.Value != memberAccessExpression.OperatorToken)
                    {
1480
                        return SpecializedCollections.EmptyEnumerable<TypeInferenceInfo>();
1481 1482
                    }

C
CyrusNajmabadi 已提交
1483 1484 1485
                    // We're right after the dot in "Foo.Bar".  The type for "Bar" should be
                    // whatever type we'd infer for "Foo.Bar" itself.
                    return InferTypes(memberAccessExpression);
1486 1487
                }
                else
1488
                {
1489
                    Debug.Assert(expressionOpt != null);
C
CyrusNajmabadi 已提交
1490
                    if (expressionOpt == memberAccessExpression.Expression)
1491
                    {
C
CyrusNajmabadi 已提交
1492 1493 1494 1495 1496 1497 1498 1499 1500
                        return InferTypeForExpressionOfMemberAccessExpression(memberAccessExpression);
                    }

                    // We're right after the dot in "Foo.Bar".  The type for "Bar" should be
                    // whatever type we'd infer for "Foo.Bar" itself.
                    return InferTypes(memberAccessExpression);
                }
            }

1501
            private IEnumerable<TypeInferenceInfo> InferTypeForExpressionOfMemberAccessExpression(
C
CyrusNajmabadi 已提交
1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527
                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
                //
                //      await foo.ConfigureAwait()
                //
                // then we can figure out what 'foo' should be based on teh await
                // 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)))
                {
                    // foo.ContinueWith(...)
                    // 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(
1528
                            new TypeInferenceInfo(taskOfT.Construct(this.Compilation.ObjectType)));
C
CyrusNajmabadi 已提交
1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542
                    }
                }
                else if (name.Equals(nameof(Enumerable.Select)) ||
                         name.Equals(nameof(Enumerable.Where)))
                {
                    var ienumerableType = this.Compilation.IEnumerableOfTType();

                    // foo.Select
                    // 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)
1543
                        {
C
CyrusNajmabadi 已提交
1544 1545
                            var argumentExpression = invocation.ArgumentList.Arguments[0].Expression;

1546
                            if (argumentExpression != null)
1547
                            {
1548
                                var argumentTypes = GetTypes(argumentExpression);
1549
                                var delegateType = argumentTypes.FirstOrDefault().InferredType.GetDelegateType(this.Compilation);
1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560
                                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(
1561
                                    new TypeInferenceInfo(ienumerableType.Construct(typeArg)));
1562 1563
                            }
                        }
1564
                    }
1565
                }
C
CyrusNajmabadi 已提交
1566

1567
                return SpecializedCollections.EmptyEnumerable<TypeInferenceInfo>();
1568 1569
            }

1570 1571 1572 1573 1574 1575
            private ITypeSymbol InferTypeForFirstParameterOfLambda(
                LambdaExpressionSyntax lambdaExpression)
            {
                if (lambdaExpression is ParenthesizedLambdaExpressionSyntax)
                {
                    return InferTypeForFirstParameterOfParenthesizedLambda(
1576
                        (ParenthesizedLambdaExpressionSyntax)lambdaExpression);
1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616
                }
                else if (lambdaExpression is SimpleLambdaExpressionSyntax)
                {
                    return InferTypeForFirstParameterOfSimpleLambda(
                        (SimpleLambdaExpressionSyntax)lambdaExpression);
                }

                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;
1617 1618
                    if (identifierName.Identifier.ValueText.Equals(parameterName) &&
                        SemanticModel.GetSymbolInfo(identifierName.Identifier).Symbol?.Kind == SymbolKind.Parameter)
1619
                    {
1620
                        return InferTypes(identifierName).FirstOrDefault().InferredType;
1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640
                    }
                }
                else
                {
                    foreach (var child in node.ChildNodesAndTokens())
                    {
                        if (child.IsNode)
                        {
                            var type = InferTypeForFirstParameterOfLambda(parameterName, child.AsNode());
                            if (type != null)
                            {
                                return type;
                            }
                        }
                    }
                }

                return null;
            }

1641
            private IEnumerable<TypeInferenceInfo> InferTypeInNameEquals(NameEqualsSyntax nameEquals, SyntaxToken? previousToken = null)
P
Pilchie 已提交
1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656
            {
                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);
                }

                var attributeArgumentSyntax = nameEquals.Parent as AttributeArgumentSyntax;
                if (attributeArgumentSyntax != null)
                {
                    var argumentExpression = attributeArgumentSyntax.Expression;
                    return this.GetTypes(argumentExpression);
                }

1657
                return SpecializedCollections.EmptyEnumerable<TypeInferenceInfo>();
P
Pilchie 已提交
1658 1659
            }

1660
            private IEnumerable<TypeInferenceInfo> InferTypeInPostfixUnaryExpression(PostfixUnaryExpressionSyntax postfixUnaryExpressionSyntax, SyntaxToken? previousToken = null)
P
Pilchie 已提交
1661 1662 1663 1664
            {
                // If we're after a postfix ++ or -- then we can't infer anything.
                if (previousToken.HasValue)
                {
1665
                    return SpecializedCollections.EmptyEnumerable<TypeInferenceInfo>();
P
Pilchie 已提交
1666 1667
                }

1668
                switch (postfixUnaryExpressionSyntax.Kind())
P
Pilchie 已提交
1669
                {
1670 1671
                    case SyntaxKind.PostDecrementExpression:
                    case SyntaxKind.PostIncrementExpression:
1672
                        return SpecializedCollections.SingletonEnumerable(new TypeInferenceInfo(this.Compilation.GetSpecialType(SpecialType.System_Int32)));
P
Pilchie 已提交
1673 1674
                }

1675
                return SpecializedCollections.EmptyEnumerable<TypeInferenceInfo>();
P
Pilchie 已提交
1676 1677
            }

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

1683
                switch (prefixUnaryExpression.Kind())
P
Pilchie 已提交
1684
                {
1685 1686 1687 1688
                    case SyntaxKind.PreDecrementExpression:
                    case SyntaxKind.PreIncrementExpression:
                    case SyntaxKind.UnaryPlusExpression:
                    case SyntaxKind.UnaryMinusExpression:
B
Brandon 已提交
1689
                        // ++, --, +Foo(), -Foo();
1690
                        return SpecializedCollections.SingletonEnumerable(new TypeInferenceInfo(this.Compilation.GetSpecialType(SpecialType.System_Int32)));
P
Pilchie 已提交
1691

B
Brandon 已提交
1692 1693
                    case SyntaxKind.BitwiseNotExpression:
                        // ~Foo()
1694
                        var types = InferTypes(prefixUnaryExpression);
B
Brandon 已提交
1695 1696
                        if (!types.Any())
                        {
1697
                            return SpecializedCollections.SingletonEnumerable(new TypeInferenceInfo(this.Compilation.GetSpecialType(SpecialType.System_Int32)));
B
Brandon 已提交
1698 1699 1700 1701 1702 1703
                        }
                        else
                        {
                            return types;
                        }

1704 1705
                    case SyntaxKind.LogicalNotExpression:
                        // !Foo()
1706
                        return SpecializedCollections.SingletonEnumerable(new TypeInferenceInfo(this.Compilation.GetSpecialType(SpecialType.System_Boolean)));
P
Pilchie 已提交
1707 1708
                }

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

1712
            private IEnumerable<TypeInferenceInfo> InferTypeInAwaitExpression(AwaitExpressionSyntax awaitExpression, SyntaxToken? previousToken = null)
1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724
            {
                // 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)
                {
1725
                    return SpecializedCollections.EmptyEnumerable<TypeInferenceInfo>();
1726 1727 1728 1729
                }

                if (!types.Any())
                {
1730
                    return SpecializedCollections.SingletonEnumerable(new TypeInferenceInfo(task));
1731 1732
                }

1733
                return types.Select(t => t.InferredType.SpecialType == SpecialType.System_Void ? new TypeInferenceInfo(task) : new TypeInferenceInfo(taskOfT.Construct(t.InferredType)));
1734 1735
            }

1736
            private IEnumerable<TypeInferenceInfo> InferTypeInYieldStatement(YieldStatementSyntax yieldStatement, SyntaxToken? previousToken = null)
P
Pilchie 已提交
1737 1738 1739 1740
            {
                // 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)))
                {
1741
                    return SpecializedCollections.EmptyEnumerable<TypeInferenceInfo>();
P
Pilchie 已提交
1742 1743
                }

1744
                var memberSymbol = GetDeclaredMemberSymbolFromOriginalSemanticModel(SemanticModel, yieldStatement.GetAncestorOrThis<MemberDeclarationSyntax>());
P
Pilchie 已提交
1745

C
CyrusNajmabadi 已提交
1746 1747 1748 1749 1750 1751
                var memberType = (ITypeSymbol)null;
                switch (memberSymbol)
                {
                    case IMethodSymbol method: memberType = method.ReturnType; break;
                    case IPropertySymbol property: memberType = property.Type; break;
                }
P
Pilchie 已提交
1752 1753 1754 1755 1756 1757

                if (memberType is INamedTypeSymbol)
                {
                    if (memberType.OriginalDefinition.SpecialType == SpecialType.System_Collections_Generic_IEnumerable_T ||
                        memberType.OriginalDefinition.SpecialType == SpecialType.System_Collections_Generic_IEnumerator_T)
                    {
1758
                        return SpecializedCollections.SingletonEnumerable(new TypeInferenceInfo(((INamedTypeSymbol)memberType).TypeArguments[0]));
P
Pilchie 已提交
1759 1760 1761
                    }
                }

1762
                return SpecializedCollections.EmptyEnumerable<TypeInferenceInfo>();
P
Pilchie 已提交
1763 1764
            }

1765
            private IEnumerable<TypeInferenceInfo> InferTypeForReturnStatement(ReturnStatementSyntax returnStatement, SyntaxToken? previousToken = null)
P
Pilchie 已提交
1766
            {
1767
                bool isAsync;
1768
                IEnumerable<TypeInferenceInfo> types;
1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779

                InferTypeForReturnStatement(returnStatement, previousToken, out isAsync, out types);

                if (!isAsync)
                {
                    return types;
                }

                var taskOfT = this.Compilation.TaskOfTType();
                if (taskOfT == null || types == null)
                {
1780
                    return SpecializedCollections.EmptyEnumerable<TypeInferenceInfo>();
1781 1782 1783
                }

                return from t in types
1784 1785
                       where t.InferredType != null && t.InferredType.OriginalDefinition.Equals(taskOfT)
                       let nt = (INamedTypeSymbol)t.InferredType
1786
                       where nt.TypeArguments.Length == 1
1787
                       select new TypeInferenceInfo(nt.TypeArguments[0]);
1788 1789 1790
            }

            private void InferTypeForReturnStatement(
1791
                ReturnStatementSyntax returnStatement, SyntaxToken? previousToken, out bool isAsync, out IEnumerable<TypeInferenceInfo> types)
1792 1793
            {
                isAsync = false;
1794
                types = SpecializedCollections.EmptyEnumerable<TypeInferenceInfo>();
1795

P
Pilchie 已提交
1796 1797 1798
                // If we are position based, then we have to be after the return statement.
                if (previousToken.HasValue && previousToken.Value != returnStatement.ReturnKeyword)
                {
1799
                    return;
P
Pilchie 已提交
1800 1801
                }

B
Basoundr_ms 已提交
1802 1803
                var ancestorExpressions = returnStatement.GetAncestorsOrThis<ExpressionSyntax>();

P
Typos:  
Pharring 已提交
1804
                // If we're in a lambda, then use the return type of the lambda to figure out what to
P
Pilchie 已提交
1805
                // infer.  i.e.   Func<int,string> f = i => { return Foo(); }
J
jasonmalinowski 已提交
1806
                var lambda = ancestorExpressions.FirstOrDefault(e => e.IsKind(SyntaxKind.ParenthesizedLambdaExpression, SyntaxKind.SimpleLambdaExpression));
P
Pilchie 已提交
1807 1808
                if (lambda != null)
                {
1809
                    types = InferTypeInLambdaExpression(lambda);
1810 1811
                    isAsync = lambda is ParenthesizedLambdaExpressionSyntax && ((ParenthesizedLambdaExpressionSyntax)lambda).AsyncKeyword.Kind() != SyntaxKind.None;
                    return;
P
Pilchie 已提交
1812 1813
                }

B
Basoundr_ms 已提交
1814
                // If we are inside a delegate then use the return type of the Invoke Method of the delegate type
1815
                var delegateExpression = (AnonymousMethodExpressionSyntax)ancestorExpressions.FirstOrDefault(e => e.IsKind(SyntaxKind.AnonymousMethodExpression));
B
Basoundr_ms 已提交
1816 1817
                if (delegateExpression != null)
                {
1818
                    var delegateType = InferTypes(delegateExpression).FirstOrDefault().InferredType;
B
Basoundr_ms 已提交
1819 1820 1821 1822 1823
                    if (delegateType != null && delegateType.IsDelegateType())
                    {
                        var delegateInvokeMethod = delegateType.GetDelegateType(this.Compilation).DelegateInvokeMethod;
                        if (delegateInvokeMethod != null)
                        {
1824
                            types = SpecializedCollections.SingletonEnumerable(new TypeInferenceInfo(delegateInvokeMethod.ReturnType));
1825 1826
                            isAsync = delegateExpression.AsyncKeyword.Kind() != SyntaxKind.None;
                            return;
B
Basoundr_ms 已提交
1827 1828 1829 1830
                        }
                    }
                }

1831
                var memberSymbol = GetDeclaredMemberSymbolFromOriginalSemanticModel(SemanticModel, returnStatement.GetAncestorOrThis<MemberDeclarationSyntax>());
P
Pilchie 已提交
1832 1833 1834 1835 1836

                if (memberSymbol.IsKind(SymbolKind.Method))
                {
                    var method = memberSymbol as IMethodSymbol;

1837
                    isAsync = method.IsAsync;
1838
                    types = SpecializedCollections.SingletonEnumerable(new TypeInferenceInfo(method.ReturnType));
1839
                    return;
P
Pilchie 已提交
1840 1841 1842
                }
                else if (memberSymbol.IsKind(SymbolKind.Property))
                {
1843
                    types = SpecializedCollections.SingletonEnumerable(new TypeInferenceInfo((memberSymbol as IPropertySymbol).Type));
1844
                    return;
P
Pilchie 已提交
1845 1846 1847
                }
                else if (memberSymbol.IsKind(SymbolKind.Field))
                {
1848
                    types = SpecializedCollections.SingletonEnumerable(new TypeInferenceInfo((memberSymbol as IFieldSymbol).Type));
1849
                    return;
P
Pilchie 已提交
1850 1851 1852 1853 1854 1855 1856 1857 1858 1859
                }
            }

            private ISymbol GetDeclaredMemberSymbolFromOriginalSemanticModel(SemanticModel currentSemanticModel, MemberDeclarationSyntax declarationInCurrentTree)
            {
                var originalSemanticModel = currentSemanticModel.GetOriginalSemanticModel();
                MemberDeclarationSyntax declaration;

                if (currentSemanticModel.IsSpeculativeSemanticModel)
                {
1860
                    var tokenInOriginalTree = originalSemanticModel.SyntaxTree.GetRoot(CancellationToken).FindToken(currentSemanticModel.OriginalPositionForSpeculation);
P
Pilchie 已提交
1861 1862 1863 1864 1865 1866 1867
                    declaration = tokenInOriginalTree.GetAncestor<MemberDeclarationSyntax>();
                }
                else
                {
                    declaration = declarationInCurrentTree;
                }

1868
                return originalSemanticModel.GetDeclaredSymbol(declaration, CancellationToken);
P
Pilchie 已提交
1869 1870
            }

1871
            private IEnumerable<TypeInferenceInfo> InferTypeInSwitchLabel(
P
Pilchie 已提交
1872 1873 1874 1875
                SwitchLabelSyntax switchLabel, SyntaxToken? previousToken = null)
            {
                if (previousToken.HasValue)
                {
1876
                    if (previousToken.Value != switchLabel.Keyword ||
1877
                        switchLabel.Kind() != SyntaxKind.CaseSwitchLabel)
P
Pilchie 已提交
1878
                    {
1879
                        return SpecializedCollections.EmptyEnumerable<TypeInferenceInfo>();
P
Pilchie 已提交
1880 1881 1882 1883 1884 1885 1886
                    }
                }

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

1887
            private IEnumerable<TypeInferenceInfo> InferTypeInSwitchStatement(
P
Pilchie 已提交
1888 1889 1890 1891 1892
                SwitchStatementSyntax switchStatement, SyntaxToken? previousToken = null)
            {
                // If we have a position, then it has to be after "switch("
                if (previousToken.HasValue && previousToken.Value != switchStatement.OpenParenToken)
                {
1893
                    return SpecializedCollections.EmptyEnumerable<TypeInferenceInfo>();
P
Pilchie 已提交
1894 1895 1896 1897 1898
                }

                // Use the first case label to determine the return type.
                var firstCase =
                    switchStatement.Sections.SelectMany(ss => ss.Labels)
1899
                                                  .FirstOrDefault(label => label.Kind() == SyntaxKind.CaseSwitchLabel)
1900
                                                  as CaseSwitchLabelSyntax;
P
Pilchie 已提交
1901 1902 1903 1904 1905 1906 1907 1908 1909
                if (firstCase != null)
                {
                    var result = GetTypes(firstCase.Value);
                    if (result.Any())
                    {
                        return result;
                    }
                }

1910
                return SpecializedCollections.SingletonEnumerable(new TypeInferenceInfo(this.Compilation.GetSpecialType(SpecialType.System_Int32)));
P
Pilchie 已提交
1911 1912
            }

1913
            private IEnumerable<TypeInferenceInfo> InferTypeInThrowStatement(ThrowStatementSyntax throwStatement, SyntaxToken? previousToken = null)
P
Pilchie 已提交
1914 1915 1916 1917
            {
                // If we have a position, it has to be after the 'throw' keyword.
                if (previousToken.HasValue && previousToken.Value != throwStatement.ThrowKeyword)
                {
1918
                    return SpecializedCollections.EmptyEnumerable<TypeInferenceInfo>();
P
Pilchie 已提交
1919 1920
                }

1921
                return SpecializedCollections.SingletonEnumerable(new TypeInferenceInfo(this.Compilation.ExceptionType()));
P
Pilchie 已提交
1922 1923
            }

1924
            private IEnumerable<TypeInferenceInfo> InferTypeInUsingStatement(UsingStatementSyntax usingStatement, SyntaxToken? previousToken = null)
P
Pilchie 已提交
1925 1926 1927 1928
            {
                // If we have a position, it has to be after "using("
                if (previousToken.HasValue && previousToken.Value != usingStatement.OpenParenToken)
                {
1929
                    return SpecializedCollections.EmptyEnumerable<TypeInferenceInfo>();
P
Pilchie 已提交
1930 1931
                }

1932
                return SpecializedCollections.SingletonEnumerable(new TypeInferenceInfo(this.Compilation.GetSpecialType(SpecialType.System_IDisposable)));
P
Pilchie 已提交
1933 1934
            }

1935
            private IEnumerable<TypeInferenceInfo> InferTypeInVariableDeclarator(VariableDeclaratorSyntax variableDeclarator)
P
Pilchie 已提交
1936 1937
            {
                var variableType = variableDeclarator.GetVariableType();
1938 1939
                if (variableType == null)
                {
1940
                    return SpecializedCollections.EmptyEnumerable<TypeInferenceInfo>();
1941 1942
                }

C
Cyrus Najmabadi 已提交
1943
                var types = GetTypes(variableType).Where(IsUsableTypeFunc);
P
Pilchie 已提交
1944 1945 1946 1947 1948 1949 1950 1951 1952

                if (variableType.IsVar)
                {
                    var variableDeclaration = variableDeclarator.Parent as VariableDeclarationSyntax;
                    if (variableDeclaration != null)
                    {
                        if (variableDeclaration.IsParentKind(SyntaxKind.UsingStatement))
                        {
                            // using (var v = Foo())
1953
                            return SpecializedCollections.SingletonEnumerable(new TypeInferenceInfo(this.Compilation.GetSpecialType(SpecialType.System_IDisposable)));
P
Pilchie 已提交
1954 1955 1956 1957 1958
                        }

                        if (variableDeclaration.IsParentKind(SyntaxKind.ForStatement))
                        {
                            // for (var v = Foo(); ..
1959
                            return SpecializedCollections.SingletonEnumerable(new TypeInferenceInfo(this.Compilation.GetSpecialType(SpecialType.System_Int32)));
P
Pilchie 已提交
1960 1961 1962
                        }

                        // Return the types here if they actually bound to a type called 'var'.
1963
                        return types.Where(t => t.InferredType.Name == "var");
P
Pilchie 已提交
1964 1965 1966 1967 1968 1969
                    }
                }

                return types;
            }

1970
            private IEnumerable<TypeInferenceInfo> InferTypeInVariableComponentAssignment(ExpressionSyntax left)
1971
            {
1972
                if (left.IsKind(SyntaxKind.DeclarationExpression))
1973
                {
1974 1975 1976 1977 1978 1979 1980 1981 1982 1983
                    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);
1984

1985 1986 1987
                    if (tupleType != null)
                    {
                        return SpecializedCollections.SingletonEnumerable(new TypeInferenceInfo(tupleType));
1988 1989 1990 1991 1992 1993 1994
                    }
                }

                return SpecializedCollections.EmptyEnumerable<TypeInferenceInfo>();
            }

            private ITypeSymbol GetTupleType(
1995
                TupleExpressionSyntax tuple)
1996 1997 1998 1999
            {
                ImmutableArray<ITypeSymbol> elementTypes;
                ImmutableArray<string> elementNames;

2000
                if (!TryGetTupleTypesAndNames(tuple.Arguments, out elementTypes, out elementNames))
2001 2002 2003 2004 2005 2006 2007 2008
                {
                    return null;
                }

                return Compilation.CreateTupleTypeSymbol(elementTypes, elementNames);
            }

            private bool TryGetTupleTypesAndNames(
2009
                SeparatedSyntaxList<ArgumentSyntax> arguments,
2010 2011 2012 2013 2014 2015 2016 2017 2018 2019
                out ImmutableArray<ITypeSymbol> elementTypes,
                out ImmutableArray<string> elementNames)
            {
                elementTypes = default(ImmutableArray<ITypeSymbol>);
                elementNames = default(ImmutableArray<string>);

                var elementTypesBuilder = ArrayBuilder<ITypeSymbol>.GetInstance();
                var elementNamesBuilder = ArrayBuilder<string>.GetInstance();
                try
                {
2020
                    foreach (var arg in arguments)
2021
                    {
2022 2023
                        var expr = arg.Expression;
                        if (expr.IsKind(SyntaxKind.DeclarationExpression))
2024
                        {
2025
                            AddTypeAndName((DeclarationExpressionSyntax)expr, elementTypesBuilder, elementNamesBuilder);
2026
                        }
2027
                        else if (expr.IsKind(SyntaxKind.TupleExpression))
2028
                        {
2029
                            AddTypeAndName((TupleExpressionSyntax)expr, elementTypesBuilder, elementNamesBuilder);
2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041 2042 2043 2044 2045 2046 2047 2048 2049
                        }
                    }

                    if (elementTypesBuilder.Contains(null))
                    {
                        return false;
                    }

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

            private void AddTypeAndName(
2050 2051
                DeclarationExpressionSyntax declaration,
                ArrayBuilder<ITypeSymbol> elementTypesBuilder,
2052 2053
                ArrayBuilder<string> elementNamesBuilder)
            {
2054
                elementTypesBuilder.Add(GetTypes(declaration.Type).FirstOrDefault().InferredType);
2055

2056
                var designation = declaration.Designation;
2057 2058 2059
                if (designation.IsKind(SyntaxKind.SingleVariableDesignation))
                {
                    var singleVariable = (SingleVariableDesignationSyntax)designation;
2060 2061 2062 2063 2064 2065 2066
                    var name = singleVariable.Identifier.ValueText;

                    if (name != string.Empty)
                    {
                        elementNamesBuilder.Add(name);
                        return;
                    }
2067
                }
2068 2069

                elementNamesBuilder.Add(null);
2070 2071 2072
            }

            private void AddTypeAndName(
2073 2074
                TupleExpressionSyntax tuple,
                ArrayBuilder<ITypeSymbol> elementTypesBuilder,
2075 2076
                ArrayBuilder<string> elementNamesBuilder)
            {
2077
                var tupleType = GetTupleType(tuple);
2078 2079 2080 2081
                elementTypesBuilder.Add(tupleType);
                elementNamesBuilder.Add(null);
            }

2082
            private IEnumerable<TypeInferenceInfo> InferTypeInWhileStatement(WhileStatementSyntax whileStatement, SyntaxToken? previousToken = null)
P
Pilchie 已提交
2083 2084 2085 2086
            {
                // If we're position based, then we have to be after the "while("
                if (previousToken.HasValue && previousToken.Value != whileStatement.OpenParenToken)
                {
2087
                    return SpecializedCollections.EmptyEnumerable<TypeInferenceInfo>();
P
Pilchie 已提交
2088 2089
                }

2090
                return SpecializedCollections.SingletonEnumerable(new TypeInferenceInfo(this.Compilation.GetSpecialType(SpecialType.System_Boolean)));
P
Pilchie 已提交
2091 2092
            }

2093
            private IEnumerable<TypeInferenceInfo> GetCollectionElementType(INamedTypeSymbol type, int parameterIndex)
P
Pilchie 已提交
2094 2095 2096
            {
                if (type != null)
                {
2097 2098 2099 2100 2101
                    var parameters = type.GetAllTypeArguments();

                    var elementType = parameters.ElementAtOrDefault(parameterIndex);
                    if (elementType != null)
                    {
2102
                        return SpecializedCollections.SingletonCollection(new TypeInferenceInfo(elementType));
2103
                    }
P
Pilchie 已提交
2104 2105
                }

2106
                return SpecializedCollections.EmptyEnumerable<TypeInferenceInfo>();
P
Pilchie 已提交
2107 2108 2109 2110
            }
        }
    }
}