static bool GetRootEntityTypeFromLinqQuery(ExpressionSyntax expr, SyntaxNodeAnalysisContext context, EFUsageContext efContext, out EFCodeFirstClassInfo clsInfo)
        {
            clsInfo = null;

            // from $var in ???
            var memberExpr = expr as MemberAccessExpressionSyntax;
            var ident      = expr as IdentifierNameSyntax;

            if (memberExpr != null) //??? = $ident.$prop
            {
                return(LinqExpressionValidator.MemberAccessIsAccessingDbContext(memberExpr, context, efContext, out clsInfo));
            }
            else if (ident != null)
            {
                var si    = context.SemanticModel.GetSymbolInfo(ident);
                var local = si.Symbol as ILocalSymbol;
                if (local != null)
                {
                    var nts = local.Type as INamedTypeSymbol;
                    if (nts != null && nts.TypeArguments.Length == 1)
                    {
                        var typeArg = nts.TypeArguments[0];
                        clsInfo = efContext.GetClassInfo(typeArg);
                        if (clsInfo != null)
                        {
                            return(LinqExpressionValidator.SymbolCanBeTracedBackToDbContext(local, context, efContext, clsInfo));
                        }
                    }
                }
            }
            return(false);
        }
        public static Dictionary <string, ContextualLinqParameter> BuildContext(QueryExpressionSyntax query, SyntaxNodeAnalysisContext context, EFUsageContext efContext)
        {
            var cparams = new Dictionary <string, ContextualLinqParameter>();

            //From x
            var fromExpr = query.FromClause.Identifier;
            //in <expr>
            var    inExpr = query.FromClause.Expression;
            string name   = fromExpr.ValueText;

            var memberExpr = inExpr as MemberAccessExpressionSyntax;

            if (memberExpr != null)
            {
                EFCodeFirstClassInfo cls;
                if (LinqExpressionValidator.MemberAccessIsAccessingDbContext(memberExpr, context, efContext, out cls))
                {
                    cparams[name] = new ContextualLinqParameter(name, cls);
                }
            }

            //Still not set, just set as a contextual parameter with no known type
            if (!cparams.ContainsKey(name))
            {
                cparams[name] = new ContextualLinqParameter(name);
            }

            return(cparams);
        }
        private static void AnalyzeQueryExpression(SyntaxNodeAnalysisContext context, EFUsageContext efContext, QueryExpressionSyntax query)
        {
            //I can't believe how much easier this is compared to Extension Method syntax! Then again
            //query syntax does mean its own dedicated set of C# keywords, which would means its own
            //dedicated set of syntax node types


            //First item on checklist, find out our root queryable
            EFCodeFirstClassInfo cls;
            bool isConnectedToDbContext = GetRootEntityTypeFromLinqQuery(query.FromClause.Expression, context, efContext, out cls);

            if (cls != null)
            {
                bool treatAsWarning = !isConnectedToDbContext;

                var paramNodes  = ContextualLinqParameter.BuildContext(query, context, efContext);
                var descendants = query.Body.DescendantNodes();

                LinqExpressionValidator.ValidateLinqToEntitiesUsageInSyntaxNodes(descendants, cls, context, efContext, paramNodes, treatAsWarning);
            }
        }
        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);
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }