151 lines
5.3 KiB
C#
151 lines
5.3 KiB
C#
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
|
using Microsoft.CodeAnalysis;
|
|
using Microsoft.CodeAnalysis.CSharp;
|
|
|
|
namespace RobotNet.WebApp.Scripts.Monaco;
|
|
|
|
public static class MonacoExtensions
|
|
{
|
|
public static bool IsInStaticContext(this SyntaxNode node)
|
|
{
|
|
// this/base calls are always static.
|
|
if (node.FirstAncestorOrSelf<ConstructorInitializerSyntax>() != null)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
var memberDeclaration = node.FirstAncestorOrSelf<MemberDeclarationSyntax>();
|
|
if (memberDeclaration == null)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
switch (memberDeclaration.Kind())
|
|
{
|
|
case SyntaxKind.MethodDeclaration:
|
|
case SyntaxKind.ConstructorDeclaration:
|
|
case SyntaxKind.EventDeclaration:
|
|
case SyntaxKind.IndexerDeclaration:
|
|
return GetModifiers(memberDeclaration).Any(SyntaxKind.StaticKeyword);
|
|
|
|
case SyntaxKind.PropertyDeclaration:
|
|
return GetModifiers(memberDeclaration).Any(SyntaxKind.StaticKeyword) ||
|
|
node.IsFoundUnder((PropertyDeclarationSyntax p) => p.Initializer);
|
|
|
|
case SyntaxKind.FieldDeclaration:
|
|
case SyntaxKind.EventFieldDeclaration:
|
|
// Inside a field one can only access static members of a type (unless it's top-level).
|
|
return !memberDeclaration.Parent.IsKind(SyntaxKind.CompilationUnit);
|
|
|
|
case SyntaxKind.DestructorDeclaration:
|
|
return false;
|
|
}
|
|
|
|
// Global statements are not a static context.
|
|
if (node.FirstAncestorOrSelf<GlobalStatementSyntax>() != null)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
// any other location is considered static
|
|
return true;
|
|
}
|
|
|
|
public static SyntaxTokenList GetModifiers(SyntaxNode member)
|
|
{
|
|
if (member != null)
|
|
{
|
|
switch (member.Kind())
|
|
{
|
|
case SyntaxKind.EnumDeclaration:
|
|
return ((EnumDeclarationSyntax)member).Modifiers;
|
|
case SyntaxKind.ClassDeclaration:
|
|
case SyntaxKind.InterfaceDeclaration:
|
|
case SyntaxKind.StructDeclaration:
|
|
return ((TypeDeclarationSyntax)member).Modifiers;
|
|
case SyntaxKind.DelegateDeclaration:
|
|
return ((DelegateDeclarationSyntax)member).Modifiers;
|
|
case SyntaxKind.FieldDeclaration:
|
|
return ((FieldDeclarationSyntax)member).Modifiers;
|
|
case SyntaxKind.EventFieldDeclaration:
|
|
return ((EventFieldDeclarationSyntax)member).Modifiers;
|
|
case SyntaxKind.ConstructorDeclaration:
|
|
return ((ConstructorDeclarationSyntax)member).Modifiers;
|
|
case SyntaxKind.DestructorDeclaration:
|
|
return ((DestructorDeclarationSyntax)member).Modifiers;
|
|
case SyntaxKind.PropertyDeclaration:
|
|
return ((PropertyDeclarationSyntax)member).Modifiers;
|
|
case SyntaxKind.EventDeclaration:
|
|
return ((EventDeclarationSyntax)member).Modifiers;
|
|
case SyntaxKind.IndexerDeclaration:
|
|
return ((IndexerDeclarationSyntax)member).Modifiers;
|
|
case SyntaxKind.OperatorDeclaration:
|
|
return ((OperatorDeclarationSyntax)member).Modifiers;
|
|
case SyntaxKind.ConversionOperatorDeclaration:
|
|
return ((ConversionOperatorDeclarationSyntax)member).Modifiers;
|
|
case SyntaxKind.MethodDeclaration:
|
|
return ((MethodDeclarationSyntax)member).Modifiers;
|
|
case SyntaxKind.GetAccessorDeclaration:
|
|
case SyntaxKind.SetAccessorDeclaration:
|
|
case SyntaxKind.AddAccessorDeclaration:
|
|
case SyntaxKind.RemoveAccessorDeclaration:
|
|
return ((AccessorDeclarationSyntax)member).Modifiers;
|
|
}
|
|
}
|
|
|
|
return default;
|
|
}
|
|
|
|
public static bool IsFoundUnder<TParent>(this SyntaxNode node, Func<TParent, SyntaxNode?> childGetter)
|
|
where TParent : SyntaxNode
|
|
{
|
|
var ancestor = node.GetAncestor<TParent>();
|
|
if (ancestor == null)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
var child = childGetter(ancestor);
|
|
|
|
// See if node passes through child on the way up to ancestor.
|
|
return node.GetAncestorsOrThis<SyntaxNode>().Contains(child);
|
|
}
|
|
|
|
public static TNode? GetAncestor<TNode>(this SyntaxNode node)
|
|
where TNode : SyntaxNode
|
|
{
|
|
var current = node.Parent;
|
|
while (current != null)
|
|
{
|
|
if (current is TNode tNode)
|
|
{
|
|
return tNode;
|
|
}
|
|
|
|
current = current.GetParent();
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
public static IEnumerable<TNode> GetAncestorsOrThis<TNode>(this SyntaxNode node)
|
|
where TNode : SyntaxNode
|
|
{
|
|
var current = node;
|
|
while (current != null)
|
|
{
|
|
if (current is TNode tNode)
|
|
{
|
|
yield return tNode;
|
|
}
|
|
|
|
current = current.GetParent();
|
|
}
|
|
}
|
|
|
|
private static SyntaxNode? GetParent(this SyntaxNode node)
|
|
{
|
|
return node is IStructuredTriviaSyntax trivia ? trivia.ParentTrivia.Token.Parent : node.Parent;
|
|
}
|
|
}
|