Skip to content

Commit 132b636

Browse files
committed
Changes for extension methods and static invocations
1 parent 2c0bc6f commit 132b636

File tree

5 files changed

+215
-9
lines changed

5 files changed

+215
-9
lines changed

src/OmniSharp.Roslyn.CSharp/OmniSharp.Roslyn.CSharp.csproj

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,14 @@
55
<PlatformTarget>AnyCPU</PlatformTarget>
66
</PropertyGroup>
77

8+
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
9+
<LangVersion>7.1</LangVersion>
10+
</PropertyGroup>
11+
12+
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
13+
<LangVersion>7.1</LangVersion>
14+
</PropertyGroup>
15+
816
<ItemGroup>
917
<ProjectReference Include="..\OmniSharp.Abstractions\OmniSharp.Abstractions.csproj" />
1018
<ProjectReference Include="..\OmniSharp.Roslyn\OmniSharp.Roslyn.csproj" />
Lines changed: 175 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,175 @@
1+
using Microsoft.CodeAnalysis;
2+
using Microsoft.CodeAnalysis.CSharp;
3+
using Microsoft.CodeAnalysis.CSharp.Syntax;
4+
using System;
5+
using System.Collections.Generic;
6+
using System.Linq;
7+
namespace OmniSharp.Roslyn.CSharp.Services.Signatures
8+
{
9+
static internal class CheckForStatic
10+
{
11+
public static bool IsInStaticContext(this SyntaxNode node)
12+
{
13+
// this/base calls are always static.
14+
if (node.FirstAncestorOrSelf<ConstructorInitializerSyntax>() != null)
15+
{
16+
return true;
17+
}
18+
19+
var memberDeclaration = node.FirstAncestorOrSelf<MemberDeclarationSyntax>();
20+
if (memberDeclaration == null)
21+
{
22+
return false;
23+
}
24+
25+
switch (memberDeclaration.Kind())
26+
{
27+
case SyntaxKind.MethodDeclaration:
28+
case SyntaxKind.ConstructorDeclaration:
29+
case SyntaxKind.EventDeclaration:
30+
case SyntaxKind.IndexerDeclaration:
31+
return GetModifiers(memberDeclaration).Any(SyntaxKind.StaticKeyword);
32+
33+
case SyntaxKind.PropertyDeclaration:
34+
return GetModifiers(memberDeclaration).Any(SyntaxKind.StaticKeyword) ||
35+
node.IsFoundUnder((PropertyDeclarationSyntax p) => p.Initializer);
36+
37+
case SyntaxKind.FieldDeclaration:
38+
case SyntaxKind.EventFieldDeclaration:
39+
// Inside a field one can only access static members of a type (unless it's top-level).
40+
return !memberDeclaration.Parent.IsKind(SyntaxKind.CompilationUnit);
41+
42+
case SyntaxKind.DestructorDeclaration:
43+
return false;
44+
}
45+
46+
// Global statements are not a static context.
47+
if (node.FirstAncestorOrSelf<GlobalStatementSyntax>() != null)
48+
{
49+
return false;
50+
}
51+
52+
// any other location is considered static
53+
return true;
54+
}
55+
public static SyntaxTokenList GetModifiers(SyntaxNode member)
56+
{
57+
if (member != null)
58+
{
59+
switch (member.Kind())
60+
{
61+
case SyntaxKind.EnumDeclaration:
62+
return ((EnumDeclarationSyntax)member).Modifiers;
63+
case SyntaxKind.ClassDeclaration:
64+
case SyntaxKind.InterfaceDeclaration:
65+
case SyntaxKind.StructDeclaration:
66+
return ((TypeDeclarationSyntax)member).Modifiers;
67+
case SyntaxKind.DelegateDeclaration:
68+
return ((DelegateDeclarationSyntax)member).Modifiers;
69+
case SyntaxKind.FieldDeclaration:
70+
return ((FieldDeclarationSyntax)member).Modifiers;
71+
case SyntaxKind.EventFieldDeclaration:
72+
return ((EventFieldDeclarationSyntax)member).Modifiers;
73+
case SyntaxKind.ConstructorDeclaration:
74+
return ((ConstructorDeclarationSyntax)member).Modifiers;
75+
case SyntaxKind.DestructorDeclaration:
76+
return ((DestructorDeclarationSyntax)member).Modifiers;
77+
case SyntaxKind.PropertyDeclaration:
78+
return ((PropertyDeclarationSyntax)member).Modifiers;
79+
case SyntaxKind.EventDeclaration:
80+
return ((EventDeclarationSyntax)member).Modifiers;
81+
case SyntaxKind.IndexerDeclaration:
82+
return ((IndexerDeclarationSyntax)member).Modifiers;
83+
case SyntaxKind.OperatorDeclaration:
84+
return ((OperatorDeclarationSyntax)member).Modifiers;
85+
case SyntaxKind.ConversionOperatorDeclaration:
86+
return ((ConversionOperatorDeclarationSyntax)member).Modifiers;
87+
case SyntaxKind.MethodDeclaration:
88+
return ((MethodDeclarationSyntax)member).Modifiers;
89+
case SyntaxKind.GetAccessorDeclaration:
90+
case SyntaxKind.SetAccessorDeclaration:
91+
case SyntaxKind.AddAccessorDeclaration:
92+
case SyntaxKind.RemoveAccessorDeclaration:
93+
return ((AccessorDeclarationSyntax)member).Modifiers;
94+
}
95+
}
96+
97+
return default;
98+
}
99+
public static bool IsFoundUnder<TParent>(this SyntaxNode node, Func<TParent, SyntaxNode> childGetter)
100+
where TParent : SyntaxNode
101+
{
102+
var ancestor = node.GetAncestor<TParent>();
103+
if (ancestor == null)
104+
{
105+
return false;
106+
}
107+
108+
var child = childGetter(ancestor);
109+
110+
// See if node passes through child on the way up to ancestor.
111+
return node.GetAncestorsOrThis<SyntaxNode>().Contains(child);
112+
}
113+
public static TNode GetAncestor<TNode>(this SyntaxNode node)
114+
where TNode : SyntaxNode
115+
{
116+
var current = node.Parent;
117+
while (current != null)
118+
{
119+
if (current is TNode tNode)
120+
{
121+
return tNode;
122+
}
123+
124+
current = current.GetParent();
125+
}
126+
127+
return null;
128+
}
129+
private static SyntaxNode GetParent(this SyntaxNode node)
130+
{
131+
return node is IStructuredTriviaSyntax trivia ? trivia.ParentTrivia.Token.Parent : node.Parent;
132+
}
133+
134+
public static TNode FirstAncestorOrSelfUntil<TNode>(this SyntaxNode node, Func<SyntaxNode, bool> predicate)
135+
where TNode : SyntaxNode
136+
{
137+
for (var current = node; current != null; current = current.GetParent())
138+
{
139+
if (current is TNode tnode)
140+
{
141+
return tnode;
142+
}
143+
144+
if (predicate(current))
145+
{
146+
break;
147+
}
148+
}
149+
150+
return default;
151+
}
152+
153+
public static TNode GetAncestorOrThis<TNode>(this SyntaxNode node)
154+
where TNode : SyntaxNode
155+
{
156+
return node?.GetAncestorsOrThis<TNode>().FirstOrDefault();
157+
}
158+
159+
public static IEnumerable<TNode> GetAncestorsOrThis<TNode>(this SyntaxNode node)
160+
where TNode : SyntaxNode
161+
{
162+
var current = node;
163+
while (current != null)
164+
{
165+
if (current is TNode tNode)
166+
{
167+
yield return tNode;
168+
}
169+
170+
current = current.GetParent();
171+
}
172+
}
173+
}
174+
}
175+

src/OmniSharp.Roslyn.CSharp/Services/Signatures/InvocationContext.cs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,23 +13,26 @@ internal class InvocationContext
1313
public SyntaxNode Receiver { get; }
1414
public IEnumerable<TypeInfo> ArgumentTypes { get; }
1515
public IEnumerable<SyntaxToken> Separators { get; }
16+
public bool IsStatic { get; }
1617

17-
public InvocationContext(SemanticModel semModel, int position, SyntaxNode receiver, ArgumentListSyntax argList)
18+
public InvocationContext(SemanticModel semModel, int position, SyntaxNode receiver, ArgumentListSyntax argList, bool isStatic)
1819
{
1920
SemanticModel = semModel;
2021
Position = position;
2122
Receiver = receiver;
2223
ArgumentTypes = argList.Arguments.Select(argument => semModel.GetTypeInfo(argument.Expression));
2324
Separators = argList.Arguments.GetSeparators();
25+
IsStatic = isStatic;
2426
}
2527

26-
public InvocationContext(SemanticModel semModel, int position, SyntaxNode receiver, AttributeArgumentListSyntax argList)
28+
public InvocationContext(SemanticModel semModel, int position, SyntaxNode receiver, AttributeArgumentListSyntax argList, bool isStatic)
2729
{
2830
SemanticModel = semModel;
2931
Position = position;
3032
Receiver = receiver;
3133
ArgumentTypes = argList.Arguments.Select(argument => semModel.GetTypeInfo(argument.Expression));
3234
Separators = argList.Arguments.GetSeparators();
35+
IsStatic = isStatic;
3336
}
3437
}
3538
}

src/OmniSharp.Roslyn.CSharp/Services/Signatures/SignatureHelpService.cs

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
using System.Linq;
44
using System.Threading.Tasks;
55
using Microsoft.CodeAnalysis;
6+
using Microsoft.CodeAnalysis.CSharp;
67
using Microsoft.CodeAnalysis.CSharp.Syntax;
78
using Microsoft.CodeAnalysis.Text;
89
using OmniSharp.Mef;
@@ -59,7 +60,25 @@ public async Task<SignatureHelpResponse> Handle(SignatureHelpRequest request)
5960
foreach (var invocation in invocations)
6061
{
6162
var types = invocation.ArgumentTypes;
62-
foreach (var methodOverload in invocation.SemanticModel.GetMemberGroup(invocation.Receiver).OfType<IMethodSymbol>())
63+
ISymbol throughSymbol = null;
64+
ISymbol throughType = null;
65+
var methodGroup = invocation.SemanticModel.GetMemberGroup(invocation.Receiver).OfType<IMethodSymbol>();
66+
if (invocation.Receiver is MemberAccessExpressionSyntax)
67+
{
68+
var throughExpression = ((MemberAccessExpressionSyntax)invocation.Receiver).Expression;
69+
throughSymbol = invocation.SemanticModel.GetSpeculativeSymbolInfo(invocation.Position, throughExpression, SpeculativeBindingOption.BindAsExpression).Symbol;
70+
throughType = invocation.SemanticModel.GetSpeculativeTypeInfo(invocation.Position, throughExpression, SpeculativeBindingOption.BindAsTypeOrNamespace).Type;
71+
var includeInstance = throughSymbol != null && !(throughSymbol is ITypeSymbol);
72+
var includeStatic = (throughSymbol is INamedTypeSymbol) || throughType != null;
73+
methodGroup = methodGroup.Where(m => (m.IsStatic && includeStatic) || (!m.IsStatic && includeInstance));
74+
}
75+
76+
else if (invocation.Receiver is SimpleNameSyntax && invocation.IsStatic)
77+
{
78+
methodGroup = methodGroup.Where(m => m.IsStatic);
79+
}
80+
81+
foreach (var methodOverload in methodGroup)
6382
{
6483
var signature = BuildSignature(methodOverload);
6584
signaturesSet.Add(signature);
@@ -94,19 +113,19 @@ private async Task<InvocationContext> GetInvocation(Document document, Request r
94113
if (node is InvocationExpressionSyntax invocation && invocation.ArgumentList.Span.Contains(position))
95114
{
96115
var semanticModel = await document.GetSemanticModelAsync();
97-
return new InvocationContext(semanticModel, position, invocation.Expression, invocation.ArgumentList);
116+
return new InvocationContext(semanticModel, position, invocation.Expression, invocation.ArgumentList, invocation.IsInStaticContext());
98117
}
99118

100119
if (node is ObjectCreationExpressionSyntax objectCreation && objectCreation.ArgumentList.Span.Contains(position))
101120
{
102121
var semanticModel = await document.GetSemanticModelAsync();
103-
return new InvocationContext(semanticModel, position, objectCreation, objectCreation.ArgumentList);
122+
return new InvocationContext(semanticModel, position, objectCreation, objectCreation.ArgumentList,objectCreation.IsInStaticContext());
104123
}
105124

106125
if (node is AttributeSyntax attributeSyntax && attributeSyntax.ArgumentList.Span.Contains(position))
107126
{
108127
var semanticModel = await document.GetSemanticModelAsync();
109-
return new InvocationContext(semanticModel, position, attributeSyntax, attributeSyntax.ArgumentList);
128+
return new InvocationContext(semanticModel, position, attributeSyntax, attributeSyntax.ArgumentList, attributeSyntax.IsInStaticContext());
110129
}
111130

112131
node = node.Parent;
@@ -141,7 +160,7 @@ private int InvocationScore(IMethodSymbol symbol, IEnumerable<TypeInfo> types)
141160
}
142161
}
143162

144-
return score;
163+
return score;
145164
}
146165

147166
private static SignatureHelpItem BuildSignature(IMethodSymbol symbol)
@@ -163,5 +182,6 @@ private static SignatureHelpItem BuildSignature(IMethodSymbol symbol)
163182

164183
return signature;
165184
}
185+
166186
}
167187
}

tests/OmniSharp.Roslyn.CSharp.Tests/SignatureHelpFacts.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -661,11 +661,11 @@ public void M1(int a, int b) { }
661661
662662
class B : A
663663
{
664-
static void M1(int a,int b,int c)
664+
void M1(int a,int b,int c)
665665
{
666666
M1($$)
667667
}
668-
public void M1(int a,int b,int c,int d) { }
668+
static void M1(int a,int b,int c,int d) { }
669669
}";
670670
var actual = await GetSignatureHelp(source);
671671
Assert.Equal(4, actual.Signatures.Count());

0 commit comments

Comments
 (0)