The names of all canonical methods that are supported by Entity Framework https://msdn.microsoft.com/en-us/library/bb738626.aspx https://msdn.microsoft.com/en-us/library/bb738681.aspx
        internal static void ValidateMethodCallInLinqExpression(InvocationExpressionSyntax node, EFCodeFirstClassInfo rootQueryableType, SyntaxNodeAnalysisContext context, EFUsageContext efContext, Dictionary <string, ContextualLinqParameter> parameterNodes, bool treatAsWarning)
        {
            string methodName = null;
            var    memberExpr = node.Expression as MemberAccessExpressionSyntax;
            var    identExpr  = node.Expression as IdentifierNameSyntax;

            if (memberExpr != null)
            {
                methodName = memberExpr?.Name?.Identifier.ValueText;

                //This is a LINQ operator (Where, Select, etc)
                if (CanonicalMethodNames.IsLinqOperator(methodName))
                {
                    var expr = memberExpr.Expression as MemberAccessExpressionSyntax;
                    if (expr != null) //a.b.<linq operator>()
                    {
                        //What is b?
                        var member = expr.Name as IdentifierNameSyntax;
                        if (member != null)
                        {
                            string memberName        = member.Identifier.ValueText;
                            var    applicableClasses = efContext.GetClassForProperty(memberName)
                                                       .Where(c => c.HasProperty(memberName));

                            if (applicableClasses.Count() > 1)
                            {
                                //See if semantic model can help us disambiguate
                                var si   = context.SemanticModel.GetSymbolInfo(expr.Expression);
                                var type = si.Symbol?.TryGetType();
                                if (type != null)
                                {
                                    var cls = efContext.GetClassInfo(type);
                                    //There is only one class with this property and it is confirmed to be a collection
                                    //navigation property
                                    if (cls != null && cls.IsCollectionNavigationProperty(memberName))
                                    {
                                        ValidateNavigationPropertyAccess(node, context, efContext, treatAsWarning, memberName, cls);
                                    }
                                }
                                else
                                {
                                    //This potential navigation property resolves to multiple classes, see if we can resolve to a
                                    //single one via contextual variables
                                    var inst = expr.Expression as IdentifierNameSyntax;
                                    if (inst != null)
                                    {
                                        string name = inst.Identifier.ValueText;
                                        ContextualLinqParameter cparam;
                                        if (parameterNodes.TryGetValue(name, out cparam) &&
                                            cparam.ParameterType == ContextualLinqParameterType.Queryable &&
                                            applicableClasses.Any(c => c.ClassType == cparam.QueryableType.ClassType))
                                        {
                                            //TODO: Code fix candidate
                                            //
                                            //In such a case, inject an .AsQueryable() before the LINQ operator call
                                            //and add using System.Linq if required
                                            var diagnostic = Diagnostic.Create(treatAsWarning ? DiagnosticCodes.EFLINQ009 : DiagnosticCodes.EFLINQ008, member.GetLocation(), memberName, cparam.QueryableType.Name);
                                            context.ReportDiagnostic(diagnostic);
                                        }
                                        else
                                        {
                                            //TODO: Code fix candidate
                                            //
                                            //In such a case, inject an .AsQueryable() before the LINQ operator call
                                            //and add using System.Linq if required
                                            var diagnostic = Diagnostic.Create(DiagnosticCodes.EFLINQ010, member.GetLocation(), memberName);
                                            context.ReportDiagnostic(diagnostic);
                                        }
                                    }
                                    else
                                    {
                                        //TODO: Code fix candidate
                                        //
                                        //In such a case, inject an .AsQueryable() before the LINQ operator call
                                        //and add using System.Linq if required
                                        var diagnostic = Diagnostic.Create(DiagnosticCodes.EFLINQ010, member.GetLocation(), memberName);
                                        context.ReportDiagnostic(diagnostic);
                                    }
                                }
                            }
                            else
                            {
                                var cls = applicableClasses.FirstOrDefault();
                                //There is only one class with this property and it is confirmed to be a collection
                                //navigation property
                                if (cls != null && cls.IsCollectionNavigationProperty(memberName))
                                {
                                    ValidateNavigationPropertyAccess(node, context, efContext, treatAsWarning, memberName, cls);
                                }
                            }
                        }
                        //TODO: If not, check that the preceding member is IQueryable<T> and that T is a known
                        //entity type
                    }
                }
                else
                {
                    //TODO: AsQueryable() shouldn't be a blanket exception.
                    //We obviously should check what precedes it
                    if (methodName != EFSpecialIdentifiers.AsQueryable)
                    {
                        bool bValid = IsSupportedLinqToEntitiesMethod(node, memberExpr, rootQueryableType, efContext, context);
                        if (!bValid)
                        {
                            var diagnostic = Diagnostic.Create(treatAsWarning ? DiagnosticCodes.EFLINQ007 : DiagnosticCodes.EFLINQ004, node.GetLocation(), methodName);
                            context.ReportDiagnostic(diagnostic);
                        }
                    }
                }
            }
            else if (identExpr != null) //A non-instance (static) method call, most certainly illegal
            {
                if (!CanonicalMethodNames.IsKnownMethod(identExpr))
                {
                    methodName = identExpr.Identifier.ValueText;
                    var diagnostic = Diagnostic.Create(treatAsWarning ? DiagnosticCodes.EFLINQ006 : DiagnosticCodes.EFLINQ003, node.GetLocation(), methodName);
                    context.ReportDiagnostic(diagnostic);
                }
            }
        }
        private static void AnalyzeLambdaInLinqExpression(SyntaxNodeAnalysisContext context, EFUsageContext efContext, LambdaExpressionSyntax lambda)
        {
            var lambdaAssign = lambda.Parent as EqualsValueClauseSyntax;
            var arg          = lambda.Parent as ArgumentSyntax;

            if (arg != null) //The lambda in question is being passed as an argument
            {
                var parent = arg.Parent;
                while (parent != null && !(parent is ArgumentListSyntax))
                {
                    parent = parent.Parent;
                }

                if (parent != null) //Which should be part of an ArgumentList
                {
                    var argList = parent;
                    var invoc   = argList?.Parent as InvocationExpressionSyntax;
                    if (invoc != null) //Which should be part of an invocation
                    {
                        var memberExpr = invoc.Expression as MemberAccessExpressionSyntax;
                        if (memberExpr != null)
                        {
                            if (CanonicalMethodNames.IsLinqOperator(memberExpr?.Name?.Identifier.ValueText))
                            {
                                var si = context.SemanticModel.GetSymbolInfo(memberExpr.Expression);

                                var lts = si.Symbol as ILocalSymbol;
                                var pts = si.Symbol as IPropertySymbol;
                                //Is this method called on a property?
                                if (pts != null)
                                {
                                    var nts = pts.Type as INamedTypeSymbol;
                                    if (nts != null)
                                    {
                                        //Like a DbSet<T>?
                                        if (nts.IsDbSet())
                                        {
                                            //That is part of a class derived from DbContext?
                                            if (pts?.ContainingType?.BaseType?.Name == EFSpecialIdentifiers.DbContext)
                                            {
                                                var typeArg = nts.TypeArguments[0];
                                                //Let's give our method some assistance, by checking what T actually is
                                                var clsInfo = efContext.GetClassInfo(typeArg);
                                                if (clsInfo != null)
                                                {
                                                    //Okay now let's see if this lambda is valid in the EF context
                                                    LinqExpressionValidator.ValidateLinqToEntitiesExpression(lambda, clsInfo, context, efContext);
                                                }
                                            }
                                        }
                                    }
                                }
                                else if (lts != null) //The linq method was called on a local variable
                                {
                                    var nts = lts.Type as INamedTypeSymbol;
                                    if (nts != null && nts.TypeArguments.Length == 1)
                                    {
                                        //This is some generic type with one type argument
                                        var typeArg = nts.TypeArguments[0];
                                        var clsInfo = efContext.GetClassInfo(typeArg);
                                        if (clsInfo != null)
                                        {
                                            if (nts.IsDbSet())
                                            {
                                                //TODO: Should still actually check that it is ultimately assigned
                                                //from a DbSet<T> property of a DbContext derived class

                                                LinqExpressionValidator.ValidateLinqToEntitiesExpression(lambda, clsInfo, context, efContext);
                                            }
                                            else if (nts.IsQueryable())
                                            {
                                                bool treatAsWarning = !LinqExpressionValidator.SymbolCanBeTracedBackToDbContext(lts, context, efContext, clsInfo);
                                                LinqExpressionValidator.ValidateLinqToEntitiesExpression(lambda, clsInfo, context, efContext, treatAsWarning);
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
            else if (lambdaAssign != null) //The lambda in question is being assigned
            {
                var localLambdaDecl = lambdaAssign?.Parent?.Parent?.Parent as LocalDeclarationStatementSyntax;
                if (localLambdaDecl != null)
                {
                    var declType = localLambdaDecl?.Declaration?.Type as GenericNameSyntax;
                    if (declType != null)
                    {
                        //Is Expression<T>
                        if (declType.Identifier.ValueText == EFSpecialIdentifiers.Expression && declType.TypeArgumentList.Arguments.Count == 1)
                        {
                            //The T is Func<TInput, TOutput>
                            var exprTypeArg = declType.TypeArgumentList.Arguments[0] as GenericNameSyntax;
                            if (exprTypeArg != null &&
                                exprTypeArg.Identifier.ValueText == EFSpecialIdentifiers.Func &&
                                exprTypeArg.TypeArgumentList.Arguments.Count == 2)
                            {
                                var inputType  = exprTypeArg.TypeArgumentList.Arguments[0] as IdentifierNameSyntax;
                                var outputType = exprTypeArg.TypeArgumentList.Arguments[1] as PredefinedTypeSyntax;
                                //The TOutput in Func<TInput, TOutput> is bool
                                if (inputType != null && outputType != null && outputType.Keyword.ValueText == EFSpecialIdentifiers.BooleanShort)
                                {
                                    var si = context.SemanticModel.GetSymbolInfo(inputType);
                                    var ts = efContext.EntityTypes.FirstOrDefault(t => t == si.Symbol);
                                    if (ts != null)
                                    {
                                        var clsInfo = efContext.GetClassInfo(ts);
                                        if (clsInfo != null)
                                        {
                                            LinqExpressionValidator.ValidateLinqToEntitiesExpression(lambda, clsInfo, context, efContext);
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
 private static bool IsSupportedLinqToEntitiesMethod(InvocationExpressionSyntax node, MemberAccessExpressionSyntax memberExpr, EFCodeFirstClassInfo rootQueryableType, EFUsageContext efContext, SyntaxNodeAnalysisContext context) => CanonicalMethodNames.IsKnownMethod(node, memberExpr, rootQueryableType, efContext, context);