Skip to content

Commit 5dc0a90

Browse files
authored
Merge pull request #43043 from genlu/stackallocCompletion
show stackalloc completion in expression context
2 parents 2d3b98b + 08469d6 commit 5dc0a90

File tree

2 files changed

+58
-60
lines changed

2 files changed

+58
-60
lines changed

src/EditorFeatures/CSharpTest2/Recommendations/StackAllocKeywordRecommenderTests.cs

Lines changed: 53 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -12,32 +12,32 @@ namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.Recommendations
1212
public class StackAllocKeywordRecommenderTests : KeywordRecommenderTests
1313
{
1414
[Fact, Trait(Traits.Feature, Traits.Features.KeywordRecommending)]
15-
public async Task TestNotAtRoot_Interactive()
15+
public async Task TestAtRoot_Interactive()
1616
{
17-
await VerifyAbsenceAsync(SourceCodeKind.Script,
17+
await VerifyKeywordAsync(SourceCodeKind.Script,
1818
@"$$");
1919
}
2020

2121
[Fact, Trait(Traits.Feature, Traits.Features.KeywordRecommending)]
22-
public async Task TestNotAfterClass_Interactive()
22+
public async Task TestAfterClass_Interactive()
2323
{
24-
await VerifyAbsenceAsync(SourceCodeKind.Script,
24+
await VerifyKeywordAsync(SourceCodeKind.Script,
2525
@"class C { }
2626
$$");
2727
}
2828

2929
[Fact, Trait(Traits.Feature, Traits.Features.KeywordRecommending)]
30-
public async Task TestNotAfterGlobalStatement_Interactive()
30+
public async Task TestAfterGlobalStatement_Interactive()
3131
{
32-
await VerifyAbsenceAsync(SourceCodeKind.Script,
32+
await VerifyKeywordAsync(SourceCodeKind.Script,
3333
@"System.Console.WriteLine();
3434
$$");
3535
}
3636

3737
[Fact, Trait(Traits.Feature, Traits.Features.KeywordRecommending)]
38-
public async Task TestNotAfterGlobalVariableDeclaration_Interactive()
38+
public async Task TestAfterGlobalVariableDeclaration_Interactive()
3939
{
40-
await VerifyAbsenceAsync(SourceCodeKind.Script,
40+
await VerifyKeywordAsync(SourceCodeKind.Script,
4141
@"int i = 0;
4242
$$");
4343
}
@@ -50,9 +50,11 @@ await VerifyAbsenceAsync(
5050
}
5151

5252
[Fact, Trait(Traits.Feature, Traits.Features.KeywordRecommending)]
53-
public async Task TestNotInEmptyStatement()
53+
public async Task TestInEmptyStatement()
5454
{
55-
await VerifyAbsenceAsync(AddInsideMethod(
55+
// e.g. this is a valid statement
56+
// stackalloc[] { 1, 2, 3 }.IndexOf(1);
57+
await VerifyKeywordAsync(AddInsideMethod(
5658
@"$$"));
5759
}
5860

@@ -92,11 +94,14 @@ void Goo() {
9294
}
9395

9496
[Fact, Trait(Traits.Feature, Traits.Features.KeywordRecommending)]
95-
public async Task TestNotInField()
97+
public async Task TestInField()
9698
{
97-
await VerifyAbsenceAsync(
98-
@"unsafe class C {
99-
int* v = $$");
99+
// While assigning stackalloc'd value to a field is invalid,
100+
// using one in the initializer is OK. e.g.
101+
// int _f = stackalloc[] { 1, 2, 3 }.IndexOf(1);
102+
await VerifyKeywordAsync(
103+
@"class C {
104+
int v = $$");
100105
}
101106

102107
[WorkItem(544504, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/544504")]
@@ -268,5 +273,39 @@ await VerifyAbsenceAsync(AddInsideMethod(@"
268273
await VerifyAbsenceAsync(AddInsideMethod(@"
269274
x $$ ="));
270275
}
276+
277+
[WorkItem(41736, "https://github.com/dotnet/roslyn/issues/41736")]
278+
[Fact, Trait(Traits.Feature, Traits.Features.KeywordRecommending)]
279+
public async Task TestInArgument()
280+
{
281+
await VerifyKeywordAsync(@"
282+
class Program
283+
{
284+
static void Method(System.Span<byte> span)
285+
{
286+
Method($$);
287+
}
288+
}");
289+
290+
await VerifyKeywordAsync(@"
291+
class Program
292+
{
293+
static void Method(int x, System.Span<byte> span)
294+
{
295+
Method(1, $$);
296+
}
297+
}");
298+
}
299+
300+
[WorkItem(41736, "https://github.com/dotnet/roslyn/issues/41736")]
301+
[Fact, Trait(Traits.Feature, Traits.Features.KeywordRecommending)]
302+
public async Task TestNotInConstFieldInitializer()
303+
{
304+
await VerifyAbsenceAsync(@"
305+
class Program
306+
{
307+
private const int _f = $$
308+
}");
309+
}
271310
}
272311
}

src/Features/CSharp/Portable/Completion/KeywordRecommenders/StackAllocKeywordRecommender.cs

Lines changed: 5 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -17,52 +17,11 @@ public StackAllocKeywordRecommender()
1717

1818
protected override bool IsValidContext(int position, CSharpSyntaxContext context, CancellationToken cancellationToken)
1919
{
20-
var node = context.TargetToken.Parent;
21-
22-
// At start of a file
23-
if (node == null)
24-
{
25-
return false;
26-
}
27-
28-
// After a cast or parenthesized expression: (Span<int>)stackalloc
29-
if (context.TargetToken.IsAfterPossibleCast())
30-
{
31-
node = node.Parent;
32-
}
33-
34-
// Inside a conditional expression: value ? stackalloc : stackalloc
35-
while (node.IsKind(SyntaxKind.ConditionalExpression) &&
36-
(context.TargetToken.IsKind(SyntaxKind.QuestionToken, SyntaxKind.ColonToken) || context.TargetToken.IsAfterPossibleCast()))
37-
{
38-
node = node.Parent;
39-
}
40-
41-
// assignment: x = stackalloc
42-
if (node.IsKind(SyntaxKind.SimpleAssignmentExpression))
43-
{
44-
return node.Parent.IsKind(SyntaxKind.ExpressionStatement);
45-
}
46-
47-
// declaration: var x = stackalloc
48-
if (node.IsKind(SyntaxKind.EqualsValueClause))
49-
{
50-
node = node.Parent;
51-
52-
if (node.IsKind(SyntaxKind.VariableDeclarator))
53-
{
54-
node = node.Parent;
55-
56-
if (node.IsKind(SyntaxKind.VariableDeclaration))
57-
{
58-
node = node.Parent;
59-
60-
return node.IsKind(SyntaxKind.LocalDeclarationStatement, SyntaxKind.ForStatement);
61-
}
62-
}
63-
}
64-
65-
return false;
20+
// Beginning with C# 8.0, stackalloc expression can be used inside other expressions
21+
// whenever a Span<T> or ReadOnlySpan<T> variable is allowed.
22+
return (context.IsAnyExpressionContext && !context.IsConstantExpressionContext) ||
23+
context.IsStatementContext ||
24+
context.IsGlobalStatementContext;
6625
}
6726
}
6827
}

0 commit comments

Comments
 (0)