private static IValidationError SpacesInsideParenthesisCheck(IAstNode node, LintOptions options, bool projectedBuffer) { // There should be no space after (, [ or [[ and no space before ), ] or ]] // unless ] or ]] is preceded by a comma as in x[1, ] if (!options.SpacesInsideParenthesis || !(node is TokenNode t)) { return(null); } var tp = node.Root.TextProvider; switch (t.Token.TokenType) { case RTokenType.OpenBrace: case RTokenType.OpenSquareBracket: case RTokenType.OpenDoubleSquareBracket: // x[1, OK x( 2) is not if (!tp.IsNewLineAfterPosition(node.End) && tp.IsWhitespaceAfterPosition(node.End - 1)) { var lineEnd = tp.IndexOf('\n', node.End); lineEnd = lineEnd >= 0 ? lineEnd : tp.Length; var text = tp.GetText(TextRange.FromBounds(node.End, lineEnd)); var wsEnd = text.IndexWhere(ch => !char.IsWhiteSpace(ch)).FirstOrDefault(); wsEnd = wsEnd > 0 ? wsEnd + node.End : tp.Length; return(new ValidationWarning(TextRange.FromBounds(node.End, wsEnd), Resources.Lint_SpaceAfterLeftParenthesis, ErrorLocation.Token)); } break; case RTokenType.CloseBrace: // () is OK, (,,,) is OK, x( ) is not OK. But we do allow line break before ) if (tp.IsWhitespaceBeforePosition(node.Start) && !tp.IsNewLineBeforePosition(node.Start)) { var i = node.Start - 1; for (; i >= 0; i--) { if (!char.IsWhiteSpace(tp[i]) || tp[i] == '\r' || tp[i] == '\n') { i++; break; } } i = Math.Max(i, 0); return(new ValidationWarning(TextRange.FromBounds(i, node.Start), Resources.Lint_SpaceBeforeClosingBrace, ErrorLocation.Token)); } break; case RTokenType.CloseSquareBracket: case RTokenType.CloseDoubleSquareBracket: // x[1] is OK, x[1,] is not OK, should be x[1, ] var prevChar = node.Start > 0 ? tp[node.Start - 1] : '\0'; if (!tp.IsWhitespaceAfterPosition(node.End - 1) && prevChar == ',') { return(new ValidationWarning(node, Resources.Lint_NoSpaceBetweenCommaAndClosingBracket, ErrorLocation.Token)); } break; } return(null); }
private static IValidationError DoubleQuotesCheck(IAstNode node, LintOptions options, bool projectedBuffer) { // open_curly_linter: check that opening curly braces are never on their own line and are // always followed by a newline if (options.DoubleQuotes) { if (node is TokenNode t && t.Token.TokenType == RTokenType.String) { if (node.Root.TextProvider[node.Start] != '\"') { return(new ValidationWarning(node, Resources.Lint_DoubleQuotes, ErrorLocation.Token)); } } } return(null); }
private static IValidationError OpenCurlyPositionCheck(IAstNode node, LintOptions options) { // open_curly_linter: check that opening curly braces are never on their own line // and are always followed by a newline if (options.OpenCurlyPosition) { if (node is TokenNode t && t.Token.TokenType == RTokenType.OpenCurlyBrace) { var tp = node.Root.TextProvider; if (!HasLineTextBeforePosition(tp, node.Start) || !tp.IsNewLineAfterPosition(node.End)) { return(new ValidationWarning(node, Resources.Lint_OpenCurlyPosition, ErrorLocation.Token)); } } } return(null); }
private static IValidationError InfixOperatorsSpacesCheck(IAstNode node, LintOptions options) { // infix_spaces_linter: check that all infix operators have spaces around them. if (options.SpacesAroundOperators) { if (node is IOperator op && !op.IsUnary && op is TokenOperator to) { var tp = node.Root.TextProvider; var t = to.OperatorToken; if (!tp.IsWhitespaceBeforePosition(t.Start) || !tp.IsWhitespaceAfterPosition(t.End - 1)) { return(new ValidationWarning(t, Resources.Lint_OperatorSpaces, ErrorLocation.Token)); } } } return(null); }
private static IValidationError CloseCurlySeparateLineCheck(IAstNode node, LintOptions options, bool projectedBuffer) { // closed_curly_linter: check that closed curly braces should always be // on their own line unless they follow an else if (!options.CloseCurlySeparateLine) { return(null); } if (!(node is TokenNode t) || t.Token.TokenType != RTokenType.CloseCurlyBrace) { return(null); } // Special case {r in R Markdown if (projectedBuffer && IsRMarkdownBlock(node)) { return(null); } // Check 'after' case first to we allow '{x})' or '{x},' var text = GetLineTextAfterPosition(node.Root.TextProvider, node.Start).TrimStart(); // Handle '},', '})' and '} else' if (text.StartsWithOrdinal(",") || text.StartsWithOrdinal(")")) { return(null); } if (!string.IsNullOrWhiteSpace(text) && !text.StartsWithOrdinal("else")) { return(new ValidationWarning(node, Resources.Lint_CloseCurlySeparateLine, ErrorLocation.Token)); } text = GetLineTextBeforePosition(node.Root.TextProvider, node.Start); // allow '{ }' if (string.IsNullOrWhiteSpace(text) || text.TrimEnd().EndsWithOrdinal("{")) { return(null); } return(new ValidationWarning(node, Resources.Lint_CloseCurlySeparateLine, ErrorLocation.Token)); }
private static IValidationError OpenCurlyPositionCheck(IAstNode node, LintOptions options, bool projectedBuffer) { // open_curly_linter: check that opening curly braces are never on their own line // and are always followed by a newline if (options.OpenCurlyPosition) { if (node is TokenNode t && t.Token.TokenType == RTokenType.OpenCurlyBrace) { var tp = node.Root.TextProvider; // Special case {r in R Markdown if (projectedBuffer && IsRMarkdownBlock(node)) { return(null); } if (!HasLineTextBeforePosition(tp, node.Start, out var unused) || !tp.IsNewLineAfterPosition(node.End)) { return(new ValidationWarning(node, Resources.Lint_OpenCurlyPosition, ErrorLocation.Token)); } } } return(null); }
private static IValidationError OpenCurlyPositionCheck(IAstNode node, LintOptions options, bool projectedBuffer) { // open_curly_linter: check that opening curly braces are never on their own line // and are always followed by a newline if (!options.OpenCurlyPosition) { return(null); } if (!(node is TokenNode t) || t.Token.TokenType != RTokenType.OpenCurlyBrace) { return(null); } // Special case {r in R Markdown if (projectedBuffer && IsRMarkdownBlock(node)) { return(null); } var tp = node.Root.TextProvider; var text = GetLineTextBeforePosition(tp, node.Start); if (string.IsNullOrWhiteSpace(text)) { return(new ValidationWarning(node, Resources.Lint_OpenCurlyPosition, ErrorLocation.Token)); } // allow '{ }' text = GetLineTextAfterPosition(tp, node.Start); if (string.IsNullOrWhiteSpace(text) || text.TrimStart().StartsWithOrdinal("}")) { return(null); } return(new ValidationWarning(node, Resources.Lint_OpenCurlyPosition, ErrorLocation.Token)); }