|
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using Microsoft.CodeAnalysis.Syntax.InternalSyntax;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.CSharp.Syntax.InternalSyntax
{
/// <summary>
/// Set of well-known SyntaxTokens commonly found within XML doc comments.
/// </summary>
internal static class DocumentationCommentXmlTokens
{
// Well-known tags that typically have no leading trivia
private static readonly SyntaxToken s_seeToken = Identifier(DocumentationCommentXmlNames.SeeElementName);
private static readonly SyntaxToken s_codeToken = Identifier(DocumentationCommentXmlNames.CodeElementName);
private static readonly SyntaxToken s_listToken = Identifier(DocumentationCommentXmlNames.ListElementName);
private static readonly SyntaxToken s_paramToken = Identifier(DocumentationCommentXmlNames.ParameterElementName);
private static readonly SyntaxToken s_valueToken = Identifier(DocumentationCommentXmlNames.ValueElementName);
private static readonly SyntaxToken s_exampleToken = Identifier(DocumentationCommentXmlNames.ExampleElementName);
private static readonly SyntaxToken s_includeToken = Identifier(DocumentationCommentXmlNames.IncludeElementName);
private static readonly SyntaxToken s_remarksToken = Identifier(DocumentationCommentXmlNames.RemarksElementName);
private static readonly SyntaxToken s_seealsoToken = Identifier(DocumentationCommentXmlNames.SeeAlsoElementName);
private static readonly SyntaxToken s_summaryToken = Identifier(DocumentationCommentXmlNames.SummaryElementName);
private static readonly SyntaxToken s_exceptionToken = Identifier(DocumentationCommentXmlNames.ExceptionElementName);
private static readonly SyntaxToken s_typeparamToken = Identifier(DocumentationCommentXmlNames.TypeParameterElementName);
private static readonly SyntaxToken s_permissionToken = Identifier(DocumentationCommentXmlNames.PermissionElementName);
private static readonly SyntaxToken s_typeparamrefToken = Identifier(DocumentationCommentXmlNames.TypeParameterReferenceElementName);
// Well-known tags that typically have a single space in leading trivia
private static readonly SyntaxToken s_crefToken = IdentifierWithLeadingSpace(DocumentationCommentXmlNames.CrefAttributeName);
private static readonly SyntaxToken s_fileToken = IdentifierWithLeadingSpace(DocumentationCommentXmlNames.FileAttributeName);
private static readonly SyntaxToken s_nameToken = IdentifierWithLeadingSpace(DocumentationCommentXmlNames.NameAttributeName);
private static readonly SyntaxToken s_pathToken = IdentifierWithLeadingSpace(DocumentationCommentXmlNames.PathAttributeName);
private static readonly SyntaxToken s_typeToken = IdentifierWithLeadingSpace(DocumentationCommentXmlNames.TypeAttributeName);
private static SyntaxToken Identifier(string text)
{
return SyntaxFactory.Identifier(SyntaxKind.None, null, text, text, trailing: null);
}
private static SyntaxToken IdentifierWithLeadingSpace(string text)
{
return SyntaxFactory.Identifier(SyntaxKind.None, SyntaxFactory.Space, text, text, trailing: null);
}
private static bool IsSingleSpaceTrivia(SyntaxListBuilder syntax)
{
return syntax.Count == 1 && SyntaxFactory.Space.IsEquivalentTo(syntax[0]);
}
/// <summary>
/// Look up a well known SyntaxToken for a given XML element tag or attribute.
/// This is a performance optimization to avoid creating duplicate tokens for the same content.
/// </summary>
/// <param name="text">The text of the tag or attribute.</param>
/// <param name="leading">The leading trivia of the token.</param>
/// <returns>The SyntaxToken representing the well-known tag or attribute or null if it's not well-known.</returns>
public static SyntaxToken? LookupToken(string text, SyntaxListBuilder? leading)
{
if (leading == null)
{
return LookupXmlElementTag(text);
}
if (IsSingleSpaceTrivia(leading))
{
return LookupXmlAttribute(text);
}
return null;
}
private static SyntaxToken? LookupXmlElementTag(string text)
{
switch (text.Length)
{
case 3:
if (text == DocumentationCommentXmlNames.SeeElementName)
{
return s_seeToken;
}
break;
case 4:
switch (text)
{
case DocumentationCommentXmlNames.CodeElementName:
return s_codeToken;
case DocumentationCommentXmlNames.ListElementName:
return s_listToken;
}
break;
case 5:
switch (text)
{
case DocumentationCommentXmlNames.ParameterElementName:
return s_paramToken;
case DocumentationCommentXmlNames.ValueElementName:
return s_valueToken;
}
break;
case 7:
switch (text)
{
case DocumentationCommentXmlNames.ExampleElementName:
return s_exampleToken;
case DocumentationCommentXmlNames.IncludeElementName:
return s_includeToken;
case DocumentationCommentXmlNames.RemarksElementName:
return s_remarksToken;
case DocumentationCommentXmlNames.SeeAlsoElementName:
return s_seealsoToken;
case DocumentationCommentXmlNames.SummaryElementName:
return s_summaryToken;
}
break;
case 9:
switch (text)
{
case DocumentationCommentXmlNames.ExceptionElementName:
return s_exceptionToken;
case DocumentationCommentXmlNames.TypeParameterElementName:
return s_typeparamToken;
}
break;
case 10:
if (text == DocumentationCommentXmlNames.PermissionElementName)
{
return s_permissionToken;
}
break;
case 12:
if (text == DocumentationCommentXmlNames.TypeParameterElementName)
{
return s_typeparamrefToken;
}
break;
}
return null;
}
private static SyntaxToken? LookupXmlAttribute(string text)
{
// It happens that all tokens have text of length 4
if (text.Length != 4)
{
return null;
}
// The compiler may choose to turn this switch statement into a dictionary lookup
switch (text)
{
case DocumentationCommentXmlNames.CrefAttributeName:
return s_crefToken;
case DocumentationCommentXmlNames.FileAttributeName:
return s_fileToken;
case DocumentationCommentXmlNames.NameAttributeName:
return s_nameToken;
case DocumentationCommentXmlNames.PathAttributeName:
return s_pathToken;
case DocumentationCommentXmlNames.TypeAttributeName:
return s_typeToken;
}
return null;
}
}
}
|