-
Notifications
You must be signed in to change notification settings - Fork 420
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
5 changed files
with
216 additions
and
21 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
175 changes: 175 additions & 0 deletions
175
src/OmniSharp.Roslyn.CSharp/Services/Signatures/CheckStaticInvocation.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,175 @@ | ||
using Microsoft.CodeAnalysis; | ||
using Microsoft.CodeAnalysis.CSharp; | ||
using Microsoft.CodeAnalysis.CSharp.Syntax; | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Linq; | ||
namespace OmniSharp.Roslyn.CSharp.Services.Signatures | ||
{ | ||
static internal class CheckForStatic | ||
{ | ||
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; | ||
} | ||
private static SyntaxNode GetParent(this SyntaxNode node) | ||
{ | ||
return node is IStructuredTriviaSyntax trivia ? trivia.ParentTrivia.Token.Parent : node.Parent; | ||
} | ||
|
||
public static TNode FirstAncestorOrSelfUntil<TNode>(this SyntaxNode node, Func<SyntaxNode, bool> predicate) | ||
where TNode : SyntaxNode | ||
{ | ||
for (var current = node; current != null; current = current.GetParent()) | ||
{ | ||
if (current is TNode tnode) | ||
{ | ||
return tnode; | ||
} | ||
|
||
if (predicate(current)) | ||
{ | ||
break; | ||
} | ||
} | ||
|
||
return default; | ||
} | ||
|
||
public static TNode GetAncestorOrThis<TNode>(this SyntaxNode node) | ||
where TNode : SyntaxNode | ||
{ | ||
return node?.GetAncestorsOrThis<TNode>().FirstOrDefault(); | ||
} | ||
|
||
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(); | ||
} | ||
} | ||
} | ||
} | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters