/// <summary>
        /// Gets the first token on the textline that the given token is on.
        /// </summary>
        /// <param name="token">The token used to determine the textline.</param>
        /// <returns>The first token on the textline of the given token.</returns>
        public static SyntaxToken GetFirstTokenOnTextLine(SyntaxToken token)
        {
            while (true)
            {
                var precedingToken = token.GetPreviousToken();
                if (precedingToken.IsKind(SyntaxKind.None))
                {
                    return token;
                }

                if (precedingToken.GetLine() < token.GetLine())
                {
                    return token;
                }

                token = precedingToken;
            }
        }
        private static void HandleCloseParenToken(SyntaxTreeAnalysisContext context, SyntaxToken token)
        {
            if (token.IsMissing)
            {
                return;
            }

            bool precededBySpace = token.IsFirstInLine() || token.IsPrecededByWhitespace(context.CancellationToken);
            bool followedBySpace = token.IsFollowedByWhitespace();
            bool lastInLine      = token.IsLastInLine();
            bool precedesStickyCharacter;
            bool allowEndOfLine = false;
            bool preserveLayout = false;

            bool suppressFollowingSpaceError = false;

            SyntaxToken nextToken = token.GetNextToken();

            switch (nextToken.Kind())
            {
            case SyntaxKind.OpenParenToken:
                // Allow a space between an open and a close paren when:
                // - they are part of an if statement
                // - they are on the same line
                // - the open paren is part of a parenthesized expression or a tuple expression.
                precedesStickyCharacter =
                    !(token.Parent.IsKind(SyntaxKind.IfStatement) &&
                      (token.GetLine() == nextToken.GetLine()) &&
                      (nextToken.Parent.IsKind(SyntaxKind.ParenthesizedExpression) || nextToken.Parent.IsKind(SyntaxKindEx.TupleExpression)));
                break;

            case SyntaxKind.CloseParenToken:
            case SyntaxKind.OpenBracketToken:
            case SyntaxKind.CloseBracketToken:
            case SyntaxKind.SemicolonToken:
            case SyntaxKind.CommaToken:
            case SyntaxKind.DoubleQuoteToken:
            case SyntaxKindEx.DotDotToken:
                precedesStickyCharacter = true;
                break;

            case SyntaxKind.GreaterThanToken:
                precedesStickyCharacter = nextToken.Parent.IsKind(SyntaxKind.TypeArgumentList);
                break;

            case SyntaxKind.QuestionToken:
                if (nextToken.Parent.IsKind(SyntaxKind.ConditionalAccessExpression))
                {
                    // allow a space for this case, but only if the ')' character is the last on the line
                    allowEndOfLine          = true;
                    precedesStickyCharacter = true;
                }
                else
                {
                    // A space follows unless this is a nullable tuple type
                    precedesStickyCharacter = nextToken.Parent.IsKind(SyntaxKind.NullableType);
                }

                break;

            case SyntaxKind.PlusToken:
                precedesStickyCharacter = nextToken.Parent.IsKind(SyntaxKind.UnaryPlusExpression);

                // this will be reported as SA1022
                suppressFollowingSpaceError = precedesStickyCharacter;
                break;

            case SyntaxKind.MinusToken:
                precedesStickyCharacter = nextToken.Parent.IsKind(SyntaxKind.UnaryMinusExpression);

                // this will be reported as SA1021
                suppressFollowingSpaceError = precedesStickyCharacter;
                break;

            case SyntaxKind.DotToken:
                // allow a space for this case, but only if the ')' character is the last on the line
                allowEndOfLine          = true;
                precedesStickyCharacter = true;

                preserveLayout = nextToken.Parent.IsKind(SyntaxKind.SimpleMemberAccessExpression);
                break;

            case SyntaxKind.MinusGreaterThanToken:
                // allow a space for this case, but only if the ')' character is the last on the line
                allowEndOfLine          = true;
                precedesStickyCharacter = true;
                break;

            case SyntaxKind.ColonToken:
                bool requireSpace =
                    nextToken.Parent.IsKind(SyntaxKind.ConditionalExpression) ||
                    nextToken.Parent.IsKind(SyntaxKind.BaseConstructorInitializer) ||
                    nextToken.Parent.IsKind(SyntaxKind.ThisConstructorInitializer) ||
                    nextToken.Parent.IsKind(SyntaxKind.BaseList);
                precedesStickyCharacter = !requireSpace;
                break;

            case SyntaxKind.PlusPlusToken:
            case SyntaxKind.MinusMinusToken:
                precedesStickyCharacter     = true;
                suppressFollowingSpaceError = false;
                break;

            case SyntaxKind.CloseBraceToken:
                precedesStickyCharacter = nextToken.Parent is InterpolationSyntax;
                break;

            case SyntaxKind.ExclamationToken when nextToken.Parent.IsKind(SyntaxKindEx.SuppressNullableWarningExpression):
                precedesStickyCharacter = true;

                break;

            default:
                precedesStickyCharacter = false;
                break;
            }

            switch (token.Parent.Kind())
            {
            case SyntaxKind.CastExpression:
                precedesStickyCharacter = true;
                break;

            default:
                break;
            }

            foreach (var trivia in token.TrailingTrivia)
            {
                if (trivia.IsKind(SyntaxKind.EndOfLineTrivia))
                {
                    break;
                }
                else if (trivia.IsKind(SyntaxKind.SingleLineCommentTrivia) ||
                         trivia.IsKind(SyntaxKind.MultiLineCommentTrivia))
                {
                    lastInLine = false;
                    precedesStickyCharacter = false;
                    break;
                }
            }

            if (precededBySpace)
            {
                // Closing parenthesis should{ not} be {preceded} by a space.
                ImmutableDictionary <string, string> properties;

                if (preserveLayout)
                {
                    properties = TokenSpacingProperties.RemovePrecedingPreserveLayout;
                }
                else
                {
                    properties = token.IsFirstInLine()
                        ? TokenSpacingProperties.RemovePreceding
                        : TokenSpacingProperties.RemoveImmediatePreceding;
                }

                context.ReportDiagnostic(Diagnostic.Create(DescriptorNotPreceded, token.GetLocation(), properties));
            }

            if (!suppressFollowingSpaceError)
            {
                if (!precedesStickyCharacter && !followedBySpace && !lastInLine)
                {
                    // Closing parenthesis should{} be {followed} by a space.
                    var properties = TokenSpacingProperties.InsertFollowing;
#pragma warning disable RS1005 // ReportDiagnostic invoked with an unsupported DiagnosticDescriptor (https://github.com/dotnet/roslyn-analyzers/issues/4103)
                    context.ReportDiagnostic(Diagnostic.Create(DescriptorFollowed, token.GetLocation(), properties));
#pragma warning restore RS1005 // ReportDiagnostic invoked with an unsupported DiagnosticDescriptor
                }
                else if (precedesStickyCharacter && followedBySpace && (!lastInLine || !allowEndOfLine))
                {
                    // Closing parenthesis should{ not} be {followed} by a space.
                    var properties = TokenSpacingProperties.RemoveFollowing;
#pragma warning disable RS1005 // ReportDiagnostic invoked with an unsupported DiagnosticDescriptor (https://github.com/dotnet/roslyn-analyzers/issues/4103)
                    context.ReportDiagnostic(Diagnostic.Create(DescriptorNotFollowed, token.GetLocation(), properties));
#pragma warning restore RS1005 // ReportDiagnostic invoked with an unsupported DiagnosticDescriptor
                }
            }
        }
 private static void Analyze(
     SyntaxNodeAnalysisContext context,
     SyntaxToken openParenOrBracketToken,
     SyntaxNode firstParameter,
     SyntaxNode secondParameter)
 {
     int firstParameterLine = firstParameter.GetLineSpan().StartLinePosition.Line;
     if (openParenOrBracketToken.GetLine() == firstParameterLine)
     {
         if (firstParameterLine != secondParameter.GetLineSpan().StartLinePosition.Line)
         {
             context.ReportDiagnostic(Diagnostic.Create(Descriptor, firstParameter.GetLocation()));
         }
     }
 }
Beispiel #4
0
        /// <summary>
        /// Gets a value indicating whether the <paramref name="token"/> is the first token in a line and it is only preceded by whitespace.
        /// </summary>
        /// <param name="token">The token to process.</param>
        /// <returns>true if the token is the first token in a line and it is only preceded by whitespace.</returns>
        internal static bool IsOnlyPrecededByWhitespaceInLine(this SyntaxToken token)
        {
            SyntaxToken precedingToken = token.GetPreviousToken();

            if (!precedingToken.IsKind(SyntaxKind.None) && (precedingToken.GetLine() == token.GetLine()))
            {
                return(false);
            }

            var precedingTriviaList = TriviaHelper.MergeTriviaLists(precedingToken.TrailingTrivia, token.LeadingTrivia);

            for (var i = precedingTriviaList.Count - 1; i >= 0; i--)
            {
                switch (precedingTriviaList[i].Kind())
                {
                case SyntaxKind.WhitespaceTrivia:
                    break;

                case SyntaxKind.EndOfLineTrivia:
                    return(true);

                default:
                    return(false);
                }
            }

            return(true);
        }
        private static void CheckBraces(SyntaxNodeAnalysisContext context, SyntaxToken openBraceToken, SyntaxToken closeBraceToken)
        {
            bool checkCloseBrace    = true;
            int  openBraceTokenLine = openBraceToken.GetLine();

            if (openBraceTokenLine == closeBraceToken.GetLine())
            {
                if (context.Node.IsKind(SyntaxKind.ArrayInitializerExpression))
                {
                    switch (context.Node.Parent.Kind())
                    {
                    case SyntaxKind.EqualsValueClause:
                        if (((EqualsValueClauseSyntax)context.Node.Parent).EqualsToken.GetLine() == openBraceTokenLine)
                        {
                            return;
                        }

                        break;

                    case SyntaxKind.ArrayCreationExpression:
                        if (((ArrayCreationExpressionSyntax)context.Node.Parent).NewKeyword.GetLine() == openBraceTokenLine)
                        {
                            return;
                        }

                        break;

                    case SyntaxKind.ImplicitArrayCreationExpression:
                        if (((ImplicitArrayCreationExpressionSyntax)context.Node.Parent).NewKeyword.GetLine() == openBraceTokenLine)
                        {
                            return;
                        }

                        break;

                    case SyntaxKind.ArrayInitializerExpression:
                        if (!InitializerExpressionSharesLine((InitializerExpressionSyntax)context.Node))
                        {
                            return;
                        }

                        checkCloseBrace = false;
                        break;

                    default:
                        break;
                    }
                }
                else
                {
                    switch (context.Node.Parent.Kind())
                    {
                    case SyntaxKind.GetAccessorDeclaration:
                    case SyntaxKind.SetAccessorDeclaration:
                    case SyntaxKind.AddAccessorDeclaration:
                    case SyntaxKind.RemoveAccessorDeclaration:
                    case SyntaxKind.UnknownAccessorDeclaration:
                        if (((AccessorDeclarationSyntax)context.Node.Parent).Keyword.GetLine() == openBraceTokenLine)
                        {
                            // reported as SA1504, if at all
                            return;
                        }

                        checkCloseBrace = false;
                        break;

                    default:
                        // reported by SA1501 or SA1502
                        return;
                    }
                }
            }

            CheckBraceToken(context, openBraceToken);
            if (checkCloseBrace)
            {
                CheckBraceToken(context, closeBraceToken);
            }
        }
        /// <summary>
        /// Gets a value indicating whether the <paramref name="token"/> is last in line.
        /// </summary>
        /// <param name="token">The token to process.</param>
        /// <returns>true if token is last in line, otherwise false.</returns>
        internal static bool IsLastInLine(this SyntaxToken token)
        {
            SyntaxToken nextToken = token.GetNextToken();

            return(nextToken.IsKind(SyntaxKind.None) || token.GetEndLine() < nextToken.GetLine());
        }
        /// <summary>
        /// Gets a value indicating whether the <paramref name="token"/> is first in line.
        /// </summary>
        /// <param name="token">The token to process.</param>
        /// <returns>true if token is first in line, otherwise false.</returns>
        internal static bool IsFirstInLine(this SyntaxToken token)
        {
            SyntaxToken previousToken = token.GetPreviousToken();

            return(previousToken.IsKind(SyntaxKind.None) || previousToken.GetEndLine() < token.GetLine());
        }
Beispiel #8
0
 public override string ToString()
 {
     return($"строки {Open.GetLine() + 1}–{Close.GetLine() + 1}");
 }
Beispiel #9
0
        public static SyntaxToken GetFirstTokenAtLine(SyntaxToken token)
        {
            var tokenLineSpanStart = token.SyntaxTree.GetText().Lines[token.GetLine()].Start;

            return(token.SyntaxTree.GetRoot().FindToken(tokenLineSpanStart));
        }