using Microsoft.SqlServer.TransactSql.ScriptDom; using SQLLinter.Common; using SQLLinter.Common.Helpers; using System.Text.RegularExpressions; namespace SQLLinter.Infrastructure.Rules; /// /// Ожидается наличие BEGIN - END в блоке IF /// public class ConditionalBeginEndRule : BaseRuleVisitor, IRule { private readonly Regex IsWhiteSpaceOrSemiColon = new Regex(@"\s|;", RegexOptions.Compiled); public override string Text => "Ожидается наличие BEGIN - END в блоке IF"; public override void Visit(IfStatement node) { if (node.ThenStatement != null && node.ThenStatement is not BeginEndBlockStatement && node.ThenStatement is not TryCatchStatement) { if (node.ThenStatement.StartLine != node.StartLine || node.ScriptTokenStream.Where(t => t.Offset <= node.ThenStatement.StartOffset + node.ThenStatement.FragmentLength).Max(t => t.Line) != node.StartLine) { AddViolation(node.ThenStatement); } } if (node.ElseStatement != null && node.ElseStatement is not BeginEndBlockStatement && node.ElseStatement is not TryCatchStatement && node.ElseStatement is not IfStatement) { if (node.ElseStatement.StartLine != node.StartLine || node.ScriptTokenStream.Where(t => t.Offset <= node.ElseStatement.StartOffset + node.ElseStatement.FragmentLength).Max(t => t.Line) != node.StartLine) { AddViolation(node.ElseStatement); } } } public override void FixViolation(List fileLines, IRuleViolation ruleViolation, FileLineActions actions) { var ifNode = FixHelpers.FindViolatingNode(fileLines, ruleViolation); TSqlStatement statement; if (ifNode == null) { (statement, ifNode) = FindElse(fileLines, ruleViolation); } else { statement = ifNode.ThenStatement; } var stream = statement.ScriptTokenStream; var indent = FixHelpers.GetIndent(fileLines, ifNode); var beingLine = stream[statement.FirstTokenIndex].Line - 1; var ifNodeLastToken = stream[statement.LastTokenIndex]; var endLine = stream[statement.LastTokenIndex].Line; if (statement.StartLine == ifNodeLastToken.Line) { var index = statement.LastTokenIndex; actions.InsertInLine(statement.StartLine - 1, stream[index].Column, " END"); actions.InsertInLine(statement.StartLine - 1, statement.StartColumn - 1, "BEGIN "); } else { actions.Insert(endLine, $"{indent}END"); actions.Insert(beingLine, $"{indent}BEGIN"); } static (TSqlStatement, IfStatement) FindElse(List fileLines, IRuleViolation ruleViolation) { return FixHelpers.FindViolatingNode( fileLines, ruleViolation, x => x.ElseStatement); } } }