Repository: dotnet/roslyn
File: src/Compilers/CSharp/Portable/Parser/SyntaxParser.cs (C#)

Code before:
                token = WithAdditionalDiagnostics(token, this.GetExpectedTokenError(kind, token.Kind, offset, width));
            }

            this.MoveToNextToken();
            return token;

            (int offset, int width) getDiagnosticSpan()
            {
                // We got the wrong kind while forcefully eating this token.  If it's on the same line as the last
                // token, just squiggle it as being the wrong kind. If it's on the next line, move the squiggle back to
                // the end of the previous token and make it zero width, indicating the expected token was missed at
                // that location.

                var trivia = _prevTokenTrailingTrivia;
                var triviaList = new SyntaxList<CSharpSyntaxNode>(trivia);
                if (triviaList.Any((int)SyntaxKind.EndOfLineTrivia))
                    return (offset: -(trivia.FullWidth + token.GetLeadingTriviaWidth()), width: 0);

                return (offset: 0, token.Width);
            }
        }

        protected SyntaxToken EatTokenWithPrejudice(ErrorCode errorCode, params object[] args)
        {
            var token = this.EatToken();
            token = WithAdditionalDiagnostics(token, MakeError(offset: 0, token.Width, errorCode, args));
            return token;
        }

        protected SyntaxToken EatContextualToken(SyntaxKind kind, ErrorCode code, bool reportError = true)
        {
            Debug.Assert(SyntaxFacts.IsAnyToken(kind));

            if (this.CurrentToken.ContextualKind != kind)
            {
                return CreateMissingToken(kind, code, reportError);
            }
            else
            {
                return ConvertToKeyword(this.EatToken());
            }
        }

        protected SyntaxToken EatContextualToken(SyntaxKind kind)
        {
            Debug.Assert(SyntaxFacts.IsAnyToken(kind));

            var contextualKind = this.CurrentToken.ContextualKind;
            if (contextualKind != kind)
            {
                return CreateMissingToken(kind, contextualKind);

Review comment (suggestion):
this logic is now meaningfully different from getOffsetAndWidthBasedOnPriorAndNextTokens.

Note: i would be ok with not doing the work to move the diagnostic backwards.  but it does impact existing tests.  so this preserves behavior for them.

Code after:
        protected SyntaxToken EatTokenEvenWithIncorrectKind(SyntaxKind kind)
        {
            var token = this.CurrentToken;
            Debug.Assert(SyntaxFacts.IsAnyToken(kind));
            if (token.Kind != kind)
            {
                var (offset, width) = getDiagnosticSpan();
                token = WithAdditionalDiagnostics(token, this.GetExpectedTokenError(kind, token.Kind, offset, width));
            }

            this.MoveToNextToken();
            return token;

            (int offset, int width) getDiagnosticSpan()
            {
                // We got the wrong kind while forcefully eating this token.  If it's on the same line as the last
                // token, just squiggle it as being the wrong kind. If it's on the next line, move the squiggle back to
                // the end of the previous token and make it zero width, indicating the expected token was missed at
                // that location (even though we're still unilaterally consuming this token).

                var trivia = _prevTokenTrailingTrivia;
                var triviaList = new SyntaxList<CSharpSyntaxNode>(trivia);
                if (triviaList.Any((int)SyntaxKind.EndOfLineTrivia))
                    return (offset: -(trivia.FullWidth + token.GetLeadingTriviaWidth()), width: 0);

                return (offset: 0, token.Width);
            }
        }

        protected SyntaxToken EatTokenWithPrejudice(ErrorCode errorCode, params object[] args)
        {
            var token = this.EatToken();
            token = WithAdditionalDiagnostics(token, MakeError(offset: 0, token.Width, errorCode, args));
            return token;
        }

        protected SyntaxToken EatContextualToken(SyntaxKind kind, ErrorCode code, bool reportError = true)
        {
            Debug.Assert(SyntaxFacts.IsAnyToken(kind));

            if (this.CurrentToken.ContextualKind != kind)
            {
                return CreateMissingToken(kind, code, reportError);
            }
            else
            {
                return ConvertToKeyword(this.EatToken());
            }
        }

        protected SyntaxToken EatContextualToken(SyntaxKind kind)