提交 d6aed247 编写于 作者: C CyrusNajmabadi

Break out code for index building into its own service.

上级 55c8d481
......@@ -3,6 +3,7 @@
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Composition;
using System.Diagnostics;
using System.Linq;
using System.Text;
......@@ -13,6 +14,7 @@
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.FindSymbols;
using Microsoft.CodeAnalysis.Formatting;
using Microsoft.CodeAnalysis.Host.Mef;
using Microsoft.CodeAnalysis.LanguageServices;
using Microsoft.CodeAnalysis.Shared.Extensions;
using Microsoft.CodeAnalysis.Text;
......@@ -20,1221 +22,1221 @@
namespace Microsoft.CodeAnalysis.CSharp
{
internal class CSharpSyntaxFactsService : AbstractSyntaxFactsService, ISyntaxFactsService
[ExportLanguageService(typeof(IDeclaredSymbolInfoFactoryService), LanguageNames.CSharp), Shared]
internal class CSharpDeclaredSymbolInfoFactoryService : AbstractDeclaredSymbolInfoFactoryService
{
internal static readonly CSharpSyntaxFactsService Instance = new CSharpSyntaxFactsService();
private CSharpSyntaxFactsService()
{
}
public bool IsCaseSensitive => true;
public StringComparer StringComparer { get; } = StringComparer.Ordinal;
protected override IDocumentationCommentService DocumentationCommentService
=> CSharpDocumentationCommentService.Instance;
public bool SupportsIndexingInitializer(ParseOptions options)
=> ((CSharpParseOptions)options).LanguageVersion >= LanguageVersion.CSharp6;
public bool SupportsThrowExpression(ParseOptions options)
=> ((CSharpParseOptions)options).LanguageVersion >= LanguageVersion.CSharp7;
public bool IsAwaitKeyword(SyntaxToken token)
{
return token.IsKind(SyntaxKind.AwaitKeyword);
}
public bool IsIdentifier(SyntaxToken token)
{
return token.IsKind(SyntaxKind.IdentifierToken);
}
public bool IsGlobalNamespaceKeyword(SyntaxToken token)
{
return token.IsKind(SyntaxKind.GlobalKeyword);
}
public bool IsVerbatimIdentifier(SyntaxToken token)
{
return token.IsVerbatimIdentifier();
}
public bool IsOperator(SyntaxToken token)
{
var kind = token.Kind();
return
(SyntaxFacts.IsAnyUnaryExpression(kind) &&
(token.Parent is PrefixUnaryExpressionSyntax || token.Parent is PostfixUnaryExpressionSyntax || token.Parent is OperatorDeclarationSyntax)) ||
(SyntaxFacts.IsBinaryExpression(kind) && (token.Parent is BinaryExpressionSyntax || token.Parent is OperatorDeclarationSyntax)) ||
(SyntaxFacts.IsAssignmentExpressionOperatorToken(kind) && token.Parent is AssignmentExpressionSyntax);
}
public bool IsKeyword(SyntaxToken token)
{
var kind = (SyntaxKind)token.RawKind;
return
SyntaxFacts.IsKeywordKind(kind); // both contextual and reserved keywords
}
public bool IsContextualKeyword(SyntaxToken token)
{
var kind = (SyntaxKind)token.RawKind;
return
SyntaxFacts.IsContextualKeyword(kind);
}
public bool IsPreprocessorKeyword(SyntaxToken token)
{
var kind = (SyntaxKind)token.RawKind;
return
SyntaxFacts.IsPreprocessorKeyword(kind);
}
public bool IsHashToken(SyntaxToken token)
{
return (SyntaxKind)token.RawKind == SyntaxKind.HashToken;
}
public bool IsInInactiveRegion(SyntaxTree syntaxTree, int position, CancellationToken cancellationToken)
private ImmutableArray<string> GetInheritanceNames(Project project, BaseListSyntax baseList)
{
var csharpTree = syntaxTree as SyntaxTree;
if (csharpTree == null)
if (baseList == null)
{
return false;
return ImmutableArray<string>.Empty;
}
return csharpTree.IsInInactiveRegion(position, cancellationToken);
}
var builder = ArrayBuilder<string>.GetInstance(baseList.Types.Count);
public bool IsInNonUserCode(SyntaxTree syntaxTree, int position, CancellationToken cancellationToken)
{
var csharpTree = syntaxTree as SyntaxTree;
if (csharpTree == null)
// It's not sufficient to just store the textual names we see in the inheritance list
// of a type. For example if we have:
//
// using Y = X;
// ...
// using Z = Y;
// ...
// class C : Z
//
// It's insufficient to just state that 'C' derives from 'Z'. If we search for derived
// types from 'B' we won't examine 'C'. To solve this, we keep track of the aliasing
// that occurs in containing scopes. Then, when we're adding an inheritance name we
// walk the alias maps and we also add any names that these names alias to. In the
// above example we'd put Z, Y, and X in the inheritance names list for 'C'.
// Each dictionary in this list is a mapping from alias name to the name of the thing
// it aliases. Then, each scope with alias mapping gets its own entry in this list.
// For the above example, we would produce: [{Z => Y}, {Y => X}]
var aliasMaps = AllocateAliasMapList();
try
{
return false;
}
AddAliasMaps(baseList, aliasMaps);
return csharpTree.IsInNonUserCode(position, cancellationToken);
}
foreach (var baseType in baseList.Types)
{
AddInheritanceName(builder, baseType.Type, aliasMaps);
}
public bool IsEntirelyWithinStringOrCharOrNumericLiteral(SyntaxTree syntaxTree, int position, CancellationToken cancellationToken)
{
var csharpTree = syntaxTree as SyntaxTree;
if (csharpTree == null)
DeclaredSymbolInfo.Intern(project, builder);
return builder.ToImmutableAndFree();
}
finally
{
return false;
FreeAliasMapList(aliasMaps);
}
return csharpTree.IsEntirelyWithinStringOrCharLiteral(position, cancellationToken);
}
public bool IsDirective(SyntaxNode node)
{
return node is DirectiveTriviaSyntax;
}
public bool TryGetExternalSourceInfo(SyntaxNode node, out ExternalSourceInfo info)
private void AddAliasMaps(SyntaxNode node, List<Dictionary<string, string>> aliasMaps)
{
var lineDirective = node as LineDirectiveTriviaSyntax;
if (lineDirective != null)
for (var current = node; current != null; current = current.Parent)
{
if (lineDirective.Line.Kind() == SyntaxKind.DefaultKeyword)
if (current.IsKind(SyntaxKind.NamespaceDeclaration))
{
info = new ExternalSourceInfo(null, ends: true);
return true;
ProcessUsings(aliasMaps, ((NamespaceDeclarationSyntax)current).Usings);
}
else if (lineDirective.Line.Kind() == SyntaxKind.NumericLiteralToken &&
lineDirective.Line.Value is int)
else if (current.IsKind(SyntaxKind.CompilationUnit))
{
info = new ExternalSourceInfo((int)lineDirective.Line.Value, false);
return true;
ProcessUsings(aliasMaps, ((CompilationUnitSyntax)current).Usings);
}
}
info = default(ExternalSourceInfo);
return false;
}
public bool IsRightSideOfQualifiedName(SyntaxNode node)
{
var name = node as SimpleNameSyntax;
return name.IsRightSideOfQualifiedName();
}
public bool IsNameOfMemberAccessExpression(SyntaxNode node)
{
var name = node as SimpleNameSyntax;
return name.IsMemberAccessExpressionName();
}
public bool IsObjectCreationExpressionType(SyntaxNode node)
{
return node.IsParentKind(SyntaxKind.ObjectCreationExpression) &&
((ObjectCreationExpressionSyntax)node.Parent).Type == node;
}
public bool IsAttributeName(SyntaxNode node)
private void ProcessUsings(List<Dictionary<string, string>> aliasMaps, SyntaxList<UsingDirectiveSyntax> usings)
{
return SyntaxFacts.IsAttributeName(node);
}
Dictionary<string, string> aliasMap = null;
public bool IsInvocationExpression(SyntaxNode node)
{
return node is InvocationExpressionSyntax;
}
foreach (var usingDecl in usings)
{
if (usingDecl.Alias != null)
{
var mappedName = GetTypeName(usingDecl.Name);
if (mappedName != null)
{
aliasMap = aliasMap ?? AllocateAliasMap();
public bool IsAnonymousFunction(SyntaxNode node)
{
return node is ParenthesizedLambdaExpressionSyntax ||
node is SimpleLambdaExpressionSyntax ||
node is AnonymousMethodExpressionSyntax;
}
// If we have: using X = Foo, then we store a mapping from X -> Foo
// here. That way if we see a class that inherits from X we also state
// that it inherits from Foo as well.
aliasMap[usingDecl.Alias.Name.Identifier.ValueText] = mappedName;
}
}
}
public bool IsGenericName(SyntaxNode node)
{
return node is GenericNameSyntax;
if (aliasMap != null)
{
aliasMaps.Add(aliasMap);
}
}
public bool IsNamedParameter(SyntaxNode node)
=> node.CheckParent<NameColonSyntax>(p => p.Name == node);
public SyntaxNode GetDefaultOfParameter(SyntaxNode node)
=> (node as ParameterSyntax)?.Default;
public bool IsSkippedTokensTrivia(SyntaxNode node)
private void AddInheritanceName(
ArrayBuilder<string> builder, TypeSyntax type,
List<Dictionary<string, string>> aliasMaps)
{
return node is SkippedTokensTriviaSyntax;
}
var name = GetTypeName(type);
if (name != null)
{
// First, add the name that the typename that the type directly says it inherits from.
builder.Add(name);
public bool HasIncompleteParentMember(SyntaxNode node)
{
return node.IsParentKind(SyntaxKind.IncompleteMember);
}
// Now, walk the alias chain and add any names this alias may eventually map to.
var currentName = name;
foreach (var aliasMap in aliasMaps)
{
if (aliasMap.TryGetValue(currentName, out var mappedName))
{
// Looks like this could be an alias. Also include the name the alias points to
builder.Add(mappedName);
public SyntaxToken GetIdentifierOfGenericName(SyntaxNode genericName)
{
var csharpGenericName = genericName as GenericNameSyntax;
return csharpGenericName != null
? csharpGenericName.Identifier
: default(SyntaxToken);
// Keep on searching. An alias in an inner namespcae can refer to an
// alias in an outer namespace.
currentName = mappedName;
}
}
}
}
public bool IsUsingDirectiveName(SyntaxNode node)
public override bool TryGetDeclaredSymbolInfo(Project project, SyntaxNode node, out DeclaredSymbolInfo declaredSymbolInfo)
{
return
node.IsParentKind(SyntaxKind.UsingDirective) &&
((UsingDirectiveSyntax)node.Parent).Name == node;
}
switch (node.Kind())
{
case SyntaxKind.ClassDeclaration:
var classDecl = (ClassDeclarationSyntax)node;
declaredSymbolInfo = new DeclaredSymbolInfo(
project,
classDecl.Identifier.ValueText,
GetTypeParameterSuffix(classDecl.TypeParameterList),
GetContainerDisplayName(node.Parent),
GetFullyQualifiedContainerName(node.Parent),
DeclaredSymbolInfoKind.Class,
GetAccessibility(classDecl, classDecl.Modifiers),
classDecl.Identifier.Span,
GetInheritanceNames(project, classDecl.BaseList));
return true;
case SyntaxKind.ConstructorDeclaration:
var ctorDecl = (ConstructorDeclarationSyntax)node;
declaredSymbolInfo = new DeclaredSymbolInfo(
project,
ctorDecl.Identifier.ValueText,
GetConstructorSuffix(ctorDecl),
GetContainerDisplayName(node.Parent),
GetFullyQualifiedContainerName(node.Parent),
DeclaredSymbolInfoKind.Constructor,
GetAccessibility(ctorDecl, ctorDecl.Modifiers),
ctorDecl.Identifier.Span,
inheritanceNames: ImmutableArray<string>.Empty,
parameterCount: ctorDecl.ParameterList?.Parameters.Count ?? 0);
return true;
case SyntaxKind.DelegateDeclaration:
var delegateDecl = (DelegateDeclarationSyntax)node;
declaredSymbolInfo = new DeclaredSymbolInfo(
project,
delegateDecl.Identifier.ValueText,
GetTypeParameterSuffix(delegateDecl.TypeParameterList),
GetContainerDisplayName(node.Parent),
GetFullyQualifiedContainerName(node.Parent),
DeclaredSymbolInfoKind.Delegate,
GetAccessibility(delegateDecl, delegateDecl.Modifiers),
delegateDecl.Identifier.Span,
inheritanceNames: ImmutableArray<string>.Empty);
return true;
case SyntaxKind.EnumDeclaration:
var enumDecl = (EnumDeclarationSyntax)node;
declaredSymbolInfo = new DeclaredSymbolInfo(
project,
enumDecl.Identifier.ValueText, null,
GetContainerDisplayName(node.Parent),
GetFullyQualifiedContainerName(node.Parent),
DeclaredSymbolInfoKind.Enum,
GetAccessibility(enumDecl, enumDecl.Modifiers),
enumDecl.Identifier.Span,
inheritanceNames: ImmutableArray<string>.Empty);
return true;
case SyntaxKind.EnumMemberDeclaration:
var enumMember = (EnumMemberDeclarationSyntax)node;
declaredSymbolInfo = new DeclaredSymbolInfo(
project,
enumMember.Identifier.ValueText, null,
GetContainerDisplayName(node.Parent),
GetFullyQualifiedContainerName(node.Parent),
DeclaredSymbolInfoKind.EnumMember,
Accessibility.Public,
enumMember.Identifier.Span,
inheritanceNames: ImmutableArray<string>.Empty);
return true;
case SyntaxKind.EventDeclaration:
var eventDecl = (EventDeclarationSyntax)node;
declaredSymbolInfo = new DeclaredSymbolInfo(
project,
eventDecl.Identifier.ValueText, null,
GetContainerDisplayName(node.Parent),
GetFullyQualifiedContainerName(node.Parent),
DeclaredSymbolInfoKind.Event,
GetAccessibility(eventDecl, eventDecl.Modifiers),
eventDecl.Identifier.Span,
inheritanceNames: ImmutableArray<string>.Empty);
return true;
case SyntaxKind.IndexerDeclaration:
var indexerDecl = (IndexerDeclarationSyntax)node;
declaredSymbolInfo = new DeclaredSymbolInfo(
project,
"this", GetIndexerSuffix(indexerDecl),
GetContainerDisplayName(node.Parent),
GetFullyQualifiedContainerName(node.Parent),
DeclaredSymbolInfoKind.Indexer,
GetAccessibility(indexerDecl, indexerDecl.Modifiers),
indexerDecl.ThisKeyword.Span,
inheritanceNames: ImmutableArray<string>.Empty);
return true;
case SyntaxKind.InterfaceDeclaration:
var interfaceDecl = (InterfaceDeclarationSyntax)node;
declaredSymbolInfo = new DeclaredSymbolInfo(
project,
interfaceDecl.Identifier.ValueText, GetTypeParameterSuffix(interfaceDecl.TypeParameterList),
GetContainerDisplayName(node.Parent),
GetFullyQualifiedContainerName(node.Parent),
DeclaredSymbolInfoKind.Interface,
GetAccessibility(interfaceDecl, interfaceDecl.Modifiers),
interfaceDecl.Identifier.Span,
GetInheritanceNames(project, interfaceDecl.BaseList));
return true;
case SyntaxKind.MethodDeclaration:
var method = (MethodDeclarationSyntax)node;
declaredSymbolInfo = new DeclaredSymbolInfo(
project,
method.Identifier.ValueText, GetMethodSuffix(method),
GetContainerDisplayName(node.Parent),
GetFullyQualifiedContainerName(node.Parent),
IsExtensionMethod(method) ? DeclaredSymbolInfoKind.ExtensionMethod : DeclaredSymbolInfoKind.Method,
GetAccessibility(method, method.Modifiers),
method.Identifier.Span,
inheritanceNames: ImmutableArray<string>.Empty,
parameterCount: method.ParameterList?.Parameters.Count ?? 0,
typeParameterCount: method.TypeParameterList?.Parameters.Count ?? 0);
return true;
case SyntaxKind.PropertyDeclaration:
var property = (PropertyDeclarationSyntax)node;
declaredSymbolInfo = new DeclaredSymbolInfo(
project,
property.Identifier.ValueText, null,
GetContainerDisplayName(node.Parent),
GetFullyQualifiedContainerName(node.Parent),
DeclaredSymbolInfoKind.Property,
GetAccessibility(property, property.Modifiers),
property.Identifier.Span,
inheritanceNames: ImmutableArray<string>.Empty);
return true;
case SyntaxKind.StructDeclaration:
var structDecl = (StructDeclarationSyntax)node;
declaredSymbolInfo = new DeclaredSymbolInfo(
project,
structDecl.Identifier.ValueText, GetTypeParameterSuffix(structDecl.TypeParameterList),
GetContainerDisplayName(node.Parent),
GetFullyQualifiedContainerName(node.Parent),
DeclaredSymbolInfoKind.Struct,
GetAccessibility(structDecl, structDecl.Modifiers),
structDecl.Identifier.Span,
GetInheritanceNames(project, structDecl.BaseList));
return true;
case SyntaxKind.VariableDeclarator:
// could either be part of a field declaration or an event field declaration
var variableDeclarator = (VariableDeclaratorSyntax)node;
var variableDeclaration = variableDeclarator.Parent as VariableDeclarationSyntax;
var fieldDeclaration = variableDeclaration?.Parent as BaseFieldDeclarationSyntax;
if (fieldDeclaration != null)
{
var kind = fieldDeclaration is EventFieldDeclarationSyntax
? DeclaredSymbolInfoKind.Event
: fieldDeclaration.Modifiers.Any(m => m.Kind() == SyntaxKind.ConstKeyword)
? DeclaredSymbolInfoKind.Constant
: DeclaredSymbolInfoKind.Field;
public bool IsForEachStatement(SyntaxNode node)
{
return node is ForEachStatementSyntax;
}
declaredSymbolInfo = new DeclaredSymbolInfo(
project,
variableDeclarator.Identifier.ValueText, null,
GetContainerDisplayName(fieldDeclaration.Parent),
GetFullyQualifiedContainerName(fieldDeclaration.Parent),
kind,
GetAccessibility(fieldDeclaration, fieldDeclaration.Modifiers),
variableDeclarator.Identifier.Span,
inheritanceNames: ImmutableArray<string>.Empty);
return true;
}
public bool IsLockStatement(SyntaxNode node)
{
return node is LockStatementSyntax;
break;
}
declaredSymbolInfo = default(DeclaredSymbolInfo);
return false;
}
public bool IsUsingStatement(SyntaxNode node)
=> node.Kind() == SyntaxKind.UsingStatement;
private string GetConstructorSuffix(ConstructorDeclarationSyntax constructor)
=> constructor.Modifiers.Any(SyntaxKind.StaticKeyword)
? ".static " + constructor.Identifier + "()"
: GetSuffix('(', ')', constructor.ParameterList.Parameters);
public bool IsReturnStatement(SyntaxNode node)
=> node.Kind() == SyntaxKind.ReturnStatement;
private string GetMethodSuffix(MethodDeclarationSyntax method)
=> GetTypeParameterSuffix(method.TypeParameterList) +
GetSuffix('(', ')', method.ParameterList.Parameters);
public SyntaxNode GetExpressionOfReturnStatement(SyntaxNode node)
=> (node as ReturnStatementSyntax)?.Expression;
private string GetIndexerSuffix(IndexerDeclarationSyntax indexer)
=> GetSuffix('[', ']', indexer.ParameterList.Parameters);
public bool IsThisConstructorInitializer(SyntaxToken token)
private string GetTypeParameterSuffix(TypeParameterListSyntax typeParameterList)
{
return token.Parent.IsKind(SyntaxKind.ThisConstructorInitializer) &&
((ConstructorInitializerSyntax)token.Parent).ThisOrBaseKeyword == token;
}
if (typeParameterList == null)
{
return null;
}
public bool IsBaseConstructorInitializer(SyntaxToken token)
{
return token.Parent.IsKind(SyntaxKind.BaseConstructorInitializer) &&
((ConstructorInitializerSyntax)token.Parent).ThisOrBaseKeyword == token;
}
var pooledBuilder = PooledStringBuilder.GetInstance();
public bool IsQueryExpression(SyntaxNode node)
=> node.Kind() == SyntaxKind.QueryExpression;
var builder = pooledBuilder.Builder;
builder.Append('<');
public bool IsThrowExpression(SyntaxNode node)
=> node.Kind() == SyntaxKind.ThrowExpression;
var first = true;
foreach (var parameter in typeParameterList.Parameters)
{
if (!first)
{
builder.Append(", ");
}
public bool IsPredefinedType(SyntaxToken token)
=> TryGetPredefinedType(token, out var actualType) && actualType != PredefinedType.None;
builder.Append(parameter.Identifier.Text);
}
public bool IsPredefinedType(SyntaxToken token, PredefinedType type)
=> TryGetPredefinedType(token, out var actualType) && actualType == type;
builder.Append('>');
public bool TryGetPredefinedType(SyntaxToken token, out PredefinedType type)
return pooledBuilder.ToStringAndFree();
}
/// <summary>
/// Builds up the suffix to show for something with parameters in navigate-to.
/// While it would be nice to just use the compiler SymbolDisplay API for this,
/// it would be too expensive as it requires going back to Symbols (which requires
/// creating compilations, etc.) in a perf sensitive area.
///
/// So, instead, we just build a reasonable suffix using the pure syntax that a
/// user provided. That means that if they wrote "Method(System.Int32 i)" we'll
/// show that as "Method(System.Int32)" not "Method(int)". Given that this is
/// actually what the user wrote, and it saves us from ever having to go back to
/// symbols/compilations, this is well worth it, even if it does mean we have to
/// create our own 'symbol display' logic here.
/// </summary>
private string GetSuffix(
char openBrace, char closeBrace, SeparatedSyntaxList<ParameterSyntax> parameters)
{
type = GetPredefinedType(token);
return type != PredefinedType.None;
var pooledBuilder = PooledStringBuilder.GetInstance();
var builder = pooledBuilder.Builder;
builder.Append(openBrace);
AppendParameters(parameters, builder);
builder.Append(closeBrace);
return pooledBuilder.ToStringAndFree();
}
private PredefinedType GetPredefinedType(SyntaxToken token)
private void AppendParameters(SeparatedSyntaxList<ParameterSyntax> parameters, StringBuilder builder)
{
switch ((SyntaxKind)token.RawKind)
var first = true;
foreach (var parameter in parameters)
{
case SyntaxKind.BoolKeyword:
return PredefinedType.Boolean;
case SyntaxKind.ByteKeyword:
return PredefinedType.Byte;
case SyntaxKind.SByteKeyword:
return PredefinedType.SByte;
case SyntaxKind.IntKeyword:
return PredefinedType.Int32;
case SyntaxKind.UIntKeyword:
return PredefinedType.UInt32;
case SyntaxKind.ShortKeyword:
return PredefinedType.Int16;
case SyntaxKind.UShortKeyword:
return PredefinedType.UInt16;
case SyntaxKind.LongKeyword:
return PredefinedType.Int64;
case SyntaxKind.ULongKeyword:
return PredefinedType.UInt64;
case SyntaxKind.FloatKeyword:
return PredefinedType.Single;
case SyntaxKind.DoubleKeyword:
return PredefinedType.Double;
case SyntaxKind.DecimalKeyword:
return PredefinedType.Decimal;
case SyntaxKind.StringKeyword:
return PredefinedType.String;
case SyntaxKind.CharKeyword:
return PredefinedType.Char;
case SyntaxKind.ObjectKeyword:
return PredefinedType.Object;
case SyntaxKind.VoidKeyword:
return PredefinedType.Void;
default:
return PredefinedType.None;
}
}
if (!first)
{
builder.Append(", ");
}
foreach (var modifier in parameter.Modifiers)
{
builder.Append(modifier.Text);
builder.Append(' ');
}
public bool IsPredefinedOperator(SyntaxToken token)
{
return TryGetPredefinedOperator(token, out var actualOperator) && actualOperator != PredefinedOperator.None;
}
if (parameter.Type != null)
{
AppendTokens(parameter.Type, builder);
}
else
{
builder.Append(parameter.Identifier.Text);
}
public bool IsPredefinedOperator(SyntaxToken token, PredefinedOperator op)
{
return TryGetPredefinedOperator(token, out var actualOperator) && actualOperator == op;
first = false;
}
}
public bool TryGetPredefinedOperator(SyntaxToken token, out PredefinedOperator op)
{
op = GetPredefinedOperator(token);
return op != PredefinedOperator.None;
}
private string GetContainerDisplayName(SyntaxNode node)
=> CSharpSyntaxFactsService.Instance.GetDisplayName(node, DisplayNameOptions.IncludeTypeParameters);
private PredefinedOperator GetPredefinedOperator(SyntaxToken token)
private string GetFullyQualifiedContainerName(SyntaxNode node)
=> CSharpSyntaxFactsService.Instance.GetDisplayName(node, DisplayNameOptions.IncludeNamespaces);
private Accessibility GetAccessibility(SyntaxNode node, SyntaxTokenList modifiers)
{
switch ((SyntaxKind)token.RawKind)
var sawInternal = false;
foreach (var modifier in modifiers)
{
case SyntaxKind.PlusToken:
case SyntaxKind.PlusEqualsToken:
return PredefinedOperator.Addition;
case SyntaxKind.MinusToken:
case SyntaxKind.MinusEqualsToken:
return PredefinedOperator.Subtraction;
case SyntaxKind.AmpersandToken:
case SyntaxKind.AmpersandEqualsToken:
return PredefinedOperator.BitwiseAnd;
switch (modifier.Kind())
{
case SyntaxKind.PublicKeyword: return Accessibility.Public;
case SyntaxKind.PrivateKeyword: return Accessibility.Private;
case SyntaxKind.ProtectedKeyword: return Accessibility.Protected;
case SyntaxKind.InternalKeyword:
sawInternal = true;
continue;
}
}
case SyntaxKind.BarToken:
case SyntaxKind.BarEqualsToken:
return PredefinedOperator.BitwiseOr;
if (sawInternal)
{
return Accessibility.Internal;
}
case SyntaxKind.MinusMinusToken:
return PredefinedOperator.Decrement;
// No accessibility modifiers:
switch (node.Parent.Kind())
{
case SyntaxKind.ClassDeclaration:
case SyntaxKind.StructDeclaration:
// Anything without modifiers is private if it's in a class/struct declaration.
return Accessibility.Private;
case SyntaxKind.InterfaceDeclaration:
// Anything without modifiers is public if it's in an interface declaration.
return Accessibility.Public;
case SyntaxKind.CompilationUnit:
// Things are private by default in script
if (((CSharpParseOptions)node.SyntaxTree.Options).Kind == SourceCodeKind.Script)
{
return Accessibility.Private;
}
case SyntaxKind.PlusPlusToken:
return PredefinedOperator.Increment;
return Accessibility.Internal;
case SyntaxKind.SlashToken:
case SyntaxKind.SlashEqualsToken:
return PredefinedOperator.Division;
default:
// Otherwise it's internal
return Accessibility.Internal;
}
}
case SyntaxKind.EqualsEqualsToken:
return PredefinedOperator.Equality;
private string GetTypeName(TypeSyntax type)
{
if (type is SimpleNameSyntax simpleName)
{
return GetSimpleTypeName(simpleName);
}
else if (type is QualifiedNameSyntax qualifiedName)
{
return GetSimpleTypeName(qualifiedName.Right);
}
else if (type is AliasQualifiedNameSyntax aliasName)
{
return GetSimpleTypeName(aliasName.Name);
}
case SyntaxKind.CaretToken:
case SyntaxKind.CaretEqualsToken:
return PredefinedOperator.ExclusiveOr;
return null;
}
case SyntaxKind.GreaterThanToken:
return PredefinedOperator.GreaterThan;
private static string GetSimpleTypeName(SimpleNameSyntax name)
=> name.Identifier.ValueText;
case SyntaxKind.GreaterThanEqualsToken:
return PredefinedOperator.GreaterThanOrEqual;
private bool IsExtensionMethod(MethodDeclarationSyntax method)
=> method.ParameterList.Parameters.Count > 0 &&
method.ParameterList.Parameters[0].Modifiers.Any(SyntaxKind.ThisKeyword);
}
case SyntaxKind.ExclamationEqualsToken:
return PredefinedOperator.Inequality;
internal class CSharpSyntaxFactsService : AbstractSyntaxFactsService, ISyntaxFactsService
{
internal static readonly CSharpSyntaxFactsService Instance = new CSharpSyntaxFactsService();
case SyntaxKind.LessThanLessThanToken:
case SyntaxKind.LessThanLessThanEqualsToken:
return PredefinedOperator.LeftShift;
private CSharpSyntaxFactsService()
{
}
case SyntaxKind.LessThanEqualsToken:
return PredefinedOperator.LessThanOrEqual;
public bool IsCaseSensitive => true;
case SyntaxKind.AsteriskToken:
case SyntaxKind.AsteriskEqualsToken:
return PredefinedOperator.Multiplication;
public StringComparer StringComparer { get; } = StringComparer.Ordinal;
case SyntaxKind.PercentToken:
case SyntaxKind.PercentEqualsToken:
return PredefinedOperator.Modulus;
protected override IDocumentationCommentService DocumentationCommentService
=> CSharpDocumentationCommentService.Instance;
case SyntaxKind.ExclamationToken:
case SyntaxKind.TildeToken:
return PredefinedOperator.Complement;
public bool SupportsIndexingInitializer(ParseOptions options)
=> ((CSharpParseOptions)options).LanguageVersion >= LanguageVersion.CSharp6;
case SyntaxKind.GreaterThanGreaterThanToken:
case SyntaxKind.GreaterThanGreaterThanEqualsToken:
return PredefinedOperator.RightShift;
}
public bool SupportsThrowExpression(ParseOptions options)
=> ((CSharpParseOptions)options).LanguageVersion >= LanguageVersion.CSharp7;
return PredefinedOperator.None;
public bool IsAwaitKeyword(SyntaxToken token)
{
return token.IsKind(SyntaxKind.AwaitKeyword);
}
public string GetText(int kind)
public bool IsIdentifier(SyntaxToken token)
{
return SyntaxFacts.GetText((SyntaxKind)kind);
return token.IsKind(SyntaxKind.IdentifierToken);
}
public bool IsIdentifierStartCharacter(char c)
public bool IsGlobalNamespaceKeyword(SyntaxToken token)
{
return SyntaxFacts.IsIdentifierStartCharacter(c);
return token.IsKind(SyntaxKind.GlobalKeyword);
}
public bool IsIdentifierPartCharacter(char c)
public bool IsVerbatimIdentifier(SyntaxToken token)
{
return SyntaxFacts.IsIdentifierPartCharacter(c);
return token.IsVerbatimIdentifier();
}
public bool IsIdentifierEscapeCharacter(char c)
public bool IsOperator(SyntaxToken token)
{
return c == '@';
var kind = token.Kind();
return
(SyntaxFacts.IsAnyUnaryExpression(kind) &&
(token.Parent is PrefixUnaryExpressionSyntax || token.Parent is PostfixUnaryExpressionSyntax || token.Parent is OperatorDeclarationSyntax)) ||
(SyntaxFacts.IsBinaryExpression(kind) && (token.Parent is BinaryExpressionSyntax || token.Parent is OperatorDeclarationSyntax)) ||
(SyntaxFacts.IsAssignmentExpressionOperatorToken(kind) && token.Parent is AssignmentExpressionSyntax);
}
public bool IsValidIdentifier(string identifier)
public bool IsKeyword(SyntaxToken token)
{
var token = SyntaxFactory.ParseToken(identifier);
return IsIdentifier(token) && !token.ContainsDiagnostics && token.ToString().Length == identifier.Length;
var kind = (SyntaxKind)token.RawKind;
return
SyntaxFacts.IsKeywordKind(kind); // both contextual and reserved keywords
}
public bool IsVerbatimIdentifier(string identifier)
public bool IsContextualKeyword(SyntaxToken token)
{
var token = SyntaxFactory.ParseToken(identifier);
return IsIdentifier(token) && !token.ContainsDiagnostics && token.ToString().Length == identifier.Length && token.IsVerbatimIdentifier();
var kind = (SyntaxKind)token.RawKind;
return
SyntaxFacts.IsContextualKeyword(kind);
}
public bool IsTypeCharacter(char c)
public bool IsPreprocessorKeyword(SyntaxToken token)
{
return false;
var kind = (SyntaxKind)token.RawKind;
return
SyntaxFacts.IsPreprocessorKeyword(kind);
}
public bool IsStartOfUnicodeEscapeSequence(char c)
public bool IsHashToken(SyntaxToken token)
{
return c == '\\';
return (SyntaxKind)token.RawKind == SyntaxKind.HashToken;
}
public bool IsLiteral(SyntaxToken token)
public bool IsInInactiveRegion(SyntaxTree syntaxTree, int position, CancellationToken cancellationToken)
{
switch (token.Kind())
var csharpTree = syntaxTree as SyntaxTree;
if (csharpTree == null)
{
case SyntaxKind.NumericLiteralToken:
case SyntaxKind.CharacterLiteralToken:
case SyntaxKind.StringLiteralToken:
case SyntaxKind.NullKeyword:
case SyntaxKind.TrueKeyword:
case SyntaxKind.FalseKeyword:
case SyntaxKind.InterpolatedStringStartToken:
case SyntaxKind.InterpolatedStringEndToken:
case SyntaxKind.InterpolatedVerbatimStringStartToken:
case SyntaxKind.InterpolatedStringTextToken:
return true;
return false;
}
return false;
return csharpTree.IsInInactiveRegion(position, cancellationToken);
}
public bool IsStringLiteralOrInterpolatedStringLiteral(SyntaxToken token)
public bool IsInNonUserCode(SyntaxTree syntaxTree, int position, CancellationToken cancellationToken)
{
return token.IsKind(SyntaxKind.StringLiteralToken, SyntaxKind.InterpolatedStringTextToken);
}
var csharpTree = syntaxTree as SyntaxTree;
if (csharpTree == null)
{
return false;
}
public bool IsNumericLiteralExpression(SyntaxNode node)
{
return node?.IsKind(SyntaxKind.NumericLiteralExpression) == true;
return csharpTree.IsInNonUserCode(position, cancellationToken);
}
public bool IsTypeNamedVarInVariableOrFieldDeclaration(SyntaxToken token, SyntaxNode parent)
public bool IsEntirelyWithinStringOrCharOrNumericLiteral(SyntaxTree syntaxTree, int position, CancellationToken cancellationToken)
{
var typedToken = token;
var typedParent = parent;
if (typedParent.IsKind(SyntaxKind.IdentifierName))
{
TypeSyntax declaredType = null;
if (typedParent.IsParentKind(SyntaxKind.VariableDeclaration))
{
declaredType = ((VariableDeclarationSyntax)typedParent.Parent).Type;
}
else if (typedParent.IsParentKind(SyntaxKind.FieldDeclaration))
{
declaredType = ((FieldDeclarationSyntax)typedParent.Parent).Declaration.Type;
}
return declaredType == typedParent && typedToken.ValueText == "var";
var csharpTree = syntaxTree as SyntaxTree;
if (csharpTree == null)
{
return false;
}
return false;
return csharpTree.IsEntirelyWithinStringOrCharLiteral(position, cancellationToken);
}
public bool IsTypeNamedDynamic(SyntaxToken token, SyntaxNode parent)
public bool IsDirective(SyntaxNode node)
{
var typedParent = parent as ExpressionSyntax;
return node is DirectiveTriviaSyntax;
}
if (typedParent != null)
public bool TryGetExternalSourceInfo(SyntaxNode node, out ExternalSourceInfo info)
{
var lineDirective = node as LineDirectiveTriviaSyntax;
if (lineDirective != null)
{
if (SyntaxFacts.IsInTypeOnlyContext(typedParent) &&
typedParent.IsKind(SyntaxKind.IdentifierName) &&
token.ValueText == "dynamic")
if (lineDirective.Line.Kind() == SyntaxKind.DefaultKeyword)
{
info = new ExternalSourceInfo(null, ends: true);
return true;
}
}
return false;
}
public bool IsBindableToken(SyntaxToken token)
{
if (this.IsWord(token) || this.IsLiteral(token) || this.IsOperator(token))
{
switch ((SyntaxKind)token.RawKind)
else if (lineDirective.Line.Kind() == SyntaxKind.NumericLiteralToken &&
lineDirective.Line.Value is int)
{
case SyntaxKind.DelegateKeyword:
case SyntaxKind.VoidKeyword:
return false;
info = new ExternalSourceInfo((int)lineDirective.Line.Value, false);
return true;
}
return true;
}
info = default(ExternalSourceInfo);
return false;
}
public bool IsSimpleMemberAccessExpression(SyntaxNode node)
=> (node as MemberAccessExpressionSyntax)?.Kind() == SyntaxKind.SimpleMemberAccessExpression;
public bool IsConditionalMemberAccessExpression(SyntaxNode node)
=> node is ConditionalAccessExpressionSyntax;
public bool IsPointerMemberAccessExpression(SyntaxNode node)
=> (node as MemberAccessExpressionSyntax)?.Kind() == SyntaxKind.PointerMemberAccessExpression;
public void GetNameAndArityOfSimpleName(SyntaxNode node, out string name, out int arity)
public bool IsRightSideOfQualifiedName(SyntaxNode node)
{
name = null;
arity = 0;
var simpleName = node as SimpleNameSyntax;
if (simpleName != null)
{
name = simpleName.Identifier.ValueText;
arity = simpleName.Arity;
}
var name = node as SimpleNameSyntax;
return name.IsRightSideOfQualifiedName();
}
public SyntaxNode GetTargetOfMemberBinding(SyntaxNode node)
=> (node as MemberBindingExpressionSyntax).GetParentConditionalAccessExpression()?.Expression;
public SyntaxNode GetExpressionOfMemberAccessExpression(SyntaxNode node, bool allowImplicitTarget)
=> (node as MemberAccessExpressionSyntax)?.Expression;
public SyntaxNode GetExpressionOfConditionalAccessExpression(SyntaxNode node)
=> (node as ConditionalAccessExpressionSyntax)?.Expression;
public SyntaxNode GetExpressionOfElementAccessExpression(SyntaxNode node)
=> (node as ElementAccessExpressionSyntax)?.Expression;
public SyntaxNode GetArgumentListOfElementAccessExpression(SyntaxNode node)
=> (node as ElementAccessExpressionSyntax)?.ArgumentList;
public SyntaxNode GetExpressionOfInterpolation(SyntaxNode node)
=> (node as InterpolationSyntax)?.Expression;
public bool IsNameOfMemberAccessExpression(SyntaxNode node)
{
var name = node as SimpleNameSyntax;
return name.IsMemberAccessExpressionName();
}
public bool IsInStaticContext(SyntaxNode node)
public bool IsObjectCreationExpressionType(SyntaxNode node)
{
return node.IsInStaticContext();
return node.IsParentKind(SyntaxKind.ObjectCreationExpression) &&
((ObjectCreationExpressionSyntax)node.Parent).Type == node;
}
public bool IsInNamespaceOrTypeContext(SyntaxNode node)
public bool IsAttributeName(SyntaxNode node)
{
return SyntaxFacts.IsInNamespaceOrTypeContext(node as ExpressionSyntax);
return SyntaxFacts.IsAttributeName(node);
}
public SyntaxNode GetExpressionOfArgument(SyntaxNode node)
public bool IsInvocationExpression(SyntaxNode node)
{
return ((ArgumentSyntax)node).Expression;
return node is InvocationExpressionSyntax;
}
public RefKind GetRefKindOfArgument(SyntaxNode node)
=> (node as ArgumentSyntax).GetRefKind();
public bool IsAnonymousFunction(SyntaxNode node)
{
return node is ParenthesizedLambdaExpressionSyntax ||
node is SimpleLambdaExpressionSyntax ||
node is AnonymousMethodExpressionSyntax;
}
public bool IsSimpleArgument(SyntaxNode node)
public bool IsGenericName(SyntaxNode node)
{
var argument = (ArgumentSyntax)node;
return argument.RefOrOutKeyword.Kind() == SyntaxKind.None &&
argument.NameColon == null;
return node is GenericNameSyntax;
}
public bool IsNamedParameter(SyntaxNode node)
=> node.CheckParent<NameColonSyntax>(p => p.Name == node);
public SyntaxNode GetDefaultOfParameter(SyntaxNode node)
=> (node as ParameterSyntax)?.Default;
public bool IsInConstantContext(SyntaxNode node)
public bool IsSkippedTokensTrivia(SyntaxNode node)
{
return (node as ExpressionSyntax).IsInConstantContext();
return node is SkippedTokensTriviaSyntax;
}
public bool IsInConstructor(SyntaxNode node)
public bool HasIncompleteParentMember(SyntaxNode node)
{
return node.GetAncestor<ConstructorDeclarationSyntax>() != null;
return node.IsParentKind(SyntaxKind.IncompleteMember);
}
public bool IsUnsafeContext(SyntaxNode node)
public SyntaxToken GetIdentifierOfGenericName(SyntaxNode genericName)
{
return node.IsUnsafeContext();
var csharpGenericName = genericName as GenericNameSyntax;
return csharpGenericName != null
? csharpGenericName.Identifier
: default(SyntaxToken);
}
public SyntaxNode GetNameOfAttribute(SyntaxNode node)
public bool IsUsingDirectiveName(SyntaxNode node)
{
return ((AttributeSyntax)node).Name;
return
node.IsParentKind(SyntaxKind.UsingDirective) &&
((UsingDirectiveSyntax)node.Parent).Name == node;
}
public bool IsAttribute(SyntaxNode node)
public bool IsForEachStatement(SyntaxNode node)
{
return node is AttributeSyntax;
return node is ForEachStatementSyntax;
}
public bool IsAttributeNamedArgumentIdentifier(SyntaxNode node)
public bool IsLockStatement(SyntaxNode node)
{
var identifier = node as IdentifierNameSyntax;
return identifier.IsAttributeNamedArgumentIdentifier();
return node is LockStatementSyntax;
}
public SyntaxNode GetContainingTypeDeclaration(SyntaxNode root, int position)
{
if (root == null)
{
throw new ArgumentNullException(nameof(root));
}
public bool IsUsingStatement(SyntaxNode node)
=> node.Kind() == SyntaxKind.UsingStatement;
if (position < 0 || position > root.Span.End)
{
throw new ArgumentOutOfRangeException(nameof(position));
}
public bool IsReturnStatement(SyntaxNode node)
=> node.Kind() == SyntaxKind.ReturnStatement;
return root
.FindToken(position)
.GetAncestors<SyntaxNode>()
.FirstOrDefault(n => n is BaseTypeDeclarationSyntax || n is DelegateDeclarationSyntax);
}
public SyntaxNode GetExpressionOfReturnStatement(SyntaxNode node)
=> (node as ReturnStatementSyntax)?.Expression;
public SyntaxNode GetContainingVariableDeclaratorOfFieldDeclaration(SyntaxNode node)
public bool IsThisConstructorInitializer(SyntaxToken token)
{
throw ExceptionUtilities.Unreachable;
return token.Parent.IsKind(SyntaxKind.ThisConstructorInitializer) &&
((ConstructorInitializerSyntax)token.Parent).ThisOrBaseKeyword == token;
}
public SyntaxToken FindTokenOnLeftOfPosition(
SyntaxNode node, int position, bool includeSkipped, bool includeDirectives, bool includeDocumentationComments)
public bool IsBaseConstructorInitializer(SyntaxToken token)
{
return node.FindTokenOnLeftOfPosition(position, includeSkipped, includeDirectives, includeDocumentationComments);
return token.Parent.IsKind(SyntaxKind.BaseConstructorInitializer) &&
((ConstructorInitializerSyntax)token.Parent).ThisOrBaseKeyword == token;
}
public SyntaxToken FindTokenOnRightOfPosition(
SyntaxNode node, int position, bool includeSkipped, bool includeDirectives, bool includeDocumentationComments)
{
return node.FindTokenOnRightOfPosition(position, includeSkipped, includeDirectives, includeDocumentationComments);
}
public bool IsQueryExpression(SyntaxNode node)
=> node.Kind() == SyntaxKind.QueryExpression;
public bool IsObjectCreationExpression(SyntaxNode node)
{
return node is ObjectCreationExpressionSyntax;
}
public bool IsThrowExpression(SyntaxNode node)
=> node.Kind() == SyntaxKind.ThrowExpression;
public bool IsObjectInitializerNamedAssignmentIdentifier(SyntaxNode node)
public bool IsPredefinedType(SyntaxToken token)
=> TryGetPredefinedType(token, out var actualType) && actualType != PredefinedType.None;
public bool IsPredefinedType(SyntaxToken token, PredefinedType type)
=> TryGetPredefinedType(token, out var actualType) && actualType == type;
public bool TryGetPredefinedType(SyntaxToken token, out PredefinedType type)
{
return IsObjectInitializerNamedAssignmentIdentifier(node, out var unused);
type = GetPredefinedType(token);
return type != PredefinedType.None;
}
public bool IsObjectInitializerNamedAssignmentIdentifier(
SyntaxNode node, out SyntaxNode initializedInstance)
private PredefinedType GetPredefinedType(SyntaxToken token)
{
initializedInstance = null;
var identifier = node as IdentifierNameSyntax;
if (identifier != null &&
identifier.IsLeftSideOfAssignExpression() &&
identifier.Parent.IsParentKind(SyntaxKind.ObjectInitializerExpression))
switch ((SyntaxKind)token.RawKind)
{
var objectInitializer = identifier.Parent.Parent;
if (objectInitializer.IsParentKind(SyntaxKind.ObjectCreationExpression))
{
initializedInstance = objectInitializer.Parent;
return true;
}
else if (objectInitializer.IsParentKind(SyntaxKind.SimpleAssignmentExpression))
{
initializedInstance = ((AssignmentExpressionSyntax)objectInitializer.Parent).Left;
return true;
}
case SyntaxKind.BoolKeyword:
return PredefinedType.Boolean;
case SyntaxKind.ByteKeyword:
return PredefinedType.Byte;
case SyntaxKind.SByteKeyword:
return PredefinedType.SByte;
case SyntaxKind.IntKeyword:
return PredefinedType.Int32;
case SyntaxKind.UIntKeyword:
return PredefinedType.UInt32;
case SyntaxKind.ShortKeyword:
return PredefinedType.Int16;
case SyntaxKind.UShortKeyword:
return PredefinedType.UInt16;
case SyntaxKind.LongKeyword:
return PredefinedType.Int64;
case SyntaxKind.ULongKeyword:
return PredefinedType.UInt64;
case SyntaxKind.FloatKeyword:
return PredefinedType.Single;
case SyntaxKind.DoubleKeyword:
return PredefinedType.Double;
case SyntaxKind.DecimalKeyword:
return PredefinedType.Decimal;
case SyntaxKind.StringKeyword:
return PredefinedType.String;
case SyntaxKind.CharKeyword:
return PredefinedType.Char;
case SyntaxKind.ObjectKeyword:
return PredefinedType.Object;
case SyntaxKind.VoidKeyword:
return PredefinedType.Void;
default:
return PredefinedType.None;
}
return false;
}
public bool IsElementAccessExpression(SyntaxNode node)
public bool IsPredefinedOperator(SyntaxToken token)
{
return node.Kind() == SyntaxKind.ElementAccessExpression;
return TryGetPredefinedOperator(token, out var actualOperator) && actualOperator != PredefinedOperator.None;
}
public SyntaxNode ConvertToSingleLine(SyntaxNode node, bool useElasticTrivia = false)
=> node.ConvertToSingleLine(useElasticTrivia);
public SyntaxToken ToIdentifierToken(string name)
public bool IsPredefinedOperator(SyntaxToken token, PredefinedOperator op)
{
return name.ToIdentifierToken();
return TryGetPredefinedOperator(token, out var actualOperator) && actualOperator == op;
}
public SyntaxNode Parenthesize(SyntaxNode expression, bool includeElasticTrivia)
public bool TryGetPredefinedOperator(SyntaxToken token, out PredefinedOperator op)
{
return ((ExpressionSyntax)expression).Parenthesize(includeElasticTrivia);
op = GetPredefinedOperator(token);
return op != PredefinedOperator.None;
}
public bool IsIndexerMemberCRef(SyntaxNode node)
private PredefinedOperator GetPredefinedOperator(SyntaxToken token)
{
return node.Kind() == SyntaxKind.IndexerMemberCref;
}
switch ((SyntaxKind)token.RawKind)
{
case SyntaxKind.PlusToken:
case SyntaxKind.PlusEqualsToken:
return PredefinedOperator.Addition;
public SyntaxNode GetContainingMemberDeclaration(SyntaxNode root, int position, bool useFullSpan = true)
{
Contract.ThrowIfNull(root, "root");
Contract.ThrowIfTrue(position < 0 || position > root.FullSpan.End, "position");
case SyntaxKind.MinusToken:
case SyntaxKind.MinusEqualsToken:
return PredefinedOperator.Subtraction;
var end = root.FullSpan.End;
if (end == 0)
{
// empty file
return null;
}
case SyntaxKind.AmpersandToken:
case SyntaxKind.AmpersandEqualsToken:
return PredefinedOperator.BitwiseAnd;
// make sure position doesn't touch end of root
position = Math.Min(position, end - 1);
case SyntaxKind.BarToken:
case SyntaxKind.BarEqualsToken:
return PredefinedOperator.BitwiseOr;
var node = root.FindToken(position).Parent;
while (node != null)
{
if (useFullSpan || node.Span.Contains(position))
{
var kind = node.Kind();
if ((kind != SyntaxKind.GlobalStatement) && (kind != SyntaxKind.IncompleteMember) && (node is MemberDeclarationSyntax))
{
return node;
}
}
case SyntaxKind.MinusMinusToken:
return PredefinedOperator.Decrement;
node = node.Parent;
}
case SyntaxKind.PlusPlusToken:
return PredefinedOperator.Increment;
return null;
}
case SyntaxKind.SlashToken:
case SyntaxKind.SlashEqualsToken:
return PredefinedOperator.Division;
public bool IsMethodLevelMember(SyntaxNode node)
{
return node is BaseMethodDeclarationSyntax || node is BasePropertyDeclarationSyntax || node is EnumMemberDeclarationSyntax || node is BaseFieldDeclarationSyntax;
}
case SyntaxKind.EqualsEqualsToken:
return PredefinedOperator.Equality;
public bool IsTopLevelNodeWithMembers(SyntaxNode node)
{
return node is NamespaceDeclarationSyntax ||
node is TypeDeclarationSyntax ||
node is EnumDeclarationSyntax;
}
case SyntaxKind.CaretToken:
case SyntaxKind.CaretEqualsToken:
return PredefinedOperator.ExclusiveOr;
public bool TryGetDeclaredSymbolInfo(Project project, SyntaxNode node, out DeclaredSymbolInfo declaredSymbolInfo)
{
switch (node.Kind())
{
case SyntaxKind.ClassDeclaration:
var classDecl = (ClassDeclarationSyntax)node;
declaredSymbolInfo = new DeclaredSymbolInfo(
project,
classDecl.Identifier.ValueText,
GetTypeParameterSuffix(classDecl.TypeParameterList),
GetContainerDisplayName(node.Parent),
GetFullyQualifiedContainerName(node.Parent),
DeclaredSymbolInfoKind.Class,
GetAccessibility(classDecl, classDecl.Modifiers),
classDecl.Identifier.Span,
GetInheritanceNames(project, classDecl.BaseList));
return true;
case SyntaxKind.ConstructorDeclaration:
var ctorDecl = (ConstructorDeclarationSyntax)node;
declaredSymbolInfo = new DeclaredSymbolInfo(
project,
ctorDecl.Identifier.ValueText,
GetConstructorSuffix(ctorDecl),
GetContainerDisplayName(node.Parent),
GetFullyQualifiedContainerName(node.Parent),
DeclaredSymbolInfoKind.Constructor,
GetAccessibility(ctorDecl, ctorDecl.Modifiers),
ctorDecl.Identifier.Span,
inheritanceNames: ImmutableArray<string>.Empty,
parameterCount: ctorDecl.ParameterList?.Parameters.Count ?? 0);
return true;
case SyntaxKind.DelegateDeclaration:
var delegateDecl = (DelegateDeclarationSyntax)node;
declaredSymbolInfo = new DeclaredSymbolInfo(
project,
delegateDecl.Identifier.ValueText,
GetTypeParameterSuffix(delegateDecl.TypeParameterList),
GetContainerDisplayName(node.Parent),
GetFullyQualifiedContainerName(node.Parent),
DeclaredSymbolInfoKind.Delegate,
GetAccessibility(delegateDecl, delegateDecl.Modifiers),
delegateDecl.Identifier.Span,
inheritanceNames: ImmutableArray<string>.Empty);
return true;
case SyntaxKind.EnumDeclaration:
var enumDecl = (EnumDeclarationSyntax)node;
declaredSymbolInfo = new DeclaredSymbolInfo(
project,
enumDecl.Identifier.ValueText, null,
GetContainerDisplayName(node.Parent),
GetFullyQualifiedContainerName(node.Parent),
DeclaredSymbolInfoKind.Enum,
GetAccessibility(enumDecl, enumDecl.Modifiers),
enumDecl.Identifier.Span,
inheritanceNames: ImmutableArray<string>.Empty);
return true;
case SyntaxKind.EnumMemberDeclaration:
var enumMember = (EnumMemberDeclarationSyntax)node;
declaredSymbolInfo = new DeclaredSymbolInfo(
project,
enumMember.Identifier.ValueText, null,
GetContainerDisplayName(node.Parent),
GetFullyQualifiedContainerName(node.Parent),
DeclaredSymbolInfoKind.EnumMember,
Accessibility.Public,
enumMember.Identifier.Span,
inheritanceNames: ImmutableArray<string>.Empty);
return true;
case SyntaxKind.EventDeclaration:
var eventDecl = (EventDeclarationSyntax)node;
declaredSymbolInfo = new DeclaredSymbolInfo(
project,
eventDecl.Identifier.ValueText, null,
GetContainerDisplayName(node.Parent),
GetFullyQualifiedContainerName(node.Parent),
DeclaredSymbolInfoKind.Event,
GetAccessibility(eventDecl, eventDecl.Modifiers),
eventDecl.Identifier.Span,
inheritanceNames: ImmutableArray<string>.Empty);
return true;
case SyntaxKind.IndexerDeclaration:
var indexerDecl = (IndexerDeclarationSyntax)node;
declaredSymbolInfo = new DeclaredSymbolInfo(
project,
"this", GetIndexerSuffix(indexerDecl),
GetContainerDisplayName(node.Parent),
GetFullyQualifiedContainerName(node.Parent),
DeclaredSymbolInfoKind.Indexer,
GetAccessibility(indexerDecl, indexerDecl.Modifiers),
indexerDecl.ThisKeyword.Span,
inheritanceNames: ImmutableArray<string>.Empty);
return true;
case SyntaxKind.InterfaceDeclaration:
var interfaceDecl = (InterfaceDeclarationSyntax)node;
declaredSymbolInfo = new DeclaredSymbolInfo(
project,
interfaceDecl.Identifier.ValueText, GetTypeParameterSuffix(interfaceDecl.TypeParameterList),
GetContainerDisplayName(node.Parent),
GetFullyQualifiedContainerName(node.Parent),
DeclaredSymbolInfoKind.Interface,
GetAccessibility(interfaceDecl, interfaceDecl.Modifiers),
interfaceDecl.Identifier.Span,
GetInheritanceNames(project, interfaceDecl.BaseList));
return true;
case SyntaxKind.MethodDeclaration:
var method = (MethodDeclarationSyntax)node;
declaredSymbolInfo = new DeclaredSymbolInfo(
project,
method.Identifier.ValueText, GetMethodSuffix(method),
GetContainerDisplayName(node.Parent),
GetFullyQualifiedContainerName(node.Parent),
IsExtensionMethod(method) ? DeclaredSymbolInfoKind.ExtensionMethod : DeclaredSymbolInfoKind.Method,
GetAccessibility(method, method.Modifiers),
method.Identifier.Span,
inheritanceNames: ImmutableArray<string>.Empty,
parameterCount: method.ParameterList?.Parameters.Count ?? 0,
typeParameterCount: method.TypeParameterList?.Parameters.Count ?? 0);
return true;
case SyntaxKind.PropertyDeclaration:
var property = (PropertyDeclarationSyntax)node;
declaredSymbolInfo = new DeclaredSymbolInfo(
project,
property.Identifier.ValueText, null,
GetContainerDisplayName(node.Parent),
GetFullyQualifiedContainerName(node.Parent),
DeclaredSymbolInfoKind.Property,
GetAccessibility(property, property.Modifiers),
property.Identifier.Span,
inheritanceNames: ImmutableArray<string>.Empty);
return true;
case SyntaxKind.StructDeclaration:
var structDecl = (StructDeclarationSyntax)node;
declaredSymbolInfo = new DeclaredSymbolInfo(
project,
structDecl.Identifier.ValueText, GetTypeParameterSuffix(structDecl.TypeParameterList),
GetContainerDisplayName(node.Parent),
GetFullyQualifiedContainerName(node.Parent),
DeclaredSymbolInfoKind.Struct,
GetAccessibility(structDecl, structDecl.Modifiers),
structDecl.Identifier.Span,
GetInheritanceNames(project, structDecl.BaseList));
return true;
case SyntaxKind.VariableDeclarator:
// could either be part of a field declaration or an event field declaration
var variableDeclarator = (VariableDeclaratorSyntax)node;
var variableDeclaration = variableDeclarator.Parent as VariableDeclarationSyntax;
var fieldDeclaration = variableDeclaration?.Parent as BaseFieldDeclarationSyntax;
if (fieldDeclaration != null)
{
var kind = fieldDeclaration is EventFieldDeclarationSyntax
? DeclaredSymbolInfoKind.Event
: fieldDeclaration.Modifiers.Any(m => m.Kind() == SyntaxKind.ConstKeyword)
? DeclaredSymbolInfoKind.Constant
: DeclaredSymbolInfoKind.Field;
case SyntaxKind.GreaterThanToken:
return PredefinedOperator.GreaterThan;
case SyntaxKind.GreaterThanEqualsToken:
return PredefinedOperator.GreaterThanOrEqual;
case SyntaxKind.ExclamationEqualsToken:
return PredefinedOperator.Inequality;
case SyntaxKind.LessThanLessThanToken:
case SyntaxKind.LessThanLessThanEqualsToken:
return PredefinedOperator.LeftShift;
case SyntaxKind.LessThanEqualsToken:
return PredefinedOperator.LessThanOrEqual;
case SyntaxKind.AsteriskToken:
case SyntaxKind.AsteriskEqualsToken:
return PredefinedOperator.Multiplication;
case SyntaxKind.PercentToken:
case SyntaxKind.PercentEqualsToken:
return PredefinedOperator.Modulus;
declaredSymbolInfo = new DeclaredSymbolInfo(
project,
variableDeclarator.Identifier.ValueText, null,
GetContainerDisplayName(fieldDeclaration.Parent),
GetFullyQualifiedContainerName(fieldDeclaration.Parent),
kind,
GetAccessibility(fieldDeclaration, fieldDeclaration.Modifiers),
variableDeclarator.Identifier.Span,
inheritanceNames: ImmutableArray<string>.Empty);
return true;
}
case SyntaxKind.ExclamationToken:
case SyntaxKind.TildeToken:
return PredefinedOperator.Complement;
break;
case SyntaxKind.GreaterThanGreaterThanToken:
case SyntaxKind.GreaterThanGreaterThanEqualsToken:
return PredefinedOperator.RightShift;
}
declaredSymbolInfo = default(DeclaredSymbolInfo);
return false;
return PredefinedOperator.None;
}
private string GetConstructorSuffix(ConstructorDeclarationSyntax constructor)
=> constructor.Modifiers.Any(SyntaxKind.StaticKeyword)
? ".static " + constructor.Identifier + "()"
: GetSuffix('(', ')', constructor.ParameterList.Parameters);
public string GetText(int kind)
{
return SyntaxFacts.GetText((SyntaxKind)kind);
}
private string GetMethodSuffix(MethodDeclarationSyntax method)
=> GetTypeParameterSuffix(method.TypeParameterList) +
GetSuffix('(', ')', method.ParameterList.Parameters);
public bool IsIdentifierStartCharacter(char c)
{
return SyntaxFacts.IsIdentifierStartCharacter(c);
}
private string GetIndexerSuffix(IndexerDeclarationSyntax indexer)
=> GetSuffix('[', ']', indexer.ParameterList.Parameters);
public bool IsIdentifierPartCharacter(char c)
{
return SyntaxFacts.IsIdentifierPartCharacter(c);
}
private string GetTypeParameterSuffix(TypeParameterListSyntax typeParameterList)
public bool IsIdentifierEscapeCharacter(char c)
{
if (typeParameterList == null)
return c == '@';
}
public bool IsValidIdentifier(string identifier)
{
var token = SyntaxFactory.ParseToken(identifier);
return IsIdentifier(token) && !token.ContainsDiagnostics && token.ToString().Length == identifier.Length;
}
public bool IsVerbatimIdentifier(string identifier)
{
var token = SyntaxFactory.ParseToken(identifier);
return IsIdentifier(token) && !token.ContainsDiagnostics && token.ToString().Length == identifier.Length && token.IsVerbatimIdentifier();
}
public bool IsTypeCharacter(char c)
{
return false;
}
public bool IsStartOfUnicodeEscapeSequence(char c)
{
return c == '\\';
}
public bool IsLiteral(SyntaxToken token)
{
switch (token.Kind())
{
return null;
case SyntaxKind.NumericLiteralToken:
case SyntaxKind.CharacterLiteralToken:
case SyntaxKind.StringLiteralToken:
case SyntaxKind.NullKeyword:
case SyntaxKind.TrueKeyword:
case SyntaxKind.FalseKeyword:
case SyntaxKind.InterpolatedStringStartToken:
case SyntaxKind.InterpolatedStringEndToken:
case SyntaxKind.InterpolatedVerbatimStringStartToken:
case SyntaxKind.InterpolatedStringTextToken:
return true;
}
var pooledBuilder = PooledStringBuilder.GetInstance();
return false;
}
var builder = pooledBuilder.Builder;
builder.Append('<');
public bool IsStringLiteralOrInterpolatedStringLiteral(SyntaxToken token)
{
return token.IsKind(SyntaxKind.StringLiteralToken, SyntaxKind.InterpolatedStringTextToken);
}
var first = true;
foreach (var parameter in typeParameterList.Parameters)
public bool IsNumericLiteralExpression(SyntaxNode node)
{
return node?.IsKind(SyntaxKind.NumericLiteralExpression) == true;
}
public bool IsTypeNamedVarInVariableOrFieldDeclaration(SyntaxToken token, SyntaxNode parent)
{
var typedToken = token;
var typedParent = parent;
if (typedParent.IsKind(SyntaxKind.IdentifierName))
{
if (!first)
TypeSyntax declaredType = null;
if (typedParent.IsParentKind(SyntaxKind.VariableDeclaration))
{
builder.Append(", ");
declaredType = ((VariableDeclarationSyntax)typedParent.Parent).Type;
}
else if (typedParent.IsParentKind(SyntaxKind.FieldDeclaration))
{
declaredType = ((FieldDeclarationSyntax)typedParent.Parent).Declaration.Type;
}
builder.Append(parameter.Identifier.Text);
return declaredType == typedParent && typedToken.ValueText == "var";
}
builder.Append('>');
return pooledBuilder.ToStringAndFree();
return false;
}
/// <summary>
/// Builds up the suffix to show for something with parameters in navigate-to.
/// While it would be nice to just use the compiler SymbolDisplay API for this,
/// it would be too expensive as it requires going back to Symbols (which requires
/// creating compilations, etc.) in a perf sensitive area.
///
/// So, instead, we just build a reasonable suffix using the pure syntax that a
/// user provided. That means that if they wrote "Method(System.Int32 i)" we'll
/// show that as "Method(System.Int32)" not "Method(int)". Given that this is
/// actually what the user wrote, and it saves us from ever having to go back to
/// symbols/compilations, this is well worth it, even if it does mean we have to
/// create our own 'symbol display' logic here.
/// </summary>
private string GetSuffix(
char openBrace, char closeBrace, SeparatedSyntaxList<ParameterSyntax> parameters)
public bool IsTypeNamedDynamic(SyntaxToken token, SyntaxNode parent)
{
var pooledBuilder = PooledStringBuilder.GetInstance();
var typedParent = parent as ExpressionSyntax;
var builder = pooledBuilder.Builder;
builder.Append(openBrace);
AppendParameters(parameters, builder);
builder.Append(closeBrace);
if (typedParent != null)
{
if (SyntaxFacts.IsInTypeOnlyContext(typedParent) &&
typedParent.IsKind(SyntaxKind.IdentifierName) &&
token.ValueText == "dynamic")
{
return true;
}
}
return pooledBuilder.ToStringAndFree();
return false;
}
private void AppendParameters(SeparatedSyntaxList<ParameterSyntax> parameters, StringBuilder builder)
public bool IsBindableToken(SyntaxToken token)
{
var first = true;
foreach (var parameter in parameters)
if (this.IsWord(token) || this.IsLiteral(token) || this.IsOperator(token))
{
if (!first)
switch ((SyntaxKind)token.RawKind)
{
builder.Append(", ");
case SyntaxKind.DelegateKeyword:
case SyntaxKind.VoidKeyword:
return false;
}
foreach (var modifier in parameter.Modifiers)
{
builder.Append(modifier.Text);
builder.Append(' ');
}
return true;
}
return false;
}
public bool IsSimpleMemberAccessExpression(SyntaxNode node)
=> (node as MemberAccessExpressionSyntax)?.Kind() == SyntaxKind.SimpleMemberAccessExpression;
public bool IsConditionalMemberAccessExpression(SyntaxNode node)
=> node is ConditionalAccessExpressionSyntax;
public bool IsPointerMemberAccessExpression(SyntaxNode node)
=> (node as MemberAccessExpressionSyntax)?.Kind() == SyntaxKind.PointerMemberAccessExpression;
public void GetNameAndArityOfSimpleName(SyntaxNode node, out string name, out int arity)
{
name = null;
arity = 0;
var simpleName = node as SimpleNameSyntax;
if (simpleName != null)
{
name = simpleName.Identifier.ValueText;
arity = simpleName.Arity;
}
}
public SyntaxNode GetTargetOfMemberBinding(SyntaxNode node)
=> (node as MemberBindingExpressionSyntax).GetParentConditionalAccessExpression()?.Expression;
public SyntaxNode GetExpressionOfMemberAccessExpression(SyntaxNode node, bool allowImplicitTarget)
=> (node as MemberAccessExpressionSyntax)?.Expression;
public SyntaxNode GetExpressionOfConditionalAccessExpression(SyntaxNode node)
=> (node as ConditionalAccessExpressionSyntax)?.Expression;
public SyntaxNode GetExpressionOfElementAccessExpression(SyntaxNode node)
=> (node as ElementAccessExpressionSyntax)?.Expression;
public SyntaxNode GetArgumentListOfElementAccessExpression(SyntaxNode node)
=> (node as ElementAccessExpressionSyntax)?.ArgumentList;
public SyntaxNode GetExpressionOfInterpolation(SyntaxNode node)
=> (node as InterpolationSyntax)?.Expression;
public bool IsInStaticContext(SyntaxNode node)
{
return node.IsInStaticContext();
}
public bool IsInNamespaceOrTypeContext(SyntaxNode node)
{
return SyntaxFacts.IsInNamespaceOrTypeContext(node as ExpressionSyntax);
}
public SyntaxNode GetExpressionOfArgument(SyntaxNode node)
{
return ((ArgumentSyntax)node).Expression;
}
public RefKind GetRefKindOfArgument(SyntaxNode node)
=> (node as ArgumentSyntax).GetRefKind();
public bool IsSimpleArgument(SyntaxNode node)
{
var argument = (ArgumentSyntax)node;
return argument.RefOrOutKeyword.Kind() == SyntaxKind.None &&
argument.NameColon == null;
}
public bool IsInConstantContext(SyntaxNode node)
{
return (node as ExpressionSyntax).IsInConstantContext();
}
public bool IsInConstructor(SyntaxNode node)
{
return node.GetAncestor<ConstructorDeclarationSyntax>() != null;
}
public bool IsUnsafeContext(SyntaxNode node)
{
return node.IsUnsafeContext();
}
if (parameter.Type != null)
{
AppendTokens(parameter.Type, builder);
}
else
{
builder.Append(parameter.Identifier.Text);
}
public SyntaxNode GetNameOfAttribute(SyntaxNode node)
{
return ((AttributeSyntax)node).Name;
}
first = false;
}
public bool IsAttribute(SyntaxNode node)
{
return node is AttributeSyntax;
}
private bool IsExtensionMethod(MethodDeclarationSyntax method)
=> method.ParameterList.Parameters.Count > 0 &&
method.ParameterList.Parameters[0].Modifiers.Any(SyntaxKind.ThisKeyword);
public bool IsAttributeNamedArgumentIdentifier(SyntaxNode node)
{
var identifier = node as IdentifierNameSyntax;
return identifier.IsAttributeNamedArgumentIdentifier();
}
private Accessibility GetAccessibility(SyntaxNode node, SyntaxTokenList modifiers)
public SyntaxNode GetContainingTypeDeclaration(SyntaxNode root, int position)
{
var sawInternal = false;
foreach (var modifier in modifiers)
if (root == null)
{
switch (modifier.Kind())
{
case SyntaxKind.PublicKeyword: return Accessibility.Public;
case SyntaxKind.PrivateKeyword: return Accessibility.Private;
case SyntaxKind.ProtectedKeyword: return Accessibility.Protected;
case SyntaxKind.InternalKeyword:
sawInternal = true;
continue;
}
throw new ArgumentNullException(nameof(root));
}
if (sawInternal)
if (position < 0 || position > root.Span.End)
{
return Accessibility.Internal;
throw new ArgumentOutOfRangeException(nameof(position));
}
// No accessibility modifiers:
switch (node.Parent.Kind())
{
case SyntaxKind.ClassDeclaration:
case SyntaxKind.StructDeclaration:
// Anything without modifiers is private if it's in a class/struct declaration.
return Accessibility.Private;
case SyntaxKind.InterfaceDeclaration:
// Anything without modifiers is public if it's in an interface declaration.
return Accessibility.Public;
case SyntaxKind.CompilationUnit:
// Things are private by default in script
if (((CSharpParseOptions)node.SyntaxTree.Options).Kind == SourceCodeKind.Script)
{
return Accessibility.Private;
}
return Accessibility.Internal;
default:
// Otherwise it's internal
return Accessibility.Internal;
}
return root
.FindToken(position)
.GetAncestors<SyntaxNode>()
.FirstOrDefault(n => n is BaseTypeDeclarationSyntax || n is DelegateDeclarationSyntax);
}
private ImmutableArray<string> GetInheritanceNames(Project project, BaseListSyntax baseList)
public SyntaxNode GetContainingVariableDeclaratorOfFieldDeclaration(SyntaxNode node)
{
if (baseList == null)
{
return ImmutableArray<string>.Empty;
}
var builder = ArrayBuilder<string>.GetInstance(baseList.Types.Count);
throw ExceptionUtilities.Unreachable;
}
// It's not sufficient to just store the textual names we see in the inheritance list
// of a type. For example if we have:
//
// using Y = X;
// ...
// using Z = Y;
// ...
// class C : Z
//
// It's insufficient to just state that 'C' derives from 'Z'. If we search for derived
// types from 'B' we won't examine 'C'. To solve this, we keep track of the aliasing
// that occurs in containing scopes. Then, when we're adding an inheritance name we
// walk the alias maps and we also add any names that these names alias to. In the
// above example we'd put Z, Y, and X in the inheritance names list for 'C'.
public SyntaxToken FindTokenOnLeftOfPosition(
SyntaxNode node, int position, bool includeSkipped, bool includeDirectives, bool includeDocumentationComments)
{
return node.FindTokenOnLeftOfPosition(position, includeSkipped, includeDirectives, includeDocumentationComments);
}
// Each dictionary in this list is a mapping from alias name to the name of the thing
// it aliases. Then, each scope with alias mapping gets its own entry in this list.
// For the above example, we would produce: [{Z => Y}, {Y => X}]
var aliasMaps = AllocateAliasMapList();
try
{
AddAliasMaps(baseList, aliasMaps);
public SyntaxToken FindTokenOnRightOfPosition(
SyntaxNode node, int position, bool includeSkipped, bool includeDirectives, bool includeDocumentationComments)
{
return node.FindTokenOnRightOfPosition(position, includeSkipped, includeDirectives, includeDocumentationComments);
}
foreach (var baseType in baseList.Types)
{
AddInheritanceName(builder, baseType.Type, aliasMaps);
}
public bool IsObjectCreationExpression(SyntaxNode node)
{
return node is ObjectCreationExpressionSyntax;
}
DeclaredSymbolInfo.Intern(project, builder);
return builder.ToImmutableAndFree();
}
finally
{
FreeAliasMapList(aliasMaps);
}
public bool IsObjectInitializerNamedAssignmentIdentifier(SyntaxNode node)
{
return IsObjectInitializerNamedAssignmentIdentifier(node, out var unused);
}
private void AddAliasMaps(SyntaxNode node, List<Dictionary<string, string>> aliasMaps)
public bool IsObjectInitializerNamedAssignmentIdentifier(
SyntaxNode node, out SyntaxNode initializedInstance)
{
for (var current = node; current != null; current = current.Parent)
initializedInstance = null;
var identifier = node as IdentifierNameSyntax;
if (identifier != null &&
identifier.IsLeftSideOfAssignExpression() &&
identifier.Parent.IsParentKind(SyntaxKind.ObjectInitializerExpression))
{
if (current.IsKind(SyntaxKind.NamespaceDeclaration))
var objectInitializer = identifier.Parent.Parent;
if (objectInitializer.IsParentKind(SyntaxKind.ObjectCreationExpression))
{
ProcessUsings(aliasMaps, ((NamespaceDeclarationSyntax)current).Usings);
initializedInstance = objectInitializer.Parent;
return true;
}
else if (current.IsKind(SyntaxKind.CompilationUnit))
else if (objectInitializer.IsParentKind(SyntaxKind.SimpleAssignmentExpression))
{
ProcessUsings(aliasMaps, ((CompilationUnitSyntax)current).Usings);
initializedInstance = ((AssignmentExpressionSyntax)objectInitializer.Parent).Left;
return true;
}
}
return false;
}
private void ProcessUsings(List<Dictionary<string, string>> aliasMaps, SyntaxList<UsingDirectiveSyntax> usings)
public bool IsElementAccessExpression(SyntaxNode node)
{
Dictionary<string, string> aliasMap = null;
return node.Kind() == SyntaxKind.ElementAccessExpression;
}
foreach (var usingDecl in usings)
{
if (usingDecl.Alias != null)
{
var mappedName = GetTypeName(usingDecl.Name);
if (mappedName != null)
{
aliasMap = aliasMap ?? AllocateAliasMap();
public SyntaxNode ConvertToSingleLine(SyntaxNode node, bool useElasticTrivia = false)
=> node.ConvertToSingleLine(useElasticTrivia);
// If we have: using X = Foo, then we store a mapping from X -> Foo
// here. That way if we see a class that inherits from X we also state
// that it inherits from Foo as well.
aliasMap[usingDecl.Alias.Name.Identifier.ValueText] = mappedName;
}
}
}
public SyntaxToken ToIdentifierToken(string name)
{
return name.ToIdentifierToken();
}
if (aliasMap != null)
{
aliasMaps.Add(aliasMap);
}
public SyntaxNode Parenthesize(SyntaxNode expression, bool includeElasticTrivia)
{
return ((ExpressionSyntax)expression).Parenthesize(includeElasticTrivia);
}
private void AddInheritanceName(
ArrayBuilder<string> builder, TypeSyntax type,
List<Dictionary<string, string>> aliasMaps)
public bool IsIndexerMemberCRef(SyntaxNode node)
{
var name = GetTypeName(type);
if (name != null)
return node.Kind() == SyntaxKind.IndexerMemberCref;
}
public SyntaxNode GetContainingMemberDeclaration(SyntaxNode root, int position, bool useFullSpan = true)
{
Contract.ThrowIfNull(root, "root");
Contract.ThrowIfTrue(position < 0 || position > root.FullSpan.End, "position");
var end = root.FullSpan.End;
if (end == 0)
{
// First, add the name that the typename that the type directly says it inherits from.
builder.Add(name);
// empty file
return null;
}
// Now, walk the alias chain and add any names this alias may eventually map to.
var currentName = name;
foreach (var aliasMap in aliasMaps)
// make sure position doesn't touch end of root
position = Math.Min(position, end - 1);
var node = root.FindToken(position).Parent;
while (node != null)
{
if (useFullSpan || node.Span.Contains(position))
{
if (aliasMap.TryGetValue(currentName, out var mappedName))
var kind = node.Kind();
if ((kind != SyntaxKind.GlobalStatement) && (kind != SyntaxKind.IncompleteMember) && (node is MemberDeclarationSyntax))
{
// Looks like this could be an alias. Also include the name the alias points to
builder.Add(mappedName);
// Keep on searching. An alias in an inner namespcae can refer to an
// alias in an outer namespace.
currentName = mappedName;
return node;
}
}
}
}
private string GetTypeName(TypeSyntax type)
{
if (type is SimpleNameSyntax simpleName)
{
return GetSimpleTypeName(simpleName);
}
else if (type is QualifiedNameSyntax qualifiedName)
{
return GetSimpleTypeName(qualifiedName.Right);
}
else if (type is AliasQualifiedNameSyntax aliasName)
{
return GetSimpleTypeName(aliasName.Name);
node = node.Parent;
}
return null;
}
private static string GetSimpleTypeName(SimpleNameSyntax name)
=> name.Identifier.ValueText;
private string GetContainerDisplayName(SyntaxNode node)
public bool IsMethodLevelMember(SyntaxNode node)
{
return GetDisplayName(node, DisplayNameOptions.IncludeTypeParameters);
return node is BaseMethodDeclarationSyntax || node is BasePropertyDeclarationSyntax || node is EnumMemberDeclarationSyntax || node is BaseFieldDeclarationSyntax;
}
private string GetFullyQualifiedContainerName(SyntaxNode node)
public bool IsTopLevelNodeWithMembers(SyntaxNode node)
{
return GetDisplayName(node, DisplayNameOptions.IncludeNamespaces);
return node is NamespaceDeclarationSyntax ||
node is TypeDeclarationSyntax ||
node is EnumDeclarationSyntax;
}
private const string dotToken = ".";
......
......@@ -5,6 +5,7 @@
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.ErrorReporting;
using Microsoft.CodeAnalysis.Host;
using Microsoft.CodeAnalysis.LanguageServices;
using Microsoft.CodeAnalysis.Shared.Extensions;
using Microsoft.CodeAnalysis.Shared.Utilities;
......@@ -12,6 +13,11 @@
namespace Microsoft.CodeAnalysis.FindSymbols
{
internal interface IDeclaredSymbolInfoFactoryService : ILanguageService
{
bool TryGetDeclaredSymbolInfo(Project project, SyntaxNode node, out DeclaredSymbolInfo declaredSymbolInfo);
}
internal sealed partial class SyntaxTreeIndex
{
// The probability of getting a false positive when calling ContainsIdentifier.
......@@ -28,6 +34,7 @@ internal sealed partial class SyntaxTreeIndex
{
var project = document.Project;
var syntaxFacts = document.GetLanguageService<ISyntaxFactsService>();
var infoFactory = document.GetLanguageService<IDeclaredSymbolInfoFactoryService>();
var ignoreCase = syntaxFacts != null && !syntaxFacts.IsCaseSensitive;
var isCaseSensitive = !ignoreCase;
......@@ -68,6 +75,7 @@ internal sealed partial class SyntaxTreeIndex
containsQueryExpression = containsQueryExpression || syntaxFacts.IsQueryExpression(node);
containsElementAccess = containsElementAccess || syntaxFacts.IsElementAccessExpression(node);
containsIndexerMemberCref = containsIndexerMemberCref || syntaxFacts.IsIndexerMemberCRef(node);
// We've received a number of error reports where DeclaredSymbolInfo.GetSymbolAsync() will
// crash because the document's syntax root doesn't contain the span of the node returned
// by TryGetDeclaredSymbolInfo(). There are two possibilities for this crash:
......@@ -78,7 +86,7 @@ internal sealed partial class SyntaxTreeIndex
// the future then we know the problem lies in (2). If, however, the problem is really in
// TryGetDeclaredSymbolInfo, then this will at least prevent us from returning bad spans
// and will prevent the crash from occurring.
if (syntaxFacts.TryGetDeclaredSymbolInfo(project, node, out var declaredSymbolInfo))
if (infoFactory.TryGetDeclaredSymbolInfo(project, node, out var declaredSymbolInfo))
{
if (root.FullSpan.Contains(declaredSymbolInfo.Span))
{
......
......@@ -2,19 +2,20 @@
using System;
using System.Collections.Generic;
using Microsoft.CodeAnalysis.Shared.Extensions;
using System.Collections.Immutable;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading;
using Microsoft.CodeAnalysis.FindSymbols;
using Microsoft.CodeAnalysis.Shared.Extensions;
using Microsoft.CodeAnalysis.Shared.Utilities;
using Microsoft.CodeAnalysis.Text;
using Roslyn.Utilities;
using System.Text;
namespace Microsoft.CodeAnalysis.LanguageServices
{
internal abstract class AbstractSyntaxFactsService
internal abstract class AbstractDeclaredSymbolInfoFactoryService : IDeclaredSymbolInfoFactoryService
{
private readonly static ObjectPool<List<Dictionary<string, string>>> s_aliasMapListPool =
new ObjectPool<List<Dictionary<string, string>>>(() => new List<Dictionary<string, string>>());
......@@ -27,6 +28,53 @@ internal abstract class AbstractSyntaxFactsService
private readonly static ObjectPool<Dictionary<string, string>> s_aliasMapPool =
new ObjectPool<Dictionary<string, string>>(() => new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase));
protected static List<Dictionary<string, string>> AllocateAliasMapList()
=> s_aliasMapListPool.Allocate();
protected static void FreeAliasMapList(List<Dictionary<string, string>> list)
{
if (list != null)
{
foreach (var aliasMap in list)
{
FreeAliasMap(aliasMap);
}
s_aliasMapListPool.ClearAndFree(list);
}
}
protected static void FreeAliasMap(Dictionary<string, string> aliasMap)
{
if (aliasMap != null)
{
s_aliasMapPool.ClearAndFree(aliasMap);
}
}
protected static Dictionary<string, string> AllocateAliasMap()
=> s_aliasMapPool.Allocate();
protected static void AppendTokens(SyntaxNode node, StringBuilder builder)
{
foreach (var child in node.ChildNodesAndTokens())
{
if (child.IsToken)
{
builder.Append(child.AsToken().Text);
}
else
{
AppendTokens(child.AsNode(), builder);
}
}
}
public abstract bool TryGetDeclaredSymbolInfo(Project project, SyntaxNode node, out DeclaredSymbolInfo declaredSymbolInfo);
}
internal abstract class AbstractSyntaxFactsService
{
private readonly static ObjectPool<Stack<(SyntaxNodeOrToken nodeOrToken, bool leading, bool trailing)>> s_stackPool =
new ObjectPool<Stack<(SyntaxNodeOrToken nodeOrToken, bool leading, bool trailing)>>(() => new Stack<(SyntaxNodeOrToken nodeOrToken, bool leading, bool trailing)>());
......@@ -77,33 +125,6 @@ protected AbstractSyntaxFactsService()
public abstract bool IsShebangDirectiveTrivia(SyntaxTrivia trivia);
public abstract bool IsPreprocessorDirective(SyntaxTrivia trivia);
protected static List<Dictionary<string, string>> AllocateAliasMapList()
=> s_aliasMapListPool.Allocate();
protected static void FreeAliasMapList(List<Dictionary<string, string>> list)
{
if (list != null)
{
foreach (var aliasMap in list)
{
FreeAliasMap(aliasMap);
}
s_aliasMapListPool.ClearAndFree(list);
}
}
protected static void FreeAliasMap(Dictionary<string, string> aliasMap)
{
if (aliasMap != null)
{
s_aliasMapPool.ClearAndFree(aliasMap);
}
}
protected static Dictionary<string, string> AllocateAliasMap()
=> s_aliasMapPool.Allocate();
public bool IsOnSingleLine(SyntaxNode node, bool fullSpan)
{
// Use an actual Stack so we can write out deeply recursive structures without overflowing.
......@@ -392,20 +413,5 @@ public string GetBannerText(SyntaxNode documentationCommentTriviaSyntax, Cancell
=> DocumentationCommentService.GetBannerText(documentationCommentTriviaSyntax, cancellationToken);
protected abstract IDocumentationCommentService DocumentationCommentService { get; }
protected static void AppendTokens(SyntaxNode node, StringBuilder builder)
{
foreach (var child in node.ChildNodesAndTokens())
{
if (child.IsToken)
{
builder.Append(child.AsToken().Text);
}
else
{
AppendTokens(child.AsNode(), builder);
}
}
}
}
}
\ No newline at end of file
......@@ -4,7 +4,6 @@
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Threading;
using Microsoft.CodeAnalysis.FindSymbols;
using Microsoft.CodeAnalysis.Host;
using Microsoft.CodeAnalysis.Text;
......@@ -224,8 +223,6 @@ internal interface ISyntaxFactsService : ILanguageService
bool AreEquivalent(SyntaxToken token1, SyntaxToken token2);
bool AreEquivalent(SyntaxNode node1, SyntaxNode node2);
bool TryGetDeclaredSymbolInfo(Project project, SyntaxNode node, out DeclaredSymbolInfo declaredSymbolInfo);
string GetDisplayName(SyntaxNode node, DisplayNameOptions options, string rootNamespace = null);
SyntaxNode GetContainingTypeDeclaration(SyntaxNode root, int position);
......
......@@ -16,1238 +16,1241 @@ Imports Microsoft.CodeAnalysis.VisualBasic.Syntax
Imports Microsoft.CodeAnalysis.VisualBasic.SyntaxFacts
Namespace Microsoft.CodeAnalysis.VisualBasic
<ExportLanguageServiceFactory(GetType(ISyntaxFactsService), LanguageNames.VisualBasic), [Shared]>
Friend Class VisualBasicSyntaxFactsServiceFactory
Implements ILanguageServiceFactory
Public Function CreateLanguageService(languageServices As HostLanguageServices) As ILanguageService Implements ILanguageServiceFactory.CreateLanguageService
Return VisualBasicSyntaxFactsService.Instance
End Function
End Class
Friend Class VisualBasicSyntaxFactsService
Inherits AbstractSyntaxFactsService
Implements ISyntaxFactsService
Public Shared ReadOnly Property Instance As New VisualBasicSyntaxFactsService
Private Sub New()
End Sub
Public ReadOnly Property IsCaseSensitive As Boolean Implements ISyntaxFactsService.IsCaseSensitive
Get
Return False
End Get
End Property
Public ReadOnly Property StringComparer As StringComparer Implements ISyntaxFactsService.StringComparer
Get
Return CaseInsensitiveComparison.Comparer
End Get
End Property
Protected Overrides ReadOnly Property DocumentationCommentService As IDocumentationCommentService
Get
Return VisualBasicDocumentationCommentService.Instance
End Get
End Property
Public Function SupportsIndexingInitializer(options As ParseOptions) As Boolean Implements ISyntaxFactsService.SupportsIndexingInitializer
Return False
End Function
Public Function SupportsThrowExpression(options As ParseOptions) As Boolean Implements ISyntaxFactsService.SupportsThrowExpression
Return False
End Function
<ExportLanguageService(GetType(IDeclaredSymbolInfoFactoryService), LanguageNames.VisualBasic), [Shared]>
Friend Class VisualBasicDeclaredSymbolInfoFactoryService
Inherits AbstractDeclaredSymbolInfoFactoryService
Public Function IsAwaitKeyword(token As SyntaxToken) As Boolean Implements ISyntaxFactsService.IsAwaitKeyword
Return token.Kind = SyntaxKind.AwaitKeyword
End Function
Private Function GetInheritanceNames(project As Project, typeBlock As TypeBlockSyntax) As ImmutableArray(Of String)
Dim builder = ArrayBuilder(Of String).GetInstance()
Public Function IsIdentifier(token As SyntaxToken) As Boolean Implements ISyntaxFactsService.IsIdentifier
Return token.Kind = SyntaxKind.IdentifierToken
End Function
Dim aliasMap = GetAliasMap(typeBlock)
Try
For Each inheritsStatement In typeBlock.Inherits
AddInheritanceNames(builder, inheritsStatement.Types, aliasMap)
Next
Public Function IsGlobalNamespaceKeyword(token As SyntaxToken) As Boolean Implements ISyntaxFactsService.IsGlobalNamespaceKeyword
Return token.Kind = SyntaxKind.GlobalKeyword
End Function
For Each implementsStatement In typeBlock.Implements
AddInheritanceNames(builder, implementsStatement.Types, aliasMap)
Next
Public Function IsVerbatimIdentifier(token As SyntaxToken) As Boolean Implements ISyntaxFactsService.IsVerbatimIdentifier
Return False
DeclaredSymbolInfo.Intern(project, builder)
Return builder.ToImmutableAndFree()
Finally
FreeAliasMap(aliasMap)
End Try
End Function
Public Function IsOperator(token As SyntaxToken) As Boolean Implements ISyntaxFactsService.IsOperator
Return (IsUnaryExpressionOperatorToken(CType(token.Kind, SyntaxKind)) AndAlso (TypeOf token.Parent Is UnaryExpressionSyntax OrElse TypeOf token.Parent Is OperatorStatementSyntax)) OrElse
(IsBinaryExpressionOperatorToken(CType(token.Kind, SyntaxKind)) AndAlso (TypeOf token.Parent Is BinaryExpressionSyntax OrElse TypeOf token.Parent Is OperatorStatementSyntax))
End Function
Private Function GetAliasMap(typeBlock As TypeBlockSyntax) As Dictionary(Of String, String)
Dim compilationUnit = typeBlock.SyntaxTree.GetCompilationUnitRoot()
Public Function IsContextualKeyword(token As SyntaxToken) As Boolean Implements ISyntaxFactsService.IsContextualKeyword
Return token.IsContextualKeyword()
End Function
Dim aliasMap As Dictionary(Of String, String) = Nothing
For Each import In compilationUnit.Imports
For Each clause In import.ImportsClauses
If clause.IsKind(SyntaxKind.SimpleImportsClause) Then
Dim simpleImport = DirectCast(clause, SimpleImportsClauseSyntax)
If simpleImport.Alias IsNot Nothing Then
Dim mappedName = GetTypeName(simpleImport.Name)
If mappedName IsNot Nothing Then
aliasMap = If(aliasMap, AllocateAliasMap())
aliasMap(simpleImport.Alias.Identifier.ValueText) = mappedName
End If
End If
End If
Next
Next
Public Function IsKeyword(token As SyntaxToken) As Boolean Implements ISyntaxFactsService.IsKeyword
Return token.IsKeyword()
Return aliasMap
End Function
Public Function IsPreprocessorKeyword(token As SyntaxToken) As Boolean Implements ISyntaxFactsService.IsPreprocessorKeyword
Return token.IsPreprocessorKeyword()
End Function
Private Sub AddInheritanceNames(
builder As ArrayBuilder(Of String),
types As SeparatedSyntaxList(Of TypeSyntax),
aliasMap As Dictionary(Of String, String))
Public Function IsHashToken(token As SyntaxToken) As Boolean Implements ISyntaxFactsService.IsHashToken
Return token.Kind = SyntaxKind.HashToken
End Function
For Each typeSyntax In types
AddInheritanceName(builder, typeSyntax, aliasMap)
Next
End Sub
Public Function TryGetCorrespondingOpenBrace(token As SyntaxToken, ByRef openBrace As SyntaxToken) As Boolean Implements ISyntaxFactsService.TryGetCorrespondingOpenBrace
Private Sub AddInheritanceName(
builder As ArrayBuilder(Of String),
typeSyntax As TypeSyntax,
aliasMap As Dictionary(Of String, String))
Dim name = GetTypeName(typeSyntax)
If name IsNot Nothing Then
builder.Add(name)
If token.Kind = SyntaxKind.CloseBraceToken Then
Dim tuples = token.Parent.GetBraces()
openBrace = tuples.Item1
Return openBrace.Kind = SyntaxKind.OpenBraceToken
Dim mappedName As String = Nothing
If aliasMap?.TryGetValue(name, mappedName) = True Then
' Looks Like this could be an alias. Also include the name the alias points to
builder.Add(mappedName)
End If
End If
End Sub
Return False
End Function
Public Function IsInInactiveRegion(syntaxTree As SyntaxTree, position As Integer, cancellationToken As CancellationToken) As Boolean Implements ISyntaxFactsService.IsInInactiveRegion
Dim vbTree = TryCast(syntaxTree, SyntaxTree)
If vbTree Is Nothing Then
Return False
Private Function GetTypeName(typeSyntax As TypeSyntax) As String
If TypeOf typeSyntax Is SimpleNameSyntax Then
Return GetSimpleName(DirectCast(typeSyntax, SimpleNameSyntax))
ElseIf TypeOf typeSyntax Is QualifiedNameSyntax Then
Return GetSimpleName(DirectCast(typeSyntax, QualifiedNameSyntax).Right)
End If
Return vbTree.IsInInactiveRegion(position, cancellationToken)
Return Nothing
End Function
Public Function IsInNonUserCode(syntaxTree As SyntaxTree, position As Integer, cancellationToken As CancellationToken) As Boolean Implements ISyntaxFactsService.IsInNonUserCode
Dim vbTree = TryCast(syntaxTree, SyntaxTree)
If vbTree Is Nothing Then
Return False
End If
Return vbTree.IsInNonUserCode(position, cancellationToken)
Private Function GetSimpleName(simpleName As SimpleNameSyntax) As String
Return simpleName.Identifier.ValueText
End Function
Public Function IsEntirelyWithinStringOrCharOrNumericLiteral(syntaxTree As SyntaxTree, position As Integer, cancellationToken As CancellationToken) As Boolean Implements ISyntaxFactsService.IsEntirelyWithinStringOrCharOrNumericLiteral
Dim vbTree = TryCast(syntaxTree, SyntaxTree)
If vbTree Is Nothing Then
Return False
End If
Return vbTree.IsEntirelyWithinStringOrCharOrNumericLiteral(position, cancellationToken)
Private Function GetContainerDisplayName(node As SyntaxNode) As String
Return VisualBasicSyntaxFactsService.Instance.GetDisplayName(node, DisplayNameOptions.IncludeTypeParameters)
End Function
Public Function IsDirective(node As SyntaxNode) As Boolean Implements ISyntaxFactsService.IsDirective
Return TypeOf node Is DirectiveTriviaSyntax
Private Function GetFullyQualifiedContainerName(node As SyntaxNode) As String
Return VisualBasicSyntaxFactsService.Instance.GetDisplayName(node, DisplayNameOptions.IncludeNamespaces)
End Function
Public Function TryGetExternalSourceInfo(node As SyntaxNode, ByRef info As ExternalSourceInfo) As Boolean Implements ISyntaxFactsService.TryGetExternalSourceInfo
Select Case node.Kind
Case SyntaxKind.ExternalSourceDirectiveTrivia
info = New ExternalSourceInfo(CInt(DirectCast(node, ExternalSourceDirectiveTriviaSyntax).LineStart.Value), False)
Public Overrides Function TryGetDeclaredSymbolInfo(project As Project, node As SyntaxNode, ByRef declaredSymbolInfo As DeclaredSymbolInfo) As Boolean
Select Case node.Kind()
Case SyntaxKind.ClassBlock
Dim classDecl = CType(node, ClassBlockSyntax)
declaredSymbolInfo = New DeclaredSymbolInfo(
project,
classDecl.ClassStatement.Identifier.ValueText,
GetTypeParameterSuffix(classDecl.ClassStatement.TypeParameterList),
GetContainerDisplayName(node.Parent),
GetFullyQualifiedContainerName(node.Parent),
DeclaredSymbolInfoKind.Class,
GetAccessibility(classDecl, classDecl.ClassStatement.Modifiers),
classDecl.ClassStatement.Identifier.Span,
GetInheritanceNames(project, classDecl))
Return True
Case SyntaxKind.ConstructorBlock
Dim constructor = CType(node, ConstructorBlockSyntax)
Dim typeBlock = TryCast(constructor.Parent, TypeBlockSyntax)
If typeBlock IsNot Nothing Then
declaredSymbolInfo = New DeclaredSymbolInfo(
project,
typeBlock.BlockStatement.Identifier.ValueText,
GetConstructorSuffix(constructor),
GetContainerDisplayName(node.Parent),
GetFullyQualifiedContainerName(node.Parent),
DeclaredSymbolInfoKind.Constructor,
GetAccessibility(constructor, constructor.SubNewStatement.Modifiers),
constructor.SubNewStatement.NewKeyword.Span,
ImmutableArray(Of String).Empty,
parameterCount:=If(constructor.SubNewStatement.ParameterList?.Parameters.Count, 0))
Case SyntaxKind.EndExternalSourceDirectiveTrivia
info = New ExternalSourceInfo(Nothing, True)
Return True
End If
Case SyntaxKind.DelegateFunctionStatement, SyntaxKind.DelegateSubStatement
Dim delegateDecl = CType(node, DelegateStatementSyntax)
declaredSymbolInfo = New DeclaredSymbolInfo(
project,
delegateDecl.Identifier.ValueText,
GetTypeParameterSuffix(delegateDecl.TypeParameterList),
GetContainerDisplayName(node.Parent),
GetFullyQualifiedContainerName(node.Parent),
DeclaredSymbolInfoKind.Delegate,
GetAccessibility(delegateDecl, delegateDecl.Modifiers),
delegateDecl.Identifier.Span,
ImmutableArray(Of String).Empty)
Return True
End Select
Return False
End Function
Public Function IsObjectCreationExpressionType(node As SyntaxNode) As Boolean Implements ISyntaxFactsService.IsObjectCreationExpressionType
Return node.IsParentKind(SyntaxKind.ObjectCreationExpression) AndAlso
DirectCast(node.Parent, ObjectCreationExpressionSyntax).Type Is node
End Function
Public Function IsAttributeName(node As SyntaxNode) As Boolean Implements ISyntaxFactsService.IsAttributeName
Return node.IsParentKind(SyntaxKind.Attribute) AndAlso
DirectCast(node.Parent, AttributeSyntax).Name Is node
End Function
Public Function IsRightSideOfQualifiedName(node As SyntaxNode) As Boolean Implements ISyntaxFactsService.IsRightSideOfQualifiedName
Dim vbNode = TryCast(node, SimpleNameSyntax)
Return vbNode IsNot Nothing AndAlso vbNode.IsRightSideOfQualifiedName()
End Function
Public Function IsNameOfMemberAccessExpression(node As SyntaxNode) As Boolean Implements ISyntaxFactsService.IsNameOfMemberAccessExpression
Dim vbNode = TryCast(node, SimpleNameSyntax)
Return vbNode IsNot Nothing AndAlso vbNode.IsMemberAccessExpressionName()
End Function
Public Function IsConditionalMemberAccessExpression(node As SyntaxNode) As Boolean Implements ISyntaxFactsService.IsConditionalMemberAccessExpression
Return TypeOf node Is ConditionalAccessExpressionSyntax
End Function
Public Function IsInvocationExpression(node As SyntaxNode) As Boolean Implements ISyntaxFactsService.IsInvocationExpression
Return TypeOf node Is InvocationExpressionSyntax
End Function
Public Function IsAnonymousFunction(node As SyntaxNode) As Boolean Implements ISyntaxFactsService.IsAnonymousFunction
Return TypeOf node Is LambdaExpressionSyntax
End Function
Public Function IsGenericName(node As SyntaxNode) As Boolean Implements ISyntaxFactsService.IsGenericName
Return TypeOf node Is GenericNameSyntax
End Function
Public Function IsNamedParameter(node As SyntaxNode) As Boolean Implements ISyntaxFactsService.IsNamedParameter
Return node.CheckParent(Of SimpleArgumentSyntax)(Function(p) p.IsNamed AndAlso p.NameColonEquals.Name Is node)
End Function
Public Function GetDefaultOfParameter(node As SyntaxNode) As SyntaxNode Implements ISyntaxFactsService.GetDefaultOfParameter
Return TryCast(node, ParameterSyntax)?.Default
End Function
Case SyntaxKind.EnumBlock
Dim enumDecl = CType(node, EnumBlockSyntax)
declaredSymbolInfo = New DeclaredSymbolInfo(
project,
enumDecl.EnumStatement.Identifier.ValueText, Nothing,
GetContainerDisplayName(node.Parent),
GetFullyQualifiedContainerName(node.Parent),
DeclaredSymbolInfoKind.Enum,
GetAccessibility(enumDecl, enumDecl.EnumStatement.Modifiers),
enumDecl.EnumStatement.Identifier.Span,
ImmutableArray(Of String).Empty)
Return True
Case SyntaxKind.EnumMemberDeclaration
Dim enumMember = CType(node, EnumMemberDeclarationSyntax)
declaredSymbolInfo = New DeclaredSymbolInfo(
project,
enumMember.Identifier.ValueText, Nothing,
GetContainerDisplayName(node.Parent),
GetFullyQualifiedContainerName(node.Parent),
DeclaredSymbolInfoKind.EnumMember,
Accessibility.Public,
enumMember.Identifier.Span,
ImmutableArray(Of String).Empty)
Return True
Case SyntaxKind.EventStatement
Dim eventDecl = CType(node, EventStatementSyntax)
Dim statementOrBlock = If(TypeOf node.Parent Is EventBlockSyntax, node.Parent, node)
Dim eventParent = statementOrBlock.Parent
declaredSymbolInfo = New DeclaredSymbolInfo(
project,
eventDecl.Identifier.ValueText, Nothing,
GetContainerDisplayName(eventParent),
GetFullyQualifiedContainerName(eventParent),
DeclaredSymbolInfoKind.Event,
GetAccessibility(statementOrBlock, eventDecl.Modifiers),
eventDecl.Identifier.Span,
ImmutableArray(Of String).Empty)
Return True
Case SyntaxKind.FunctionBlock, SyntaxKind.SubBlock
Dim funcDecl = CType(node, MethodBlockSyntax)
declaredSymbolInfo = New DeclaredSymbolInfo(
project,
funcDecl.SubOrFunctionStatement.Identifier.ValueText,
GetMethodSuffix(funcDecl),
GetContainerDisplayName(node.Parent),
GetFullyQualifiedContainerName(node.Parent),
DeclaredSymbolInfoKind.Method,
GetAccessibility(node, funcDecl.SubOrFunctionStatement.Modifiers),
funcDecl.SubOrFunctionStatement.Identifier.Span,
ImmutableArray(Of String).Empty,
parameterCount:=If(funcDecl.SubOrFunctionStatement.ParameterList?.Parameters.Count, 0),
typeParameterCount:=If(funcDecl.SubOrFunctionStatement.TypeParameterList?.Parameters.Count, 0))
Return True
Case SyntaxKind.InterfaceBlock
Dim interfaceDecl = CType(node, InterfaceBlockSyntax)
declaredSymbolInfo = New DeclaredSymbolInfo(
project,
interfaceDecl.InterfaceStatement.Identifier.ValueText,
GetTypeParameterSuffix(interfaceDecl.InterfaceStatement.TypeParameterList),
GetContainerDisplayName(node.Parent),
GetFullyQualifiedContainerName(node.Parent),
DeclaredSymbolInfoKind.Interface,
GetAccessibility(interfaceDecl, interfaceDecl.InterfaceStatement.Modifiers),
interfaceDecl.InterfaceStatement.Identifier.Span,
GetInheritanceNames(project, interfaceDecl))
Return True
Case SyntaxKind.ModifiedIdentifier
Dim modifiedIdentifier = CType(node, ModifiedIdentifierSyntax)
Dim variableDeclarator = TryCast(modifiedIdentifier.Parent, VariableDeclaratorSyntax)
Dim fieldDecl = TryCast(variableDeclarator?.Parent, FieldDeclarationSyntax)
If fieldDecl IsNot Nothing Then
Dim kind = If(fieldDecl.Modifiers.Any(Function(m) m.Kind() = SyntaxKind.ConstKeyword),
DeclaredSymbolInfoKind.Constant,
DeclaredSymbolInfoKind.Field)
declaredSymbolInfo = New DeclaredSymbolInfo(
project,
modifiedIdentifier.Identifier.ValueText, Nothing,
GetContainerDisplayName(fieldDecl.Parent),
GetFullyQualifiedContainerName(fieldDecl.Parent),
kind, GetAccessibility(fieldDecl, fieldDecl.Modifiers),
modifiedIdentifier.Identifier.Span,
ImmutableArray(Of String).Empty)
Return True
End If
Case SyntaxKind.ModuleBlock
Dim moduleDecl = CType(node, ModuleBlockSyntax)
declaredSymbolInfo = New DeclaredSymbolInfo(
project,
moduleDecl.ModuleStatement.Identifier.ValueText,
GetTypeParameterSuffix(moduleDecl.ModuleStatement.TypeParameterList),
GetContainerDisplayName(node.Parent),
GetFullyQualifiedContainerName(node.Parent),
DeclaredSymbolInfoKind.Module,
GetAccessibility(moduleDecl, moduleDecl.ModuleStatement.Modifiers),
moduleDecl.ModuleStatement.Identifier.Span,
GetInheritanceNames(project, moduleDecl))
Return True
Case SyntaxKind.PropertyStatement
Dim propertyDecl = CType(node, PropertyStatementSyntax)
Dim statementOrBlock = If(TypeOf node.Parent Is PropertyBlockSyntax, node.Parent, node)
Dim propertyParent = statementOrBlock.Parent
declaredSymbolInfo = New DeclaredSymbolInfo(
project,
propertyDecl.Identifier.ValueText, GetPropertySuffix(propertyDecl),
GetContainerDisplayName(propertyParent),
GetFullyQualifiedContainerName(propertyParent),
DeclaredSymbolInfoKind.Property,
GetAccessibility(statementOrBlock, propertyDecl.Modifiers),
propertyDecl.Identifier.Span,
ImmutableArray(Of String).Empty)
Return True
Case SyntaxKind.StructureBlock
Dim structDecl = CType(node, StructureBlockSyntax)
declaredSymbolInfo = New DeclaredSymbolInfo(
project,
structDecl.StructureStatement.Identifier.ValueText,
GetTypeParameterSuffix(structDecl.StructureStatement.TypeParameterList),
GetContainerDisplayName(node.Parent),
GetFullyQualifiedContainerName(node.Parent),
DeclaredSymbolInfoKind.Struct,
GetAccessibility(structDecl, structDecl.StructureStatement.Modifiers),
structDecl.StructureStatement.Identifier.Span,
GetInheritanceNames(project, structDecl))
Return True
End Select
Public Function IsSkippedTokensTrivia(node As SyntaxNode) As Boolean Implements ISyntaxFactsService.IsSkippedTokensTrivia
Return TypeOf node Is SkippedTokensTriviaSyntax
declaredSymbolInfo = Nothing
Return False
End Function
Public Function HasIncompleteParentMember(node As SyntaxNode) As Boolean Implements ISyntaxFactsService.HasIncompleteParentMember
Return node.IsParentKind(SyntaxKind.IncompleteMember)
End Function
Private Function GetAccessibility(node As SyntaxNode, modifiers As SyntaxTokenList) As Accessibility
Dim sawFriend = False
Public Function GetIdentifierOfGenericName(genericName As SyntaxNode) As SyntaxToken Implements ISyntaxFactsService.GetIdentifierOfGenericName
Dim vbGenericName = TryCast(genericName, GenericNameSyntax)
Return If(vbGenericName IsNot Nothing, vbGenericName.Identifier, Nothing)
End Function
For Each modifier In modifiers
Select Case modifier.Kind()
Case SyntaxKind.PublicKeyword : Return Accessibility.Public
Case SyntaxKind.PrivateKeyword : Return Accessibility.Private
Case SyntaxKind.ProtectedKeyword : Return Accessibility.Protected
Case SyntaxKind.FriendKeyword
sawFriend = True
Continue For
End Select
Next
Public Function IsUsingDirectiveName(node As SyntaxNode) As Boolean Implements ISyntaxFactsService.IsUsingDirectiveName
Return node.IsParentKind(SyntaxKind.SimpleImportsClause) AndAlso
DirectCast(node.Parent, SimpleImportsClauseSyntax).Name Is node
End Function
If sawFriend Then
Return Accessibility.Internal
End If
Public Function IsForEachStatement(node As SyntaxNode) As Boolean Implements ISyntaxFactsService.IsForEachStatement
Return TypeOf node Is ForEachStatementSyntax
End Function
' No accessibility modifiers
Select Case node.Parent.Kind()
Case SyntaxKind.ClassBlock
' In a class, fields and shared-constructors are private by default,
' everything Else Is Public
If node.Kind() = SyntaxKind.FieldDeclaration Then
Return Accessibility.Private
End If
Public Function IsLockStatement(node As SyntaxNode) As Boolean Implements ISyntaxFactsService.IsLockStatement
Return TypeOf node Is SyncLockStatementSyntax
End Function
If node.Kind() = SyntaxKind.ConstructorBlock AndAlso
DirectCast(node, ConstructorBlockSyntax).SubNewStatement.Modifiers.Any(SyntaxKind.SharedKeyword) Then
Return Accessibility.Private
End If
Public Function IsUsingStatement(node As SyntaxNode) As Boolean Implements ISyntaxFactsService.IsUsingStatement
Return node.Kind() = SyntaxKind.UsingStatement
Return Accessibility.Public
Case SyntaxKind.StructureBlock, SyntaxKind.InterfaceBlock, SyntaxKind.ModuleBlock
' Everything in a struct/interface/module is public
Return Accessibility.Public
End Select
' Otherwise, it's internal
Return Accessibility.Internal
End Function
Public Function IsReturnStatement(node As SyntaxNode) As Boolean Implements ISyntaxFactsService.IsReturnStatement
Return node.Kind() = SyntaxKind.ReturnStatement
Private Function GetMethodSuffix(method As MethodBlockSyntax) As String
Return GetTypeParameterSuffix(method.SubOrFunctionStatement.TypeParameterList) &
GetSuffix(method.SubOrFunctionStatement.ParameterList)
End Function
Public Function GetExpressionOfReturnStatement(node As SyntaxNode) As SyntaxNode Implements ISyntaxFactsService.GetExpressionOfReturnStatement
Return TryCast(node, ReturnStatementSyntax)?.Expression
Private Function GetConstructorSuffix(method As ConstructorBlockSyntax) As String
Return ".New" & GetSuffix(method.SubNewStatement.ParameterList)
End Function
Public Function IsThisConstructorInitializer(token As SyntaxToken) As Boolean Implements ISyntaxFactsService.IsThisConstructorInitializer
If TypeOf token.Parent Is IdentifierNameSyntax AndAlso token.HasMatchingText(SyntaxKind.NewKeyword) Then
Dim memberAccess = TryCast(token.Parent.Parent, MemberAccessExpressionSyntax)
Return memberAccess.IsThisConstructorInitializer()
Private Function GetPropertySuffix([property] As PropertyStatementSyntax) As String
If [property].ParameterList Is Nothing Then
Return Nothing
End If
Return False
Return GetSuffix([property].ParameterList)
End Function
Public Function IsBaseConstructorInitializer(token As SyntaxToken) As Boolean Implements ISyntaxFactsService.IsBaseConstructorInitializer
If TypeOf token.Parent Is IdentifierNameSyntax AndAlso token.HasMatchingText(SyntaxKind.NewKeyword) Then
Dim memberAccess = TryCast(token.Parent.Parent, MemberAccessExpressionSyntax)
Return memberAccess.IsBaseConstructorInitializer()
Private Function GetTypeParameterSuffix(typeParameterList As TypeParameterListSyntax) As String
If typeParameterList Is Nothing Then
Return Nothing
End If
Return False
End Function
Dim pooledBuilder = PooledStringBuilder.GetInstance()
Public Function IsQueryExpression(node As SyntaxNode) As Boolean Implements ISyntaxFactsService.IsQueryExpression
Return node.Kind() = SyntaxKind.QueryExpression
End Function
Dim builder = pooledBuilder.Builder
builder.Append("(Of ")
Public Function IsThrowExpression(node As SyntaxNode) As Boolean Implements ISyntaxFactsService.IsThrowExpression
' VB does not support throw expressions currently.
Return False
End Function
Dim First = True
For Each parameter In typeParameterList.Parameters
If Not First Then
builder.Append(", ")
End If
Public Function IsPredefinedType(token As SyntaxToken) As Boolean Implements ISyntaxFactsService.IsPredefinedType
Dim actualType As PredefinedType = PredefinedType.None
Return TryGetPredefinedType(token, actualType) AndAlso actualType <> PredefinedType.None
End Function
builder.Append(parameter.Identifier.Text)
First = False
Next
Public Function IsPredefinedType(token As SyntaxToken, type As PredefinedType) As Boolean Implements ISyntaxFactsService.IsPredefinedType
Dim actualType As PredefinedType = PredefinedType.None
Return TryGetPredefinedType(token, actualType) AndAlso actualType = type
End Function
builder.Append(")"c)
Public Function TryGetPredefinedType(token As SyntaxToken, ByRef type As PredefinedType) As Boolean Implements ISyntaxFactsService.TryGetPredefinedType
type = GetPredefinedType(token)
Return type <> PredefinedType.None
Return pooledBuilder.ToStringAndFree()
End Function
Private Function GetPredefinedType(token As SyntaxToken) As PredefinedType
Select Case token.Kind
Case SyntaxKind.BooleanKeyword
Return PredefinedType.Boolean
Case SyntaxKind.ByteKeyword
Return PredefinedType.Byte
Case SyntaxKind.SByteKeyword
Return PredefinedType.SByte
Case SyntaxKind.IntegerKeyword
Return PredefinedType.Int32
Case SyntaxKind.UIntegerKeyword
Return PredefinedType.UInt32
Case SyntaxKind.ShortKeyword
Return PredefinedType.Int16
Case SyntaxKind.UShortKeyword
Return PredefinedType.UInt16
Case SyntaxKind.LongKeyword
Return PredefinedType.Int64
Case SyntaxKind.ULongKeyword
Return PredefinedType.UInt64
Case SyntaxKind.SingleKeyword
Return PredefinedType.Single
Case SyntaxKind.DoubleKeyword
Return PredefinedType.Double
Case SyntaxKind.DecimalKeyword
Return PredefinedType.Decimal
Case SyntaxKind.StringKeyword
Return PredefinedType.String
Case SyntaxKind.CharKeyword
Return PredefinedType.Char
Case SyntaxKind.ObjectKeyword
Return PredefinedType.Object
Case SyntaxKind.DateKeyword
Return PredefinedType.DateTime
Case Else
Return PredefinedType.None
End Select
End Function
''' <summary>
''' Builds up the suffix to show for something with parameters in navigate-to.
''' While it would be nice to just use the compiler SymbolDisplay API for this,
''' it would be too expensive as it requires going back to Symbols (which requires
''' creating compilations, etc.) in a perf sensitive area.
'''
''' So, instead, we just build a reasonable suffix using the pure syntax that a
''' user provided. That means that if they wrote "Method(System.Int32 i)" we'll
''' show that as "Method(System.Int32)" Not "Method(Integer)". Given that this Is
''' actually what the user wrote, And it saves us from ever having to go back to
''' symbols/compilations, this Is well worth it, even if it does mean we have to
''' create our own 'symbol display' logic here.
''' </summary>
Private Function GetSuffix(parameterList As ParameterListSyntax) As String
If parameterList Is Nothing OrElse parameterList.Parameters.Count = 0 Then
Return "()"
End If
Public Function IsPredefinedOperator(token As SyntaxToken) As Boolean Implements ISyntaxFactsService.IsPredefinedOperator
Dim actualOp As PredefinedOperator = PredefinedOperator.None
Return TryGetPredefinedOperator(token, actualOp) AndAlso actualOp <> PredefinedOperator.None
End Function
Dim pooledBuilder = PooledStringBuilder.GetInstance()
Public Function IsPredefinedOperator(token As SyntaxToken, op As PredefinedOperator) As Boolean Implements ISyntaxFactsService.IsPredefinedOperator
Dim actualOp As PredefinedOperator = PredefinedOperator.None
Return TryGetPredefinedOperator(token, actualOp) AndAlso actualOp = op
End Function
Dim builder = pooledBuilder.Builder
builder.Append("("c)
If parameterList IsNot Nothing Then
AppendParameters(parameterList.Parameters, builder)
End If
builder.Append(")"c)
Public Function TryGetPredefinedOperator(token As SyntaxToken, ByRef op As PredefinedOperator) As Boolean Implements ISyntaxFactsService.TryGetPredefinedOperator
op = GetPredefinedOperator(token)
Return op <> PredefinedOperator.None
Return pooledBuilder.ToStringAndFree()
End Function
Private Function GetPredefinedOperator(token As SyntaxToken) As PredefinedOperator
Select Case token.Kind
Case SyntaxKind.PlusToken, SyntaxKind.PlusEqualsToken
Return PredefinedOperator.Addition
Case SyntaxKind.MinusToken, SyntaxKind.MinusEqualsToken
Return PredefinedOperator.Subtraction
Case SyntaxKind.AndKeyword, SyntaxKind.AndAlsoKeyword
Return PredefinedOperator.BitwiseAnd
Case SyntaxKind.OrKeyword, SyntaxKind.OrElseKeyword
Return PredefinedOperator.BitwiseOr
Case SyntaxKind.AmpersandToken, SyntaxKind.AmpersandEqualsToken
Return PredefinedOperator.Concatenate
Case SyntaxKind.SlashToken, SyntaxKind.SlashEqualsToken
Return PredefinedOperator.Division
Case SyntaxKind.EqualsToken
Return PredefinedOperator.Equality
Case SyntaxKind.XorKeyword
Return PredefinedOperator.ExclusiveOr
Private Sub AppendParameters(parameters As SeparatedSyntaxList(Of ParameterSyntax), builder As StringBuilder)
Dim First = True
For Each parameter In parameters
If Not First Then
builder.Append(", ")
End If
Case SyntaxKind.CaretToken, SyntaxKind.CaretEqualsToken
Return PredefinedOperator.Exponent
For Each modifier In parameter.Modifiers
If modifier.Kind() <> SyntaxKind.ByValKeyword Then
builder.Append(modifier.Text)
builder.Append(" "c)
End If
Next
Case SyntaxKind.GreaterThanToken
Return PredefinedOperator.GreaterThan
If parameter.AsClause?.Type IsNot Nothing Then
AppendTokens(parameter.AsClause.Type, builder)
End If
Case SyntaxKind.GreaterThanEqualsToken
Return PredefinedOperator.GreaterThanOrEqual
First = False
Next
End Sub
End Class
Case SyntaxKind.LessThanGreaterThanToken
Return PredefinedOperator.Inequality
<ExportLanguageServiceFactory(GetType(ISyntaxFactsService), LanguageNames.VisualBasic), [Shared]>
Friend Class VisualBasicSyntaxFactsServiceFactory
Implements ILanguageServiceFactory
Case SyntaxKind.BackslashToken, SyntaxKind.BackslashEqualsToken
Return PredefinedOperator.IntegerDivision
Public Function CreateLanguageService(languageServices As HostLanguageServices) As ILanguageService Implements ILanguageServiceFactory.CreateLanguageService
Return VisualBasicSyntaxFactsService.Instance
End Function
End Class
Case SyntaxKind.LessThanLessThanToken, SyntaxKind.LessThanLessThanEqualsToken
Return PredefinedOperator.LeftShift
Friend Class VisualBasicSyntaxFactsService
Inherits AbstractSyntaxFactsService
Implements ISyntaxFactsService
Case SyntaxKind.LessThanToken
Return PredefinedOperator.LessThan
Public Shared ReadOnly Property Instance As New VisualBasicSyntaxFactsService
Case SyntaxKind.LessThanEqualsToken
Return PredefinedOperator.LessThanOrEqual
Private Sub New()
End Sub
Case SyntaxKind.LikeKeyword
Return PredefinedOperator.Like
Public ReadOnly Property IsCaseSensitive As Boolean Implements ISyntaxFactsService.IsCaseSensitive
Get
Return False
End Get
End Property
Case SyntaxKind.NotKeyword
Return PredefinedOperator.Complement
Public ReadOnly Property StringComparer As StringComparer Implements ISyntaxFactsService.StringComparer
Get
Return CaseInsensitiveComparison.Comparer
End Get
End Property
Case SyntaxKind.ModKeyword
Return PredefinedOperator.Modulus
Protected Overrides ReadOnly Property DocumentationCommentService As IDocumentationCommentService
Get
Return VisualBasicDocumentationCommentService.Instance
End Get
End Property
Case SyntaxKind.AsteriskToken, SyntaxKind.AsteriskEqualsToken
Return PredefinedOperator.Multiplication
Public Function SupportsIndexingInitializer(options As ParseOptions) As Boolean Implements ISyntaxFactsService.SupportsIndexingInitializer
Return False
End Function
Case SyntaxKind.GreaterThanGreaterThanToken, SyntaxKind.GreaterThanGreaterThanEqualsToken
Return PredefinedOperator.RightShift
Public Function SupportsThrowExpression(options As ParseOptions) As Boolean Implements ISyntaxFactsService.SupportsThrowExpression
Return False
End Function
Case Else
Return PredefinedOperator.None
End Select
Public Function IsAwaitKeyword(token As SyntaxToken) As Boolean Implements ISyntaxFactsService.IsAwaitKeyword
Return token.Kind = SyntaxKind.AwaitKeyword
End Function
Public Function GetText(kind As Integer) As String Implements ISyntaxFactsService.GetText
Return SyntaxFacts.GetText(CType(kind, SyntaxKind))
Public Function IsIdentifier(token As SyntaxToken) As Boolean Implements ISyntaxFactsService.IsIdentifier
Return token.Kind = SyntaxKind.IdentifierToken
End Function
Public Function IsIdentifierPartCharacter(c As Char) As Boolean Implements ISyntaxFactsService.IsIdentifierPartCharacter
Return SyntaxFacts.IsIdentifierPartCharacter(c)
Public Function IsGlobalNamespaceKeyword(token As SyntaxToken) As Boolean Implements ISyntaxFactsService.IsGlobalNamespaceKeyword
Return token.Kind = SyntaxKind.GlobalKeyword
End Function
Public Function IsIdentifierStartCharacter(c As Char) As Boolean Implements ISyntaxFactsService.IsIdentifierStartCharacter
Return SyntaxFacts.IsIdentifierStartCharacter(c)
Public Function IsVerbatimIdentifier(token As SyntaxToken) As Boolean Implements ISyntaxFactsService.IsVerbatimIdentifier
Return False
End Function
Public Function IsIdentifierEscapeCharacter(c As Char) As Boolean Implements ISyntaxFactsService.IsIdentifierEscapeCharacter
Return c = "["c OrElse c = "]"c
Public Function IsOperator(token As SyntaxToken) As Boolean Implements ISyntaxFactsService.IsOperator
Return (IsUnaryExpressionOperatorToken(CType(token.Kind, SyntaxKind)) AndAlso (TypeOf token.Parent Is UnaryExpressionSyntax OrElse TypeOf token.Parent Is OperatorStatementSyntax)) OrElse
(IsBinaryExpressionOperatorToken(CType(token.Kind, SyntaxKind)) AndAlso (TypeOf token.Parent Is BinaryExpressionSyntax OrElse TypeOf token.Parent Is OperatorStatementSyntax))
End Function
Public Function IsValidIdentifier(identifier As String) As Boolean Implements ISyntaxFactsService.IsValidIdentifier
Dim token = SyntaxFactory.ParseToken(identifier)
' TODO: There is no way to get the diagnostics to see if any are actually errors?
Return IsIdentifier(token) AndAlso Not token.ContainsDiagnostics AndAlso token.ToString().Length = identifier.Length
Public Function IsContextualKeyword(token As SyntaxToken) As Boolean Implements ISyntaxFactsService.IsContextualKeyword
Return token.IsContextualKeyword()
End Function
Public Function IsVerbatimIdentifier(identifier As String) As Boolean Implements ISyntaxFactsService.IsVerbatimIdentifier
Return IsValidIdentifier(identifier) AndAlso MakeHalfWidthIdentifier(identifier.First()) = "[" AndAlso MakeHalfWidthIdentifier(identifier.Last()) = "]"
Public Function IsKeyword(token As SyntaxToken) As Boolean Implements ISyntaxFactsService.IsKeyword
Return token.IsKeyword()
End Function
Public Function IsTypeCharacter(c As Char) As Boolean Implements ISyntaxFactsService.IsTypeCharacter
Return c = "%"c OrElse
c = "&"c OrElse
c = "@"c OrElse
c = "!"c OrElse
c = "#"c OrElse
c = "$"c
Public Function IsPreprocessorKeyword(token As SyntaxToken) As Boolean Implements ISyntaxFactsService.IsPreprocessorKeyword
Return token.IsPreprocessorKeyword()
End Function
Public Function IsStartOfUnicodeEscapeSequence(c As Char) As Boolean Implements ISyntaxFactsService.IsStartOfUnicodeEscapeSequence
Return False ' VB does not support identifiers with escaped unicode characters
Public Function IsHashToken(token As SyntaxToken) As Boolean Implements ISyntaxFactsService.IsHashToken
Return token.Kind = SyntaxKind.HashToken
End Function
Public Function IsLiteral(token As SyntaxToken) As Boolean Implements ISyntaxFactsService.IsLiteral
Select Case token.Kind()
Case _
SyntaxKind.IntegerLiteralToken,
SyntaxKind.CharacterLiteralToken,
SyntaxKind.DecimalLiteralToken,
SyntaxKind.FloatingLiteralToken,
SyntaxKind.DateLiteralToken,
SyntaxKind.StringLiteralToken,
SyntaxKind.DollarSignDoubleQuoteToken,
SyntaxKind.DoubleQuoteToken,
SyntaxKind.InterpolatedStringTextToken,
SyntaxKind.TrueKeyword,
SyntaxKind.FalseKeyword,
SyntaxKind.NothingKeyword
Return True
End Select
Public Function TryGetCorrespondingOpenBrace(token As SyntaxToken, ByRef openBrace As SyntaxToken) As Boolean Implements ISyntaxFactsService.TryGetCorrespondingOpenBrace
If token.Kind = SyntaxKind.CloseBraceToken Then
Dim tuples = token.Parent.GetBraces()
openBrace = tuples.Item1
Return openBrace.Kind = SyntaxKind.OpenBraceToken
End If
Return False
End Function
Public Function IsStringLiteralOrInterpolatedStringLiteral(token As SyntaxToken) As Boolean Implements ISyntaxFactsService.IsStringLiteralOrInterpolatedStringLiteral
Return token.IsKind(SyntaxKind.StringLiteralToken, SyntaxKind.InterpolatedStringTextToken)
End Function
Public Function IsInInactiveRegion(syntaxTree As SyntaxTree, position As Integer, cancellationToken As CancellationToken) As Boolean Implements ISyntaxFactsService.IsInInactiveRegion
Dim vbTree = TryCast(syntaxTree, SyntaxTree)
If vbTree Is Nothing Then
Return False
End If
Public Function IsNumericLiteralExpression(node As SyntaxNode) As Boolean Implements ISyntaxFactsService.IsNumericLiteralExpression
Return If(node Is Nothing, False, node.IsKind(SyntaxKind.NumericLiteralExpression))
Return vbTree.IsInInactiveRegion(position, cancellationToken)
End Function
Public Function IsBindableToken(token As Microsoft.CodeAnalysis.SyntaxToken) As Boolean Implements ISyntaxFactsService.IsBindableToken
Return Me.IsWord(token) OrElse
Me.IsLiteral(token) OrElse
Me.IsOperator(token)
End Function
Public Function IsInNonUserCode(syntaxTree As SyntaxTree, position As Integer, cancellationToken As CancellationToken) As Boolean Implements ISyntaxFactsService.IsInNonUserCode
Dim vbTree = TryCast(syntaxTree, SyntaxTree)
If vbTree Is Nothing Then
Return False
End If
Public Function IsSimpleMemberAccessExpression(node As SyntaxNode) As Boolean Implements ISyntaxFactsService.IsSimpleMemberAccessExpression
Return TypeOf node Is MemberAccessExpressionSyntax AndAlso
DirectCast(node, MemberAccessExpressionSyntax).Kind = SyntaxKind.SimpleMemberAccessExpression
End Function
Public Function IsPointerMemberAccessExpression(node As SyntaxNode) As Boolean Implements ISyntaxFactsService.IsPointerMemberAccessExpression
Return False
Return vbTree.IsInNonUserCode(position, cancellationToken)
End Function
Public Sub GetNameAndArityOfSimpleName(node As SyntaxNode, ByRef name As String, ByRef arity As Integer) Implements ISyntaxFactsService.GetNameAndArityOfSimpleName
Dim simpleName = TryCast(node, SimpleNameSyntax)
If simpleName IsNot Nothing Then
name = simpleName.Identifier.ValueText
arity = simpleName.Arity
Public Function IsEntirelyWithinStringOrCharOrNumericLiteral(syntaxTree As SyntaxTree, position As Integer, cancellationToken As CancellationToken) As Boolean Implements ISyntaxFactsService.IsEntirelyWithinStringOrCharOrNumericLiteral
Dim vbTree = TryCast(syntaxTree, SyntaxTree)
If vbTree Is Nothing Then
Return False
End If
End Sub
Public Function GetExpressionOfMemberAccessExpression(node As SyntaxNode, Optional allowImplicitTarget As Boolean = False) As SyntaxNode Implements ISyntaxFactsService.GetExpressionOfMemberAccessExpression
Return TryCast(node, MemberAccessExpressionSyntax)?.GetExpressionOfMemberAccessExpression(allowImplicitTarget)
Return vbTree.IsEntirelyWithinStringOrCharOrNumericLiteral(position, cancellationToken)
End Function
Public Function GetTargetOfMemberBinding(node As SyntaxNode) As SyntaxNode Implements ISyntaxFactsService.GetTargetOfMemberBinding
' Member bindings are a C# concept.
Return Nothing
Public Function IsDirective(node As SyntaxNode) As Boolean Implements ISyntaxFactsService.IsDirective
Return TypeOf node Is DirectiveTriviaSyntax
End Function
Public Function GetExpressionOfConditionalAccessExpression(node As SyntaxNode) As SyntaxNode Implements ISyntaxFactsService.GetExpressionOfConditionalAccessExpression
Return TryCast(node, ConditionalAccessExpressionSyntax)?.Expression
End Function
Public Function TryGetExternalSourceInfo(node As SyntaxNode, ByRef info As ExternalSourceInfo) As Boolean Implements ISyntaxFactsService.TryGetExternalSourceInfo
Select Case node.Kind
Case SyntaxKind.ExternalSourceDirectiveTrivia
info = New ExternalSourceInfo(CInt(DirectCast(node, ExternalSourceDirectiveTriviaSyntax).LineStart.Value), False)
Return True
Public Function GetExpressionOfElementAccessExpression(node As SyntaxNode) As SyntaxNode Implements ISyntaxFactsService.GetExpressionOfElementAccessExpression
Return TryCast(node, InvocationExpressionSyntax)?.Expression
End Function
Case SyntaxKind.EndExternalSourceDirectiveTrivia
info = New ExternalSourceInfo(Nothing, True)
Return True
End Select
Public Function GetArgumentListOfElementAccessExpression(node As SyntaxNode) As SyntaxNode Implements ISyntaxFactsService.GetArgumentListOfElementAccessExpression
Return TryCast(node, InvocationExpressionSyntax)?.ArgumentList
Return False
End Function
Public Function GetExpressionOfInterpolation(node As SyntaxNode) As SyntaxNode Implements ISyntaxFactsService.GetExpressionOfInterpolation
Return TryCast(node, InterpolationSyntax)?.Expression
Public Function IsObjectCreationExpressionType(node As SyntaxNode) As Boolean Implements ISyntaxFactsService.IsObjectCreationExpressionType
Return node.IsParentKind(SyntaxKind.ObjectCreationExpression) AndAlso
DirectCast(node.Parent, ObjectCreationExpressionSyntax).Type Is node
End Function
Public Function IsInNamespaceOrTypeContext(node As SyntaxNode) As Boolean Implements ISyntaxFactsService.IsInNamespaceOrTypeContext
Return SyntaxFacts.IsInNamespaceOrTypeContext(node)
Public Function IsAttributeName(node As SyntaxNode) As Boolean Implements ISyntaxFactsService.IsAttributeName
Return node.IsParentKind(SyntaxKind.Attribute) AndAlso
DirectCast(node.Parent, AttributeSyntax).Name Is node
End Function
Public Function IsInStaticContext(node As Microsoft.CodeAnalysis.SyntaxNode) As Boolean Implements ISyntaxFactsService.IsInStaticContext
Return node.IsInStaticContext()
Public Function IsRightSideOfQualifiedName(node As SyntaxNode) As Boolean Implements ISyntaxFactsService.IsRightSideOfQualifiedName
Dim vbNode = TryCast(node, SimpleNameSyntax)
Return vbNode IsNot Nothing AndAlso vbNode.IsRightSideOfQualifiedName()
End Function
Public Function GetExpressionOfArgument(node As Microsoft.CodeAnalysis.SyntaxNode) As Microsoft.CodeAnalysis.SyntaxNode Implements ISyntaxFactsService.GetExpressionOfArgument
Return TryCast(node, ArgumentSyntax).GetArgumentExpression()
Public Function IsNameOfMemberAccessExpression(node As SyntaxNode) As Boolean Implements ISyntaxFactsService.IsNameOfMemberAccessExpression
Dim vbNode = TryCast(node, SimpleNameSyntax)
Return vbNode IsNot Nothing AndAlso vbNode.IsMemberAccessExpressionName()
End Function
Public Function GetRefKindOfArgument(node As Microsoft.CodeAnalysis.SyntaxNode) As Microsoft.CodeAnalysis.RefKind Implements ISyntaxFactsService.GetRefKindOfArgument
' TODO(cyrusn): Consider the method this argument is passed to, to determine this.
Return RefKind.None
Public Function IsConditionalMemberAccessExpression(node As SyntaxNode) As Boolean Implements ISyntaxFactsService.IsConditionalMemberAccessExpression
Return TypeOf node Is ConditionalAccessExpressionSyntax
End Function
Public Function IsSimpleArgument(node As SyntaxNode) As Boolean Implements ISyntaxFactsService.IsSimpleArgument
Dim argument = DirectCast(node, ArgumentSyntax)
Return Not argument.IsNamed AndAlso Not argument.IsOmitted
Public Function IsInvocationExpression(node As SyntaxNode) As Boolean Implements ISyntaxFactsService.IsInvocationExpression
Return TypeOf node Is InvocationExpressionSyntax
End Function
Public Function IsInConstantContext(node As Microsoft.CodeAnalysis.SyntaxNode) As Boolean Implements ISyntaxFactsService.IsInConstantContext
Return node.IsInConstantContext()
Public Function IsAnonymousFunction(node As SyntaxNode) As Boolean Implements ISyntaxFactsService.IsAnonymousFunction
Return TypeOf node Is LambdaExpressionSyntax
End Function
Public Function IsInConstructor(node As Microsoft.CodeAnalysis.SyntaxNode) As Boolean Implements ISyntaxFactsService.IsInConstructor
Return node.GetAncestors(Of StatementSyntax).Any(Function(s) s.Kind = SyntaxKind.ConstructorBlock)
Public Function IsGenericName(node As SyntaxNode) As Boolean Implements ISyntaxFactsService.IsGenericName
Return TypeOf node Is GenericNameSyntax
End Function
Public Function IsUnsafeContext(node As Microsoft.CodeAnalysis.SyntaxNode) As Boolean Implements ISyntaxFactsService.IsUnsafeContext
Return False
Public Function IsNamedParameter(node As SyntaxNode) As Boolean Implements ISyntaxFactsService.IsNamedParameter
Return node.CheckParent(Of SimpleArgumentSyntax)(Function(p) p.IsNamed AndAlso p.NameColonEquals.Name Is node)
End Function
Public Function GetNameOfAttribute(node As Microsoft.CodeAnalysis.SyntaxNode) As Microsoft.CodeAnalysis.SyntaxNode Implements ISyntaxFactsService.GetNameOfAttribute
Return DirectCast(node, AttributeSyntax).Name
Public Function GetDefaultOfParameter(node As SyntaxNode) As SyntaxNode Implements ISyntaxFactsService.GetDefaultOfParameter
Return TryCast(node, ParameterSyntax)?.Default
End Function
Public Function IsAttribute(node As Microsoft.CodeAnalysis.SyntaxNode) As Boolean Implements ISyntaxFactsService.IsAttribute
Return TypeOf node Is AttributeSyntax
Public Function IsSkippedTokensTrivia(node As SyntaxNode) As Boolean Implements ISyntaxFactsService.IsSkippedTokensTrivia
Return TypeOf node Is SkippedTokensTriviaSyntax
End Function
Public Function IsAttributeNamedArgumentIdentifier(node As SyntaxNode) As Boolean Implements ISyntaxFactsService.IsAttributeNamedArgumentIdentifier
Dim identifierName = TryCast(node, IdentifierNameSyntax)
Return identifierName.IsParentKind(SyntaxKind.NameColonEquals) AndAlso
identifierName.Parent.IsParentKind(SyntaxKind.SimpleArgument) AndAlso
identifierName.Parent.Parent.IsParentKind(SyntaxKind.ArgumentList) AndAlso
identifierName.Parent.Parent.Parent.IsParentKind(SyntaxKind.Attribute)
Public Function HasIncompleteParentMember(node As SyntaxNode) As Boolean Implements ISyntaxFactsService.HasIncompleteParentMember
Return node.IsParentKind(SyntaxKind.IncompleteMember)
End Function
Public Function GetContainingTypeDeclaration(root As SyntaxNode, position As Integer) As SyntaxNode Implements ISyntaxFactsService.GetContainingTypeDeclaration
If root Is Nothing Then
Throw New ArgumentNullException(NameOf(root))
End If
If position < 0 OrElse position > root.Span.End Then
Throw New ArgumentOutOfRangeException(NameOf(position))
End If
Return root.
FindToken(position).
GetAncestors(Of SyntaxNode)().
FirstOrDefault(Function(n) TypeOf n Is TypeBlockSyntax OrElse TypeOf n Is DelegateStatementSyntax)
Public Function GetIdentifierOfGenericName(genericName As SyntaxNode) As SyntaxToken Implements ISyntaxFactsService.GetIdentifierOfGenericName
Dim vbGenericName = TryCast(genericName, GenericNameSyntax)
Return If(vbGenericName IsNot Nothing, vbGenericName.Identifier, Nothing)
End Function
Public Function GetContainingVariableDeclaratorOfFieldDeclaration(node As SyntaxNode) As SyntaxNode Implements ISyntaxFactsService.GetContainingVariableDeclaratorOfFieldDeclaration
If node Is Nothing Then
Throw New ArgumentNullException(NameOf(node))
End If
Dim parent = node.Parent
While node IsNot Nothing
If node.Kind = SyntaxKind.VariableDeclarator AndAlso node.IsParentKind(SyntaxKind.FieldDeclaration) Then
Return node
End If
node = node.Parent
End While
Return Nothing
Public Function IsUsingDirectiveName(node As SyntaxNode) As Boolean Implements ISyntaxFactsService.IsUsingDirectiveName
Return node.IsParentKind(SyntaxKind.SimpleImportsClause) AndAlso
DirectCast(node.Parent, SimpleImportsClauseSyntax).Name Is node
End Function
Public Function FindTokenOnLeftOfPosition(node As SyntaxNode,
position As Integer,
Optional includeSkipped As Boolean = True,
Optional includeDirectives As Boolean = False,
Optional includeDocumentationComments As Boolean = False) As SyntaxToken Implements ISyntaxFactsService.FindTokenOnLeftOfPosition
Return node.FindTokenOnLeftOfPosition(position, includeSkipped, includeDirectives, includeDocumentationComments)
Public Function IsForEachStatement(node As SyntaxNode) As Boolean Implements ISyntaxFactsService.IsForEachStatement
Return TypeOf node Is ForEachStatementSyntax
End Function
Public Function FindTokenOnRightOfPosition(node As SyntaxNode,
position As Integer,
Optional includeSkipped As Boolean = True,
Optional includeDirectives As Boolean = False,
Optional includeDocumentationComments As Boolean = False) As SyntaxToken Implements ISyntaxFactsService.FindTokenOnRightOfPosition
Return node.FindTokenOnRightOfPosition(position, includeSkipped, includeDirectives, includeDocumentationComments)
Public Function IsLockStatement(node As SyntaxNode) As Boolean Implements ISyntaxFactsService.IsLockStatement
Return TypeOf node Is SyncLockStatementSyntax
End Function
Public Function IsObjectCreationExpression(node As SyntaxNode) As Boolean Implements ISyntaxFactsService.IsObjectCreationExpression
Return TypeOf node Is ObjectCreationExpressionSyntax
Public Function IsUsingStatement(node As SyntaxNode) As Boolean Implements ISyntaxFactsService.IsUsingStatement
Return node.Kind() = SyntaxKind.UsingStatement
End Function
Public Function IsObjectInitializerNamedAssignmentIdentifier(node As SyntaxNode) As Boolean Implements ISyntaxFactsService.IsObjectInitializerNamedAssignmentIdentifier
Dim unused As SyntaxNode = Nothing
Return IsObjectInitializerNamedAssignmentIdentifier(node, unused)
Public Function IsReturnStatement(node As SyntaxNode) As Boolean Implements ISyntaxFactsService.IsReturnStatement
Return node.Kind() = SyntaxKind.ReturnStatement
End Function
Public Function IsObjectInitializerNamedAssignmentIdentifier(
node As SyntaxNode,
ByRef initializedInstance As SyntaxNode) As Boolean Implements ISyntaxFactsService.IsObjectInitializerNamedAssignmentIdentifier
Public Function GetExpressionOfReturnStatement(node As SyntaxNode) As SyntaxNode Implements ISyntaxFactsService.GetExpressionOfReturnStatement
Return TryCast(node, ReturnStatementSyntax)?.Expression
End Function
Dim identifier = TryCast(node, IdentifierNameSyntax)
If identifier?.IsChildNode(Of NamedFieldInitializerSyntax)(Function(n) n.Name) Then
' .parent is the NamedField.
' .parent.parent is the ObjectInitializer.
' .parent.parent.parent will be the ObjectCreationExpression.
initializedInstance = identifier.Parent.Parent.Parent
Return True
Public Function IsThisConstructorInitializer(token As SyntaxToken) As Boolean Implements ISyntaxFactsService.IsThisConstructorInitializer
If TypeOf token.Parent Is IdentifierNameSyntax AndAlso token.HasMatchingText(SyntaxKind.NewKeyword) Then
Dim memberAccess = TryCast(token.Parent.Parent, MemberAccessExpressionSyntax)
Return memberAccess.IsThisConstructorInitializer()
End If
Return False
End Function
Public Function IsElementAccessExpression(node As SyntaxNode) As Boolean Implements ISyntaxFactsService.IsElementAccessExpression
' VB doesn't have a specialized node for element access. Instead, it just uses an
' invocation expression or dictionary access expression.
Return node.Kind = SyntaxKind.InvocationExpression OrElse node.Kind = SyntaxKind.DictionaryAccessExpression
End Function
Public Function IsBaseConstructorInitializer(token As SyntaxToken) As Boolean Implements ISyntaxFactsService.IsBaseConstructorInitializer
If TypeOf token.Parent Is IdentifierNameSyntax AndAlso token.HasMatchingText(SyntaxKind.NewKeyword) Then
Dim memberAccess = TryCast(token.Parent.Parent, MemberAccessExpressionSyntax)
Return memberAccess.IsBaseConstructorInitializer()
End If
Public Function ToIdentifierToken(name As String) As SyntaxToken Implements ISyntaxFactsService.ToIdentifierToken
Return name.ToIdentifierToken()
Return False
End Function
Public Function Parenthesize(expression As SyntaxNode, Optional includeElasticTrivia As Boolean = True) As SyntaxNode Implements ISyntaxFactsService.Parenthesize
Return DirectCast(expression, ExpressionSyntax).Parenthesize()
Public Function IsQueryExpression(node As SyntaxNode) As Boolean Implements ISyntaxFactsService.IsQueryExpression
Return node.Kind() = SyntaxKind.QueryExpression
End Function
Public Function IsTypeNamedVarInVariableOrFieldDeclaration(token As SyntaxToken, parent As SyntaxNode) As Boolean Implements ISyntaxFactsService.IsTypeNamedVarInVariableOrFieldDeclaration
Public Function IsThrowExpression(node As SyntaxNode) As Boolean Implements ISyntaxFactsService.IsThrowExpression
' VB does not support throw expressions currently.
Return False
End Function
Public Function IsTypeNamedDynamic(token As SyntaxToken, parent As SyntaxNode) As Boolean Implements ISyntaxFactsService.IsTypeNamedDynamic
Return False
Public Function IsPredefinedType(token As SyntaxToken) As Boolean Implements ISyntaxFactsService.IsPredefinedType
Dim actualType As PredefinedType = PredefinedType.None
Return TryGetPredefinedType(token, actualType) AndAlso actualType <> PredefinedType.None
End Function
Public Function IsIndexerMemberCRef(node As SyntaxNode) As Boolean Implements ISyntaxFactsService.IsIndexerMemberCRef
Return False
Public Function IsPredefinedType(token As SyntaxToken, type As PredefinedType) As Boolean Implements ISyntaxFactsService.IsPredefinedType
Dim actualType As PredefinedType = PredefinedType.None
Return TryGetPredefinedType(token, actualType) AndAlso actualType = type
End Function
Public Function GetContainingMemberDeclaration(root As SyntaxNode, position As Integer, Optional useFullSpan As Boolean = True) As SyntaxNode Implements ISyntaxFactsService.GetContainingMemberDeclaration
Contract.ThrowIfNull(root, NameOf(root))
Contract.ThrowIfTrue(position < 0 OrElse position > root.FullSpan.End, NameOf(position))
Dim [end] = root.FullSpan.End
If [end] = 0 Then
' empty file
Return Nothing
End If
' make sure position doesn't touch end of root
position = Math.Min(position, [end] - 1)
Dim node = root.FindToken(position).Parent
While node IsNot Nothing
If useFullSpan OrElse node.Span.Contains(position) Then
If TypeOf node Is MethodBlockBaseSyntax AndAlso Not TypeOf node.Parent Is PropertyBlockSyntax Then
Return node
End If
If TypeOf node Is PropertyStatementSyntax AndAlso Not TypeOf node.Parent Is PropertyBlockSyntax Then
Return node
End If
If TypeOf node Is EventStatementSyntax AndAlso Not TypeOf node.Parent Is EventBlockSyntax Then
Return node
End If
If TypeOf node Is PropertyBlockSyntax OrElse
TypeOf node Is TypeBlockSyntax OrElse
TypeOf node Is EnumBlockSyntax OrElse
TypeOf node Is NamespaceBlockSyntax OrElse
TypeOf node Is EventBlockSyntax OrElse
TypeOf node Is FieldDeclarationSyntax Then
Return node
End If
End If
node = node.Parent
End While
Return Nothing
Public Function TryGetPredefinedType(token As SyntaxToken, ByRef type As PredefinedType) As Boolean Implements ISyntaxFactsService.TryGetPredefinedType
type = GetPredefinedType(token)
Return type <> PredefinedType.None
End Function
Public Function IsMethodLevelMember(node As SyntaxNode) As Boolean Implements ISyntaxFactsService.IsMethodLevelMember
Private Function GetPredefinedType(token As SyntaxToken) As PredefinedType
Select Case token.Kind
Case SyntaxKind.BooleanKeyword
Return PredefinedType.Boolean
Case SyntaxKind.ByteKeyword
Return PredefinedType.Byte
Case SyntaxKind.SByteKeyword
Return PredefinedType.SByte
Case SyntaxKind.IntegerKeyword
Return PredefinedType.Int32
Case SyntaxKind.UIntegerKeyword
Return PredefinedType.UInt32
Case SyntaxKind.ShortKeyword
Return PredefinedType.Int16
Case SyntaxKind.UShortKeyword
Return PredefinedType.UInt16
Case SyntaxKind.LongKeyword
Return PredefinedType.Int64
Case SyntaxKind.ULongKeyword
Return PredefinedType.UInt64
Case SyntaxKind.SingleKeyword
Return PredefinedType.Single
Case SyntaxKind.DoubleKeyword
Return PredefinedType.Double
Case SyntaxKind.DecimalKeyword
Return PredefinedType.Decimal
Case SyntaxKind.StringKeyword
Return PredefinedType.String
Case SyntaxKind.CharKeyword
Return PredefinedType.Char
Case SyntaxKind.ObjectKeyword
Return PredefinedType.Object
Case SyntaxKind.DateKeyword
Return PredefinedType.DateTime
Case Else
Return PredefinedType.None
End Select
End Function
' Note: Derived types of MethodBaseSyntax are expanded explicitly, since PropertyStatementSyntax and
' EventStatementSyntax will NOT be parented by MethodBlockBaseSyntax. Additionally, there are things
' like AccessorStatementSyntax and DelegateStatementSyntax that we never want to tread as method level
' members.
Public Function IsPredefinedOperator(token As SyntaxToken) As Boolean Implements ISyntaxFactsService.IsPredefinedOperator
Dim actualOp As PredefinedOperator = PredefinedOperator.None
Return TryGetPredefinedOperator(token, actualOp) AndAlso actualOp <> PredefinedOperator.None
End Function
If TypeOf node Is MethodStatementSyntax AndAlso Not TypeOf node.Parent Is MethodBlockBaseSyntax Then
Return True
End If
Public Function IsPredefinedOperator(token As SyntaxToken, op As PredefinedOperator) As Boolean Implements ISyntaxFactsService.IsPredefinedOperator
Dim actualOp As PredefinedOperator = PredefinedOperator.None
Return TryGetPredefinedOperator(token, actualOp) AndAlso actualOp = op
End Function
If TypeOf node Is SubNewStatementSyntax AndAlso Not TypeOf node.Parent Is MethodBlockBaseSyntax Then
Return True
End If
Public Function TryGetPredefinedOperator(token As SyntaxToken, ByRef op As PredefinedOperator) As Boolean Implements ISyntaxFactsService.TryGetPredefinedOperator
op = GetPredefinedOperator(token)
Return op <> PredefinedOperator.None
End Function
If TypeOf node Is OperatorStatementSyntax AndAlso Not TypeOf node.Parent Is MethodBlockBaseSyntax Then
Return True
End If
Private Function GetPredefinedOperator(token As SyntaxToken) As PredefinedOperator
Select Case token.Kind
Case SyntaxKind.PlusToken, SyntaxKind.PlusEqualsToken
Return PredefinedOperator.Addition
If TypeOf node Is PropertyStatementSyntax AndAlso Not TypeOf node.Parent Is PropertyBlockSyntax Then
Return True
End If
Case SyntaxKind.MinusToken, SyntaxKind.MinusEqualsToken
Return PredefinedOperator.Subtraction
If TypeOf node Is EventStatementSyntax AndAlso Not TypeOf node.Parent Is EventBlockSyntax Then
Return True
End If
Case SyntaxKind.AndKeyword, SyntaxKind.AndAlsoKeyword
Return PredefinedOperator.BitwiseAnd
If TypeOf node Is DeclareStatementSyntax Then
Return True
End If
Case SyntaxKind.OrKeyword, SyntaxKind.OrElseKeyword
Return PredefinedOperator.BitwiseOr
Return TypeOf node Is ConstructorBlockSyntax OrElse
TypeOf node Is MethodBlockSyntax OrElse
TypeOf node Is OperatorBlockSyntax OrElse
TypeOf node Is EventBlockSyntax OrElse
TypeOf node Is PropertyBlockSyntax OrElse
TypeOf node Is EnumMemberDeclarationSyntax OrElse
TypeOf node Is FieldDeclarationSyntax
End Function
Case SyntaxKind.AmpersandToken, SyntaxKind.AmpersandEqualsToken
Return PredefinedOperator.Concatenate
Public Function GetMemberBodySpanForSpeculativeBinding(node As SyntaxNode) As TextSpan Implements ISyntaxFactsService.GetMemberBodySpanForSpeculativeBinding
Dim member = GetContainingMemberDeclaration(node, node.SpanStart)
If member Is Nothing Then
Return Nothing
End If
Case SyntaxKind.SlashToken, SyntaxKind.SlashEqualsToken
Return PredefinedOperator.Division
' TODO: currently we only support method for now
Dim method = TryCast(member, MethodBlockBaseSyntax)
If method IsNot Nothing Then
If method.BlockStatement Is Nothing OrElse method.EndBlockStatement Is Nothing Then
Return Nothing
End If
Case SyntaxKind.EqualsToken
Return PredefinedOperator.Equality
' We don't want to include the BlockStatement or any trailing trivia up to and including its statement
' terminator in the span. Instead, we use the start of the first statement's leading trivia (if any) up
' to the start of the EndBlockStatement. If there aren't any statements in the block, we use the start
' of the EndBlockStatements leading trivia.
Case SyntaxKind.XorKeyword
Return PredefinedOperator.ExclusiveOr
Dim firstStatement = method.Statements.FirstOrDefault()
Dim spanStart = If(firstStatement IsNot Nothing,
firstStatement.FullSpan.Start,
method.EndBlockStatement.FullSpan.Start)
Case SyntaxKind.CaretToken, SyntaxKind.CaretEqualsToken
Return PredefinedOperator.Exponent
Return TextSpan.FromBounds(spanStart, method.EndBlockStatement.SpanStart)
End If
Case SyntaxKind.GreaterThanToken
Return PredefinedOperator.GreaterThan
Return Nothing
End Function
Case SyntaxKind.GreaterThanEqualsToken
Return PredefinedOperator.GreaterThanOrEqual
Public Function ContainsInMemberBody(node As SyntaxNode, span As TextSpan) As Boolean Implements ISyntaxFactsService.ContainsInMemberBody
Dim method = TryCast(node, MethodBlockBaseSyntax)
If method IsNot Nothing Then
Return method.Statements.Count > 0 AndAlso ContainsExclusively(GetSyntaxListSpan(method.Statements), span)
End If
Case SyntaxKind.LessThanGreaterThanToken
Return PredefinedOperator.Inequality
Dim [event] = TryCast(node, EventBlockSyntax)
If [event] IsNot Nothing Then
Return [event].Accessors.Count > 0 AndAlso ContainsExclusively(GetSyntaxListSpan([event].Accessors), span)
End If
Case SyntaxKind.BackslashToken, SyntaxKind.BackslashEqualsToken
Return PredefinedOperator.IntegerDivision
Dim [property] = TryCast(node, PropertyBlockSyntax)
If [property] IsNot Nothing Then
Return [property].Accessors.Count > 0 AndAlso ContainsExclusively(GetSyntaxListSpan([property].Accessors), span)
End If
Case SyntaxKind.LessThanLessThanToken, SyntaxKind.LessThanLessThanEqualsToken
Return PredefinedOperator.LeftShift
Dim field = TryCast(node, FieldDeclarationSyntax)
If field IsNot Nothing Then
Return field.Declarators.Count > 0 AndAlso ContainsExclusively(GetSeparatedSyntaxListSpan(field.Declarators), span)
End If
Case SyntaxKind.LessThanToken
Return PredefinedOperator.LessThan
Dim [enum] = TryCast(node, EnumMemberDeclarationSyntax)
If [enum] IsNot Nothing Then
Return [enum].Initializer IsNot Nothing AndAlso ContainsExclusively([enum].Initializer.Span, span)
End If
Case SyntaxKind.LessThanEqualsToken
Return PredefinedOperator.LessThanOrEqual
Dim propStatement = TryCast(node, PropertyStatementSyntax)
If propStatement IsNot Nothing Then
Return propStatement.Initializer IsNot Nothing AndAlso ContainsExclusively(propStatement.Initializer.Span, span)
End If
Case SyntaxKind.LikeKeyword
Return PredefinedOperator.Like
Return False
Case SyntaxKind.NotKeyword
Return PredefinedOperator.Complement
Case SyntaxKind.ModKeyword
Return PredefinedOperator.Modulus
Case SyntaxKind.AsteriskToken, SyntaxKind.AsteriskEqualsToken
Return PredefinedOperator.Multiplication
Case SyntaxKind.GreaterThanGreaterThanToken, SyntaxKind.GreaterThanGreaterThanEqualsToken
Return PredefinedOperator.RightShift
Case Else
Return PredefinedOperator.None
End Select
End Function
Private Function ContainsExclusively(outerSpan As TextSpan, innerSpan As TextSpan) As Boolean
If innerSpan.IsEmpty Then
Return outerSpan.Contains(innerSpan.Start)
End If
Public Function GetText(kind As Integer) As String Implements ISyntaxFactsService.GetText
Return SyntaxFacts.GetText(CType(kind, SyntaxKind))
End Function
Return outerSpan.Contains(innerSpan)
Public Function IsIdentifierPartCharacter(c As Char) As Boolean Implements ISyntaxFactsService.IsIdentifierPartCharacter
Return SyntaxFacts.IsIdentifierPartCharacter(c)
End Function
Private Function GetSyntaxListSpan(Of T As SyntaxNode)(list As SyntaxList(Of T)) As TextSpan
Contract.Requires(list.Count > 0)
Return TextSpan.FromBounds(list.First.SpanStart, list.Last.Span.End)
Public Function IsIdentifierStartCharacter(c As Char) As Boolean Implements ISyntaxFactsService.IsIdentifierStartCharacter
Return SyntaxFacts.IsIdentifierStartCharacter(c)
End Function
Private Function GetSeparatedSyntaxListSpan(Of T As SyntaxNode)(list As SeparatedSyntaxList(Of T)) As TextSpan
Contract.Requires(list.Count > 0)
Return TextSpan.FromBounds(list.First.SpanStart, list.Last.Span.End)
Public Function IsIdentifierEscapeCharacter(c As Char) As Boolean Implements ISyntaxFactsService.IsIdentifierEscapeCharacter
Return c = "["c OrElse c = "]"c
End Function
Public Function GetMethodLevelMembers(root As SyntaxNode) As List(Of SyntaxNode) Implements ISyntaxFactsService.GetMethodLevelMembers
Dim list = New List(Of SyntaxNode)()
AppendMethodLevelMembers(root, list)
Return list
Public Function IsValidIdentifier(identifier As String) As Boolean Implements ISyntaxFactsService.IsValidIdentifier
Dim token = SyntaxFactory.ParseToken(identifier)
' TODO: There is no way to get the diagnostics to see if any are actually errors?
Return IsIdentifier(token) AndAlso Not token.ContainsDiagnostics AndAlso token.ToString().Length = identifier.Length
End Function
Public Function IsTopLevelNodeWithMembers(node As SyntaxNode) As Boolean Implements ISyntaxFactsService.IsTopLevelNodeWithMembers
Return TypeOf node Is NamespaceBlockSyntax OrElse
TypeOf node Is TypeBlockSyntax OrElse
TypeOf node Is EnumBlockSyntax
Public Function IsVerbatimIdentifier(identifier As String) As Boolean Implements ISyntaxFactsService.IsVerbatimIdentifier
Return IsValidIdentifier(identifier) AndAlso MakeHalfWidthIdentifier(identifier.First()) = "[" AndAlso MakeHalfWidthIdentifier(identifier.Last()) = "]"
End Function
Public Function TryGetDeclaredSymbolInfo(project As Project, node As SyntaxNode, ByRef declaredSymbolInfo As DeclaredSymbolInfo) As Boolean Implements ISyntaxFactsService.TryGetDeclaredSymbolInfo
Select Case node.Kind()
Case SyntaxKind.ClassBlock
Dim classDecl = CType(node, ClassBlockSyntax)
declaredSymbolInfo = New DeclaredSymbolInfo(
project,
classDecl.ClassStatement.Identifier.ValueText,
GetTypeParameterSuffix(classDecl.ClassStatement.TypeParameterList),
GetContainerDisplayName(node.Parent),
GetFullyQualifiedContainerName(node.Parent),
DeclaredSymbolInfoKind.Class,
GetAccessibility(classDecl, classDecl.ClassStatement.Modifiers),
classDecl.ClassStatement.Identifier.Span,
GetInheritanceNames(project, classDecl))
Return True
Case SyntaxKind.ConstructorBlock
Dim constructor = CType(node, ConstructorBlockSyntax)
Dim typeBlock = TryCast(constructor.Parent, TypeBlockSyntax)
If typeBlock IsNot Nothing Then
declaredSymbolInfo = New DeclaredSymbolInfo(
project,
typeBlock.BlockStatement.Identifier.ValueText,
GetConstructorSuffix(constructor),
GetContainerDisplayName(node.Parent),
GetFullyQualifiedContainerName(node.Parent),
DeclaredSymbolInfoKind.Constructor,
GetAccessibility(constructor, constructor.SubNewStatement.Modifiers),
constructor.SubNewStatement.NewKeyword.Span,
ImmutableArray(Of String).Empty,
parameterCount:=If(constructor.SubNewStatement.ParameterList?.Parameters.Count, 0))
Public Function IsTypeCharacter(c As Char) As Boolean Implements ISyntaxFactsService.IsTypeCharacter
Return c = "%"c OrElse
c = "&"c OrElse
c = "@"c OrElse
c = "!"c OrElse
c = "#"c OrElse
c = "$"c
End Function
Return True
End If
Case SyntaxKind.DelegateFunctionStatement, SyntaxKind.DelegateSubStatement
Dim delegateDecl = CType(node, DelegateStatementSyntax)
declaredSymbolInfo = New DeclaredSymbolInfo(
project,
delegateDecl.Identifier.ValueText,
GetTypeParameterSuffix(delegateDecl.TypeParameterList),
GetContainerDisplayName(node.Parent),
GetFullyQualifiedContainerName(node.Parent),
DeclaredSymbolInfoKind.Delegate,
GetAccessibility(delegateDecl, delegateDecl.Modifiers),
delegateDecl.Identifier.Span,
ImmutableArray(Of String).Empty)
Return True
Case SyntaxKind.EnumBlock
Dim enumDecl = CType(node, EnumBlockSyntax)
declaredSymbolInfo = New DeclaredSymbolInfo(
project,
enumDecl.EnumStatement.Identifier.ValueText, Nothing,
GetContainerDisplayName(node.Parent),
GetFullyQualifiedContainerName(node.Parent),
DeclaredSymbolInfoKind.Enum,
GetAccessibility(enumDecl, enumDecl.EnumStatement.Modifiers),
enumDecl.EnumStatement.Identifier.Span,
ImmutableArray(Of String).Empty)
Return True
Case SyntaxKind.EnumMemberDeclaration
Dim enumMember = CType(node, EnumMemberDeclarationSyntax)
declaredSymbolInfo = New DeclaredSymbolInfo(
project,
enumMember.Identifier.ValueText, Nothing,
GetContainerDisplayName(node.Parent),
GetFullyQualifiedContainerName(node.Parent),
DeclaredSymbolInfoKind.EnumMember,
Accessibility.Public,
enumMember.Identifier.Span,
ImmutableArray(Of String).Empty)
Return True
Case SyntaxKind.EventStatement
Dim eventDecl = CType(node, EventStatementSyntax)
Dim statementOrBlock = If(TypeOf node.Parent Is EventBlockSyntax, node.Parent, node)
Dim eventParent = statementOrBlock.Parent
declaredSymbolInfo = New DeclaredSymbolInfo(
project,
eventDecl.Identifier.ValueText, Nothing,
GetContainerDisplayName(eventParent),
GetFullyQualifiedContainerName(eventParent),
DeclaredSymbolInfoKind.Event,
GetAccessibility(statementOrBlock, eventDecl.Modifiers),
eventDecl.Identifier.Span,
ImmutableArray(Of String).Empty)
Return True
Case SyntaxKind.FunctionBlock, SyntaxKind.SubBlock
Dim funcDecl = CType(node, MethodBlockSyntax)
declaredSymbolInfo = New DeclaredSymbolInfo(
project,
funcDecl.SubOrFunctionStatement.Identifier.ValueText,
GetMethodSuffix(funcDecl),
GetContainerDisplayName(node.Parent),
GetFullyQualifiedContainerName(node.Parent),
DeclaredSymbolInfoKind.Method,
GetAccessibility(node, funcDecl.SubOrFunctionStatement.Modifiers),
funcDecl.SubOrFunctionStatement.Identifier.Span,
ImmutableArray(Of String).Empty,
parameterCount:=If(funcDecl.SubOrFunctionStatement.ParameterList?.Parameters.Count, 0),
typeParameterCount:=If(funcDecl.SubOrFunctionStatement.TypeParameterList?.Parameters.Count, 0))
Return True
Case SyntaxKind.InterfaceBlock
Dim interfaceDecl = CType(node, InterfaceBlockSyntax)
declaredSymbolInfo = New DeclaredSymbolInfo(
project,
interfaceDecl.InterfaceStatement.Identifier.ValueText,
GetTypeParameterSuffix(interfaceDecl.InterfaceStatement.TypeParameterList),
GetContainerDisplayName(node.Parent),
GetFullyQualifiedContainerName(node.Parent),
DeclaredSymbolInfoKind.Interface,
GetAccessibility(interfaceDecl, interfaceDecl.InterfaceStatement.Modifiers),
interfaceDecl.InterfaceStatement.Identifier.Span,
GetInheritanceNames(project, interfaceDecl))
Return True
Case SyntaxKind.ModifiedIdentifier
Dim modifiedIdentifier = CType(node, ModifiedIdentifierSyntax)
Dim variableDeclarator = TryCast(modifiedIdentifier.Parent, VariableDeclaratorSyntax)
Dim fieldDecl = TryCast(variableDeclarator?.Parent, FieldDeclarationSyntax)
If fieldDecl IsNot Nothing Then
Dim kind = If(fieldDecl.Modifiers.Any(Function(m) m.Kind() = SyntaxKind.ConstKeyword),
DeclaredSymbolInfoKind.Constant,
DeclaredSymbolInfoKind.Field)
declaredSymbolInfo = New DeclaredSymbolInfo(
project,
modifiedIdentifier.Identifier.ValueText, Nothing,
GetContainerDisplayName(fieldDecl.Parent),
GetFullyQualifiedContainerName(fieldDecl.Parent),
kind, GetAccessibility(fieldDecl, fieldDecl.Modifiers),
modifiedIdentifier.Identifier.Span,
ImmutableArray(Of String).Empty)
Return True
End If
Case SyntaxKind.ModuleBlock
Dim moduleDecl = CType(node, ModuleBlockSyntax)
declaredSymbolInfo = New DeclaredSymbolInfo(
project,
moduleDecl.ModuleStatement.Identifier.ValueText,
GetTypeParameterSuffix(moduleDecl.ModuleStatement.TypeParameterList),
GetContainerDisplayName(node.Parent),
GetFullyQualifiedContainerName(node.Parent),
DeclaredSymbolInfoKind.Module,
GetAccessibility(moduleDecl, moduleDecl.ModuleStatement.Modifiers),
moduleDecl.ModuleStatement.Identifier.Span,
GetInheritanceNames(project, moduleDecl))
Return True
Case SyntaxKind.PropertyStatement
Dim propertyDecl = CType(node, PropertyStatementSyntax)
Dim statementOrBlock = If(TypeOf node.Parent Is PropertyBlockSyntax, node.Parent, node)
Dim propertyParent = statementOrBlock.Parent
declaredSymbolInfo = New DeclaredSymbolInfo(
project,
propertyDecl.Identifier.ValueText, GetPropertySuffix(propertyDecl),
GetContainerDisplayName(propertyParent),
GetFullyQualifiedContainerName(propertyParent),
DeclaredSymbolInfoKind.Property,
GetAccessibility(statementOrBlock, propertyDecl.Modifiers),
propertyDecl.Identifier.Span,
ImmutableArray(Of String).Empty)
Return True
Case SyntaxKind.StructureBlock
Dim structDecl = CType(node, StructureBlockSyntax)
declaredSymbolInfo = New DeclaredSymbolInfo(
project,
structDecl.StructureStatement.Identifier.ValueText,
GetTypeParameterSuffix(structDecl.StructureStatement.TypeParameterList),
GetContainerDisplayName(node.Parent),
GetFullyQualifiedContainerName(node.Parent),
DeclaredSymbolInfoKind.Struct,
GetAccessibility(structDecl, structDecl.StructureStatement.Modifiers),
structDecl.StructureStatement.Identifier.Span,
GetInheritanceNames(project, structDecl))
Public Function IsStartOfUnicodeEscapeSequence(c As Char) As Boolean Implements ISyntaxFactsService.IsStartOfUnicodeEscapeSequence
Return False ' VB does not support identifiers with escaped unicode characters
End Function
Public Function IsLiteral(token As SyntaxToken) As Boolean Implements ISyntaxFactsService.IsLiteral
Select Case token.Kind()
Case _
SyntaxKind.IntegerLiteralToken,
SyntaxKind.CharacterLiteralToken,
SyntaxKind.DecimalLiteralToken,
SyntaxKind.FloatingLiteralToken,
SyntaxKind.DateLiteralToken,
SyntaxKind.StringLiteralToken,
SyntaxKind.DollarSignDoubleQuoteToken,
SyntaxKind.DoubleQuoteToken,
SyntaxKind.InterpolatedStringTextToken,
SyntaxKind.TrueKeyword,
SyntaxKind.FalseKeyword,
SyntaxKind.NothingKeyword
Return True
End Select
declaredSymbolInfo = Nothing
Return False
End Function
Private Function GetMethodSuffix(method As MethodBlockSyntax) As String
Return GetTypeParameterSuffix(method.SubOrFunctionStatement.TypeParameterList) &
GetSuffix(method.SubOrFunctionStatement.ParameterList)
Public Function IsStringLiteralOrInterpolatedStringLiteral(token As SyntaxToken) As Boolean Implements ISyntaxFactsService.IsStringLiteralOrInterpolatedStringLiteral
Return token.IsKind(SyntaxKind.StringLiteralToken, SyntaxKind.InterpolatedStringTextToken)
End Function
Private Function GetConstructorSuffix(method As ConstructorBlockSyntax) As String
Return ".New" & GetSuffix(method.SubNewStatement.ParameterList)
Public Function IsNumericLiteralExpression(node As SyntaxNode) As Boolean Implements ISyntaxFactsService.IsNumericLiteralExpression
Return If(node Is Nothing, False, node.IsKind(SyntaxKind.NumericLiteralExpression))
End Function
Private Function GetPropertySuffix([property] As PropertyStatementSyntax) As String
If [property].ParameterList Is Nothing Then
Return Nothing
Public Function IsBindableToken(token As Microsoft.CodeAnalysis.SyntaxToken) As Boolean Implements ISyntaxFactsService.IsBindableToken
Return Me.IsWord(token) OrElse
Me.IsLiteral(token) OrElse
Me.IsOperator(token)
End Function
Public Function IsSimpleMemberAccessExpression(node As SyntaxNode) As Boolean Implements ISyntaxFactsService.IsSimpleMemberAccessExpression
Return TypeOf node Is MemberAccessExpressionSyntax AndAlso
DirectCast(node, MemberAccessExpressionSyntax).Kind = SyntaxKind.SimpleMemberAccessExpression
End Function
Public Function IsPointerMemberAccessExpression(node As SyntaxNode) As Boolean Implements ISyntaxFactsService.IsPointerMemberAccessExpression
Return False
End Function
Public Sub GetNameAndArityOfSimpleName(node As SyntaxNode, ByRef name As String, ByRef arity As Integer) Implements ISyntaxFactsService.GetNameAndArityOfSimpleName
Dim simpleName = TryCast(node, SimpleNameSyntax)
If simpleName IsNot Nothing Then
name = simpleName.Identifier.ValueText
arity = simpleName.Arity
End If
End Sub
Return GetSuffix([property].ParameterList)
Public Function GetExpressionOfMemberAccessExpression(node As SyntaxNode, Optional allowImplicitTarget As Boolean = False) As SyntaxNode Implements ISyntaxFactsService.GetExpressionOfMemberAccessExpression
Return TryCast(node, MemberAccessExpressionSyntax)?.GetExpressionOfMemberAccessExpression(allowImplicitTarget)
End Function
Private Function GetTypeParameterSuffix(typeParameterList As TypeParameterListSyntax) As String
If typeParameterList Is Nothing Then
Return Nothing
Public Function GetTargetOfMemberBinding(node As SyntaxNode) As SyntaxNode Implements ISyntaxFactsService.GetTargetOfMemberBinding
' Member bindings are a C# concept.
Return Nothing
End Function
Public Function GetExpressionOfConditionalAccessExpression(node As SyntaxNode) As SyntaxNode Implements ISyntaxFactsService.GetExpressionOfConditionalAccessExpression
Return TryCast(node, ConditionalAccessExpressionSyntax)?.Expression
End Function
Public Function GetExpressionOfElementAccessExpression(node As SyntaxNode) As SyntaxNode Implements ISyntaxFactsService.GetExpressionOfElementAccessExpression
Return TryCast(node, InvocationExpressionSyntax)?.Expression
End Function
Public Function GetArgumentListOfElementAccessExpression(node As SyntaxNode) As SyntaxNode Implements ISyntaxFactsService.GetArgumentListOfElementAccessExpression
Return TryCast(node, InvocationExpressionSyntax)?.ArgumentList
End Function
Public Function GetExpressionOfInterpolation(node As SyntaxNode) As SyntaxNode Implements ISyntaxFactsService.GetExpressionOfInterpolation
Return TryCast(node, InterpolationSyntax)?.Expression
End Function
Public Function IsInNamespaceOrTypeContext(node As SyntaxNode) As Boolean Implements ISyntaxFactsService.IsInNamespaceOrTypeContext
Return SyntaxFacts.IsInNamespaceOrTypeContext(node)
End Function
Public Function IsInStaticContext(node As Microsoft.CodeAnalysis.SyntaxNode) As Boolean Implements ISyntaxFactsService.IsInStaticContext
Return node.IsInStaticContext()
End Function
Public Function GetExpressionOfArgument(node As Microsoft.CodeAnalysis.SyntaxNode) As Microsoft.CodeAnalysis.SyntaxNode Implements ISyntaxFactsService.GetExpressionOfArgument
Return TryCast(node, ArgumentSyntax).GetArgumentExpression()
End Function
Public Function GetRefKindOfArgument(node As Microsoft.CodeAnalysis.SyntaxNode) As Microsoft.CodeAnalysis.RefKind Implements ISyntaxFactsService.GetRefKindOfArgument
' TODO(cyrusn): Consider the method this argument is passed to, to determine this.
Return RefKind.None
End Function
Public Function IsSimpleArgument(node As SyntaxNode) As Boolean Implements ISyntaxFactsService.IsSimpleArgument
Dim argument = DirectCast(node, ArgumentSyntax)
Return Not argument.IsNamed AndAlso Not argument.IsOmitted
End Function
Public Function IsInConstantContext(node As Microsoft.CodeAnalysis.SyntaxNode) As Boolean Implements ISyntaxFactsService.IsInConstantContext
Return node.IsInConstantContext()
End Function
Public Function IsInConstructor(node As Microsoft.CodeAnalysis.SyntaxNode) As Boolean Implements ISyntaxFactsService.IsInConstructor
Return node.GetAncestors(Of StatementSyntax).Any(Function(s) s.Kind = SyntaxKind.ConstructorBlock)
End Function
Public Function IsUnsafeContext(node As Microsoft.CodeAnalysis.SyntaxNode) As Boolean Implements ISyntaxFactsService.IsUnsafeContext
Return False
End Function
Public Function GetNameOfAttribute(node As Microsoft.CodeAnalysis.SyntaxNode) As Microsoft.CodeAnalysis.SyntaxNode Implements ISyntaxFactsService.GetNameOfAttribute
Return DirectCast(node, AttributeSyntax).Name
End Function
Public Function IsAttribute(node As Microsoft.CodeAnalysis.SyntaxNode) As Boolean Implements ISyntaxFactsService.IsAttribute
Return TypeOf node Is AttributeSyntax
End Function
Public Function IsAttributeNamedArgumentIdentifier(node As SyntaxNode) As Boolean Implements ISyntaxFactsService.IsAttributeNamedArgumentIdentifier
Dim identifierName = TryCast(node, IdentifierNameSyntax)
Return identifierName.IsParentKind(SyntaxKind.NameColonEquals) AndAlso
identifierName.Parent.IsParentKind(SyntaxKind.SimpleArgument) AndAlso
identifierName.Parent.Parent.IsParentKind(SyntaxKind.ArgumentList) AndAlso
identifierName.Parent.Parent.Parent.IsParentKind(SyntaxKind.Attribute)
End Function
Public Function GetContainingTypeDeclaration(root As SyntaxNode, position As Integer) As SyntaxNode Implements ISyntaxFactsService.GetContainingTypeDeclaration
If root Is Nothing Then
Throw New ArgumentNullException(NameOf(root))
End If
Dim pooledBuilder = PooledStringBuilder.GetInstance()
If position < 0 OrElse position > root.Span.End Then
Throw New ArgumentOutOfRangeException(NameOf(position))
End If
Dim builder = pooledBuilder.Builder
builder.Append("(Of ")
Return root.
FindToken(position).
GetAncestors(Of SyntaxNode)().
FirstOrDefault(Function(n) TypeOf n Is TypeBlockSyntax OrElse TypeOf n Is DelegateStatementSyntax)
End Function
Dim First = True
For Each parameter In typeParameterList.Parameters
If Not First Then
builder.Append(", ")
Public Function GetContainingVariableDeclaratorOfFieldDeclaration(node As SyntaxNode) As SyntaxNode Implements ISyntaxFactsService.GetContainingVariableDeclaratorOfFieldDeclaration
If node Is Nothing Then
Throw New ArgumentNullException(NameOf(node))
End If
Dim parent = node.Parent
While node IsNot Nothing
If node.Kind = SyntaxKind.VariableDeclarator AndAlso node.IsParentKind(SyntaxKind.FieldDeclaration) Then
Return node
End If
builder.Append(parameter.Identifier.Text)
First = False
Next
node = node.Parent
End While
builder.Append(")"c)
Return Nothing
End Function
Return pooledBuilder.ToStringAndFree()
Public Function FindTokenOnLeftOfPosition(node As SyntaxNode,
position As Integer,
Optional includeSkipped As Boolean = True,
Optional includeDirectives As Boolean = False,
Optional includeDocumentationComments As Boolean = False) As SyntaxToken Implements ISyntaxFactsService.FindTokenOnLeftOfPosition
Return node.FindTokenOnLeftOfPosition(position, includeSkipped, includeDirectives, includeDocumentationComments)
End Function
Public Function FindTokenOnRightOfPosition(node As SyntaxNode,
position As Integer,
Optional includeSkipped As Boolean = True,
Optional includeDirectives As Boolean = False,
Optional includeDocumentationComments As Boolean = False) As SyntaxToken Implements ISyntaxFactsService.FindTokenOnRightOfPosition
Return node.FindTokenOnRightOfPosition(position, includeSkipped, includeDirectives, includeDocumentationComments)
End Function
Public Function IsObjectCreationExpression(node As SyntaxNode) As Boolean Implements ISyntaxFactsService.IsObjectCreationExpression
Return TypeOf node Is ObjectCreationExpressionSyntax
End Function
''' <summary>
''' Builds up the suffix to show for something with parameters in navigate-to.
''' While it would be nice to just use the compiler SymbolDisplay API for this,
''' it would be too expensive as it requires going back to Symbols (which requires
''' creating compilations, etc.) in a perf sensitive area.
'''
''' So, instead, we just build a reasonable suffix using the pure syntax that a
''' user provided. That means that if they wrote "Method(System.Int32 i)" we'll
''' show that as "Method(System.Int32)" Not "Method(Integer)". Given that this Is
''' actually what the user wrote, And it saves us from ever having to go back to
''' symbols/compilations, this Is well worth it, even if it does mean we have to
''' create our own 'symbol display' logic here.
''' </summary>
Private Function GetSuffix(parameterList As ParameterListSyntax) As String
If parameterList Is Nothing OrElse parameterList.Parameters.Count = 0 Then
Return "()"
Public Function IsObjectInitializerNamedAssignmentIdentifier(node As SyntaxNode) As Boolean Implements ISyntaxFactsService.IsObjectInitializerNamedAssignmentIdentifier
Dim unused As SyntaxNode = Nothing
Return IsObjectInitializerNamedAssignmentIdentifier(node, unused)
End Function
Public Function IsObjectInitializerNamedAssignmentIdentifier(
node As SyntaxNode,
ByRef initializedInstance As SyntaxNode) As Boolean Implements ISyntaxFactsService.IsObjectInitializerNamedAssignmentIdentifier
Dim identifier = TryCast(node, IdentifierNameSyntax)
If identifier?.IsChildNode(Of NamedFieldInitializerSyntax)(Function(n) n.Name) Then
' .parent is the NamedField.
' .parent.parent is the ObjectInitializer.
' .parent.parent.parent will be the ObjectCreationExpression.
initializedInstance = identifier.Parent.Parent.Parent
Return True
End If
Return False
End Function
Public Function IsElementAccessExpression(node As SyntaxNode) As Boolean Implements ISyntaxFactsService.IsElementAccessExpression
' VB doesn't have a specialized node for element access. Instead, it just uses an
' invocation expression or dictionary access expression.
Return node.Kind = SyntaxKind.InvocationExpression OrElse node.Kind = SyntaxKind.DictionaryAccessExpression
End Function
Public Function ToIdentifierToken(name As String) As SyntaxToken Implements ISyntaxFactsService.ToIdentifierToken
Return name.ToIdentifierToken()
End Function
Public Function Parenthesize(expression As SyntaxNode, Optional includeElasticTrivia As Boolean = True) As SyntaxNode Implements ISyntaxFactsService.Parenthesize
Return DirectCast(expression, ExpressionSyntax).Parenthesize()
End Function
Public Function IsTypeNamedVarInVariableOrFieldDeclaration(token As SyntaxToken, parent As SyntaxNode) As Boolean Implements ISyntaxFactsService.IsTypeNamedVarInVariableOrFieldDeclaration
Return False
End Function
Public Function IsTypeNamedDynamic(token As SyntaxToken, parent As SyntaxNode) As Boolean Implements ISyntaxFactsService.IsTypeNamedDynamic
Return False
End Function
Public Function IsIndexerMemberCRef(node As SyntaxNode) As Boolean Implements ISyntaxFactsService.IsIndexerMemberCRef
Return False
End Function
Public Function GetContainingMemberDeclaration(root As SyntaxNode, position As Integer, Optional useFullSpan As Boolean = True) As SyntaxNode Implements ISyntaxFactsService.GetContainingMemberDeclaration
Contract.ThrowIfNull(root, NameOf(root))
Contract.ThrowIfTrue(position < 0 OrElse position > root.FullSpan.End, NameOf(position))
Dim [end] = root.FullSpan.End
If [end] = 0 Then
' empty file
Return Nothing
End If
Dim pooledBuilder = PooledStringBuilder.GetInstance()
' make sure position doesn't touch end of root
position = Math.Min(position, [end] - 1)
Dim builder = pooledBuilder.Builder
builder.Append("("c)
If parameterList IsNot Nothing Then
AppendParameters(parameterList.Parameters, builder)
End If
builder.Append(")"c)
Dim node = root.FindToken(position).Parent
While node IsNot Nothing
If useFullSpan OrElse node.Span.Contains(position) Then
Return pooledBuilder.ToStringAndFree()
End Function
If TypeOf node Is MethodBlockBaseSyntax AndAlso Not TypeOf node.Parent Is PropertyBlockSyntax Then
Return node
End If
Private Sub AppendParameters(parameters As SeparatedSyntaxList(Of ParameterSyntax), builder As StringBuilder)
Dim First = True
For Each parameter In parameters
If Not First Then
builder.Append(", ")
End If
If TypeOf node Is PropertyStatementSyntax AndAlso Not TypeOf node.Parent Is PropertyBlockSyntax Then
Return node
End If
For Each modifier In parameter.Modifiers
If modifier.Kind() <> SyntaxKind.ByValKeyword Then
builder.Append(modifier.Text)
builder.Append(" "c)
If TypeOf node Is EventStatementSyntax AndAlso Not TypeOf node.Parent Is EventBlockSyntax Then
Return node
End If
Next
If parameter.AsClause?.Type IsNot Nothing Then
AppendTokens(parameter.AsClause.Type, builder)
If TypeOf node Is PropertyBlockSyntax OrElse
TypeOf node Is TypeBlockSyntax OrElse
TypeOf node Is EnumBlockSyntax OrElse
TypeOf node Is NamespaceBlockSyntax OrElse
TypeOf node Is EventBlockSyntax OrElse
TypeOf node Is FieldDeclarationSyntax Then
Return node
End If
End If
First = False
Next
End Sub
node = node.Parent
End While
Private Function GetAccessibility(node As SyntaxNode, modifiers As SyntaxTokenList) As Accessibility
Dim sawFriend = False
Return Nothing
End Function
For Each modifier In modifiers
Select Case modifier.Kind()
Case SyntaxKind.PublicKeyword : Return Accessibility.Public
Case SyntaxKind.PrivateKeyword : Return Accessibility.Private
Case SyntaxKind.ProtectedKeyword : Return Accessibility.Protected
Case SyntaxKind.FriendKeyword
sawFriend = True
Continue For
End Select
Next
Public Function IsMethodLevelMember(node As SyntaxNode) As Boolean Implements ISyntaxFactsService.IsMethodLevelMember
If sawFriend Then
Return Accessibility.Internal
' Note: Derived types of MethodBaseSyntax are expanded explicitly, since PropertyStatementSyntax and
' EventStatementSyntax will NOT be parented by MethodBlockBaseSyntax. Additionally, there are things
' like AccessorStatementSyntax and DelegateStatementSyntax that we never want to tread as method level
' members.
If TypeOf node Is MethodStatementSyntax AndAlso Not TypeOf node.Parent Is MethodBlockBaseSyntax Then
Return True
End If
' No accessibility modifiers
Select Case node.Parent.Kind()
Case SyntaxKind.ClassBlock
' In a class, fields and shared-constructors are private by default,
' everything Else Is Public
If node.Kind() = SyntaxKind.FieldDeclaration Then
Return Accessibility.Private
End If
If TypeOf node Is SubNewStatementSyntax AndAlso Not TypeOf node.Parent Is MethodBlockBaseSyntax Then
Return True
End If
If node.Kind() = SyntaxKind.ConstructorBlock AndAlso
DirectCast(node, ConstructorBlockSyntax).SubNewStatement.Modifiers.Any(SyntaxKind.SharedKeyword) Then
Return Accessibility.Private
End If
If TypeOf node Is OperatorStatementSyntax AndAlso Not TypeOf node.Parent Is MethodBlockBaseSyntax Then
Return True
End If
Return Accessibility.Public
If TypeOf node Is PropertyStatementSyntax AndAlso Not TypeOf node.Parent Is PropertyBlockSyntax Then
Return True
End If
Case SyntaxKind.StructureBlock, SyntaxKind.InterfaceBlock, SyntaxKind.ModuleBlock
' Everything in a struct/interface/module is public
Return Accessibility.Public
End Select
If TypeOf node Is EventStatementSyntax AndAlso Not TypeOf node.Parent Is EventBlockSyntax Then
Return True
End If
' Otherwise, it's internal
Return Accessibility.Internal
End Function
If TypeOf node Is DeclareStatementSyntax Then
Return True
End If
Private Function GetInheritanceNames(project As Project, typeBlock As TypeBlockSyntax) As ImmutableArray(Of String)
Dim builder = ArrayBuilder(Of String).GetInstance()
Return TypeOf node Is ConstructorBlockSyntax OrElse
TypeOf node Is MethodBlockSyntax OrElse
TypeOf node Is OperatorBlockSyntax OrElse
TypeOf node Is EventBlockSyntax OrElse
TypeOf node Is PropertyBlockSyntax OrElse
TypeOf node Is EnumMemberDeclarationSyntax OrElse
TypeOf node Is FieldDeclarationSyntax
End Function
Dim aliasMap = GetAliasMap(typeBlock)
Try
For Each inheritsStatement In typeBlock.Inherits
AddInheritanceNames(builder, inheritsStatement.Types, aliasMap)
Next
Public Function GetMemberBodySpanForSpeculativeBinding(node As SyntaxNode) As TextSpan Implements ISyntaxFactsService.GetMemberBodySpanForSpeculativeBinding
Dim member = GetContainingMemberDeclaration(node, node.SpanStart)
If member Is Nothing Then
Return Nothing
End If
For Each implementsStatement In typeBlock.Implements
AddInheritanceNames(builder, implementsStatement.Types, aliasMap)
Next
' TODO: currently we only support method for now
Dim method = TryCast(member, MethodBlockBaseSyntax)
If method IsNot Nothing Then
If method.BlockStatement Is Nothing OrElse method.EndBlockStatement Is Nothing Then
Return Nothing
End If
DeclaredSymbolInfo.Intern(project, builder)
Return builder.ToImmutableAndFree()
Finally
FreeAliasMap(aliasMap)
End Try
End Function
' We don't want to include the BlockStatement or any trailing trivia up to and including its statement
' terminator in the span. Instead, we use the start of the first statement's leading trivia (if any) up
' to the start of the EndBlockStatement. If there aren't any statements in the block, we use the start
' of the EndBlockStatements leading trivia.
Private Function GetAliasMap(typeBlock As TypeBlockSyntax) As Dictionary(Of String, String)
Dim compilationUnit = typeBlock.SyntaxTree.GetCompilationUnitRoot()
Dim firstStatement = method.Statements.FirstOrDefault()
Dim spanStart = If(firstStatement IsNot Nothing,
firstStatement.FullSpan.Start,
method.EndBlockStatement.FullSpan.Start)
Dim aliasMap As Dictionary(Of String, String) = Nothing
For Each import In compilationUnit.Imports
For Each clause In import.ImportsClauses
If clause.IsKind(SyntaxKind.SimpleImportsClause) Then
Dim simpleImport = DirectCast(clause, SimpleImportsClauseSyntax)
If simpleImport.Alias IsNot Nothing Then
Dim mappedName = GetTypeName(simpleImport.Name)
If mappedName IsNot Nothing Then
aliasMap = If(aliasMap, AllocateAliasMap())
aliasMap(simpleImport.Alias.Identifier.ValueText) = mappedName
End If
End If
End If
Next
Next
Return TextSpan.FromBounds(spanStart, method.EndBlockStatement.SpanStart)
End If
Return aliasMap
Return Nothing
End Function
Private Sub AddInheritanceNames(
builder As ArrayBuilder(Of String),
types As SeparatedSyntaxList(Of TypeSyntax),
aliasMap As Dictionary(Of String, String))
Public Function ContainsInMemberBody(node As SyntaxNode, span As TextSpan) As Boolean Implements ISyntaxFactsService.ContainsInMemberBody
Dim method = TryCast(node, MethodBlockBaseSyntax)
If method IsNot Nothing Then
Return method.Statements.Count > 0 AndAlso ContainsExclusively(GetSyntaxListSpan(method.Statements), span)
End If
For Each typeSyntax In types
AddInheritanceName(builder, typeSyntax, aliasMap)
Next
End Sub
Dim [event] = TryCast(node, EventBlockSyntax)
If [event] IsNot Nothing Then
Return [event].Accessors.Count > 0 AndAlso ContainsExclusively(GetSyntaxListSpan([event].Accessors), span)
End If
Private Sub AddInheritanceName(
builder As ArrayBuilder(Of String),
typeSyntax As TypeSyntax,
aliasMap As Dictionary(Of String, String))
Dim name = GetTypeName(typeSyntax)
If name IsNot Nothing Then
builder.Add(name)
Dim [property] = TryCast(node, PropertyBlockSyntax)
If [property] IsNot Nothing Then
Return [property].Accessors.Count > 0 AndAlso ContainsExclusively(GetSyntaxListSpan([property].Accessors), span)
End If
Dim mappedName As String = Nothing
If aliasMap?.TryGetValue(name, mappedName) = True Then
' Looks Like this could be an alias. Also include the name the alias points to
builder.Add(mappedName)
End If
Dim field = TryCast(node, FieldDeclarationSyntax)
If field IsNot Nothing Then
Return field.Declarators.Count > 0 AndAlso ContainsExclusively(GetSeparatedSyntaxListSpan(field.Declarators), span)
End If
End Sub
Private Function GetTypeName(typeSyntax As TypeSyntax) As String
If TypeOf typeSyntax Is SimpleNameSyntax Then
Return GetSimpleName(DirectCast(typeSyntax, SimpleNameSyntax))
ElseIf TypeOf typeSyntax Is QualifiedNameSyntax Then
Return GetSimpleName(DirectCast(typeSyntax, QualifiedNameSyntax).Right)
Dim [enum] = TryCast(node, EnumMemberDeclarationSyntax)
If [enum] IsNot Nothing Then
Return [enum].Initializer IsNot Nothing AndAlso ContainsExclusively([enum].Initializer.Span, span)
End If
Return Nothing
Dim propStatement = TryCast(node, PropertyStatementSyntax)
If propStatement IsNot Nothing Then
Return propStatement.Initializer IsNot Nothing AndAlso ContainsExclusively(propStatement.Initializer.Span, span)
End If
Return False
End Function
Private Function GetSimpleName(simpleName As SimpleNameSyntax) As String
Return simpleName.Identifier.ValueText
Private Function ContainsExclusively(outerSpan As TextSpan, innerSpan As TextSpan) As Boolean
If innerSpan.IsEmpty Then
Return outerSpan.Contains(innerSpan.Start)
End If
Return outerSpan.Contains(innerSpan)
End Function
Private Function GetContainerDisplayName(node As SyntaxNode) As String
Return GetDisplayName(node, DisplayNameOptions.IncludeTypeParameters)
Private Function GetSyntaxListSpan(Of T As SyntaxNode)(list As SyntaxList(Of T)) As TextSpan
Contract.Requires(list.Count > 0)
Return TextSpan.FromBounds(list.First.SpanStart, list.Last.Span.End)
End Function
Private Function GetFullyQualifiedContainerName(node As SyntaxNode) As String
Return GetDisplayName(node, DisplayNameOptions.IncludeNamespaces)
Private Function GetSeparatedSyntaxListSpan(Of T As SyntaxNode)(list As SeparatedSyntaxList(Of T)) As TextSpan
Contract.Requires(list.Count > 0)
Return TextSpan.FromBounds(list.First.SpanStart, list.Last.Span.End)
End Function
Public Function GetMethodLevelMembers(root As SyntaxNode) As List(Of SyntaxNode) Implements ISyntaxFactsService.GetMethodLevelMembers
Dim list = New List(Of SyntaxNode)()
AppendMethodLevelMembers(root, list)
Return list
End Function
Public Function IsTopLevelNodeWithMembers(node As SyntaxNode) As Boolean Implements ISyntaxFactsService.IsTopLevelNodeWithMembers
Return TypeOf node Is NamespaceBlockSyntax OrElse
TypeOf node Is TypeBlockSyntax OrElse
TypeOf node Is EnumBlockSyntax
End Function
Private Const s_dotToken As String = "."
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册