using Microsoft.SqlServer.TransactSql.ScriptDom; namespace SQLLinter.Common; public abstract class BaseRuleVisitor : TSqlFragmentVisitor, IRule { protected readonly List _violations = new(); public int DynamicSqlStartColumn { get; set; } public int DynamicSqlStartLine { get; set; } public virtual string Name { get => GetDefaultRuleName(GetType().Name); } public abstract string Text { get; } public virtual RuleViolationSeverity Severity { get; set; } = RuleViolationSeverity.Info; protected string GetDefaultRuleName(string className) => className.Substring(className.Length - 4).ToLower() == "rule" ? className.Substring(0, className.Length - 4) : className; protected virtual int GetLineNumber(TSqlFragment node) => node.StartLine + GetDynamicSqlLineOffset(); protected virtual int GetLineNumber(TSqlParserToken node) => node.Line + GetDynamicSqlLineOffset(); private int GetDynamicSqlLineOffset() => DynamicSqlStartLine > 0 ? DynamicSqlStartLine - 1 : 0; protected virtual int GetColumnNumber(TSqlFragment node) => node.StartColumn + GetDynamicSqlColumnOffset(node); protected virtual int GetColumnNumber(TSqlParserToken node) => node.Column + GetDynamicSqlColumnOffset(node); protected virtual int GetDynamicSqlColumnOffset(TSqlFragment node) => GetDynamicSqlColumnOffset(node.StartLine); protected virtual int GetDynamicSqlColumnOffset(TSqlParserToken node) => GetDynamicSqlColumnOffset(node.Line); private int GetDynamicSqlColumnOffset(int line) => DynamicSqlStartLine > 0 && line == 1 ? DynamicSqlStartColumn : 0; public virtual void FixViolation( List fileLines, IRuleViolation ruleViolation, FileLineActions actions) { } public virtual IEnumerable Analyze(TSqlFragment fragment) { _violations.Clear(); fragment.Accept(this); return _violations; } protected void AddViolation(Violation violation) { _violations.Add(violation); } protected void AddViolation(string RuleName, string Message, int Line, int Column) { _violations.Add(new(RuleName, Message, Line, Column)); } protected void AddViolation(TSqlFragment node, params string[] param) { AddViolation(Name, this.GetText(param), GetLineNumber(node), GetColumnNumber(node)); } protected string GetText(params string[] param) { return string.Format(this.Text, param); } }