Skip to content

Commit 1b2c0b3

Browse files
author
msftbot[bot]
authored
Merge pull request #44612 from AlekseyTs/master
Merge 'Top-level statements' feature into master
2 parents ffbb9c7 + a4c0276 commit 1b2c0b3

File tree

203 files changed

+21258
-5246
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

203 files changed

+21258
-5246
lines changed
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
Top-level statements
2+
=========================
3+
4+
Allow a sequence of *statements* to occur right before the *namespace_member_declaration*s of a *compilation_unit* (i.e. source file).
5+
6+
The semantics are that if such a sequence of *statements* is present, the following type declaration, modulo the actual type name and the method name, would be emitted:
7+
8+
``` c#
9+
static class Program
10+
{
11+
static async Task Main()
12+
{
13+
// statements
14+
}
15+
}
16+
```
17+
18+
Proposal: https://github.com/dotnet/csharplang/blob/master/proposals/top-level-statements.md
19+
Open issues and TODOs are tracked at https://github.com/dotnet/roslyn/issues/41704.
20+
Test plan: https://github.com/dotnet/roslyn/issues/43563.
21+
See also https://github.com/dotnet/csharplang/issues/3117.

src/Analyzers/CSharp/CodeFixes/ConvertSwitchStatementToExpression/ConvertSwitchStatementToExpressionCodeFixProvider.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ protected override async Task FixAllAsync(
8181
declaratorToRemoveTypeOpt = semanticModel.GetDeclaredSymbol(declaratorToRemoveNodeOpt).GetSymbolType();
8282
}
8383

84-
var switchStatement = (SwitchStatementSyntax)switchLocation.FindNode(cancellationToken);
84+
var switchStatement = (SwitchStatementSyntax)switchLocation.FindNode(getInnermostNodeForTie: true, cancellationToken);
8585
var switchExpression = Rewriter.Rewrite(
8686
switchStatement, declaratorToRemoveTypeOpt, nodeToGenerate,
8787
shouldMoveNextStatementToSwitchExpression: shouldRemoveNextStatement,
@@ -97,9 +97,9 @@ protected override async Task FixAllAsync(
9797
if (shouldRemoveNextStatement)
9898
{
9999
// Already morphed into the top-level switch expression.
100-
var nextStatement = switchStatement.GetNextStatement();
100+
SyntaxNode nextStatement = switchStatement.GetNextStatement();
101101
Debug.Assert(nextStatement.IsKind(SyntaxKind.ThrowStatement, SyntaxKind.ReturnStatement));
102-
editor.RemoveNode(nextStatement);
102+
editor.RemoveNode(nextStatement.IsParentKind(SyntaxKind.GlobalStatement) ? nextStatement.Parent : nextStatement);
103103
}
104104
}
105105
}

src/Analyzers/CSharp/Tests/ConvertSwitchStatementToExpression/ConvertSwitchStatementToExpressionTests.cs

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1890,5 +1890,86 @@ static void GetRef(int[] mem, int addr, int mode)
18901890
}
18911891
}");
18921892
}
1893+
1894+
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsConvertSwitchStatementToExpression)]
1895+
public async Task TopLevelStatement()
1896+
{
1897+
var source = @"
1898+
int i = 0;
1899+
[|switch|] (i)
1900+
{
1901+
case 1:
1902+
return 4;
1903+
default:
1904+
return 7;
1905+
}";
1906+
1907+
var fixedSource = @"
1908+
int i = 0;
1909+
return i switch
1910+
{
1911+
1 => 4,
1912+
_ => 7,
1913+
};
1914+
";
1915+
1916+
var test = new VerifyCS.Test
1917+
{
1918+
TestCode = source,
1919+
FixedCode = fixedSource,
1920+
LanguageVersion = LanguageVersion.Preview,
1921+
};
1922+
1923+
test.ExpectedDiagnostics.Add(
1924+
// error CS9004: Program using top-level statements must be an executable.
1925+
DiagnosticResult.CompilerError("CS9004"));
1926+
1927+
await test.RunAsync();
1928+
}
1929+
1930+
[WorkItem(44449, "https://github.com/dotnet/roslyn/issues/44449")]
1931+
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsConvertSwitchStatementToExpression)]
1932+
public async Task TopLevelStatement_FollowedWithThrow()
1933+
{
1934+
// We should be rewriting the declaration for 'j' to get 'var j = i switch ...'
1935+
var source = @"
1936+
int i = 0;
1937+
int j;
1938+
[|switch|] (i)
1939+
{
1940+
case 1:
1941+
j = 4;
1942+
break;
1943+
case 2:
1944+
j = 5;
1945+
break;
1946+
}
1947+
throw null;
1948+
";
1949+
1950+
var fixedSource = @"
1951+
int i = 0;
1952+
int j;
1953+
j = i switch
1954+
{
1955+
1 => 4,
1956+
2 => 5,
1957+
_ => throw null,
1958+
};
1959+
";
1960+
1961+
var test = new VerifyCS.Test
1962+
{
1963+
TestCode = source,
1964+
FixedCode = fixedSource,
1965+
LanguageVersion = LanguageVersion.Preview,
1966+
};
1967+
1968+
test.ExpectedDiagnostics.Add(
1969+
// error CS9004: Program using top-level statements must be an executable.
1970+
DiagnosticResult.CompilerError("CS9004"));
1971+
1972+
await test.RunAsync();
1973+
}
18931974
}
18941975
}

src/Analyzers/CSharp/Tests/InlineDeclaration/CSharpInlineDeclarationTests.cs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
using Microsoft.CodeAnalysis.CodeFixes;
77
using Microsoft.CodeAnalysis.CSharp;
88
using Microsoft.CodeAnalysis.CSharp.InlineDeclaration;
9+
using Microsoft.CodeAnalysis.CSharp.Test.Utilities;
910
using Microsoft.CodeAnalysis.Diagnostics;
1011
using Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.Diagnostics;
1112
using Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.Diagnostics.UseImplicitType;
@@ -2280,5 +2281,16 @@ void M(out C c2)
22802281
}
22812282
}");
22822283
}
2284+
2285+
[WorkItem(44429, "https://github.com/dotnet/roslyn/issues/44429")]
2286+
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsInlineDeclaration)]
2287+
public async Task TopLevelStatement()
2288+
{
2289+
await TestMissingAsync(@"
2290+
[|int|] i;
2291+
if (int.TryParse(v, out i))
2292+
{
2293+
}", new TestParameters(TestOptions.Regular));
2294+
}
22832295
}
22842296
}

src/Analyzers/CSharp/Tests/RemoveUnnecessaryCast/RemoveUnnecessaryCastTests.cs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,8 @@ static void Main()
142142
}
143143

144144
[WorkItem(545138, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/545138")]
145-
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsRemoveUnnecessaryCast)]
145+
[WorkItem(44422, "https://github.com/dotnet/roslyn/issues/44422")]
146+
[Fact(Skip = "https://github.com/dotnet/roslyn/issues/44422"), Trait(Traits.Feature, Traits.Features.CodeActionsRemoveUnnecessaryCast)]
146147
public async Task DontRemoveTypeParameterCastToObject()
147148
{
148149
var source =
@@ -173,7 +174,8 @@ await VerifyCS.VerifyCodeFixAsync(
173174
}
174175

175176
[WorkItem(545139, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/545139")]
176-
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsRemoveUnnecessaryCast)]
177+
[WorkItem(44422, "https://github.com/dotnet/roslyn/issues/44422")]
178+
[Fact(Skip = "https://github.com/dotnet/roslyn/issues/44422"), Trait(Traits.Feature, Traits.Features.CodeActionsRemoveUnnecessaryCast)]
177179
public async Task DontRemoveCastInIsTest()
178180
{
179181
var source =

src/Analyzers/CSharp/Tests/UseThrowExpression/UseThrowExpressionTests.cs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
using System.Threading.Tasks;
66
using Microsoft.CodeAnalysis.CodeFixes;
77
using Microsoft.CodeAnalysis.CSharp;
8+
using Microsoft.CodeAnalysis.CSharp.Shared.Extensions;
9+
using Microsoft.CodeAnalysis.CSharp.Test.Utilities;
810
using Microsoft.CodeAnalysis.CSharp.UseThrowExpression;
911
using Microsoft.CodeAnalysis.Diagnostics;
1012
using Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.Diagnostics;
@@ -541,5 +543,24 @@ public A(T? t)
541543
}
542544
}");
543545
}
546+
547+
[WorkItem(44454, "https://github.com/dotnet/roslyn/issues/44454")]
548+
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseThrowExpression)]
549+
public async Task TopLevelStatement()
550+
{
551+
await TestAsync(
552+
@"using System;
553+
string s = null;
554+
string x = null;
555+
if (s == null) [|throw|] new ArgumentNullException();
556+
x = s;
557+
",
558+
@"using System;
559+
string s = null;
560+
string x = null;
561+
562+
x = s ?? throw new ArgumentNullException();
563+
", TestOptions.Regular.WithLanguageVersion(LanguageVersionExtensions.CSharp9));
564+
}
544565
}
545566
}

src/Analyzers/Core/Analyzers/UseThrowExpression/AbstractUseThrowExpressionDiagnosticAnalyzer.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ private void AnalyzeOperation(OperationAnalysisContext context, INamedTypeSymbol
102102
return;
103103
}
104104

105-
if (!(semanticModel.GetOperation(ifOperation.Syntax.Parent, cancellationToken) is IBlockOperation containingBlock))
105+
if (!(ifOperation.Parent is IBlockOperation containingBlock))
106106
{
107107
return;
108108
}

src/Compilers/CSharp/CSharpAnalyzerDriver/CSharpDeclarationComputer.cs

Lines changed: 27 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -23,20 +23,21 @@ public static void ComputeDeclarationsInSpan(
2323
ArrayBuilder<DeclarationInfo> builder,
2424
CancellationToken cancellationToken)
2525
{
26-
ComputeDeclarations(model, model.SyntaxTree.GetRoot(cancellationToken),
26+
ComputeDeclarations(model, associatedSymbol: null, model.SyntaxTree.GetRoot(cancellationToken),
2727
(node, level) => !node.Span.OverlapsWith(span) || InvalidLevel(level),
2828
getSymbol, builder, null, cancellationToken);
2929
}
3030

3131
public static void ComputeDeclarationsInNode(
3232
SemanticModel model,
33+
ISymbol associatedSymbol,
3334
SyntaxNode node,
3435
bool getSymbol,
3536
ArrayBuilder<DeclarationInfo> builder,
3637
CancellationToken cancellationToken,
3738
int? levelsToCompute = null)
3839
{
39-
ComputeDeclarations(model, node, (n, level) => InvalidLevel(level), getSymbol, builder, levelsToCompute, cancellationToken);
40+
ComputeDeclarations(model, associatedSymbol, node, (n, level) => InvalidLevel(level), getSymbol, builder, levelsToCompute, cancellationToken);
4041
}
4142

4243
private static bool InvalidLevel(int? level)
@@ -51,6 +52,7 @@ private static bool InvalidLevel(int? level)
5152

5253
private static void ComputeDeclarations(
5354
SemanticModel model,
55+
ISymbol associatedSymbol,
5456
SyntaxNode node,
5557
Func<SyntaxNode, int?, bool> shouldSkip,
5658
bool getSymbol,
@@ -74,7 +76,7 @@ private static void ComputeDeclarations(
7476
var ns = (NamespaceDeclarationSyntax)node;
7577
foreach (var decl in ns.Members)
7678
{
77-
ComputeDeclarations(model, decl, shouldSkip, getSymbol, builder, newLevel, cancellationToken);
79+
ComputeDeclarations(model, associatedSymbol: null, decl, shouldSkip, getSymbol, builder, newLevel, cancellationToken);
7880
}
7981

8082
var declInfo = GetDeclarationInfo(model, node, getSymbol, cancellationToken);
@@ -100,7 +102,7 @@ private static void ComputeDeclarations(
100102
var t = (TypeDeclarationSyntax)node;
101103
foreach (var decl in t.Members)
102104
{
103-
ComputeDeclarations(model, decl, shouldSkip, getSymbol, builder, newLevel, cancellationToken);
105+
ComputeDeclarations(model, associatedSymbol: null, decl, shouldSkip, getSymbol, builder, newLevel, cancellationToken);
104106
}
105107

106108
var attributes = GetAttributes(t.AttributeLists).Concat(GetTypeParameterListAttributes(t.TypeParameterList));
@@ -113,7 +115,7 @@ private static void ComputeDeclarations(
113115
var t = (EnumDeclarationSyntax)node;
114116
foreach (var decl in t.Members)
115117
{
116-
ComputeDeclarations(model, decl, shouldSkip, getSymbol, builder, newLevel, cancellationToken);
118+
ComputeDeclarations(model, associatedSymbol: null, decl, shouldSkip, getSymbol, builder, newLevel, cancellationToken);
117119
}
118120

119121
var attributes = GetAttributes(t.AttributeLists);
@@ -147,7 +149,7 @@ private static void ComputeDeclarations(
147149
{
148150
foreach (var decl in t.AccessorList.Accessors)
149151
{
150-
ComputeDeclarations(model, decl, shouldSkip, getSymbol, builder, newLevel, cancellationToken);
152+
ComputeDeclarations(model, associatedSymbol: null, decl, shouldSkip, getSymbol, builder, newLevel, cancellationToken);
151153
}
152154
}
153155
var attributes = GetAttributes(t.AttributeLists);
@@ -187,13 +189,13 @@ private static void ComputeDeclarations(
187189
{
188190
foreach (var decl in t.AccessorList.Accessors)
189191
{
190-
ComputeDeclarations(model, decl, shouldSkip, getSymbol, builder, newLevel, cancellationToken);
192+
ComputeDeclarations(model, associatedSymbol: null, decl, shouldSkip, getSymbol, builder, newLevel, cancellationToken);
191193
}
192194
}
193195

194196
if (t.ExpressionBody != null)
195197
{
196-
ComputeDeclarations(model, t.ExpressionBody, shouldSkip, getSymbol, builder, levelsToCompute, cancellationToken);
198+
ComputeDeclarations(model, associatedSymbol: null, t.ExpressionBody, shouldSkip, getSymbol, builder, levelsToCompute, cancellationToken);
197199
}
198200

199201
var attributes = GetAttributes(t.AttributeLists);
@@ -209,13 +211,13 @@ private static void ComputeDeclarations(
209211
{
210212
foreach (var decl in t.AccessorList.Accessors)
211213
{
212-
ComputeDeclarations(model, decl, shouldSkip, getSymbol, builder, newLevel, cancellationToken);
214+
ComputeDeclarations(model, associatedSymbol: null, decl, shouldSkip, getSymbol, builder, newLevel, cancellationToken);
213215
}
214216
}
215217

216218
if (t.ExpressionBody != null)
217219
{
218-
ComputeDeclarations(model, t.ExpressionBody, shouldSkip, getSymbol, builder, levelsToCompute, cancellationToken);
220+
ComputeDeclarations(model, associatedSymbol: null, t.ExpressionBody, shouldSkip, getSymbol, builder, levelsToCompute, cancellationToken);
219221
}
220222

221223
var codeBlocks = GetParameterListInitializersAndAttributes(t.ParameterList);
@@ -277,16 +279,25 @@ private static void ComputeDeclarations(
277279
case SyntaxKind.CompilationUnit:
278280
{
279281
var t = (CompilationUnitSyntax)node;
280-
foreach (var decl in t.Members)
282+
283+
if (associatedSymbol is IMethodSymbol)
281284
{
282-
ComputeDeclarations(model, decl, shouldSkip, getSymbol, builder, newLevel, cancellationToken);
285+
builder.Add(GetDeclarationInfo(model, node, getSymbol, new[] { t }, cancellationToken));
283286
}
284-
285-
if (t.AttributeLists.Any())
287+
else
286288
{
287-
var attributes = GetAttributes(t.AttributeLists);
288-
builder.Add(GetDeclarationInfo(model, node, getSymbol, attributes, cancellationToken));
289+
foreach (var decl in t.Members)
290+
{
291+
ComputeDeclarations(model, associatedSymbol: null, decl, shouldSkip, getSymbol, builder, newLevel, cancellationToken);
292+
}
293+
294+
if (t.AttributeLists.Any())
295+
{
296+
var attributes = GetAttributes(t.AttributeLists);
297+
builder.Add(GetDeclarationInfo(model, node, getSymbol: false, attributes, cancellationToken));
298+
}
289299
}
300+
290301
return;
291302
}
292303

src/Compilers/CSharp/Portable/Binder/Binder.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -387,7 +387,7 @@ internal virtual QuickAttributeChecker QuickAttributeChecker
387387
}
388388
}
389389

390-
internal virtual Imports GetImports(ConsList<TypeSymbol> basesBeingResolved)
390+
internal virtual Imports GetImports(ConsList<TypeSymbol>? basesBeingResolved)
391391
{
392392
RoslynDebug.Assert(Next is object);
393393
return Next.GetImports(basesBeingResolved);

0 commit comments

Comments
 (0)