/// <summary>
        /// For element-scoped rules the Analyze method is executed once for every matching object in the model.
        /// </summary>
        /// <param name="ruleExecutionContext">The context object contains the TSqlObject being analyzed, a TSqlFragment
        /// that's the AST representation of the object, the current rule's descriptor, and a reference to the model being
        /// analyzed.
        /// </param>
        /// <returns>A list of problems should be returned. These will be displayed in the Visual Studio error list</returns>
        public override IList <SqlRuleProblem> Analyze(XtendSqlRuleExecutionContext context)
        {
            IList <SqlRuleProblem> problems = new List <SqlRuleProblem>();

            CursorVisitor visitor = new CursorVisitor(false, true);

            context.ScriptFragment.Accept(visitor);
            foreach (var element in visitor.IncorrectFetchCursorStatements)
            {
                var            fetch      = element.Key;
                int            fetchCount = fetch.IntoVariables.Count;
                string         cursorName = element.Value;
                SqlRuleProblem problem    = new SqlRuleProblem(
                    String.Format(
                        CultureInfo.CurrentCulture,
                        context.RuleDescriptor.DisplayDescription,
                        cursorName,
                        fetchCount),
                    context.ModelElement,
                    fetch);
                problems.Add(problem);
            }

            return(problems);
        }
        /// <summary>
        /// For element-scoped rules the Analyze method is executed once for every matching object in the model.
        /// </summary>
        /// <param name="ruleExecutionContext">The context object contains the TSqlObject being analyzed, a TSqlFragment
        /// that's the AST representation of the object, the current rule's descriptor, and a reference to the model being
        /// analyzed.
        /// </param>
        /// <returns>A list of problems should be returned. These will be displayed in the Visual Studio error list</returns>
        public override IList <SqlRuleProblem> Analyze(SqlRuleExecutionContext ruleExecutionContext)
        {
            IList <SqlRuleProblem> problems = new List <SqlRuleProblem>();

            TSqlObject     modelElement   = ruleExecutionContext.ModelElement;
            string         elementName    = ruleExecutionContext.SchemaModel.DisplayServices.GetElementName(modelElement, ElementNameStyle.EscapedFullyQualifiedName);
            TSqlFragment   fragment       = ruleExecutionContext.ScriptFragment;
            RuleDescriptor ruleDescriptor = ruleExecutionContext.RuleDescriptor;

            // Get schema of the procedure.
            TSqlObject schema = modelElement.GetReferenced(Procedure.Schema).SingleOrDefault();

            if (schema != null && fragment.FragmentLength > 0)
            {
                CursorVisitor visitor = new CursorVisitor(true, false);
                fragment.Accept(visitor);

                foreach (var element in visitor.DeclareCursorStatementsMissingDeallocate)
                {
                    string         cursorName = element.Name.Value;
                    SqlRuleProblem problem    = new SqlRuleProblem(
                        String.Format(
                            CultureInfo.CurrentCulture,
                            ruleDescriptor.DisplayDescription, "Missing deallocate",
                            cursorName,
                            elementName),
                        modelElement,
                        element.CursorDefinition);
                    problems.Add(problem);
                }

                foreach (var element in visitor.IncorrectDeallocateCursorStatements)
                {
                    string         cursorName = element.Cursor?.Name.Value ?? "NULL";
                    SqlRuleProblem problem    = new SqlRuleProblem(
                        String.Format(
                            CultureInfo.CurrentCulture,
                            ruleDescriptor.DisplayDescription, "Invalid deallocate",
                            cursorName,
                            elementName),
                        modelElement,
                        element);
                    problems.Add(problem);
                }

                foreach (var element in visitor.DeclareCursorStatementsMissingOpen)
                {
                    string         cursorName = element.Name.Value;
                    SqlRuleProblem problem    = new SqlRuleProblem(
                        String.Format(
                            CultureInfo.CurrentCulture,
                            ruleDescriptor.DisplayDescription, "Missing open",
                            cursorName,
                            elementName),
                        modelElement,
                        element.CursorDefinition);
                    problems.Add(problem);
                }

                foreach (var element in visitor.IncorrectOpenCursorStatements)
                {
                    string         cursorName = element.Cursor?.Name.Value ?? "NULL";
                    SqlRuleProblem problem    = new SqlRuleProblem(
                        String.Format(
                            CultureInfo.CurrentCulture,
                            ruleDescriptor.DisplayDescription, "Invalid open",
                            cursorName,
                            elementName),
                        modelElement,
                        element);
                    problems.Add(problem);
                }
            }
            return(problems);
        }