in src/Compilers/CSharp/Portable/Syntax/SyntaxNormalizer.cs [332:460]
private static bool NeedsSeparator(SyntaxToken token, SyntaxToken next)
{
if (token.Parent == null || next.Parent == null)
{
return false;
}
if (IsXmlTextToken(token.Kind()) || IsXmlTextToken(next.Kind()))
{
return false;
}
if (next.Kind() == SyntaxKind.EndOfDirectiveToken)
{
// In a directive, there's often no token between the directive keyword and
// the end-of-directive, so we may need a separator.
return IsKeyword(token.Kind()) && next.LeadingWidth > 0;
}
if ((token.Parent is AssignmentExpressionSyntax && AssignmentTokenNeedsSeparator(token.Kind())) ||
(next.Parent is AssignmentExpressionSyntax && AssignmentTokenNeedsSeparator(next.Kind())) ||
(token.Parent is BinaryExpressionSyntax && BinaryTokenNeedsSeparator(token.Kind())) ||
(next.Parent is BinaryExpressionSyntax && BinaryTokenNeedsSeparator(next.Kind())))
{
return true;
}
if (token.IsKind(SyntaxKind.GreaterThanToken) && token.Parent.IsKind(SyntaxKind.TypeArgumentList))
{
if (!SyntaxFacts.IsPunctuation(next.Kind()))
{
return true;
}
}
if (token.IsKind(SyntaxKind.CommaToken) &&
!next.IsKind(SyntaxKind.CommaToken) &&
!token.Parent.IsKind(SyntaxKind.EnumDeclaration))
{
return true;
}
if (token.Kind() == SyntaxKind.SemicolonToken
&& !(next.Kind() == SyntaxKind.SemicolonToken || next.Kind() == SyntaxKind.CloseParenToken))
{
return true;
}
if (token.IsKind(SyntaxKind.QuestionToken)
&& (token.Parent.IsKind(SyntaxKind.ConditionalExpression) || token.Parent is TypeSyntax))
{
return true;
}
if (token.IsKind(SyntaxKind.ColonToken))
{
return !token.Parent.IsKind(SyntaxKind.InterpolationFormatClause);
}
if (next.IsKind(SyntaxKind.ColonToken))
{
if (next.Parent.IsKind(SyntaxKind.BaseList) ||
next.Parent.IsKind(SyntaxKind.TypeParameterConstraintClause))
{
return true;
}
}
if (token.IsKind(SyntaxKind.CloseBracketToken) && IsWord(next.Kind()))
{
return true;
}
if ((next.IsKind(SyntaxKind.QuestionToken) || next.IsKind(SyntaxKind.ColonToken))
&& (next.Parent.IsKind(SyntaxKind.ConditionalExpression)))
{
return true;
}
if (token.IsKind(SyntaxKind.EqualsToken) || next.IsKind(SyntaxKind.EqualsToken))
{
return true;
}
if (token.IsKind(SyntaxKind.EqualsGreaterThanToken) || next.IsKind(SyntaxKind.EqualsGreaterThanToken))
{
return true;
}
// Can happen in directives (e.g. #line 1 "file")
if (SyntaxFacts.IsLiteral(token.Kind()) && SyntaxFacts.IsLiteral(next.Kind()))
{
return true;
}
if (IsKeyword(token.Kind()))
{
if (!next.IsKind(SyntaxKind.ColonToken) &&
!next.IsKind(SyntaxKind.DotToken) &&
!next.IsKind(SyntaxKind.QuestionToken) &&
!next.IsKind(SyntaxKind.SemicolonToken) &&
!next.IsKind(SyntaxKind.OpenBracketToken) &&
(!next.IsKind(SyntaxKind.OpenParenToken) || KeywordNeedsSeparatorBeforeOpenParen(token.Kind())) &&
!next.IsKind(SyntaxKind.CloseParenToken) &&
!next.IsKind(SyntaxKind.CloseBraceToken) &&
!next.IsKind(SyntaxKind.ColonColonToken) &&
!next.IsKind(SyntaxKind.GreaterThanToken) &&
!next.IsKind(SyntaxKind.CommaToken))
{
return true;
}
}
if (IsWord(token.Kind()) && IsWord(next.Kind()))
{
return true;
}
else if (token.Width > 1 && next.Width > 1)
{
var tokenLastChar = token.Text.Last();
var nextFirstChar = next.Text.First();
if (tokenLastChar == nextFirstChar && TokenCharacterCanBeDoubled(tokenLastChar))
{
return true;
}
}
return false;
}