diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml
index 4ea77816e3aab..49c955a19b4a3 100644
--- a/.github/ISSUE_TEMPLATE/config.yml
+++ b/.github/ISSUE_TEMPLATE/config.yml
@@ -1,5 +1,8 @@
blank_issues_enabled: true
contact_links:
+ - name: Report issues related to CAxxxx rules
+ url: https://github.com/dotnet/roslyn-analyzers/issues/new/choose
+ about: Enhancements and bug reports to CAxxxx rules are reported to dotnet/roslyn-analyzers repository.
- name: Suggest language feature
url: https://github.com/dotnet/csharplang/issues/new/choose
about: Language feature suggestions are discussed in dotnet/csharplang repository first.
diff --git a/azure-pipelines-official.yml b/azure-pipelines-official.yml
index f16df6c5ce694..35bb7e5b7e90f 100644
--- a/azure-pipelines-official.yml
+++ b/azure-pipelines-official.yml
@@ -59,6 +59,8 @@ variables:
value: true
- name: Insertion.TitlePrefix
value: '[Auto Insertion]'
+ - name: Insertion.TitleSuffix
+ value: '[Skip-SymbolCheck]'
stages:
@@ -296,7 +298,6 @@ stages:
- stage: insert
dependsOn:
- build
- - publish_using_darc
displayName: Insert to VS
jobs:
@@ -361,6 +362,7 @@ stages:
-insertionCount "1" `
-insertToolset "$(Insertion.InsertToolset)" `
-titlePrefix "$(Insertion.TitlePrefix)" `
+ -titleSuffix "$(Insertion.TitleSuffix)" `
-queueValidation "true" `
-requiredValueSentinel "REQUIRED" `
-reviewerGUID "6c25b447-1d90-4840-8fde-d8b22cb8733e" `
diff --git a/azure-pipelines-richnav.yml b/azure-pipelines-richnav.yml
index 7f37752a94118..d327060f6c65e 100644
--- a/azure-pipelines-richnav.yml
+++ b/azure-pipelines-richnav.yml
@@ -7,12 +7,14 @@ trigger:
- demos/*
# Branches that trigger builds on PR
-pr:
-- main
-- main-vs-deps
-- release/*
-- features/*
-- demos/*
+pr: none
+# Temporarily disabling richnav job on PRs
+# pr:
+# - main
+# - main-vs-deps
+# - release/*
+# - features/*
+# - demos/*
jobs:
- job: RichCodeNav_Indexing
diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml
index 629edf6934c73..e3d71b5799150 100644
--- a/eng/Version.Details.xml
+++ b/eng/Version.Details.xml
@@ -18,9 +18,9 @@
78da7776965b428ff31da8f1ff2cb073506212b7
-
+
https://github.com/dotnet/roslyn
- 03a07d1dd606ce11d62c9a595041c4c2d44c39e3
+ ca27d128f3533dc41a46b010b8e878916328f2e4
https://github.com/dotnet/arcade
diff --git a/eng/Versions.props b/eng/Versions.props
index c2b3f72ab58ce..1a88275962197 100644
--- a/eng/Versions.props
+++ b/eng/Versions.props
@@ -23,7 +23,7 @@
- 4.0.0-2.21327.4
+ 4.0.0-2.21359.14
diff --git a/eng/config/PublishData.json b/eng/config/PublishData.json
index 72df9d4da8fbc..b51b144524a5b 100644
--- a/eng/config/PublishData.json
+++ b/eng/config/PublishData.json
@@ -196,7 +196,7 @@
"version": "4.0.*",
"packageFeeds": "default",
"channels": [],
- "vsBranch": "main",
+ "vsBranch": "rel/d17.0",
"vsMajorVersion": 17,
"insertionTitlePrefix": "[d17p2]"
},
@@ -210,8 +210,7 @@
"channels": [],
"vsBranch": "main",
"vsMajorVersion": 17,
- "insertionCreateDraftPR": true,
- "insertionTitlePrefix": "[d17p3]"
+ "insertionCreateDraftPR": false
},
"main": {
"nugetKind": [
diff --git a/eng/pipelines/test-unix-job.yml b/eng/pipelines/test-unix-job.yml
index 8235d6ac21809..add1171b002a6 100644
--- a/eng/pipelines/test-unix-job.yml
+++ b/eng/pipelines/test-unix-job.yml
@@ -27,7 +27,7 @@ jobs:
# a thin client that kicks off a helix job and waits for it to complete.
# Thus we don't use a helix queue to run the job here, and instead use the plentiful AzDO vmImages.
vmImage: ubuntu-20.04
- timeoutInMinutes: 40
+ timeoutInMinutes: 90
steps:
- checkout: none
diff --git a/src/Analyzers/CSharp/CodeFixes/ConvertSwitchStatementToExpression/ConvertSwitchStatementToExpressionCodeFixProvider.cs b/src/Analyzers/CSharp/CodeFixes/ConvertSwitchStatementToExpression/ConvertSwitchStatementToExpressionCodeFixProvider.cs
index 2f36df1f646c4..df534932a3bdc 100644
--- a/src/Analyzers/CSharp/CodeFixes/ConvertSwitchStatementToExpression/ConvertSwitchStatementToExpressionCodeFixProvider.cs
+++ b/src/Analyzers/CSharp/CodeFixes/ConvertSwitchStatementToExpression/ConvertSwitchStatementToExpressionCodeFixProvider.cs
@@ -119,7 +119,7 @@ protected override async Task FixAllAsync(
private sealed class MyCodeAction : CustomCodeActions.DocumentChangeAction
{
public MyCodeAction(Func> createChangedDocument)
- : base(CSharpAnalyzersResources.Convert_switch_statement_to_expression, createChangedDocument)
+ : base(CSharpAnalyzersResources.Convert_switch_statement_to_expression, createChangedDocument, nameof(CSharpAnalyzersResources.Convert_switch_statement_to_expression))
{
}
}
diff --git a/src/Analyzers/CSharp/CodeFixes/InvokeDelegateWithConditionalAccess/InvokeDelegateWithConditionalAccessCodeFixProvider.cs b/src/Analyzers/CSharp/CodeFixes/InvokeDelegateWithConditionalAccess/InvokeDelegateWithConditionalAccessCodeFixProvider.cs
index 5665e0045e9fc..b106d7ad42428 100644
--- a/src/Analyzers/CSharp/CodeFixes/InvokeDelegateWithConditionalAccess/InvokeDelegateWithConditionalAccessCodeFixProvider.cs
+++ b/src/Analyzers/CSharp/CodeFixes/InvokeDelegateWithConditionalAccess/InvokeDelegateWithConditionalAccessCodeFixProvider.cs
@@ -166,7 +166,7 @@ private static T AppendTriviaWithoutEndOfLines(T newStatement, IfStatementSyn
private class MyCodeAction : CustomCodeActions.DocumentChangeAction
{
public MyCodeAction(Func> createChangedDocument)
- : base(CSharpAnalyzersResources.Delegate_invocation_can_be_simplified, createChangedDocument)
+ : base(CSharpAnalyzersResources.Delegate_invocation_can_be_simplified, createChangedDocument, nameof(CSharpAnalyzersResources.Delegate_invocation_can_be_simplified))
{
}
}
diff --git a/src/Analyzers/CSharp/CodeFixes/MakeStructFieldsWritable/CSharpMakeStructFieldsWritableCodeFixProvider.cs b/src/Analyzers/CSharp/CodeFixes/MakeStructFieldsWritable/CSharpMakeStructFieldsWritableCodeFixProvider.cs
index de4f87e2e1570..4051c106e79f5 100644
--- a/src/Analyzers/CSharp/CodeFixes/MakeStructFieldsWritable/CSharpMakeStructFieldsWritableCodeFixProvider.cs
+++ b/src/Analyzers/CSharp/CodeFixes/MakeStructFieldsWritable/CSharpMakeStructFieldsWritableCodeFixProvider.cs
@@ -79,7 +79,7 @@ protected override Task FixAllAsync(
private class MyCodeAction : CustomCodeActions.DocumentChangeAction
{
public MyCodeAction(Func> createChangedDocument)
- : base(CSharpAnalyzersResources.Make_readonly_fields_writable, createChangedDocument)
+ : base(CSharpAnalyzersResources.Make_readonly_fields_writable, createChangedDocument, nameof(CSharpAnalyzersResources.Make_readonly_fields_writable))
{
}
}
diff --git a/src/Analyzers/CSharp/CodeFixes/MisplacedUsingDirectives/MisplacedUsingDirectivesCodeFixProvider.cs b/src/Analyzers/CSharp/CodeFixes/MisplacedUsingDirectives/MisplacedUsingDirectivesCodeFixProvider.cs
index 46728cfa09c7e..0c4c0153d8bbc 100644
--- a/src/Analyzers/CSharp/CodeFixes/MisplacedUsingDirectives/MisplacedUsingDirectivesCodeFixProvider.cs
+++ b/src/Analyzers/CSharp/CodeFixes/MisplacedUsingDirectives/MisplacedUsingDirectivesCodeFixProvider.cs
@@ -423,7 +423,7 @@ private static CompilationUnitSyntax AddFileHeader(CompilationUnitSyntax compila
private class MoveMisplacedUsingsCodeAction : CustomCodeActions.DocumentChangeAction
{
public MoveMisplacedUsingsCodeAction(Func> createChangedDocument)
- : base(CSharpAnalyzersResources.Move_misplaced_using_directives, createChangedDocument)
+ : base(CSharpAnalyzersResources.Move_misplaced_using_directives, createChangedDocument, nameof(CSharpAnalyzersResources.Move_misplaced_using_directives))
{
}
}
diff --git a/src/Analyzers/CSharp/CodeFixes/RemoveUnnecessaryCast/CSharpRemoveUnnecessaryCastCodeFixProvider.cs b/src/Analyzers/CSharp/CodeFixes/RemoveUnnecessaryCast/CSharpRemoveUnnecessaryCastCodeFixProvider.cs
index b69ab50ccc5b5..69309be37e093 100644
--- a/src/Analyzers/CSharp/CodeFixes/RemoveUnnecessaryCast/CSharpRemoveUnnecessaryCastCodeFixProvider.cs
+++ b/src/Analyzers/CSharp/CodeFixes/RemoveUnnecessaryCast/CSharpRemoveUnnecessaryCastCodeFixProvider.cs
@@ -41,7 +41,6 @@ public CSharpRemoveUnnecessaryCastCodeFixProvider()
public sealed override Task RegisterCodeFixesAsync(CodeFixContext context)
{
context.RegisterCodeFix(new MyCodeAction(
- AnalyzersResources.Remove_Unnecessary_Cast,
c => FixAsync(context.Document, context.Diagnostics.First(), c)),
context.Diagnostics);
return Task.CompletedTask;
@@ -98,8 +97,8 @@ private ExpressionSyntax Recurse(ExpressionSyntax old)
private class MyCodeAction : CustomCodeActions.DocumentChangeAction
{
- public MyCodeAction(string title, Func> createChangedDocument)
- : base(title, createChangedDocument)
+ public MyCodeAction(Func> createChangedDocument)
+ : base(AnalyzersResources.Remove_Unnecessary_Cast, createChangedDocument, nameof(AnalyzersResources.Remove_Unnecessary_Cast))
{
}
}
diff --git a/src/Analyzers/CSharp/CodeFixes/UseExpressionBody/UseExpressionBodyCodeFixProvider.cs b/src/Analyzers/CSharp/CodeFixes/UseExpressionBody/UseExpressionBodyCodeFixProvider.cs
index e09d8c8075911..10f7e8738ac58 100644
--- a/src/Analyzers/CSharp/CodeFixes/UseExpressionBody/UseExpressionBodyCodeFixProvider.cs
+++ b/src/Analyzers/CSharp/CodeFixes/UseExpressionBody/UseExpressionBodyCodeFixProvider.cs
@@ -108,14 +108,14 @@ private class MyCodeAction : CustomCodeActions.DocumentChangeAction
{
#if CODE_STYLE // 'CodeActionPriority' is not a public API, hence not supported in CodeStyle layer.
public MyCodeAction(string title, Func> createChangedDocument)
- : base(title, createChangedDocument)
+ : base(title, createChangedDocument, title)
{
}
#else
internal override CodeActionPriority Priority { get; }
public MyCodeAction(string title, CodeActionPriority priority, Func> createChangedDocument)
- : base(title, createChangedDocument)
+ : base(title, createChangedDocument, title)
{
Priority = priority;
}
diff --git a/src/Analyzers/Core/CodeFixes/MakeFieldReadonly/AbstractMakeFieldReadonlyCodeFixProvider.cs b/src/Analyzers/Core/CodeFixes/MakeFieldReadonly/AbstractMakeFieldReadonlyCodeFixProvider.cs
index 91542e600ea95..97f67c73cc435 100644
--- a/src/Analyzers/Core/CodeFixes/MakeFieldReadonly/AbstractMakeFieldReadonlyCodeFixProvider.cs
+++ b/src/Analyzers/Core/CodeFixes/MakeFieldReadonly/AbstractMakeFieldReadonlyCodeFixProvider.cs
@@ -105,7 +105,7 @@ private static DeclarationModifiers WithReadOnly(DeclarationModifiers modifiers)
private class MyCodeAction : CustomCodeActions.DocumentChangeAction
{
public MyCodeAction(Func> createChangedDocument)
- : base(AnalyzersResources.Add_readonly_modifier, createChangedDocument)
+ : base(AnalyzersResources.Add_readonly_modifier, createChangedDocument, nameof(AnalyzersResources.Add_readonly_modifier))
{
}
}
diff --git a/src/Analyzers/Core/CodeFixes/MatchFolderAndNamespace/AbstractChangeNamespaceToMatchFolderCodeFixProvider.CustomFixAllProvider.cs b/src/Analyzers/Core/CodeFixes/MatchFolderAndNamespace/AbstractChangeNamespaceToMatchFolderCodeFixProvider.CustomFixAllProvider.cs
index 68e4558b8d6af..28cfe57790cb0 100644
--- a/src/Analyzers/Core/CodeFixes/MatchFolderAndNamespace/AbstractChangeNamespaceToMatchFolderCodeFixProvider.CustomFixAllProvider.cs
+++ b/src/Analyzers/Core/CodeFixes/MatchFolderAndNamespace/AbstractChangeNamespaceToMatchFolderCodeFixProvider.CustomFixAllProvider.cs
@@ -39,8 +39,9 @@ private class CustomFixAllProvider : FixAllProvider
if (diagnostics.IsDefaultOrEmpty)
return null;
+ var title = FixAllContextHelper.GetDefaultFixAllTitle(fixAllContext);
return new MyCodeAction(
- FixAllContextHelper.GetDefaultFixAllTitle(fixAllContext),
+ title,
cancellationToken => FixAllByDocumentAsync(
fixAllContext.Project.Solution,
diagnostics,
diff --git a/src/Analyzers/Core/CodeFixes/MatchFolderAndNamespace/AbstractChangeNamespaceToMatchFolderCodeFixProvider.cs b/src/Analyzers/Core/CodeFixes/MatchFolderAndNamespace/AbstractChangeNamespaceToMatchFolderCodeFixProvider.cs
index 94a21a782d2e5..af0a10d370e09 100644
--- a/src/Analyzers/Core/CodeFixes/MatchFolderAndNamespace/AbstractChangeNamespaceToMatchFolderCodeFixProvider.cs
+++ b/src/Analyzers/Core/CodeFixes/MatchFolderAndNamespace/AbstractChangeNamespaceToMatchFolderCodeFixProvider.cs
@@ -65,7 +65,7 @@ private static async Task FixAllInDocumentAsync(Document document, Imm
private sealed class MyCodeAction : CustomCodeActions.SolutionChangeAction
{
public MyCodeAction(string title, Func> createChangedSolution)
- : base(title, createChangedSolution)
+ : base(title, createChangedSolution, title)
{
}
}
diff --git a/src/Analyzers/Core/CodeFixes/RemoveUnnecessaryImports/AbstractRemoveUnnecessaryImportsCodeFixProvider.cs b/src/Analyzers/Core/CodeFixes/RemoveUnnecessaryImports/AbstractRemoveUnnecessaryImportsCodeFixProvider.cs
index 5f4f22e75a230..46b4b9eeced33 100644
--- a/src/Analyzers/Core/CodeFixes/RemoveUnnecessaryImports/AbstractRemoveUnnecessaryImportsCodeFixProvider.cs
+++ b/src/Analyzers/Core/CodeFixes/RemoveUnnecessaryImports/AbstractRemoveUnnecessaryImportsCodeFixProvider.cs
@@ -44,7 +44,7 @@ private static Task RemoveUnnecessaryImportsAsync(
private class MyCodeAction : CustomCodeActions.DocumentChangeAction
{
public MyCodeAction(string title, Func> createChangedDocument)
- : base(title, createChangedDocument)
+ : base(title, createChangedDocument, title)
{
}
}
diff --git a/src/Analyzers/Core/CodeFixes/RemoveUnusedMembers/AbstractRemoveUnusedMembersCodeFixProvider.cs b/src/Analyzers/Core/CodeFixes/RemoveUnusedMembers/AbstractRemoveUnusedMembersCodeFixProvider.cs
index 35f65b278b8ec..84341bcf02663 100644
--- a/src/Analyzers/Core/CodeFixes/RemoveUnusedMembers/AbstractRemoveUnusedMembersCodeFixProvider.cs
+++ b/src/Analyzers/Core/CodeFixes/RemoveUnusedMembers/AbstractRemoveUnusedMembersCodeFixProvider.cs
@@ -128,7 +128,7 @@ protected static void AdjustAndAddAppropriateDeclaratorsToRemove(SyntaxNode pare
private class MyCodeAction : CustomCodeActions.DocumentChangeAction
{
public MyCodeAction(Func> createChangedDocument)
- : base(AnalyzersResources.Remove_unused_member, createChangedDocument)
+ : base(AnalyzersResources.Remove_unused_member, createChangedDocument, nameof(AnalyzersResources.Remove_unused_member))
{
}
}
diff --git a/src/Analyzers/Core/CodeFixes/UseCoalesceExpression/UseCoalesceExpressionCodeFixProvider.cs b/src/Analyzers/Core/CodeFixes/UseCoalesceExpression/UseCoalesceExpressionCodeFixProvider.cs
index e1ea32784b3f7..6b6179144cba3 100644
--- a/src/Analyzers/Core/CodeFixes/UseCoalesceExpression/UseCoalesceExpressionCodeFixProvider.cs
+++ b/src/Analyzers/Core/CodeFixes/UseCoalesceExpression/UseCoalesceExpressionCodeFixProvider.cs
@@ -115,7 +115,7 @@ private static SyntaxNode GetCoalesceExpression(
private class MyCodeAction : CustomCodeActions.DocumentChangeAction
{
public MyCodeAction(Func> createChangedDocument)
- : base(AnalyzersResources.Use_coalesce_expression, createChangedDocument)
+ : base(AnalyzersResources.Use_coalesce_expression, createChangedDocument, nameof(AnalyzersResources.Use_coalesce_expression))
{
}
diff --git a/src/Analyzers/Core/CodeFixes/UseCoalesceExpression/UseCoalesceExpressionForNullableCodeFixProvider.cs b/src/Analyzers/Core/CodeFixes/UseCoalesceExpression/UseCoalesceExpressionForNullableCodeFixProvider.cs
index 38e6ed223e9b6..3c2be7100994a 100644
--- a/src/Analyzers/Core/CodeFixes/UseCoalesceExpression/UseCoalesceExpressionForNullableCodeFixProvider.cs
+++ b/src/Analyzers/Core/CodeFixes/UseCoalesceExpression/UseCoalesceExpressionForNullableCodeFixProvider.cs
@@ -91,7 +91,7 @@ protected override async Task FixAllAsync(
private class MyCodeAction : CustomCodeActions.DocumentChangeAction
{
public MyCodeAction(Func> createChangedDocument)
- : base(AnalyzersResources.Use_coalesce_expression, createChangedDocument)
+ : base(AnalyzersResources.Use_coalesce_expression, createChangedDocument, nameof(AnalyzersResources.Use_coalesce_expression))
{
}
diff --git a/src/Analyzers/Core/CodeFixes/UseCollectionInitializer/AbstractUseCollectionInitializerCodeFixProvider.cs b/src/Analyzers/Core/CodeFixes/UseCollectionInitializer/AbstractUseCollectionInitializerCodeFixProvider.cs
index f89e0935c7182..3761246a2e89f 100644
--- a/src/Analyzers/Core/CodeFixes/UseCollectionInitializer/AbstractUseCollectionInitializerCodeFixProvider.cs
+++ b/src/Analyzers/Core/CodeFixes/UseCollectionInitializer/AbstractUseCollectionInitializerCodeFixProvider.cs
@@ -126,7 +126,7 @@ protected abstract TStatementSyntax GetNewStatement(
private class MyCodeAction : CustomCodeActions.DocumentChangeAction
{
public MyCodeAction(Func> createChangedDocument)
- : base(AnalyzersResources.Collection_initialization_can_be_simplified, createChangedDocument)
+ : base(AnalyzersResources.Collection_initialization_can_be_simplified, createChangedDocument, nameof(AnalyzersResources.Collection_initialization_can_be_simplified))
{
}
}
diff --git a/src/Analyzers/Core/CodeFixes/UseNullPropagation/AbstractUseNullPropagationCodeFixProvider.cs b/src/Analyzers/Core/CodeFixes/UseNullPropagation/AbstractUseNullPropagationCodeFixProvider.cs
index 3b017bc2368fe..df4b76985f2c6 100644
--- a/src/Analyzers/Core/CodeFixes/UseNullPropagation/AbstractUseNullPropagationCodeFixProvider.cs
+++ b/src/Analyzers/Core/CodeFixes/UseNullPropagation/AbstractUseNullPropagationCodeFixProvider.cs
@@ -162,7 +162,7 @@ private SyntaxNode CreateConditionalAccessExpression(
private class MyCodeAction : CustomCodeActions.DocumentChangeAction
{
public MyCodeAction(Func> createChangedDocument)
- : base(AnalyzersResources.Use_null_propagation, createChangedDocument)
+ : base(AnalyzersResources.Use_null_propagation, createChangedDocument, nameof(AnalyzersResources.Use_null_propagation))
{
}
}
diff --git a/src/Analyzers/Core/CodeFixes/UseObjectInitializer/AbstractUseObjectInitializerCodeFixProvider.cs b/src/Analyzers/Core/CodeFixes/UseObjectInitializer/AbstractUseObjectInitializerCodeFixProvider.cs
index 5c9ef89534387..61b1b16d8ed99 100644
--- a/src/Analyzers/Core/CodeFixes/UseObjectInitializer/AbstractUseObjectInitializerCodeFixProvider.cs
+++ b/src/Analyzers/Core/CodeFixes/UseObjectInitializer/AbstractUseObjectInitializerCodeFixProvider.cs
@@ -125,7 +125,7 @@ protected abstract TStatementSyntax GetNewStatement(
private class MyCodeAction : CustomCodeActions.DocumentChangeAction
{
public MyCodeAction(Func> createChangedDocument)
- : base(AnalyzersResources.Object_initialization_can_be_simplified, createChangedDocument)
+ : base(AnalyzersResources.Object_initialization_can_be_simplified, createChangedDocument, nameof(AnalyzersResources.Object_initialization_can_be_simplified))
{
}
}
diff --git a/src/Analyzers/Core/CodeFixes/UseThrowExpression/UseThrowExpressionCodeFixProvider.cs b/src/Analyzers/Core/CodeFixes/UseThrowExpression/UseThrowExpressionCodeFixProvider.cs
index 24805a595c8e9..7b6c672038951 100644
--- a/src/Analyzers/Core/CodeFixes/UseThrowExpression/UseThrowExpressionCodeFixProvider.cs
+++ b/src/Analyzers/Core/CodeFixes/UseThrowExpression/UseThrowExpressionCodeFixProvider.cs
@@ -76,7 +76,7 @@ private class MyCodeAction : CustomCodeActions.DocumentChangeAction
{
public MyCodeAction(
Func> createChangedDocument)
- : base(AnalyzersResources.Use_throw_expression, createChangedDocument)
+ : base(AnalyzersResources.Use_throw_expression, createChangedDocument, nameof(AnalyzersResources.Use_throw_expression))
{
}
}
diff --git a/src/Analyzers/VisualBasic/CodeFixes/RemoveUnnecessaryByVal/VisualBasicRemoveUnnecessaryByValCodeFixProvider.vb b/src/Analyzers/VisualBasic/CodeFixes/RemoveUnnecessaryByVal/VisualBasicRemoveUnnecessaryByValCodeFixProvider.vb
index 3df6572f0ffd1..bd730f1af920b 100644
--- a/src/Analyzers/VisualBasic/CodeFixes/RemoveUnnecessaryByVal/VisualBasicRemoveUnnecessaryByValCodeFixProvider.vb
+++ b/src/Analyzers/VisualBasic/CodeFixes/RemoveUnnecessaryByVal/VisualBasicRemoveUnnecessaryByValCodeFixProvider.vb
@@ -31,7 +31,6 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.RemoveUnnecessaryByVal
Public Overrides Function RegisterCodeFixesAsync(context As CodeFixContext) As Task
For Each diagnostic In context.Diagnostics
context.RegisterCodeFix(New MyCodeAction(
- VisualBasicAnalyzersResources.Remove_ByVal,
Function(ct) FixAsync(context.Document, diagnostic, ct)),
diagnostic)
Next
@@ -51,8 +50,8 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.RemoveUnnecessaryByVal
Private Class MyCodeAction
Inherits CustomCodeActions.DocumentChangeAction
- Friend Sub New(title As String, createChangedDocument As Func(Of CancellationToken, Task(Of Document)))
- MyBase.New(title, createChangedDocument)
+ Friend Sub New(createChangedDocument As Func(Of CancellationToken, Task(Of Document)))
+ MyBase.New(VisualBasicAnalyzersResources.Remove_ByVal, createChangedDocument, NameOf(VisualBasicAnalyzersResources.Remove_ByVal))
End Sub
End Class
End Class
diff --git a/src/Analyzers/VisualBasic/CodeFixes/RemoveUnnecessaryCast/VisualBasicRemoveUnnecessaryCastCodeFixProvider.vb b/src/Analyzers/VisualBasic/CodeFixes/RemoveUnnecessaryCast/VisualBasicRemoveUnnecessaryCastCodeFixProvider.vb
index fc9d448a43b79..1a3347ddc78c0 100644
--- a/src/Analyzers/VisualBasic/CodeFixes/RemoveUnnecessaryCast/VisualBasicRemoveUnnecessaryCastCodeFixProvider.vb
+++ b/src/Analyzers/VisualBasic/CodeFixes/RemoveUnnecessaryCast/VisualBasicRemoveUnnecessaryCastCodeFixProvider.vb
@@ -38,7 +38,6 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.RemoveUnnecessaryCast
Public Overrides Function RegisterCodeFixesAsync(context As CodeFixContext) As Task
context.RegisterCodeFix(New MyCodeAction(
- AnalyzersResources.Remove_Unnecessary_Cast,
Function(c) FixAsync(context.Document, context.Diagnostics.First(), c)),
context.Diagnostics)
Return Task.CompletedTask
@@ -173,8 +172,8 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.RemoveUnnecessaryCast
Private Class MyCodeAction
Inherits CustomCodeActions.DocumentChangeAction
- Public Sub New(title As String, createChangedDocument As Func(Of CancellationToken, Task(Of Document)))
- MyBase.New(title, createChangedDocument)
+ Public Sub New(createChangedDocument As Func(Of CancellationToken, Task(Of Document)))
+ MyBase.New(AnalyzersResources.Remove_Unnecessary_Cast, createChangedDocument, NameOf(AnalyzersResources.Remove_Unnecessary_Cast))
End Sub
End Class
End Class
diff --git a/src/Compilers/CSharp/CSharpAnalyzerDriver/CSharpDeclarationComputer.cs b/src/Compilers/CSharp/CSharpAnalyzerDriver/CSharpDeclarationComputer.cs
index f7e4503bb47d1..cb7937b2de234 100644
--- a/src/Compilers/CSharp/CSharpAnalyzerDriver/CSharpDeclarationComputer.cs
+++ b/src/Compilers/CSharp/CSharpAnalyzerDriver/CSharpDeclarationComputer.cs
@@ -75,8 +75,9 @@ private static void ComputeDeclarations(
switch (node.Kind())
{
case SyntaxKind.NamespaceDeclaration:
+ case SyntaxKind.FileScopedNamespaceDeclaration:
{
- var ns = (NamespaceDeclarationSyntax)node;
+ var ns = (BaseNamespaceDeclarationSyntax)node;
foreach (var decl in ns.Members)
{
ComputeDeclarations(model, associatedSymbol: null, decl, shouldSkip, getSymbol, builder, newLevel, cancellationToken);
diff --git a/src/Compilers/CSharp/Portable/Binder/Binder.ValueChecks.cs b/src/Compilers/CSharp/Portable/Binder/Binder.ValueChecks.cs
index 93f4bfed5391f..dbba1849b977e 100644
--- a/src/Compilers/CSharp/Portable/Binder/Binder.ValueChecks.cs
+++ b/src/Compilers/CSharp/Portable/Binder/Binder.ValueChecks.cs
@@ -1261,6 +1261,15 @@ private bool IsBadBaseAccess(SyntaxNode node, BoundExpression receiverOpt, Symbo
return false;
}
+ internal static uint GetInterpolatedStringHandlerConversionEscapeScope(
+ BoundInterpolatedString interpolatedString,
+ uint scopeOfTheContainingExpression)
+ {
+ Debug.Assert(interpolatedString.InterpolationData != null);
+ var data = interpolatedString.InterpolationData.GetValueOrDefault();
+ return GetValEscape(data.Construction, scopeOfTheContainingExpression);
+ }
+
///
/// Computes the scope to which the given invocation can escape
/// NOTE: the escape scope for ref and val escapes is the same for invocations except for trivial cases (ordinary type returned by val)
@@ -2661,6 +2670,11 @@ internal static uint GetValEscape(BoundExpression expr, uint scopeOfTheContainin
var conversion = (BoundConversion)expr;
Debug.Assert(conversion.ConversionKind != ConversionKind.StackAllocToSpanType, "StackAllocToSpanType unexpected");
+ if (conversion.ConversionKind == ConversionKind.InterpolatedStringHandler)
+ {
+ return GetInterpolatedStringHandlerConversionEscapeScope((BoundInterpolatedString)conversion.Operand, scopeOfTheContainingExpression);
+ }
+
return GetValEscape(conversion.Operand, scopeOfTheContainingExpression);
case BoundKind.AssignmentOperator:
@@ -2717,6 +2731,15 @@ internal static uint GetValEscape(BoundExpression expr, uint scopeOfTheContainin
// just say it does not escape anywhere, so that we do not get false errors.
return scopeOfTheContainingExpression;
+ case BoundKind.InterpolatedStringHandlerPlaceholder:
+ // The handler placeholder cannot escape out of the current expression, as it's a compiler-synthesized
+ // location.
+ return scopeOfTheContainingExpression;
+
+ case BoundKind.InterpolatedStringArgumentPlaceholder:
+ // We saved off the safe-to-escape of the argument when we did binding
+ return ((BoundInterpolatedStringArgumentPlaceholder)expr).ValSafeToEscape;
+
case BoundKind.DisposableValuePlaceholder:
// Disposable value placeholder is only ever used to lookup a pattern dispose method
// then immediately discarded. The actual expression will be generated during lowering
@@ -2867,6 +2890,14 @@ internal static bool CheckValEscape(SyntaxNode node, BoundExpression expr, uint
}
return true;
+ case BoundKind.InterpolatedStringArgumentPlaceholder:
+ if (((BoundInterpolatedStringArgumentPlaceholder)expr).ValSafeToEscape > escapeTo)
+ {
+ Error(diagnostics, ErrorCode.ERR_EscapeLocal, node, expr.Syntax);
+ return false;
+ }
+ return true;
+
case BoundKind.Local:
var localSymbol = ((BoundLocal)expr).LocalSymbol;
if (localSymbol.ValEscapeScope > escapeTo)
@@ -3076,6 +3107,12 @@ internal static bool CheckValEscape(SyntaxNode node, BoundExpression expr, uint
case BoundKind.Conversion:
var conversion = (BoundConversion)expr;
Debug.Assert(conversion.ConversionKind != ConversionKind.StackAllocToSpanType, "StackAllocToSpanType unexpected");
+
+ if (conversion.ConversionKind == ConversionKind.InterpolatedStringHandler)
+ {
+ return CheckInterpolatedStringHandlerConversionEscape((BoundInterpolatedString)conversion.Operand, escapeFrom, escapeTo, diagnostics);
+ }
+
return CheckValEscape(node, conversion.Operand, escapeFrom, escapeTo, checkingReceiver: false, diagnostics: diagnostics);
case BoundKind.AssignmentOperator:
@@ -3346,6 +3383,40 @@ private static bool CheckValEscape(ImmutableArray expressions,
return true;
}
+ private static bool CheckInterpolatedStringHandlerConversionEscape(BoundInterpolatedString interpolatedString, uint escapeFrom, uint escapeTo, BindingDiagnosticBag diagnostics)
+ {
+ Debug.Assert(interpolatedString.InterpolationData is not null);
+
+ // We need to check to see if any values could potentially escape outside the max depth via the handler type.
+ // Consider the case where a ref-struct handler saves off the result of one call to AppendFormatted,
+ // and then on a subsequent call it either assigns that saved value to another ref struct with a larger
+ // escape, or does the opposite. In either case, we need to check.
+
+ CheckValEscape(interpolatedString.Syntax, interpolatedString.InterpolationData.GetValueOrDefault().Construction, escapeFrom, escapeTo, checkingReceiver: false, diagnostics);
+
+ foreach (var part in interpolatedString.Parts)
+ {
+ if (part is not BoundCall { Method: { Name: "AppendFormatted" } } call)
+ {
+ // Dynamic calls cannot have ref struct parameters, and AppendLiteral calls will always have literal
+ // string arguments and do not require us to be concerned with escape
+ continue;
+ }
+
+ // The interpolation component is always the first argument to the method, and it was not passed by name
+ // so there can be no reordering.
+ var argument = call.Arguments[0];
+ var success = CheckValEscape(argument.Syntax, argument, escapeFrom, escapeTo, checkingReceiver: false, diagnostics);
+
+ if (!success)
+ {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
internal enum AddressKind
{
// reference may be written to
diff --git a/src/Compilers/CSharp/Portable/Binder/BinderFactory.BinderFactoryVisitor.cs b/src/Compilers/CSharp/Portable/Binder/BinderFactory.BinderFactoryVisitor.cs
index ac2e06add3d45..a6323c00edf77 100644
--- a/src/Compilers/CSharp/Portable/Binder/BinderFactory.BinderFactoryVisitor.cs
+++ b/src/Compilers/CSharp/Portable/Binder/BinderFactory.BinderFactoryVisitor.cs
@@ -758,7 +758,7 @@ public override Binder VisitInterfaceDeclaration(InterfaceDeclarationSyntax node
public override Binder VisitRecordDeclaration(RecordDeclarationSyntax node)
=> VisitTypeDeclarationCore(node);
- public override Binder VisitNamespaceDeclaration(NamespaceDeclarationSyntax parent)
+ public sealed override Binder VisitNamespaceDeclaration(NamespaceDeclarationSyntax parent)
{
if (!LookupPosition.IsInNamespaceDeclaration(_position, parent))
{
@@ -774,7 +774,22 @@ public override Binder VisitNamespaceDeclaration(NamespaceDeclarationSyntax pare
return VisitNamespaceDeclaration(parent, _position, inBody, inUsing);
}
- internal Binder VisitNamespaceDeclaration(NamespaceDeclarationSyntax parent, int position, bool inBody, bool inUsing)
+ public override Binder VisitFileScopedNamespaceDeclaration(FileScopedNamespaceDeclarationSyntax parent)
+ {
+ if (!LookupPosition.IsInNamespaceDeclaration(_position, parent))
+ {
+ return VisitCore(parent.Parent);
+ }
+
+ // Anywhere after the `;` is in the 'body' of this namespace.
+ bool inBody = _position >= parent.SemicolonToken.EndPosition;
+
+ bool inUsing = IsInUsing(parent);
+
+ return VisitNamespaceDeclaration(parent, _position, inBody, inUsing);
+ }
+
+ internal Binder VisitNamespaceDeclaration(BaseNamespaceDeclarationSyntax parent, int position, bool inBody, bool inUsing)
{
Debug.Assert(!inUsing || inBody, "inUsing => inBody");
@@ -840,7 +855,7 @@ private static Binder MakeNamespaceBinder(CSharpSyntaxNode node, NameSyntax name
NamespaceSymbol ns = ((NamespaceSymbol)container).GetNestedNamespace(name);
if ((object)ns == null) return outer;
- if (node is NamespaceDeclarationSyntax namespaceDecl)
+ if (node is BaseNamespaceDeclarationSyntax namespaceDecl)
{
outer = AddInImportsBinders((SourceNamespaceSymbol)outer.Compilation.SourceModule.GetModuleNamespace(ns), namespaceDecl, outer, inUsing);
}
@@ -957,7 +972,7 @@ internal Binder VisitCompilationUnit(CompilationUnitSyntax compilationUnit, bool
private static Binder AddInImportsBinders(SourceNamespaceSymbol declaringSymbol, CSharpSyntaxNode declarationSyntax, Binder next, bool inUsing)
{
- Debug.Assert(declarationSyntax.IsKind(SyntaxKind.CompilationUnit) || declarationSyntax.IsKind(SyntaxKind.NamespaceDeclaration));
+ Debug.Assert(declarationSyntax.Kind() is SyntaxKind.CompilationUnit or SyntaxKind.NamespaceDeclaration or SyntaxKind.FileScopedNamespaceDeclaration);
if (inUsing)
{
diff --git a/src/Compilers/CSharp/Portable/Binder/BinderFactory.cs b/src/Compilers/CSharp/Portable/Binder/BinderFactory.cs
index ef4a330d5a7ae..7c45b4cd1e836 100644
--- a/src/Compilers/CSharp/Portable/Binder/BinderFactory.cs
+++ b/src/Compilers/CSharp/Portable/Binder/BinderFactory.cs
@@ -173,10 +173,11 @@ internal Binder GetInNamespaceBinder(CSharpSyntaxNode unit)
switch (unit.Kind())
{
case SyntaxKind.NamespaceDeclaration:
+ case SyntaxKind.FileScopedNamespaceDeclaration:
{
BinderFactoryVisitor visitor = _binderFactoryVisitorPool.Allocate();
visitor.Initialize(0, null, null);
- Binder result = visitor.VisitNamespaceDeclaration((NamespaceDeclarationSyntax)unit, unit.SpanStart, inBody: true, inUsing: false);
+ Binder result = visitor.VisitNamespaceDeclaration((BaseNamespaceDeclarationSyntax)unit, unit.SpanStart, inBody: true, inUsing: false);
_binderFactoryVisitorPool.Free(visitor);
return result;
}
diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_Attributes.cs b/src/Compilers/CSharp/Portable/Binder/Binder_Attributes.cs
index d1586fcb68699..766776e69ef34 100644
--- a/src/Compilers/CSharp/Portable/Binder/Binder_Attributes.cs
+++ b/src/Compilers/CSharp/Portable/Binder/Binder_Attributes.cs
@@ -188,7 +188,7 @@ private BoundAttribute BindAttributeCore(AttributeSyntax node, NamedTypeSymbol a
}
}
- ImmutableArray boundConstructorArgumentNamesOpt = analyzedArguments.ConstructorArguments.GetNames();
+ ImmutableArray boundConstructorArgumentNamesOpt = analyzedArguments.ConstructorArguments.GetNames();
ImmutableArray boundNamedArguments = analyzedArguments.NamedArguments?.ToImmutableAndFree() ?? ImmutableArray.Empty;
Debug.Assert(boundNamedArguments.All(arg => !arg.Right.NeedsToBeConverted()));
@@ -591,7 +591,7 @@ private ImmutableArray GetRewrittenAttributeConstructorArguments(
out ImmutableArray constructorArgumentsSourceIndices,
MethodSymbol attributeConstructor,
ImmutableArray constructorArgsArray,
- ImmutableArray constructorArgumentNamesOpt,
+ ImmutableArray constructorArgumentNamesOpt,
AttributeSyntax syntax,
BindingDiagnosticBag diagnostics,
ref bool hasErrors)
@@ -721,7 +721,7 @@ private static int[] CreateSourceIndicesArray(int paramIndex, int parameterCount
private TypedConstant GetMatchingNamedOrOptionalConstructorArgument(
out int matchingArgumentIndex,
ImmutableArray constructorArgsArray,
- ImmutableArray constructorArgumentNamesOpt,
+ ImmutableArray constructorArgumentNamesOpt,
ParameterSymbol parameter,
int startIndex,
int argumentsCount,
@@ -748,7 +748,7 @@ private TypedConstant GetMatchingNamedOrOptionalConstructorArgument(
}
}
- private static int GetMatchingNamedConstructorArgumentIndex(string parameterName, ImmutableArray argumentNamesOpt, int startIndex, int argumentsCount)
+ private static int GetMatchingNamedConstructorArgumentIndex(string parameterName, ImmutableArray argumentNamesOpt, int startIndex, int argumentsCount)
{
RoslynDebug.Assert(parameterName != null);
Debug.Assert(startIndex >= 0 && startIndex < argumentsCount);
@@ -877,7 +877,7 @@ private TypedConstant GetDefaultValueArgument(ParameterSymbol parameter, Attribu
}
private static TypedConstant GetParamArrayArgument(ParameterSymbol parameter, ImmutableArray constructorArgsArray,
- ImmutableArray constructorArgumentNamesOpt, int argumentsCount, int argsConsumedCount, Conversions conversions, out bool foundNamed)
+ ImmutableArray constructorArgumentNamesOpt, int argumentsCount, int argsConsumedCount, Conversions conversions, out bool foundNamed)
{
Debug.Assert(argsConsumedCount <= argumentsCount);
diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_Conversions.cs b/src/Compilers/CSharp/Portable/Binder/Binder_Conversions.cs
index 19405f567c66c..a4555b2a11018 100644
--- a/src/Compilers/CSharp/Portable/Binder/Binder_Conversions.cs
+++ b/src/Compilers/CSharp/Portable/Binder/Binder_Conversions.cs
@@ -143,12 +143,27 @@ protected BoundExpression CreateConversion(
var unconvertedSource = (BoundUnconvertedInterpolatedString)source;
source = new BoundInterpolatedString(
unconvertedSource.Syntax,
- unconvertedSource.Parts,
+ interpolationData: null,
+ BindInterpolatedStringParts(unconvertedSource, diagnostics),
unconvertedSource.ConstantValue,
unconvertedSource.Type,
unconvertedSource.HasErrors);
}
+ if (conversion.Kind == ConversionKind.InterpolatedStringHandler)
+ {
+ var unconvertedSource = (BoundUnconvertedInterpolatedString)source;
+ return new BoundConversion(
+ syntax,
+ BindUnconvertedInterpolatedStringToHandlerType(unconvertedSource, (NamedTypeSymbol)destination, diagnostics, isHandlerConversion: true),
+ conversion,
+ @checked: CheckOverflowAtRuntime,
+ explicitCastInCode: isCast && !wasCompilerGenerated,
+ conversionGroupOpt,
+ constantValueOpt: null,
+ destination);
+ }
+
if (source.Kind == BoundKind.UnconvertedSwitchExpression)
{
TypeSymbol? type = source.Type;
diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs b/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs
index 24f36003c8f29..e3b9bf1aa121d 100644
--- a/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs
+++ b/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs
@@ -167,13 +167,14 @@ private BoundBadExpression BadExpression(SyntaxNode syntax, LookupResultKind res
/// Generates a new with no known type, given lookupResultKind and given symbols for GetSemanticInfo API,
/// and the given bound children.
///
- private BoundBadExpression BadExpression(SyntaxNode syntax, LookupResultKind resultKind, ImmutableArray symbols, ImmutableArray childNodes)
+ private BoundBadExpression BadExpression(SyntaxNode syntax, LookupResultKind resultKind, ImmutableArray symbols, ImmutableArray childNodes, bool wasCompilerGenerated = false)
{
return new BoundBadExpression(syntax,
resultKind,
symbols,
childNodes.SelectAsArray((e, self) => self.BindToTypeForErrorRecovery(e), this),
- CreateErrorType());
+ CreateErrorType())
+ { WasCompilerGenerated = wasCompilerGenerated };
}
///
@@ -376,14 +377,7 @@ internal BoundExpression BindToNaturalType(BoundExpression expression, BindingDi
break;
case BoundUnconvertedInterpolatedString unconvertedInterpolatedString:
{
- // We determine the best method of emitting as a string (either via Concat, Format, or the builder pattern)
- // during lowering, and it's not part of the publicly-visible API, unlike conversion to a builder type.
- result = new BoundInterpolatedString(
- unconvertedInterpolatedString.Syntax,
- unconvertedInterpolatedString.Parts,
- unconvertedInterpolatedString.ConstantValue,
- unconvertedInterpolatedString.Type,
- unconvertedInterpolatedString.HasErrors);
+ result = BindUnconvertedInterpolatedStringToString(unconvertedInterpolatedString, diagnostics);
}
break;
default:
@@ -2918,7 +2912,7 @@ private void BindArgumentAndName(
}
}
- result.Names.Add(nameColonSyntax.Name);
+ result.AddName(nameColonSyntax.Name);
}
else if (hasNames)
{
@@ -2963,10 +2957,14 @@ private BoundExpression BindArgumentExpression(BindingDiagnosticBag diagnostics,
return argument;
}
+#nullable enable
private void CoerceArguments(
MemberResolutionResult methodResult,
ArrayBuilder arguments,
- BindingDiagnosticBag diagnostics)
+ BindingDiagnosticBag diagnostics,
+ TypeSymbol? receiverType,
+ RefKind? receiverRefKind,
+ uint receiverEscapeScope)
where TMember : Symbol
{
var result = methodResult.Result;
@@ -2979,18 +2977,18 @@ private void CoerceArguments(
var kind = result.ConversionForArg(arg);
BoundExpression argument = arguments[arg];
+ if (kind.IsInterpolatedStringHandler)
+ {
+ Debug.Assert(argument is BoundUnconvertedInterpolatedString);
+ TypeWithAnnotations parameterTypeWithAnnotations = GetCorrespondingParameterTypeWithAnnotations(ref result, parameters, arg);
+ reportUnsafeIfNeeded(methodResult, diagnostics, argument, parameterTypeWithAnnotations);
+ arguments[arg] = BindInterpolatedStringHandlerInMemberCall((BoundUnconvertedInterpolatedString)argument, arguments, parameters, ref result, arg, receiverType, receiverRefKind, receiverEscapeScope, diagnostics);
+ }
// https://github.com/dotnet/roslyn/issues/37119 : should we create an (Identity) conversion when the kind is Identity but the types differ?
- if (!kind.IsIdentity)
+ else if (!kind.IsIdentity)
{
TypeWithAnnotations parameterTypeWithAnnotations = GetCorrespondingParameterTypeWithAnnotations(ref result, parameters, arg);
-
- // NOTE: for some reason, dev10 doesn't report this for indexer accesses.
- if (!methodResult.Member.IsIndexer() && !argument.HasAnyErrors && parameterTypeWithAnnotations.Type.IsUnsafe())
- {
- // CONSIDER: dev10 uses the call syntax, but this seems clearer.
- ReportUnsafeIfNotAllowed(argument.Syntax, diagnostics);
- //CONSIDER: Return a bad expression so that HasErrors is true?
- }
+ reportUnsafeIfNeeded(methodResult, diagnostics, argument, parameterTypeWithAnnotations);
arguments[arg] = CreateConversion(argument.Syntax, argument, kind, isCast: false, conversionGroupOpt: null, parameterTypeWithAnnotations.Type, diagnostics);
}
@@ -3013,7 +3011,7 @@ private void CoerceArguments(
else if (argument.NeedsToBeConverted())
{
Debug.Assert(kind.IsIdentity);
- if (argument is BoundTupleLiteral sourceTuple)
+ if (argument is BoundTupleLiteral)
{
TypeWithAnnotations parameterTypeWithAnnotations = GetCorrespondingParameterTypeWithAnnotations(ref result, parameters, arg);
// CreateConversion reports tuple literal name mismatches, and constructs the expected pattern of bound nodes.
@@ -3025,8 +3023,26 @@ private void CoerceArguments(
}
}
}
+
+ void reportUnsafeIfNeeded(MemberResolutionResult methodResult, BindingDiagnosticBag diagnostics, BoundExpression argument, TypeWithAnnotations parameterTypeWithAnnotations)
+ {
+ // NOTE: for some reason, dev10 doesn't report this for indexer accesses.
+ if (!methodResult.Member.IsIndexer() && !argument.HasAnyErrors && parameterTypeWithAnnotations.Type.IsUnsafe())
+ {
+ // CONSIDER: dev10 uses the call syntax, but this seems clearer.
+ ReportUnsafeIfNotAllowed(argument.Syntax, diagnostics);
+ //CONSIDER: Return a bad expression so that HasErrors is true?
+ }
+ }
}
+ private static ParameterSymbol GetCorrespondingParameter(ref MemberAnalysisResult result, ImmutableArray parameters, int arg)
+ {
+ int paramNum = result.ParameterFromArgument(arg);
+ return parameters[paramNum];
+ }
+#nullable disable
+
private static TypeWithAnnotations GetCorrespondingParameterTypeWithAnnotations(ref MemberAnalysisResult result, ImmutableArray parameters, int arg)
{
int paramNum = result.ParameterFromArgument(arg);
@@ -4406,6 +4422,41 @@ private BoundExpression BindClassCreationExpression(ObjectCreationExpressionSynt
}
}
+#nullable enable
+ ///
+ /// Helper method to create a synthesized constructor invocation.
+ ///
+ private BoundExpression MakeConstructorInvocation(
+ NamedTypeSymbol type,
+ ArrayBuilder arguments,
+ ArrayBuilder refKinds,
+ SyntaxNode node,
+ BindingDiagnosticBag diagnostics)
+ {
+ Debug.Assert(type.TypeKind is TypeKind.Class or TypeKind.Struct);
+ var analyzedArguments = AnalyzedArguments.GetInstance();
+
+ try
+ {
+ analyzedArguments.Arguments.AddRange(arguments);
+ analyzedArguments.RefKinds.AddRange(refKinds);
+
+ if (type.IsStatic)
+ {
+ diagnostics.Add(ErrorCode.ERR_InstantiatingStaticClass, node.Location, type);
+ return MakeBadExpressionForObjectCreation(node, type, analyzedArguments, initializerOpt: null, typeSyntax: null, diagnostics, wasCompilerGenerated: true);
+ }
+
+ var creation = BindClassCreationExpression(node, type.Name, node, type, analyzedArguments, diagnostics);
+ creation.WasCompilerGenerated = true;
+ return creation;
+ }
+ finally
+ {
+ analyzedArguments.Free();
+ }
+ }
+
internal BoundExpression BindObjectCreationForErrorRecovery(BoundUnconvertedObjectCreationExpression node, BindingDiagnosticBag diagnostics)
{
var arguments = AnalyzedArguments.GetInstance(node.Arguments, node.ArgumentRefKindsOpt, node.ArgumentNamesOpt);
@@ -4414,17 +4465,19 @@ internal BoundExpression BindObjectCreationForErrorRecovery(BoundUnconvertedObje
return result;
}
- private BoundExpression MakeBadExpressionForObjectCreation(ObjectCreationExpressionSyntax node, TypeSymbol type, AnalyzedArguments analyzedArguments, BindingDiagnosticBag diagnostics)
+ private BoundExpression MakeBadExpressionForObjectCreation(ObjectCreationExpressionSyntax node, TypeSymbol type, AnalyzedArguments analyzedArguments, BindingDiagnosticBag diagnostics, bool wasCompilerGenerated = false)
{
- return MakeBadExpressionForObjectCreation(node, type, analyzedArguments, node.Initializer, node.Type, diagnostics);
+ return MakeBadExpressionForObjectCreation(node, type, analyzedArguments, node.Initializer, node.Type, diagnostics, wasCompilerGenerated);
}
- private BoundExpression MakeBadExpressionForObjectCreation(SyntaxNode node, TypeSymbol type, AnalyzedArguments analyzedArguments, InitializerExpressionSyntax initializerOpt, SyntaxNode typeSyntax, BindingDiagnosticBag diagnostics)
+ /// Shouldn't be null if is not null.
+ private BoundExpression MakeBadExpressionForObjectCreation(SyntaxNode node, TypeSymbol type, AnalyzedArguments analyzedArguments, InitializerExpressionSyntax? initializerOpt, SyntaxNode? typeSyntax, BindingDiagnosticBag diagnostics, bool wasCompilerGenerated = false)
{
var children = ArrayBuilder.GetInstance();
children.AddRange(BuildArgumentsForErrorRecovery(analyzedArguments));
if (initializerOpt != null)
{
+ Debug.Assert(typeSyntax is not null);
var boundInitializer = BindInitializerExpression(syntax: initializerOpt,
type: type,
typeSyntax: typeSyntax,
@@ -4433,8 +4486,9 @@ private BoundExpression MakeBadExpressionForObjectCreation(SyntaxNode node, Type
children.Add(boundInitializer);
}
- return new BoundBadExpression(node, LookupResultKind.NotCreatable, ImmutableArray.Create(type), children.ToImmutableAndFree(), type);
+ return new BoundBadExpression(node, LookupResultKind.NotCreatable, ImmutableArray.Create(type), children.ToImmutableAndFree(), type) { WasCompilerGenerated = wasCompilerGenerated };
}
+#nullable disable
private BoundObjectInitializerExpressionBase BindInitializerExpression(
InitializerExpressionSyntax syntax,
@@ -5242,19 +5296,17 @@ protected BoundExpression BindClassCreationExpression(
}
}
- MemberResolutionResult memberResolutionResult;
- ImmutableArray candidateConstructors;
if (TryPerformConstructorOverloadResolution(
- type,
- analyzedArguments,
- typeName,
- typeNode.Location,
- hasErrors, //don't cascade in these cases
- diagnostics,
- out memberResolutionResult,
- out candidateConstructors,
- allowProtectedConstructorsOfBaseType: false))
+ type,
+ analyzedArguments,
+ typeName,
+ typeNode.Location,
+ hasErrors, //don't cascade in these cases
+ diagnostics,
+ out MemberResolutionResult memberResolutionResult,
+ out ImmutableArray candidateConstructors,
+ allowProtectedConstructorsOfBaseType: false))
{
var method = memberResolutionResult.Member;
@@ -5577,7 +5629,7 @@ private BoundExpression BindTypeParameterCreationExpression(SyntaxNode node, Typ
/// of this method (i.e. not populating a pre-existing ).
/// Presently, rationalizing this behavior is not worthwhile.
///
- private bool TryPerformConstructorOverloadResolution(
+ internal bool TryPerformConstructorOverloadResolution(
NamedTypeSymbol typeContainingConstructors,
AnalyzedArguments analyzedArguments,
string errorName,
@@ -5638,7 +5690,7 @@ private bool TryPerformConstructorOverloadResolution(
if (succeededIgnoringAccessibility)
{
- this.CoerceArguments(result.ValidResult, analyzedArguments.Arguments, diagnostics);
+ this.CoerceArguments(result.ValidResult, analyzedArguments.Arguments, diagnostics, receiverType: null, receiverRefKind: null, receiverEscapeScope: Binder.ExternalScope);
}
// Fill in the out parameter with the result, if there was one; it might be inaccessible.
@@ -6328,7 +6380,8 @@ private BoundExpression BindInstanceMemberAccess(
ImmutableArray typeArgumentsWithAnnotations,
bool invoked,
bool indexed,
- BindingDiagnosticBag diagnostics)
+ BindingDiagnosticBag diagnostics,
+ bool searchExtensionMethodsIfNecessary = true)
{
Debug.Assert(rightArity == (typeArgumentsWithAnnotations.IsDefault ? 0 : typeArgumentsWithAnnotations.Length));
var leftType = boundLeft.Type;
@@ -6359,7 +6412,7 @@ private BoundExpression BindInstanceMemberAccess(
// SPEC: Otherwise, an attempt is made to process E.I as an extension method invocation.
// SPEC: If this fails, E.I is an invalid member reference, and a binding-time error occurs.
- var searchExtensionMethodsIfNecessary = !leftIsBaseReference;
+ searchExtensionMethodsIfNecessary = searchExtensionMethodsIfNecessary && !leftIsBaseReference;
BoundMethodGroupFlags flags = 0;
if (searchExtensionMethodsIfNecessary)
@@ -7875,7 +7928,11 @@ private BoundExpression BindIndexerOrIndexedPropertyAccess(
{
MemberResolutionResult resolutionResult = overloadResolutionResult.ValidResult;
PropertySymbol property = resolutionResult.Member;
- this.CoerceArguments(resolutionResult, analyzedArguments.Arguments, diagnostics);
+ RefKind? receiverRefKind = receiverOpt?.GetRefKind();
+ uint receiverEscapeScope = property.RequiresInstanceReceiver && receiverOpt != null
+ ? receiverRefKind?.IsWritableReference() == true ? GetRefEscape(receiverOpt, LocalScopeDepth) : GetValEscape(receiverOpt, LocalScopeDepth)
+ : Binder.ExternalScope;
+ this.CoerceArguments(resolutionResult, analyzedArguments.Arguments, diagnostics, receiverOpt?.Type, receiverRefKind, receiverEscapeScope);
var isExpanded = resolutionResult.Result.Kind == MemberResolutionKind.ApplicableInExpandedForm;
var argsToParams = resolutionResult.Result.ArgsToParamsOpt;
@@ -8106,7 +8163,7 @@ method.OriginalDefinition is var original &&
argIsRange
? ErrorCode.ERR_ImplicitRangeIndexerWithName
: ErrorCode.ERR_ImplicitIndexIndexerWithName,
- arguments.Names[0].GetLocation());
+ arguments.Names[0].GetValueOrDefault().Location);
}
return true;
diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_InterpolatedString.cs b/src/Compilers/CSharp/Portable/Binder/Binder_InterpolatedString.cs
index 963438c5abdf7..14f0a90213d07 100644
--- a/src/Compilers/CSharp/Portable/Binder/Binder_InterpolatedString.cs
+++ b/src/Compilers/CSharp/Portable/Binder/Binder_InterpolatedString.cs
@@ -2,7 +2,10 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
+using System.Collections.Immutable;
using System.Diagnostics;
+using System.Diagnostics.CodeAnalysis;
+using System.Linq;
using Microsoft.CodeAnalysis.CSharp.Symbols;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.PooledObjects;
@@ -25,7 +28,6 @@ private BoundExpression BindInterpolatedString(InterpolatedStringExpressionSynta
}
else
{
- var objectType = GetSpecialType(SpecialType.System_Object, diagnostics, node);
var intType = GetSpecialType(SpecialType.System_Int32, diagnostics, node);
foreach (var content in node.Contents)
{
@@ -35,15 +37,6 @@ private BoundExpression BindInterpolatedString(InterpolatedStringExpressionSynta
{
var interpolation = (InterpolationSyntax)content;
var value = BindValue(interpolation.Expression, diagnostics, BindValueKind.RValue);
- if (value.Type is null)
- {
- value = GenerateConversionForAssignment(objectType, value, diagnostics);
- }
- else
- {
- value = BindToNaturalType(value, diagnostics);
- _ = GenerateConversionForAssignment(objectType, value, diagnostics);
- }
// We need to ensure the argument is not a lambda, method group, etc. It isn't nice to wait until lowering,
// when we perform overload resolution, to report a problem. So we do that check by calling
@@ -93,7 +86,7 @@ private BoundExpression BindInterpolatedString(InterpolatedStringExpressionSynta
format = new BoundLiteral(interpolation.FormatClause, ConstantValue.Create(text), stringType, hasErrors);
}
- builder.Add(new BoundStringInsert(interpolation, value, alignment, format, null));
+ builder.Add(new BoundStringInsert(interpolation, value, alignment, format, isInterpolatedStringHandlerAppendCall: false));
if (!isResultConstant ||
value.ConstantValue == null ||
!(interpolation is { FormatClause: null, AlignmentClause: null }) ||
@@ -134,5 +127,637 @@ private BoundExpression BindInterpolatedString(InterpolatedStringExpressionSynta
Debug.Assert(isResultConstant == (resultConstant != null));
return new BoundUnconvertedInterpolatedString(node, builder.ToImmutableAndFree(), resultConstant, stringType);
}
+
+ private BoundInterpolatedString BindUnconvertedInterpolatedStringToString(BoundUnconvertedInterpolatedString unconvertedInterpolatedString, BindingDiagnosticBag diagnostics)
+ {
+ // We have 4 possible lowering strategies, dependent on the contents of the string, in this order:
+ // 1. The string is a constant value. We can just use the final value.
+ // 2. The string is composed of 4 or fewer components that are all strings, we can lower to a call to string.Concat without a
+ // params array. This is very efficient as the runtime can allocate a buffer for the string with exactly the correct length and
+ // make no intermediate allocations.
+ // 3. The WellKnownType DefaultInterpolatedStringHandler is available, and none of the interpolation holes contain an await expression.
+ // The builder is a ref struct, and we can guarantee the lifetime won't outlive the stack if the string doesn't contain any
+ // awaits, but if it does we cannot use it. This builder is the only way that ref structs can be directly used as interpolation
+ // hole components, which means that ref structs components and await expressions cannot be combined. It is already illegal for
+ // the user to use ref structs in an async method today, but if that were to ever change, this would still need to be respected.
+ // We also cannot use this method if the interpolated string appears within a catch filter, as the builder is disposable and we
+ // cannot put a try/finally inside a filter block.
+ // 4. The string is composed of more than 4 components that are all strings themselves. We can turn this into a single
+ // call to string.Concat. We prefer the builder over this because the builder can use pooling to avoid new allocations, while this
+ // call will need to allocate a param array.
+ // 5. The string has heterogeneous data and either InterpolatedStringHandler is unavailable, or one of the holes contains an await
+ // expression. This is turned into a call to string.Format.
+ //
+ // We need to do the determination of 1, 2, 3, or 4/5 up front, rather than in lowering, as it affects diagnostics (ref structs not being
+ // able to be used, for example). However, between 4 and 5, we don't need to know at this point, so that logic is deferred for lowering.
+
+ if (unconvertedInterpolatedString.ConstantValue is not null)
+ {
+ // Case 1
+ Debug.Assert(unconvertedInterpolatedString.Parts.All(static part => part.Type is null or { SpecialType: SpecialType.System_String }));
+ return constructWithData(BindInterpolatedStringParts(unconvertedInterpolatedString, diagnostics), data: null);
+ }
+
+ // Case 2. Attempt to see if all parts are strings.
+ if (unconvertedInterpolatedString.Parts.Length <= 4 &&
+ unconvertedInterpolatedString.Parts.All(p => p is BoundLiteral
+ or BoundStringInsert { Value: { Type: { SpecialType: SpecialType.System_String } }, Alignment: null, Format: null }))
+ {
+ return constructWithData(BindInterpolatedStringParts(unconvertedInterpolatedString, diagnostics), data: null);
+ }
+
+ if (tryBindAsHandlerType(out var result))
+ {
+ // Case 3
+ return result;
+ }
+
+ // The specifics of 4 vs 5 aren't necessary for this stage of binding. The only thing that matters is that every part needs to be convertible
+ // object.
+ return constructWithData(BindInterpolatedStringParts(unconvertedInterpolatedString, diagnostics), data: null);
+
+ BoundInterpolatedString constructWithData(ImmutableArray parts, InterpolatedStringHandlerData? data)
+ => new BoundInterpolatedString(
+ unconvertedInterpolatedString.Syntax,
+ data,
+ parts,
+ unconvertedInterpolatedString.ConstantValue,
+ unconvertedInterpolatedString.Type,
+ unconvertedInterpolatedString.HasErrors);
+
+ bool tryBindAsHandlerType([NotNullWhen(true)] out BoundInterpolatedString? result)
+ {
+ result = null;
+ if (unconvertedInterpolatedString.Parts.ContainsAwaitExpression())
+ {
+ return false;
+ }
+
+ var interpolatedStringHandlerType = Compilation.GetWellKnownType(WellKnownType.System_Runtime_CompilerServices_DefaultInterpolatedStringHandler);
+ if (interpolatedStringHandlerType is MissingMetadataTypeSymbol)
+ {
+ return false;
+ }
+
+ result = BindUnconvertedInterpolatedStringToHandlerType(unconvertedInterpolatedString, interpolatedStringHandlerType, diagnostics, isHandlerConversion: false);
+
+ return true;
+ }
+ }
+
+ private BoundInterpolatedString BindUnconvertedInterpolatedStringToHandlerType(
+ BoundUnconvertedInterpolatedString unconvertedInterpolatedString,
+ NamedTypeSymbol interpolatedStringHandlerType,
+ BindingDiagnosticBag diagnostics,
+ bool isHandlerConversion,
+ ImmutableArray additionalConstructorArguments = default,
+ ImmutableArray additionalConstructorRefKinds = default)
+ {
+ Debug.Assert(additionalConstructorArguments.IsDefault
+ ? additionalConstructorRefKinds.IsDefault
+ : additionalConstructorArguments.Length == additionalConstructorRefKinds.Length);
+ additionalConstructorArguments = additionalConstructorArguments.NullToEmpty();
+ additionalConstructorRefKinds = additionalConstructorRefKinds.NullToEmpty();
+
+ ReportUseSite(interpolatedStringHandlerType, diagnostics, unconvertedInterpolatedString.Syntax);
+
+ // We satisfy the conditions for using an interpolated string builder. Bind all the builder calls unconditionally, so that if
+ // there are errors we get better diagnostics than "could not convert to object."
+ var implicitBuilderReceiver = new BoundInterpolatedStringHandlerPlaceholder(unconvertedInterpolatedString.Syntax, interpolatedStringHandlerType) { WasCompilerGenerated = true };
+ var (appendCalls, usesBoolReturn, positionInfo, baseStringLength, numFormatHoles) = BindInterpolatedStringAppendCalls(unconvertedInterpolatedString, implicitBuilderReceiver, diagnostics);
+
+ // Prior to C# 10, all types in an interpolated string expression needed to be convertible to `object`. After 10, some types
+ // (such as Span) that are not convertible to `object` are permissible as interpolated string components, provided there
+ // is an applicable AppendFormatted method that accepts them. To preserve langversion, we therefore make sure all components
+ // are convertible to object if the current langversion is lower than the interpolation feature and we're converting this
+ // interpolation into an actual string.
+ bool needToCheckConversionToObject = false;
+ if (isHandlerConversion)
+ {
+ CheckFeatureAvailability(unconvertedInterpolatedString.Syntax, MessageID.IDS_FeatureImprovedInterpolatedStrings, diagnostics);
+ }
+ else if (!Compilation.IsFeatureEnabled(MessageID.IDS_FeatureImprovedInterpolatedStrings) && diagnostics.AccumulatesDiagnostics)
+ {
+ needToCheckConversionToObject = true;
+ }
+
+ Debug.Assert(appendCalls.Length == unconvertedInterpolatedString.Parts.Length);
+ Debug.Assert(appendCalls.All(a => a is { HasErrors: true } or BoundCall { Arguments: { Length: > 0 } } or BoundDynamicInvocation));
+
+ if (needToCheckConversionToObject)
+ {
+ TypeSymbol objectType = GetSpecialType(SpecialType.System_Object, diagnostics, unconvertedInterpolatedString.Syntax);
+ BindingDiagnosticBag conversionDiagnostics = BindingDiagnosticBag.GetInstance(withDiagnostics: true, withDependencies: false);
+ foreach (var currentPart in unconvertedInterpolatedString.Parts)
+ {
+ if (currentPart is BoundStringInsert insert)
+ {
+ var value = insert.Value;
+ bool reported = false;
+ if (value.Type is not null)
+ {
+ value = BindToNaturalType(value, conversionDiagnostics);
+ if (conversionDiagnostics.HasAnyErrors())
+ {
+ CheckFeatureAvailability(value.Syntax, MessageID.IDS_FeatureImprovedInterpolatedStrings, diagnostics);
+ reported = true;
+ }
+ }
+
+ if (!reported)
+ {
+ _ = GenerateConversionForAssignment(objectType, value, conversionDiagnostics);
+ if (conversionDiagnostics.HasAnyErrors())
+ {
+ CheckFeatureAvailability(value.Syntax, MessageID.IDS_FeatureImprovedInterpolatedStrings, diagnostics);
+ }
+ }
+
+ conversionDiagnostics.Clear();
+ }
+ }
+
+ conversionDiagnostics.Free();
+ }
+
+
+ var intType = GetSpecialType(SpecialType.System_Int32, diagnostics, unconvertedInterpolatedString.Syntax);
+ int constructorArgumentLength = 3 + additionalConstructorArguments.Length;
+ var argumentsBuilder = ArrayBuilder.GetInstance(constructorArgumentLength);
+
+ var refKindsBuilder = ArrayBuilder.GetInstance(constructorArgumentLength);
+ refKindsBuilder.Add(RefKind.None);
+ refKindsBuilder.Add(RefKind.None);
+ refKindsBuilder.AddRange(additionalConstructorRefKinds);
+
+ // Add the trailing out validity parameter for the first attempt.Note that we intentionally use `diagnostics` for resolving System.Boolean,
+ // because we want to track that we're using the type no matter what.
+ var boolType = GetSpecialType(SpecialType.System_Boolean, diagnostics, unconvertedInterpolatedString.Syntax);
+ var trailingConstructorValidityPlaceholder = new BoundInterpolatedStringArgumentPlaceholder(unconvertedInterpolatedString.Syntax, BoundInterpolatedStringArgumentPlaceholder.TrailingConstructorValidityParameter, valSafeToEscape: LocalScopeDepth, boolType);
+ var outConstructorAdditionalArguments = additionalConstructorArguments.Add(trailingConstructorValidityPlaceholder);
+ refKindsBuilder.Add(RefKind.Out);
+ populateArguments(unconvertedInterpolatedString.Syntax, outConstructorAdditionalArguments, baseStringLength, numFormatHoles, intType, argumentsBuilder);
+
+ BoundExpression constructorCall;
+ var outConstructorDiagnostics = BindingDiagnosticBag.GetInstance(withDiagnostics: true, withDependencies: diagnostics.AccumulatesDependencies);
+ var outConstructorCall = MakeConstructorInvocation(interpolatedStringHandlerType, argumentsBuilder, refKindsBuilder, unconvertedInterpolatedString.Syntax, outConstructorDiagnostics);
+ if (outConstructorCall is not BoundObjectCreationExpression { ResultKind: LookupResultKind.Viable })
+ {
+ // MakeConstructorInvocation can call CoerceArguments on the builder if overload resolution succeeded ignoring accessibility, which
+ // could still end up not succeeding, and that would end up changing the arguments. So we want to clear and repopulate.
+ argumentsBuilder.Clear();
+
+ // Try again without an out parameter.
+ populateArguments(unconvertedInterpolatedString.Syntax, additionalConstructorArguments, baseStringLength, numFormatHoles, intType, argumentsBuilder);
+ refKindsBuilder.RemoveLast();
+
+ var nonOutConstructorDiagnostics = BindingDiagnosticBag.GetInstance(template: outConstructorDiagnostics);
+ BoundExpression nonOutConstructorCall = MakeConstructorInvocation(interpolatedStringHandlerType, argumentsBuilder, refKindsBuilder, unconvertedInterpolatedString.Syntax, nonOutConstructorDiagnostics);
+
+ if (nonOutConstructorCall is BoundObjectCreationExpression { ResultKind: LookupResultKind.Viable })
+ {
+ // We successfully bound the out version, so set all the final data based on that binding
+ constructorCall = nonOutConstructorCall;
+ diagnostics.AddRangeAndFree(nonOutConstructorDiagnostics);
+ outConstructorDiagnostics.Free();
+ }
+ else
+ {
+ // We'll attempt to figure out which failure was "best" by looking to see if one failed to bind because it couldn't find
+ // a constructor with the correct number of arguments. We presume that, if one failed for this reason and the other failed
+ // for a different reason, that different reason is the one the user will want to know about. If both or neither failed
+ // because of this error, we'll report everything.
+
+ // https://github.com/dotnet/roslyn/issues/54396 Instead of inspecting errors, we should be capturing the results of overload
+ // resolution and attempting to determine which method considered was the best to report errors for.
+
+ var nonOutConstructorHasArityError = nonOutConstructorDiagnostics.DiagnosticBag?.AsEnumerableWithoutResolution().Any(d => (ErrorCode)d.Code == ErrorCode.ERR_BadCtorArgCount) ?? false;
+ var outConstructorHasArityError = outConstructorDiagnostics.DiagnosticBag?.AsEnumerableWithoutResolution().Any(d => (ErrorCode)d.Code == ErrorCode.ERR_BadCtorArgCount) ?? false;
+
+ switch ((nonOutConstructorHasArityError, outConstructorHasArityError))
+ {
+ case (true, false):
+ constructorCall = outConstructorCall;
+ additionalConstructorArguments = outConstructorAdditionalArguments;
+ diagnostics.AddRangeAndFree(outConstructorDiagnostics);
+ nonOutConstructorDiagnostics.Free();
+ break;
+ case (false, true):
+ constructorCall = nonOutConstructorCall;
+ diagnostics.AddRangeAndFree(nonOutConstructorDiagnostics);
+ outConstructorDiagnostics.Free();
+ break;
+ default:
+ // For the final output binding info, we'll go with the shorter constructor in the absence of any tiebreaker,
+ // but we'll report all diagnostics
+ constructorCall = nonOutConstructorCall;
+ diagnostics.AddRangeAndFree(nonOutConstructorDiagnostics);
+ diagnostics.AddRangeAndFree(outConstructorDiagnostics);
+ break;
+ }
+ }
+ }
+ else
+ {
+ diagnostics.AddRangeAndFree(outConstructorDiagnostics);
+ constructorCall = outConstructorCall;
+ additionalConstructorArguments = outConstructorAdditionalArguments;
+ }
+
+ argumentsBuilder.Free();
+ refKindsBuilder.Free();
+
+ Debug.Assert(constructorCall.HasErrors || constructorCall is BoundObjectCreationExpression or BoundDynamicObjectCreationExpression);
+
+ if (constructorCall is BoundDynamicObjectCreationExpression)
+ {
+ // An interpolated string handler construction cannot use dynamic. Manually construct an instance of '{0}'.
+ diagnostics.Add(ErrorCode.ERR_InterpolatedStringHandlerCreationCannotUseDynamic, unconvertedInterpolatedString.Syntax.Location, interpolatedStringHandlerType.Name);
+ }
+
+ return new BoundInterpolatedString(
+ unconvertedInterpolatedString.Syntax,
+ new InterpolatedStringHandlerData(
+ interpolatedStringHandlerType,
+ constructorCall,
+ usesBoolReturn,
+ LocalScopeDepth,
+ additionalConstructorArguments.NullToEmpty(),
+ positionInfo,
+ implicitBuilderReceiver),
+ appendCalls,
+ unconvertedInterpolatedString.ConstantValue,
+ unconvertedInterpolatedString.Type,
+ unconvertedInterpolatedString.HasErrors);
+
+ static void populateArguments(SyntaxNode syntax, ImmutableArray additionalConstructorArguments, int baseStringLength, int numFormatHoles, NamedTypeSymbol intType, ArrayBuilder argumentsBuilder)
+ {
+ // literalLength
+ argumentsBuilder.Add(new BoundLiteral(syntax, ConstantValue.Create(baseStringLength), intType) { WasCompilerGenerated = true });
+ // formattedCount
+ argumentsBuilder.Add(new BoundLiteral(syntax, ConstantValue.Create(numFormatHoles), intType) { WasCompilerGenerated = true });
+ // Any other arguments from the call site
+ argumentsBuilder.AddRange(additionalConstructorArguments);
+ }
+ }
+
+ private ImmutableArray BindInterpolatedStringParts(BoundUnconvertedInterpolatedString unconvertedInterpolatedString, BindingDiagnosticBag diagnostics)
+ {
+ ArrayBuilder? partsBuilder = null;
+ var objectType = GetSpecialType(SpecialType.System_Object, diagnostics, unconvertedInterpolatedString.Syntax);
+ for (int i = 0; i < unconvertedInterpolatedString.Parts.Length; i++)
+ {
+ var part = unconvertedInterpolatedString.Parts[i];
+ if (part is BoundStringInsert insert)
+ {
+ BoundExpression newValue;
+ if (insert.Value.Type is null)
+ {
+ newValue = GenerateConversionForAssignment(objectType, insert.Value, diagnostics);
+ }
+ else
+ {
+ newValue = BindToNaturalType(insert.Value, diagnostics);
+ _ = GenerateConversionForAssignment(objectType, insert.Value, diagnostics);
+ }
+
+ if (insert.Value != newValue)
+ {
+ if (partsBuilder is null)
+ {
+ partsBuilder = ArrayBuilder.GetInstance(unconvertedInterpolatedString.Parts.Length);
+ partsBuilder.AddRange(unconvertedInterpolatedString.Parts, i);
+ }
+
+ partsBuilder.Add(insert.Update(newValue, insert.Alignment, insert.Format, isInterpolatedStringHandlerAppendCall: false));
+ }
+ else
+ {
+ partsBuilder?.Add(part);
+ }
+ }
+ else
+ {
+ Debug.Assert(part is BoundLiteral { Type: { SpecialType: SpecialType.System_String } });
+ partsBuilder?.Add(part);
+ }
+ }
+
+ return partsBuilder?.ToImmutableAndFree() ?? unconvertedInterpolatedString.Parts;
+ }
+
+ private (ImmutableArray AppendFormatCalls, bool UsesBoolReturn, ImmutableArray<(bool IsLiteral, bool HasAlignment, bool HasFormat)>, int BaseStringLength, int NumFormatHoles) BindInterpolatedStringAppendCalls(
+ BoundUnconvertedInterpolatedString source,
+ BoundInterpolatedStringHandlerPlaceholder implicitBuilderReceiver,
+ BindingDiagnosticBag diagnostics)
+ {
+ if (source.Parts.IsEmpty)
+ {
+ return (ImmutableArray.Empty, false, ImmutableArray<(bool IsLiteral, bool HasAlignment, bool HasFormat)>.Empty, 0, 0);
+ }
+
+ bool? builderPatternExpectsBool = null;
+ var builderAppendCalls = ArrayBuilder.GetInstance(source.Parts.Length);
+ var positionInfo = ArrayBuilder<(bool IsLiteral, bool HasAlignment, bool HasFormat)>.GetInstance(source.Parts.Length);
+ var argumentsBuilder = ArrayBuilder.GetInstance(3);
+ var parameterNamesAndLocationsBuilder = ArrayBuilder<(string, Location)?>.GetInstance(3);
+ int baseStringLength = 0;
+ int numFormatHoles = 0;
+
+ foreach (var part in source.Parts)
+ {
+ Debug.Assert(part is BoundLiteral or BoundStringInsert);
+ string methodName;
+ bool isLiteral;
+ bool hasAlignment;
+ bool hasFormat;
+
+ if (part is BoundStringInsert insert)
+ {
+ methodName = "AppendFormatted";
+ argumentsBuilder.Add(insert.Value);
+ parameterNamesAndLocationsBuilder.Add(null);
+ isLiteral = false;
+ hasAlignment = false;
+ hasFormat = false;
+
+ if (insert.Alignment is not null)
+ {
+ hasAlignment = true;
+ argumentsBuilder.Add(insert.Alignment);
+ parameterNamesAndLocationsBuilder.Add(("alignment", insert.Alignment.Syntax.Location));
+ }
+ if (insert.Format is not null)
+ {
+ hasFormat = true;
+ argumentsBuilder.Add(insert.Format);
+ parameterNamesAndLocationsBuilder.Add(("format", insert.Format.Syntax.Location));
+ }
+ numFormatHoles++;
+ }
+ else
+ {
+ var boundLiteral = (BoundLiteral)part;
+ Debug.Assert(boundLiteral.ConstantValue != null && boundLiteral.ConstantValue.IsString);
+ var literalText = ConstantValueUtils.UnescapeInterpolatedStringLiteral(boundLiteral.ConstantValue.StringValue);
+ methodName = "AppendLiteral";
+ argumentsBuilder.Add(boundLiteral.Update(ConstantValue.Create(literalText), boundLiteral.Type));
+ isLiteral = true;
+ hasAlignment = false;
+ hasFormat = false;
+ baseStringLength += literalText.Length;
+ }
+
+ var arguments = argumentsBuilder.ToImmutableAndClear();
+ ImmutableArray<(string, Location)?> parameterNamesAndLocations;
+ if (parameterNamesAndLocationsBuilder.Count > 1)
+ {
+ parameterNamesAndLocations = parameterNamesAndLocationsBuilder.ToImmutableAndClear();
+ }
+ else
+ {
+ Debug.Assert(parameterNamesAndLocationsBuilder.Count == 0 || parameterNamesAndLocationsBuilder[0] == null);
+ parameterNamesAndLocations = default;
+ parameterNamesAndLocationsBuilder.Clear();
+ }
+
+ var call = MakeInvocationExpression(part.Syntax, implicitBuilderReceiver, methodName, arguments, diagnostics, names: parameterNamesAndLocations, searchExtensionMethodsIfNecessary: false);
+ builderAppendCalls.Add(call);
+ positionInfo.Add((isLiteral, hasAlignment, hasFormat));
+
+ Debug.Assert(call is BoundCall or BoundDynamicInvocation or { HasErrors: true });
+
+ // We just assume that dynamic is going to do the right thing, and runtime will fail if it does not. If there are only dynamic calls, we assume that
+ // void is returned.
+ if (call is BoundCall { Method: { ReturnType: var returnType } method })
+ {
+ bool methodReturnsBool = returnType.SpecialType == SpecialType.System_Boolean;
+ if (!methodReturnsBool && returnType.SpecialType != SpecialType.System_Void)
+ {
+ // Interpolated string handler method '{0}' is malformed. It does not return 'void' or 'bool'.
+ diagnostics.Add(ErrorCode.ERR_InterpolatedStringHandlerMethodReturnMalformed, part.Syntax.Location, method);
+ }
+ else if (builderPatternExpectsBool == null)
+ {
+ builderPatternExpectsBool = methodReturnsBool;
+ }
+ else if (builderPatternExpectsBool != methodReturnsBool)
+ {
+ // Interpolated string handler method '{0}' has inconsistent return types. Expected to return '{1}'.
+ var expected = builderPatternExpectsBool == true ? Compilation.GetSpecialType(SpecialType.System_Boolean) : Compilation.GetSpecialType(SpecialType.System_Void);
+ diagnostics.Add(ErrorCode.ERR_InterpolatedStringHandlerMethodReturnInconsistent, part.Syntax.Location, method, expected);
+ }
+ }
+ }
+
+ argumentsBuilder.Free();
+ parameterNamesAndLocationsBuilder.Free();
+ return (builderAppendCalls.ToImmutableAndFree(), builderPatternExpectsBool ?? false, positionInfo.ToImmutableAndFree(), baseStringLength, numFormatHoles);
+ }
+
+ private BoundExpression BindInterpolatedStringHandlerInMemberCall(
+ BoundUnconvertedInterpolatedString unconvertedString,
+ ArrayBuilder arguments,
+ ImmutableArray parameters,
+ ref MemberAnalysisResult memberAnalysisResult,
+ int interpolatedStringArgNum,
+ TypeSymbol? receiverType,
+ RefKind? receiverRefKind,
+ uint receiverEscapeScope,
+ BindingDiagnosticBag diagnostics)
+ {
+ var interpolatedStringConversion = memberAnalysisResult.ConversionForArg(interpolatedStringArgNum);
+ Debug.Assert(interpolatedStringConversion.IsInterpolatedStringHandler);
+ var interpolatedStringParameter = GetCorrespondingParameter(ref memberAnalysisResult, parameters, interpolatedStringArgNum);
+ Debug.Assert(interpolatedStringParameter.Type is NamedTypeSymbol { IsInterpolatedStringHandlerType: true });
+
+ if (interpolatedStringParameter.HasInterpolatedStringHandlerArgumentError)
+ {
+ // The InterpolatedStringHandlerArgumentAttribute applied to parameter '{0}' is malformed and cannot be interpreted. Construct an instance of '{1}' manually.
+ diagnostics.Add(ErrorCode.ERR_InterpolatedStringHandlerArgumentAttributeMalformed, unconvertedString.Syntax.Location, interpolatedStringParameter, interpolatedStringParameter.Type);
+ return CreateConversion(
+ unconvertedString.Syntax,
+ unconvertedString,
+ interpolatedStringConversion,
+ isCast: false,
+ conversionGroupOpt: null,
+ wasCompilerGenerated: false,
+ interpolatedStringParameter.Type,
+ diagnostics,
+ hasErrors: true);
+ }
+
+ var handlerParameterIndexes = interpolatedStringParameter.InterpolatedStringHandlerArgumentIndexes;
+ if (handlerParameterIndexes.IsEmpty)
+ {
+ // No arguments, fall back to the standard conversion steps.
+ return CreateConversion(
+ unconvertedString.Syntax,
+ unconvertedString,
+ interpolatedStringConversion,
+ isCast: false,
+ conversionGroupOpt: null,
+ interpolatedStringParameter.Type,
+ diagnostics);
+ }
+
+ Debug.Assert(handlerParameterIndexes.All((index, paramLength) => index >= BoundInterpolatedStringArgumentPlaceholder.InstanceParameter && index < paramLength,
+ parameters.Length));
+
+ // We need to find the appropriate argument expression for every expected parameter, and error on any that occur after the current parameter
+
+ ImmutableArray handlerArgumentIndexes;
+
+ if (memberAnalysisResult.ArgsToParamsOpt.IsDefault && arguments.Count == parameters.Length)
+ {
+ // No parameters are missing and no remapped indexes, we can just use the original indexes
+ handlerArgumentIndexes = handlerParameterIndexes;
+ }
+ else
+ {
+ // Args and parameters were reordered via named parameters, or parameters are missing. Find the correct argument index for each parameter.
+ var handlerArgumentIndexesBuilder = ArrayBuilder.GetInstance(handlerParameterIndexes.Length, fillWithValue: BoundInterpolatedStringArgumentPlaceholder.UnspecifiedParameter);
+ for (int handlerParameterIndex = 0; handlerParameterIndex < handlerParameterIndexes.Length; handlerParameterIndex++)
+ {
+ int handlerParameter = handlerParameterIndexes[handlerParameterIndex];
+ Debug.Assert(handlerArgumentIndexesBuilder[handlerParameterIndex] is BoundInterpolatedStringArgumentPlaceholder.UnspecifiedParameter);
+
+ if (handlerParameter == BoundInterpolatedStringArgumentPlaceholder.InstanceParameter)
+ {
+ handlerArgumentIndexesBuilder[handlerParameterIndex] = handlerParameter;
+ continue;
+ }
+
+ for (int argumentIndex = 0; argumentIndex < arguments.Count; argumentIndex++)
+ {
+ // The index in the original parameter list we're looking to match up.
+ int argumentParameterIndex = memberAnalysisResult.ParameterFromArgument(argumentIndex);
+ // Is the original parameter index of the current argument the parameter index that was specified in the attribute?
+ if (argumentParameterIndex == handlerParameter)
+ {
+ // We can't just bail out on the first match: users can duplicate parameters in attributes, causing the same value to be passed twice.
+ handlerArgumentIndexesBuilder[handlerParameterIndex] = argumentIndex;
+ }
+ }
+ }
+
+ handlerArgumentIndexes = handlerArgumentIndexesBuilder.ToImmutableAndFree();
+ }
+
+ var argumentPlaceholdersBuilder = ArrayBuilder.GetInstance(handlerArgumentIndexes.Length);
+ var argumentRefKindsBuilder = ArrayBuilder.GetInstance(handlerArgumentIndexes.Length);
+ bool hasErrors = false;
+
+ // Now, go through all the specified arguments and see if any were specified _after_ the interpolated string, and construct
+ // a set of placeholders for overload resolution.
+ for (int i = 0; i < handlerArgumentIndexes.Length; i++)
+ {
+ int argumentIndex = handlerArgumentIndexes[i];
+ Debug.Assert(argumentIndex != interpolatedStringArgNum);
+
+ RefKind refKind;
+ TypeSymbol placeholderType;
+ switch (argumentIndex)
+ {
+ case BoundInterpolatedStringArgumentPlaceholder.InstanceParameter:
+ Debug.Assert(receiverRefKind != null && receiverType is not null);
+ refKind = receiverRefKind.GetValueOrDefault();
+ placeholderType = receiverType;
+ break;
+ case BoundInterpolatedStringArgumentPlaceholder.UnspecifiedParameter:
+ {
+ // Don't error if the parameter isn't optional or params: the user will already have an error for missing an optional parameter or overload resolution failed.
+ // If it is optional, then they could otherwise not specify the parameter and that's an error
+ var originalParameterIndex = handlerParameterIndexes[i];
+ var parameter = parameters[originalParameterIndex];
+ if (parameter.IsOptional || (originalParameterIndex + 1 == parameters.Length && OverloadResolution.IsValidParamsParameter(parameter)))
+ {
+ // Parameter '{0}' is not explicitly provided, but is used as an argument to the interpolated string handler conversion on parameter '{1}'. Specify the value of '{0}' before '{1}'.
+ diagnostics.Add(
+ ErrorCode.ERR_InterpolatedStringHandlerArgumentOptionalNotSpecified,
+ unconvertedString.Syntax.Location,
+ parameter.Name,
+ interpolatedStringParameter.Name);
+ hasErrors = true;
+ }
+
+ refKind = parameter.RefKind;
+ placeholderType = parameter.Type;
+ }
+ break;
+ default:
+ {
+ var originalParameterIndex = handlerParameterIndexes[i];
+ var parameter = parameters[originalParameterIndex];
+ if (argumentIndex > interpolatedStringArgNum)
+ {
+ // Parameter '{0}' is an argument to the interpolated string handler conversion on parameter '{1}', but the corresponding argument is specified after the interpolated string expression. Reorder the arguments to move '{0}' before '{1}'.
+ diagnostics.Add(
+ ErrorCode.ERR_InterpolatedStringHandlerArgumentLocatedAfterInterpolatedString,
+ arguments[argumentIndex].Syntax.Location,
+ parameter.Name,
+ interpolatedStringParameter.Name);
+ hasErrors = true;
+ }
+
+ refKind = parameter.RefKind;
+ placeholderType = parameter.Type;
+ }
+ break;
+ }
+
+ SyntaxNode placeholderSyntax;
+ uint valSafeToEscapeScope;
+
+ switch (argumentIndex)
+ {
+ case BoundInterpolatedStringArgumentPlaceholder.InstanceParameter:
+ placeholderSyntax = unconvertedString.Syntax;
+ valSafeToEscapeScope = receiverEscapeScope;
+ break;
+ case BoundInterpolatedStringArgumentPlaceholder.UnspecifiedParameter:
+ placeholderSyntax = unconvertedString.Syntax;
+ valSafeToEscapeScope = Binder.ExternalScope;
+ break;
+ case >= 0:
+ placeholderSyntax = arguments[argumentIndex].Syntax;
+ valSafeToEscapeScope = GetValEscape(arguments[argumentIndex], LocalScopeDepth);
+ break;
+ default:
+ throw ExceptionUtilities.UnexpectedValue(argumentIndex);
+ }
+
+ argumentPlaceholdersBuilder.Add(
+ new BoundInterpolatedStringArgumentPlaceholder(
+ placeholderSyntax,
+ argumentIndex,
+ valSafeToEscapeScope,
+ placeholderType,
+ hasErrors: argumentIndex == BoundInterpolatedStringArgumentPlaceholder.UnspecifiedParameter));
+ // We use the parameter refkind, rather than what the argument was actually passed with, because that will suppress duplicated errors
+ // about arguments being passed with the wrong RefKind. The user will have already gotten an error about mismatched RefKinds or it will
+ // be a place where refkinds are allowed to differ
+ argumentRefKindsBuilder.Add(refKind);
+ }
+
+ var interpolatedString = BindUnconvertedInterpolatedStringToHandlerType(
+ unconvertedString,
+ (NamedTypeSymbol)interpolatedStringParameter.Type,
+ diagnostics,
+ isHandlerConversion: true,
+ additionalConstructorArguments: argumentPlaceholdersBuilder.ToImmutableAndFree(),
+ additionalConstructorRefKinds: argumentRefKindsBuilder.ToImmutableAndFree());
+
+ return new BoundConversion(
+ interpolatedString.Syntax,
+ interpolatedString,
+ interpolatedStringConversion,
+ @checked: CheckOverflowAtRuntime,
+ explicitCastInCode: false,
+ conversionGroupOpt: null,
+ constantValueOpt: null,
+ interpolatedStringParameter.Type,
+ hasErrors || interpolatedString.HasErrors);
+ }
}
}
diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_Invocation.cs b/src/Compilers/CSharp/Portable/Binder/Binder_Invocation.cs
index b20ae3248d918..3246c6af5a463 100644
--- a/src/Compilers/CSharp/Portable/Binder/Binder_Invocation.cs
+++ b/src/Compilers/CSharp/Portable/Binder/Binder_Invocation.cs
@@ -82,14 +82,17 @@ internal BoundExpression MakeInvocationExpression(
BindingDiagnosticBag diagnostics,
SeparatedSyntaxList typeArgsSyntax = default(SeparatedSyntaxList),
ImmutableArray typeArgs = default(ImmutableArray),
+ ImmutableArray<(string Name, Location Location)?> names = default,
CSharpSyntaxNode? queryClause = null,
bool allowFieldsAndProperties = false,
- bool allowUnexpandedForm = true)
+ bool allowUnexpandedForm = true,
+ bool searchExtensionMethodsIfNecessary = true)
{
Debug.Assert(receiver != null);
+ Debug.Assert(names.IsDefault || names.Length == args.Length);
receiver = BindToNaturalType(receiver, diagnostics);
- var boundExpression = BindInstanceMemberAccess(node, node, receiver, methodName, typeArgs.NullToEmpty().Length, typeArgsSyntax, typeArgs, invoked: true, indexed: false, diagnostics);
+ var boundExpression = BindInstanceMemberAccess(node, node, receiver, methodName, typeArgs.NullToEmpty().Length, typeArgsSyntax, typeArgs, invoked: true, indexed: false, diagnostics, searchExtensionMethodsIfNecessary);
// The other consumers of this helper (await and collection initializers) require the target member to be a method.
if (!allowFieldsAndProperties && (boundExpression.Kind == BoundKind.FieldAccess || boundExpression.Kind == BoundKind.PropertyAccess))
@@ -114,7 +117,7 @@ internal BoundExpression MakeInvocationExpression(
msgId.Localize(),
MessageID.IDS_SK_METHOD.Localize());
- return BadExpression(node, LookupResultKind.Empty, ImmutableArray.Create(symbol), args.Add(receiver));
+ return BadExpression(node, LookupResultKind.Empty, ImmutableArray.Create(symbol), args.Add(receiver), wasCompilerGenerated: true);
}
boundExpression = CheckValue(boundExpression, BindValueKind.RValueOrMethodGroup, diagnostics);
@@ -125,6 +128,12 @@ internal BoundExpression MakeInvocationExpression(
e.Kind == BoundKind.OutDeconstructVarPendingInference ||
e.Kind == BoundKind.DiscardExpression && !e.HasExpressionType()));
analyzedArguments.Arguments.AddRange(args);
+
+ if (!names.IsDefault)
+ {
+ analyzedArguments.Names.AddRange(names);
+ }
+
BoundExpression result = BindInvocationExpression(
node, node, methodName, boundExpression, analyzedArguments, diagnostics, queryClause,
allowUnexpandedForm: allowUnexpandedForm);
@@ -1000,13 +1009,7 @@ private BoundCall BindInvocationExpressionContinued(
var methodResult = result.ValidResult;
var returnType = methodResult.Member.ReturnType;
- this.CoerceArguments(methodResult, analyzedArguments.Arguments, diagnostics);
-
var method = methodResult.Member;
- var expanded = methodResult.Result.Kind == MemberResolutionKind.ApplicableInExpandedForm;
- var argsToParams = methodResult.Result.ArgsToParamsOpt;
-
- BindDefaultArguments(node, method.Parameters, analyzedArguments.Arguments, analyzedArguments.RefKinds, ref argsToParams, out var defaultArguments, expanded, enableCallerInfo: true, diagnostics);
// It is possible that overload resolution succeeded, but we have chosen an
// instance method and we're in a static method. A careful reading of the
@@ -1017,6 +1020,17 @@ private BoundCall BindInvocationExpressionContinued(
var receiver = ReplaceTypeOrValueReceiver(methodGroup.Receiver, !method.RequiresInstanceReceiver && !invokedAsExtensionMethod, diagnostics);
+ var receiverRefKind = receiver?.GetRefKind();
+ uint receiverValEscapeScope = method.RequiresInstanceReceiver && receiver != null
+ ? receiverRefKind?.IsWritableReference() == true ? GetRefEscape(receiver, LocalScopeDepth) : GetValEscape(receiver, LocalScopeDepth)
+ : Binder.ExternalScope;
+ this.CoerceArguments(methodResult, analyzedArguments.Arguments, diagnostics, receiver?.Type, receiverRefKind, receiverValEscapeScope);
+
+ var expanded = methodResult.Result.Kind == MemberResolutionKind.ApplicableInExpandedForm;
+ var argsToParams = methodResult.Result.ArgsToParamsOpt;
+
+ BindDefaultArguments(node, method.Parameters, analyzedArguments.Arguments, analyzedArguments.RefKinds, ref argsToParams, out var defaultArguments, expanded, enableCallerInfo: true, diagnostics);
+
// Note: we specifically want to do final validation (7.6.5.1) without checking delegate compatibility (15.2),
// so we're calling MethodGroupFinalValidation directly, rather than via MethodGroupConversionHasErrors.
// Note: final validation wants the receiver that corresponds to the source representation
@@ -2002,7 +2016,10 @@ private BoundFunctionPointerInvocation BindFunctionPointerInvocation(SyntaxNode
CoerceArguments(
methodResult,
analyzedArguments.Arguments,
- diagnostics);
+ diagnostics,
+ receiverType: null,
+ receiverRefKind: null,
+ receiverEscapeScope: Binder.ExternalScope);
var args = analyzedArguments.Arguments.ToImmutable();
var refKinds = analyzedArguments.RefKinds.ToImmutableOrNull();
diff --git a/src/Compilers/CSharp/Portable/Binder/Semantics/Conversions/Conversion.cs b/src/Compilers/CSharp/Portable/Binder/Semantics/Conversions/Conversion.cs
index afcffedc0426b..082400b2b10c1 100644
--- a/src/Compilers/CSharp/Portable/Binder/Semantics/Conversions/Conversion.cs
+++ b/src/Compilers/CSharp/Portable/Binder/Semantics/Conversions/Conversion.cs
@@ -199,6 +199,7 @@ private static void AssertTrivialConversion(ConversionKind kind)
case ConversionKind.ImplicitDynamic:
case ConversionKind.ExplicitDynamic:
case ConversionKind.InterpolatedString:
+ case ConversionKind.InterpolatedStringHandler:
isTrivial = true;
break;
@@ -242,6 +243,7 @@ internal static Conversion GetTrivialConversion(ConversionKind kind)
internal static Conversion ImplicitDynamic => new Conversion(ConversionKind.ImplicitDynamic);
internal static Conversion ExplicitDynamic => new Conversion(ConversionKind.ExplicitDynamic);
internal static Conversion InterpolatedString => new Conversion(ConversionKind.InterpolatedString);
+ internal static Conversion InterpolatedStringHandler => new Conversion(ConversionKind.InterpolatedStringHandler);
internal static Conversion Deconstruction => new Conversion(ConversionKind.Deconstruction);
internal static Conversion PinnedObjectToPointer => new Conversion(ConversionKind.PinnedObjectToPointer);
internal static Conversion ImplicitPointer => new Conversion(ConversionKind.ImplicitPointer);
@@ -598,6 +600,17 @@ public bool IsInterpolatedString
}
}
+ ///
+ /// Returns true if the conversion is an interpolated string builder conversion.
+ ///
+ public bool IsInterpolatedStringHandler
+ {
+ get
+ {
+ return Kind == ConversionKind.InterpolatedStringHandler;
+ }
+ }
+
///
/// Returns true if the conversion is an implicit nullable conversion or explicit nullable conversion.
///
diff --git a/src/Compilers/CSharp/Portable/Binder/Semantics/Conversions/ConversionKind.cs b/src/Compilers/CSharp/Portable/Binder/Semantics/Conversions/ConversionKind.cs
index 4985822d4e668..8d82824d3d9a5 100644
--- a/src/Compilers/CSharp/Portable/Binder/Semantics/Conversions/ConversionKind.cs
+++ b/src/Compilers/CSharp/Portable/Binder/Semantics/Conversions/ConversionKind.cs
@@ -2,12 +2,6 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
-#nullable disable
-
-using Microsoft.CodeAnalysis.CSharp.Symbols;
-using Microsoft.CodeAnalysis.CSharp.Syntax;
-using Microsoft.CodeAnalysis.Text;
-
namespace Microsoft.CodeAnalysis.CSharp
{
internal enum ConversionKind : byte
@@ -63,5 +57,7 @@ internal enum ConversionKind : byte
DefaultLiteral, // a conversion from a `default` literal to any type
ObjectCreation, // a conversion from a `new()` expression to any type
+
+ InterpolatedStringHandler, // A conversion from an interpolated string literal to a type attributed with InterpolatedStringBuilderAttribute
}
}
diff --git a/src/Compilers/CSharp/Portable/Binder/Semantics/Conversions/ConversionKindExtensions.cs b/src/Compilers/CSharp/Portable/Binder/Semantics/Conversions/ConversionKindExtensions.cs
index 63cb1e27253ce..09555f2ce90c0 100644
--- a/src/Compilers/CSharp/Portable/Binder/Semantics/Conversions/ConversionKindExtensions.cs
+++ b/src/Compilers/CSharp/Portable/Binder/Semantics/Conversions/ConversionKindExtensions.cs
@@ -48,6 +48,7 @@ public static bool IsImplicitConversion(this ConversionKind conversionKind)
case ImplicitPointerToVoid:
case ImplicitNullToPointer:
case InterpolatedString:
+ case InterpolatedStringHandler:
case SwitchExpression:
case ConditionalExpression:
case Deconstruction:
diff --git a/src/Compilers/CSharp/Portable/Binder/Semantics/Conversions/Conversions.cs b/src/Compilers/CSharp/Portable/Binder/Semantics/Conversions/Conversions.cs
index 74963ad00b10a..4d3ae007d3af5 100644
--- a/src/Compilers/CSharp/Portable/Binder/Semantics/Conversions/Conversions.cs
+++ b/src/Compilers/CSharp/Portable/Binder/Semantics/Conversions/Conversions.cs
@@ -7,7 +7,10 @@
using System;
using System.Collections.Immutable;
using System.Diagnostics;
+using System.Diagnostics.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp.Symbols;
+using Microsoft.CodeAnalysis.PooledObjects;
+using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.CSharp
{
@@ -81,10 +84,15 @@ public override Conversion GetMethodGroupFunctionPointerConversion(BoundMethodGr
protected override Conversion GetInterpolatedStringConversion(BoundUnconvertedInterpolatedString source, TypeSymbol destination, ref CompoundUseSiteInfo useSiteInfo)
{
+ if (destination is NamedTypeSymbol { IsInterpolatedStringHandlerType: true })
+ {
+ return Conversion.InterpolatedStringHandler;
+ }
+
// An interpolated string expression may be converted to the types
// System.IFormattable and System.FormattableString
- return (TypeSymbol.Equals(destination, Compilation.GetWellKnownType(WellKnownType.System_IFormattable), TypeCompareKind.ConsiderEverything2) ||
- TypeSymbol.Equals(destination, Compilation.GetWellKnownType(WellKnownType.System_FormattableString), TypeCompareKind.ConsiderEverything2))
+ return (TypeSymbol.Equals(destination, Compilation.GetWellKnownType(WellKnownType.System_IFormattable), TypeCompareKind.ConsiderEverything) ||
+ TypeSymbol.Equals(destination, Compilation.GetWellKnownType(WellKnownType.System_FormattableString), TypeCompareKind.ConsiderEverything))
? Conversion.InterpolatedString : Conversion.NoConversion;
}
diff --git a/src/Compilers/CSharp/Portable/Binder/Semantics/Conversions/ConversionsBase.cs b/src/Compilers/CSharp/Portable/Binder/Semantics/Conversions/ConversionsBase.cs
index ac97e512467e1..e40db74c57369 100644
--- a/src/Compilers/CSharp/Portable/Binder/Semantics/Conversions/ConversionsBase.cs
+++ b/src/Compilers/CSharp/Portable/Binder/Semantics/Conversions/ConversionsBase.cs
@@ -4,10 +4,9 @@
#nullable disable
-using System;
-using System.Collections.Generic;
using System.Collections.Immutable;
using System.Diagnostics;
+using System.Diagnostics.CodeAnalysis;
using System.Threading;
using Microsoft.CodeAnalysis.CSharp.Symbols;
using Microsoft.CodeAnalysis.CSharp.Syntax;
diff --git a/src/Compilers/CSharp/Portable/Binder/Semantics/Conversions/TypeConversions.cs b/src/Compilers/CSharp/Portable/Binder/Semantics/Conversions/TypeConversions.cs
index c3906596164d8..3599c567ad5f4 100644
--- a/src/Compilers/CSharp/Portable/Binder/Semantics/Conversions/TypeConversions.cs
+++ b/src/Compilers/CSharp/Portable/Binder/Semantics/Conversions/TypeConversions.cs
@@ -6,9 +6,9 @@
using Microsoft.CodeAnalysis.CSharp.Symbols;
using Roslyn.Utilities;
-using System;
-using System.Collections.Generic;
+using System.Collections.Immutable;
using System.Diagnostics;
+using System.Diagnostics.CodeAnalysis;
namespace Microsoft.CodeAnalysis.CSharp
{
diff --git a/src/Compilers/CSharp/Portable/Binder/Semantics/OverloadResolution/AnalyzedArguments.cs b/src/Compilers/CSharp/Portable/Binder/Semantics/OverloadResolution/AnalyzedArguments.cs
index 2ac4f6a1d8ecc..84cfad7da7317 100644
--- a/src/Compilers/CSharp/Portable/Binder/Semantics/OverloadResolution/AnalyzedArguments.cs
+++ b/src/Compilers/CSharp/Portable/Binder/Semantics/OverloadResolution/AnalyzedArguments.cs
@@ -2,13 +2,10 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
-#nullable disable
-
using System.Collections.Immutable;
using Microsoft.CodeAnalysis.CSharp.Symbols;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.PooledObjects;
-using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.CSharp
{
@@ -16,7 +13,7 @@ namespace Microsoft.CodeAnalysis.CSharp
internal sealed class AnalyzedArguments
{
public readonly ArrayBuilder Arguments;
- public readonly ArrayBuilder Names;
+ public readonly ArrayBuilder<(string Name, Location Location)?> Names;
public readonly ArrayBuilder RefKinds;
public bool IsExtensionMethodInvocation;
private ThreeState _lazyHasDynamicArgument;
@@ -24,7 +21,7 @@ internal sealed class AnalyzedArguments
internal AnalyzedArguments()
{
this.Arguments = new ArrayBuilder(32);
- this.Names = new ArrayBuilder(32);
+ this.Names = new ArrayBuilder<(string, Location)?>(32);
this.RefKinds = new ArrayBuilder(32);
}
@@ -42,18 +39,23 @@ public BoundExpression Argument(int i)
return Arguments[i];
}
- public string Name(int i)
+ public void AddName(IdentifierNameSyntax name)
+ {
+ Names.Add((name.Identifier.ValueText, name.Location));
+ }
+
+ public string? Name(int i)
{
if (Names.Count == 0)
{
return null;
}
- IdentifierNameSyntax syntax = Names[i];
- return syntax == null ? null : syntax.Identifier.ValueText;
+ var nameAndLocation = Names[i];
+ return nameAndLocation?.Name;
}
- public ImmutableArray GetNames()
+ public ImmutableArray GetNames()
{
int count = this.Names.Count;
@@ -62,7 +64,7 @@ public ImmutableArray GetNames()
return default;
}
- var builder = ArrayBuilder.GetInstance(this.Names.Count);
+ var builder = ArrayBuilder.GetInstance(this.Names.Count);
for (int i = 0; i < this.Names.Count; ++i)
{
builder.Add(Name(i));
@@ -96,7 +98,7 @@ public bool HasDynamicArgument
var argument = Arguments[i];
// By-ref dynamic arguments don't make the invocation dynamic.
- if ((object)argument.Type != null && argument.Type.IsDynamic() && (!hasRefKinds || RefKinds[i] == Microsoft.CodeAnalysis.RefKind.None))
+ if ((object?)argument.Type != null && argument.Type.IsDynamic() && (!hasRefKinds || RefKinds[i] == Microsoft.CodeAnalysis.RefKind.None))
{
_lazyHasDynamicArgument = ThreeState.True;
return true;
@@ -145,7 +147,7 @@ public static AnalyzedArguments GetInstance(AnalyzedArguments original)
public static AnalyzedArguments GetInstance(
ImmutableArray arguments,
ImmutableArray argumentRefKindsOpt,
- ImmutableArray argumentNamesOpt)
+ ImmutableArray<(string, Location)?> argumentNamesOpt)
{
var instance = GetInstance();
instance.Arguments.AddRange(arguments);
@@ -174,7 +176,7 @@ public void Free()
private static ObjectPool CreatePool()
{
- ObjectPool pool = null;
+ ObjectPool? pool = null;
pool = new ObjectPool(() => new AnalyzedArguments(), 10);
return pool;
}
diff --git a/src/Compilers/CSharp/Portable/Binder/Semantics/OverloadResolution/OverloadResolution.cs b/src/Compilers/CSharp/Portable/Binder/Semantics/OverloadResolution/OverloadResolution.cs
index 56dac18fef3df..52d777bb3f25b 100644
--- a/src/Compilers/CSharp/Portable/Binder/Semantics/OverloadResolution/OverloadResolution.cs
+++ b/src/Compilers/CSharp/Portable/Binder/Semantics/OverloadResolution/OverloadResolution.cs
@@ -1025,9 +1025,13 @@ public static bool IsValidParams(Symbol member)
return false;
}
- // Note: we need to confirm the "arrayness" on the original definition because
- // it's possible that the type becomes an array as a result of substitution.
ParameterSymbol final = member.GetParameters().Last();
+ return IsValidParamsParameter(final);
+ }
+
+ public static bool IsValidParamsParameter(ParameterSymbol final)
+ {
+ Debug.Assert((object)final == final.ContainingSymbol.GetParameters().Last());
return final.IsParams && ((ParameterSymbol)final.OriginalDefinition).Type.IsSZArray();
}
@@ -1965,7 +1969,7 @@ private BetterResult BetterFunctionMember(
}
}
- return PreferValOverInParameters(arguments, m1, m1LeastOverriddenParameters, m2, m2LeastOverriddenParameters);
+ return PreferValOverInOrRefInterpolatedHandlerParameters(arguments, m1, m1LeastOverriddenParameters, m2, m2LeastOverriddenParameters);
}
// If MP is a non-generic method and MQ is a generic method, then MP is better than MQ.
@@ -2105,11 +2109,11 @@ private BetterResult BetterFunctionMember(
return (m1ModifierCount < m2ModifierCount) ? BetterResult.Left : BetterResult.Right;
}
- // Otherwise, prefer methods with 'val' parameters over 'in' parameters.
- return PreferValOverInParameters(arguments, m1, m1LeastOverriddenParameters, m2, m2LeastOverriddenParameters);
+ // Otherwise, prefer methods with 'val' parameters over 'in' parameters and over 'ref' parameters when the argument is an interpolated string handler.
+ return PreferValOverInOrRefInterpolatedHandlerParameters(arguments, m1, m1LeastOverriddenParameters, m2, m2LeastOverriddenParameters);
}
- private static BetterResult PreferValOverInParameters(
+ private static BetterResult PreferValOverInOrRefInterpolatedHandlerParameters(
ArrayBuilder arguments,
MemberResolutionResult m1,
ImmutableArray parameters1,
@@ -2117,7 +2121,7 @@ private static BetterResult PreferValOverInParameters(
ImmutableArray parameters2)
where TMember : Symbol
{
- BetterResult valOverInPreference = BetterResult.Neither;
+ BetterResult valOverInOrRefInterpolatedHandlerPreference = BetterResult.Neither;
for (int i = 0; i < arguments.Count; ++i)
{
@@ -2126,32 +2130,51 @@ private static BetterResult PreferValOverInParameters(
var p1 = GetParameter(i, m1.Result, parameters1);
var p2 = GetParameter(i, m2.Result, parameters2);
- if (p1.RefKind == RefKind.None && p2.RefKind == RefKind.In)
+ bool isInterpolatedStringHandlerConversion = false;
+
+ if (m1.IsValid && m2.IsValid)
+ {
+ var c1 = m1.Result.ConversionForArg(i);
+ var c2 = m2.Result.ConversionForArg(i);
+
+ isInterpolatedStringHandlerConversion = c1.IsInterpolatedStringHandler && c2.IsInterpolatedStringHandler;
+ Debug.Assert(!isInterpolatedStringHandlerConversion || arguments[i].Kind == BoundKind.UnconvertedInterpolatedString);
+ }
+
+ if (p1.RefKind == RefKind.None && isAcceptableRefMismatch(p2.RefKind, isInterpolatedStringHandlerConversion))
{
- if (valOverInPreference == BetterResult.Right)
+ if (valOverInOrRefInterpolatedHandlerPreference == BetterResult.Right)
{
return BetterResult.Neither;
}
else
{
- valOverInPreference = BetterResult.Left;
+ valOverInOrRefInterpolatedHandlerPreference = BetterResult.Left;
}
}
- else if (p2.RefKind == RefKind.None && p1.RefKind == RefKind.In)
+ else if (p2.RefKind == RefKind.None && isAcceptableRefMismatch(p1.RefKind, isInterpolatedStringHandlerConversion))
{
- if (valOverInPreference == BetterResult.Left)
+ if (valOverInOrRefInterpolatedHandlerPreference == BetterResult.Left)
{
return BetterResult.Neither;
}
else
{
- valOverInPreference = BetterResult.Right;
+ valOverInOrRefInterpolatedHandlerPreference = BetterResult.Right;
}
}
}
}
- return valOverInPreference;
+ return valOverInOrRefInterpolatedHandlerPreference;
+
+ static bool isAcceptableRefMismatch(RefKind refKind, bool isInterpolatedStringHandlerConversion)
+ => refKind switch
+ {
+ RefKind.In => true,
+ RefKind.Ref when isInterpolatedStringHandlerConversion => true,
+ _ => false
+ };
}
private static void GetParameterCounts(MemberResolutionResult m, ArrayBuilder arguments, out int declaredParameterCount, out int parametersUsedIncludingExpansionAndOptional) where TMember : Symbol
@@ -2401,6 +2424,26 @@ private BetterResult BetterConversionFromExpression(BoundExpression node, TypeSy
return BetterResult.Neither;
}
+ // C# 10 added interpolated string handler conversions, with the following rule:
+ // Given an implicit conversion C1 that converts from an expression E to a type T1,
+ // and an implicit conversion C2 that converts from an expression E to a type T2,
+ // C1 is a better conversion than C2 if E is a non-constant interpolated string expression, C1
+ // is an interpolated string handler conversion, and C2 is not an interpolated string
+ // handler conversion
+ // https://github.com/dotnet/roslyn/issues/54584 Handle binary operators composed only of added interpolated strings
+ if (node is BoundUnconvertedInterpolatedString { ConstantValueOpt: null })
+ {
+ switch ((conv1.Kind, conv2.Kind))
+ {
+ case (ConversionKind.InterpolatedStringHandler, ConversionKind.InterpolatedStringHandler):
+ return BetterResult.Neither;
+ case (ConversionKind.InterpolatedStringHandler, _):
+ return BetterResult.Left;
+ case (_, ConversionKind.InterpolatedStringHandler):
+ return BetterResult.Right;
+ }
+ }
+
// Given an implicit conversion C1 that converts from an expression E to a type T1,
// and an implicit conversion C2 that converts from an expression E to a type T2,
// C1 is a better conversion than C2 if E does not exactly match T2 and one of the following holds:
@@ -3589,6 +3632,18 @@ private MemberAnalysisResult IsApplicable(
}
}
+ bool hasInterpolatedStringRefMismatch = false;
+ if (argument.Kind == BoundKind.UnconvertedInterpolatedString
+ && parameterRefKind == RefKind.Ref
+ && parameters.ParameterTypes[argumentPosition].Type is NamedTypeSymbol { IsInterpolatedStringHandlerType: true, IsValueType: true })
+ {
+ // For interpolated strings handlers, we allow an interpolated string expression to be passed as if `ref` was specified
+ // in the source when the handler type is a value type.
+ // https://github.com/dotnet/roslyn/issues/54584 allow binary additions of interpolated strings to match as well.
+ hasInterpolatedStringRefMismatch = true;
+ argumentRefKind = parameterRefKind;
+ }
+
conversion = CheckArgumentForApplicability(
candidate,
argument,
@@ -3597,7 +3652,8 @@ private MemberAnalysisResult IsApplicable(
parameterRefKind,
ignoreOpenTypes,
ref useSiteInfo,
- forExtensionMethodThisArg);
+ forExtensionMethodThisArg,
+ hasInterpolatedStringRefMismatch);
if (forExtensionMethodThisArg && !Conversions.IsValidExtensionMethodThisArgConversion(conversion))
{
@@ -3614,7 +3670,7 @@ private MemberAnalysisResult IsApplicable(
if (!conversion.Exists)
{
- badArguments = badArguments ?? ArrayBuilder.GetInstance();
+ badArguments ??= ArrayBuilder.GetInstance();
badArguments.Add(argumentPosition);
}
}
@@ -3658,7 +3714,8 @@ private Conversion CheckArgumentForApplicability(
RefKind parRefKind,
bool ignoreOpenTypes,
ref CompoundUseSiteInfo useSiteInfo,
- bool forExtensionMethodThisArg)
+ bool forExtensionMethodThisArg,
+ bool hasInterpolatedStringRefMismatch)
{
// Spec 7.5.3.1
// For each argument in A, the parameter passing mode of the argument (i.e., value, ref, or out) is identical
@@ -3699,12 +3756,20 @@ private Conversion CheckArgumentForApplicability(
return Conversion.Identity;
}
- if (argRefKind == RefKind.None)
+ if (argRefKind == RefKind.None || hasInterpolatedStringRefMismatch)
{
var conversion = forExtensionMethodThisArg ?
Conversions.ClassifyImplicitExtensionMethodThisArgConversion(argument, argument.Type, parameterType, ref useSiteInfo) :
Conversions.ClassifyImplicitConversionFromExpression(argument, parameterType, ref useSiteInfo);
Debug.Assert((!conversion.Exists) || conversion.IsImplicit, "ClassifyImplicitConversion should only return implicit conversions");
+
+ if (hasInterpolatedStringRefMismatch && !conversion.IsInterpolatedStringHandler)
+ {
+ // We allowed a ref mismatch under the assumption the conversion would be an interpolated string handler conversion. If it's not, then there was
+ // actually no conversion because of the refkind mismatch.
+ return Conversion.NoConversion;
+ }
+
return conversion;
}
diff --git a/src/Compilers/CSharp/Portable/Binder/Semantics/OverloadResolution/OverloadResolutionResult.cs b/src/Compilers/CSharp/Portable/Binder/Semantics/OverloadResolution/OverloadResolutionResult.cs
index db382a0cad9f1..3297c38524090 100644
--- a/src/Compilers/CSharp/Portable/Binder/Semantics/OverloadResolution/OverloadResolutionResult.cs
+++ b/src/Compilers/CSharp/Portable/Binder/Semantics/OverloadResolution/OverloadResolutionResult.cs
@@ -476,8 +476,9 @@ internal void ReportDiagnostics(
&& firstSupported.Result.Kind == MemberResolutionKind.NoCorrespondingNamedParameter)
{
int badArg = firstSupported.Result.BadArgumentsOpt[0];
- IdentifierNameSyntax badName = arguments.Names[badArg];
- diagnostics.Add(ErrorCode.ERR_FunctionPointersCannotBeCalledWithNamedArguments, badName.Location);
+ Debug.Assert(arguments.Names[badArg].HasValue);
+ Location badName = arguments.Names[badArg].GetValueOrDefault().Location;
+ diagnostics.Add(ErrorCode.ERR_FunctionPointersCannotBeCalledWithNamedArguments, badName);
return;
}
// If there are multiple supported candidates, we don't have a good way to choose the best
@@ -773,15 +774,14 @@ private static void ReportNameUsedForPositional(
int badArg = bad.Result.BadArgumentsOpt[0];
// We would not have gotten this error had there not been a named argument.
Debug.Assert(arguments.Names.Count > badArg);
- IdentifierNameSyntax badName = arguments.Names[badArg];
+ Debug.Assert(arguments.Names[badArg].HasValue);
+ (string badName, Location location) = arguments.Names[badArg].GetValueOrDefault();
Debug.Assert(badName != null);
// Named argument 'x' specifies a parameter for which a positional argument has already been given
- Location location = new SourceLocation(badName);
-
diagnostics.Add(new DiagnosticInfoWithSymbols(
ErrorCode.ERR_NamedArgumentUsedInPositional,
- new object[] { badName.Identifier.ValueText },
+ new object[] { badName },
symbols), location);
}
@@ -794,26 +794,26 @@ private static void ReportBadNonTrailingNamedArgument(
int badArg = bad.Result.BadArgumentsOpt[0];
// We would not have gotten this error had there not been a named argument.
Debug.Assert(arguments.Names.Count > badArg);
- IdentifierNameSyntax badName = arguments.Names[badArg];
+ Debug.Assert(arguments.Names[badArg].HasValue);
+ (string badName, Location location) = arguments.Names[badArg].GetValueOrDefault();
Debug.Assert(badName != null);
// Named argument 'x' is used out-of-position but is followed by an unnamed argument.
- Location location = new SourceLocation(badName);
-
diagnostics.Add(new DiagnosticInfoWithSymbols(
ErrorCode.ERR_BadNonTrailingNamedArgument,
- new object[] { badName.Identifier.ValueText },
+ new object[] { badName },
symbols), location);
}
private static void ReportDuplicateNamedArgument(MemberResolutionResult result, BindingDiagnosticBag diagnostics, AnalyzedArguments arguments)
{
Debug.Assert(result.Result.BadArgumentsOpt.Length == 1);
- IdentifierNameSyntax name = arguments.Names[result.Result.BadArgumentsOpt[0]];
+ Debug.Assert(arguments.Names[result.Result.BadArgumentsOpt[0]].HasValue);
+ (string name, Location location) = arguments.Names[result.Result.BadArgumentsOpt[0]].GetValueOrDefault();
Debug.Assert(name != null);
// CS: Named argument '{0}' cannot be specified multiple times
- diagnostics.Add(new CSDiagnosticInfo(ErrorCode.ERR_DuplicateNamedArgument, name.Identifier.Text), name.Location);
+ diagnostics.Add(new CSDiagnosticInfo(ErrorCode.ERR_DuplicateNamedArgument, name), location);
}
private static void ReportNoCorrespondingNamedParameter(
@@ -834,14 +834,13 @@ private static void ReportNoCorrespondingNamedParameter(
int badArg = bad.Result.BadArgumentsOpt[0];
// We would not have gotten this error had there not been a named argument.
Debug.Assert(arguments.Names.Count > badArg);
- IdentifierNameSyntax badName = arguments.Names[badArg];
+ Debug.Assert(arguments.Names[badArg].HasValue);
+ (string badName, Location location) = arguments.Names[badArg].GetValueOrDefault();
Debug.Assert(badName != null);
// error CS1739: The best overload for 'M' does not have a parameter named 'x'
// Error CS1746: The delegate 'D' does not have a parameter named 'x'
- Location location = new SourceLocation(badName);
-
ErrorCode code = (object)delegateTypeBeingInvoked != null ?
ErrorCode.ERR_BadNamedArgumentForDelegateInvoke :
ErrorCode.ERR_BadNamedArgument;
@@ -850,7 +849,7 @@ private static void ReportNoCorrespondingNamedParameter(
diagnostics.Add(new DiagnosticInfoWithSymbols(
code,
- new object[] { obj, badName.Identifier.ValueText },
+ new object[] { obj, badName },
symbols), location);
}
diff --git a/src/Compilers/CSharp/Portable/Binder/Semantics/OverloadResolution/OverloadResolution_ArgsToParameters.cs b/src/Compilers/CSharp/Portable/Binder/Semantics/OverloadResolution/OverloadResolution_ArgsToParameters.cs
index 42a2797387613..41ce9c824011c 100644
--- a/src/Compilers/CSharp/Portable/Binder/Semantics/OverloadResolution/OverloadResolution_ArgsToParameters.cs
+++ b/src/Compilers/CSharp/Portable/Binder/Semantics/OverloadResolution/OverloadResolution_ArgsToParameters.cs
@@ -312,12 +312,13 @@ private static ArgumentAnalysisResult AnalyzeArguments(
// SPEC VIOLATION: parameter array and allow the candidate to be applicable in its
// SPEC VIOLATION: expanded form.
- var name = arguments.Names[argumentPosition];
+ Debug.Assert(arguments.Names[argumentPosition].HasValue);
+ var name = arguments.Names[argumentPosition].GetValueOrDefault().Name;
for (int p = 0; p < memberParameters.Length; ++p)
{
// p is initialized to zero; it is ok for a named argument to "correspond" to
// _any_ parameter (not just the parameters past the point of positional arguments)
- if (memberParameters[p].Name == name.Identifier.ValueText)
+ if (memberParameters[p].Name == name)
{
if (isValidParams && p == memberParameters.Length - 1)
{
diff --git a/src/Compilers/CSharp/Portable/Binder/WithExternAliasesBinder.cs b/src/Compilers/CSharp/Portable/Binder/WithExternAliasesBinder.cs
index afcd6d04cc841..c3c00349f6659 100644
--- a/src/Compilers/CSharp/Portable/Binder/WithExternAliasesBinder.cs
+++ b/src/Compilers/CSharp/Portable/Binder/WithExternAliasesBinder.cs
@@ -90,7 +90,7 @@ private sealed class FromSyntax : WithExternAliasesBinder
internal FromSyntax(SourceNamespaceSymbol declaringSymbol, CSharpSyntaxNode declarationSyntax, Binder next)
: base(next)
{
- Debug.Assert(declarationSyntax.IsKind(SyntaxKind.CompilationUnit) || declarationSyntax.IsKind(SyntaxKind.NamespaceDeclaration));
+ Debug.Assert(declarationSyntax.Kind() is SyntaxKind.CompilationUnit or SyntaxKind.NamespaceDeclaration or SyntaxKind.FileScopedNamespaceDeclaration);
_declaringSymbol = declaringSymbol;
_declarationSyntax = declarationSyntax;
}
diff --git a/src/Compilers/CSharp/Portable/Binder/WithExternAndUsingAliasesBinder.cs b/src/Compilers/CSharp/Portable/Binder/WithExternAndUsingAliasesBinder.cs
index 8c941649433af..e9be64e2660ac 100644
--- a/src/Compilers/CSharp/Portable/Binder/WithExternAndUsingAliasesBinder.cs
+++ b/src/Compilers/CSharp/Portable/Binder/WithExternAndUsingAliasesBinder.cs
@@ -117,7 +117,7 @@ private sealed class FromSyntax : WithExternAndUsingAliasesBinder
internal FromSyntax(SourceNamespaceSymbol declaringSymbol, CSharpSyntaxNode declarationSyntax, WithUsingNamespacesAndTypesBinder next)
: base(next)
{
- Debug.Assert(declarationSyntax.IsKind(SyntaxKind.CompilationUnit) || declarationSyntax.IsKind(SyntaxKind.NamespaceDeclaration));
+ Debug.Assert(declarationSyntax.Kind() is SyntaxKind.CompilationUnit or SyntaxKind.NamespaceDeclaration or SyntaxKind.FileScopedNamespaceDeclaration);
_declaringSymbol = declaringSymbol;
_declarationSyntax = declarationSyntax;
}
@@ -186,7 +186,7 @@ internal override QuickAttributeChecker QuickAttributeChecker
usingDirectives = compilationUnit.Usings;
break;
- case NamespaceDeclarationSyntax namespaceDecl:
+ case BaseNamespaceDeclarationSyntax namespaceDecl:
usingDirectives = namespaceDecl.Usings;
break;
@@ -207,7 +207,7 @@ protected override ImportChain BuildImportChain()
{
var previous = Next!.ImportChain;
- if (_declarationSyntax is NamespaceDeclarationSyntax namespaceDecl)
+ if (_declarationSyntax is BaseNamespaceDeclarationSyntax namespaceDecl)
{
// For each dotted name add an empty entry in the chain
var name = namespaceDecl.Name;
diff --git a/src/Compilers/CSharp/Portable/Binder/WithUsingNamespacesAndTypesBinder.cs b/src/Compilers/CSharp/Portable/Binder/WithUsingNamespacesAndTypesBinder.cs
index 8ca9aa8054f37..7f0159118b522 100644
--- a/src/Compilers/CSharp/Portable/Binder/WithUsingNamespacesAndTypesBinder.cs
+++ b/src/Compilers/CSharp/Portable/Binder/WithUsingNamespacesAndTypesBinder.cs
@@ -276,7 +276,7 @@ private sealed class FromSyntax : WithUsingNamespacesAndTypesBinder
internal FromSyntax(SourceNamespaceSymbol declaringSymbol, CSharpSyntaxNode declarationSyntax, Binder next, bool withImportChainEntry)
: base(next, withImportChainEntry)
{
- Debug.Assert(declarationSyntax.IsKind(SyntaxKind.CompilationUnit) || declarationSyntax.IsKind(SyntaxKind.NamespaceDeclaration));
+ Debug.Assert(declarationSyntax.Kind() is SyntaxKind.CompilationUnit or SyntaxKind.NamespaceDeclaration or SyntaxKind.FileScopedNamespaceDeclaration);
_declaringSymbol = declaringSymbol;
_declarationSyntax = declarationSyntax;
}
diff --git a/src/Compilers/CSharp/Portable/BoundTree/BoundInterpolatedStringArgumentPlaceholder.cs b/src/Compilers/CSharp/Portable/BoundTree/BoundInterpolatedStringArgumentPlaceholder.cs
new file mode 100644
index 0000000000000..56043a700a00c
--- /dev/null
+++ b/src/Compilers/CSharp/Portable/BoundTree/BoundInterpolatedStringArgumentPlaceholder.cs
@@ -0,0 +1,13 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+namespace Microsoft.CodeAnalysis.CSharp
+{
+ internal partial class BoundInterpolatedStringArgumentPlaceholder
+ {
+ public const int InstanceParameter = -1;
+ public const int TrailingConstructorValidityParameter = -2;
+ public const int UnspecifiedParameter = -3;
+ }
+}
diff --git a/src/Compilers/CSharp/Portable/BoundTree/BoundNodeExtensions.cs b/src/Compilers/CSharp/Portable/BoundTree/BoundNodeExtensions.cs
index 1444f798772fc..e328875b0d463 100644
--- a/src/Compilers/CSharp/Portable/BoundTree/BoundNodeExtensions.cs
+++ b/src/Compilers/CSharp/Portable/BoundTree/BoundNodeExtensions.cs
@@ -66,5 +66,33 @@ public static T MakeCompilerGenerated(this T node) where T : BoundNode
node.WasCompilerGenerated = true;
return node;
}
+
+ public static bool ContainsAwaitExpression(this ImmutableArray expressions)
+ {
+ var visitor = new ContainsAwaitVisitor();
+ foreach (var expression in expressions)
+ {
+ visitor.Visit(expression);
+ if (visitor.ContainsAwait)
+ {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ private class ContainsAwaitVisitor : BoundTreeWalkerWithStackGuardWithoutRecursionOnTheLeftOfBinaryOperator
+ {
+ public bool ContainsAwait = false;
+
+ public override BoundNode? Visit(BoundNode? node) => ContainsAwait ? null : base.Visit(node);
+
+ public override BoundNode? VisitAwaitExpression(BoundAwaitExpression node)
+ {
+ ContainsAwait = true;
+ return null;
+ }
+ }
}
}
diff --git a/src/Compilers/CSharp/Portable/BoundTree/BoundNodes.xml b/src/Compilers/CSharp/Portable/BoundTree/BoundNodes.xml
index cef075a396654..866232c11182f 100644
--- a/src/Compilers/CSharp/Portable/BoundTree/BoundNodes.xml
+++ b/src/Compilers/CSharp/Portable/BoundTree/BoundNodes.xml
@@ -34,6 +34,7 @@
+
@@ -1617,7 +1618,7 @@
-
+
@@ -1632,7 +1633,7 @@
-
+
@@ -2009,8 +2010,8 @@
+ from the literal parts of the input. The odd numbered positions are the string inserts. If the interpolated
+ string has been bound using the builder pattern, literals are replaced with calls. -->
@@ -2019,12 +2020,28 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -682,7 +682,7 @@
'{0}': no suitable method found to override
- A namespace cannot directly contain members such as fields or methods
+ A namespace cannot directly contain members such as fields, methods or statements
'{0}' does not contain a definition for '{1}'
@@ -3740,6 +3740,9 @@ Give the compiler some way to differentiate the methods. For example, you can gi
The return type of an async method must be void, Task, Task<T>, a task-like type, IAsyncEnumerable<T>, or IAsyncEnumerator<T>
+
+ A generic task-like return type was expected, but the type '{0}' found in 'AsyncMethodBuilder' attribute was not suitable. It must be an unbound generic type of arity one, and its containing type (if any) must be non-generic.
+
Cannot return an expression of type 'void'
@@ -4172,9 +4175,6 @@ You should consider suppressing the warning only if you're sure that you don't w
The best overloaded Add method '{0}' for the collection initializer element is obsolete. {1}
-
- Yield statements may not appear at the top level in interactive code.
-
Security attribute '{0}' is not valid on this declaration type. Security attributes are only valid on assembly, type and method declarations.
@@ -5317,9 +5317,6 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ
For type '{0}' to be used as an AsyncMethodBuilder for type '{1}', its Task property should return type '{1}' instead of type '{2}'.
-
- Attributes are not allowed on local function parameters or type parameters
-
Module '{0}' in assembly '{1}' is forwarding the type '{2}' to multiple assemblies: '{3}' and '{4}'.
@@ -6613,6 +6610,18 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ
A function pointer cannot be called with named arguments.
+
+ file-scoped namespace
+
+
+ Source file can only contain one file-scoped namespace declaration.
+
+
+ Source file can not contain both file-scoped and normal namespace declarations.
+
+
+ File-scoped namespace must precede all other members in a file.
+
Parameter '{0}' is unread. Did you forget to use it to initialize the property with that name?
@@ -6658,6 +6667,16 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ
The positional member '{0}' found corresponding to this parameter is hidden.
+
+ interpolated string handlers
+
+
+ Interpolated string handler method '{0}' is malformed. It does not return 'void' or 'bool'.
+ void and bool are keywords
+
+
+ Interpolated string handler method '{0}' has inconsistent return type. Expected to return '{1}'.
+
Identifier or a simple member access expected.
@@ -6673,6 +6692,44 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ
A global using directive must precede all non-global using directives.
+
+ null is not a valid parameter name. To get access to the receiver of an instance method, use the empty string as the parameter name.
+
+
+ '{0}' is not an instance method, the receiver cannot be an interpolated string handler argument.
+
+
+ '{0}' is not a valid parameter name from '{1}'.
+
+
+ '{0}' is not an interpolated string handler type.
+
+
+ Parameter {0} occurs after {1} in the parameter list, but is used as an argument for interpolated string handler conversions. This will require the caller to reorder parameters with named arguments at the call site. Consider putting the interpolated string handler parameter after all arguments involved.
+
+
+ Parameter to interpolated string handler conversion occurs after handler parameter
+
+
+ InterpolatedStringHandlerArgumentAttribute arguments cannot refer to the parameter the attribute is used on.
+ InterpolatedStringHandlerArgumentAttribute is a type name and should not be translated.
+
+
+ The InterpolatedStringHandlerArgumentAttribute applied to parameter '{0}' is malformed and cannot be interpreted. Construct an instance of '{1}' manually.
+ InterpolatedStringHandlerArgumentAttribute is a type name and should not be translated.
+
+
+ Parameter '{0}' is an argument to the interpolated string handler conversion on parameter '{1}', but the corresponding argument is specified after the interpolated string expression. Reorder the arguments to move '{0}' before '{1}'.
+
+
+ Parameter '{0}' is not explicitly provided, but is used as an argument to the interpolated string handler conversion on parameter '{1}'. Specify the value of '{0}' before '{1}'.
+
+
+ An expression tree may not contain an interpolated string handler conversion.
+
+
+ An interpolated string handler construction cannot use dynamic. Manually construct an instance of '{0}'.
+
static abstract members in interfaces
diff --git a/src/Compilers/CSharp/Portable/Compilation/CSharpSemanticModel.cs b/src/Compilers/CSharp/Portable/Compilation/CSharpSemanticModel.cs
index af32453b912f2..844bf5feb66eb 100644
--- a/src/Compilers/CSharp/Portable/Compilation/CSharpSemanticModel.cs
+++ b/src/Compilers/CSharp/Portable/Compilation/CSharpSemanticModel.cs
@@ -2895,6 +2895,15 @@ internal Conversion ClassifyConversionForCast(int position, ExpressionSyntax exp
/// The namespace symbol that was declared by the namespace declaration.
public abstract INamespaceSymbol GetDeclaredSymbol(NamespaceDeclarationSyntax declarationSyntax, CancellationToken cancellationToken = default(CancellationToken));
+ ///
+ /// Given a namespace declaration syntax node, get the corresponding namespace symbol for
+ /// the declaration assembly.
+ ///
+ /// The syntax node that declares a namespace.
+ /// The cancellation token.
+ /// The namespace symbol that was declared by the namespace declaration.
+ public abstract INamespaceSymbol GetDeclaredSymbol(FileScopedNamespaceDeclarationSyntax declarationSyntax, CancellationToken cancellationToken = default(CancellationToken));
+
///
/// Given a type declaration, get the corresponding type symbol.
///
@@ -5041,6 +5050,8 @@ protected sealed override ISymbol GetDeclaredSymbolCore(SyntaxNode node, Cancell
return this.GetDeclaredSymbol((TupleElementSyntax)node, cancellationToken);
case SyntaxKind.NamespaceDeclaration:
return this.GetDeclaredSymbol((NamespaceDeclarationSyntax)node, cancellationToken);
+ case SyntaxKind.FileScopedNamespaceDeclaration:
+ return this.GetDeclaredSymbol((FileScopedNamespaceDeclarationSyntax)node, cancellationToken);
case SyntaxKind.Parameter:
return this.GetDeclaredSymbol((ParameterSyntax)node, cancellationToken);
case SyntaxKind.TypeParameter:
diff --git a/src/Compilers/CSharp/Portable/Compilation/MemberSemanticModel.cs b/src/Compilers/CSharp/Portable/Compilation/MemberSemanticModel.cs
index a106610962e31..1f1acde07e68b 100644
--- a/src/Compilers/CSharp/Portable/Compilation/MemberSemanticModel.cs
+++ b/src/Compilers/CSharp/Portable/Compilation/MemberSemanticModel.cs
@@ -580,6 +580,12 @@ private static BoundNode GetLowerBoundNode(ImmutableArray boundNodes)
return null;
}
+ public override INamespaceSymbol GetDeclaredSymbol(FileScopedNamespaceDeclarationSyntax declarationSyntax, CancellationToken cancellationToken = default(CancellationToken))
+ {
+ // Can't defined namespace inside a member.
+ return null;
+ }
+
public override INamedTypeSymbol GetDeclaredSymbol(BaseTypeDeclarationSyntax declarationSyntax, CancellationToken cancellationToken = default(CancellationToken))
{
// Can't define type inside a member.
diff --git a/src/Compilers/CSharp/Portable/Compilation/SyntaxTreeSemanticModel.cs b/src/Compilers/CSharp/Portable/Compilation/SyntaxTreeSemanticModel.cs
index 7177c2780e9dd..8214ff908929e 100644
--- a/src/Compilers/CSharp/Portable/Compilation/SyntaxTreeSemanticModel.cs
+++ b/src/Compilers/CSharp/Portable/Compilation/SyntaxTreeSemanticModel.cs
@@ -1330,13 +1330,7 @@ private bool IsRegularCSharp
#region "GetDeclaredSymbol overloads for MemberDeclarationSyntax and its subtypes"
- ///
- /// Given a namespace declaration syntax node, get the corresponding namespace symbol for the declaration
- /// assembly.
- ///
- /// The syntax node that declares a namespace.
- /// The cancellation token.
- /// The namespace symbol that was declared by the namespace declaration.
+ ///
public override INamespaceSymbol GetDeclaredSymbol(NamespaceDeclarationSyntax declarationSyntax, CancellationToken cancellationToken = default(CancellationToken))
{
CheckSyntaxNode(declarationSyntax);
@@ -1344,7 +1338,15 @@ private bool IsRegularCSharp
return GetDeclaredNamespace(declarationSyntax).GetPublicSymbol();
}
- private NamespaceSymbol GetDeclaredNamespace(NamespaceDeclarationSyntax declarationSyntax)
+ ///
+ public override INamespaceSymbol GetDeclaredSymbol(FileScopedNamespaceDeclarationSyntax declarationSyntax, CancellationToken cancellationToken = default)
+ {
+ CheckSyntaxNode(declarationSyntax);
+
+ return GetDeclaredNamespace(declarationSyntax).GetPublicSymbol();
+ }
+
+ private NamespaceSymbol GetDeclaredNamespace(BaseNamespaceDeclarationSyntax declarationSyntax)
{
Debug.Assert(declarationSyntax != null);
@@ -1429,7 +1431,7 @@ private NamedTypeSymbol GetDeclaredNamedType(CSharpSyntaxNode declarationSyntax,
private NamespaceOrTypeSymbol GetDeclaredNamespaceOrType(CSharpSyntaxNode declarationSyntax)
{
- var namespaceDeclarationSyntax = declarationSyntax as NamespaceDeclarationSyntax;
+ var namespaceDeclarationSyntax = declarationSyntax as BaseNamespaceDeclarationSyntax;
if (namespaceDeclarationSyntax != null)
{
return GetDeclaredNamespace(namespaceDeclarationSyntax);
@@ -2226,7 +2228,15 @@ private void ValidateStatementRange(StatementSyntax firstStatement, StatementSyn
throw new ArgumentException("statements not within tree");
}
- if (firstStatement.Parent == null || firstStatement.Parent != lastStatement.Parent)
+ // Global statements don't have their parent in common, but should belong to the same compilation unit
+ bool isGlobalStatement = firstStatement.Parent is GlobalStatementSyntax;
+ if (isGlobalStatement && (lastStatement.Parent is not GlobalStatementSyntax || firstStatement.Parent.Parent != lastStatement.Parent.Parent))
+ {
+ throw new ArgumentException("global statements not within the same compilation unit");
+ }
+
+ // Non-global statements, the parents should be the same
+ if (!isGlobalStatement && (firstStatement.Parent == null || firstStatement.Parent != lastStatement.Parent))
{
throw new ArgumentException("statements not within the same statement list");
}
@@ -2273,7 +2283,7 @@ private NamespaceOrTypeSymbol GetDeclaredTypeMemberContainer(CSharpSyntaxNode me
if (memberDeclaration.Parent.Kind() == SyntaxKind.CompilationUnit)
{
// top-level namespace:
- if (memberDeclaration.Kind() == SyntaxKind.NamespaceDeclaration)
+ if (memberDeclaration.Kind() is SyntaxKind.NamespaceDeclaration or SyntaxKind.FileScopedNamespaceDeclaration)
{
return _compilation.Assembly.GlobalNamespace;
}
@@ -2304,7 +2314,8 @@ private NamespaceOrTypeSymbol GetDeclaredTypeMemberContainer(CSharpSyntaxNode me
}
// a namespace or a type in an explicitly declared namespace:
- if (memberDeclaration.Kind() == SyntaxKind.NamespaceDeclaration || SyntaxFacts.IsTypeDeclaration(memberDeclaration.Kind()))
+ if (memberDeclaration.Kind() is SyntaxKind.NamespaceDeclaration or SyntaxKind.FileScopedNamespaceDeclaration
+ || SyntaxFacts.IsTypeDeclaration(memberDeclaration.Kind()))
{
return container;
}
diff --git a/src/Compilers/CSharp/Portable/Declarations/DeclarationKind.cs b/src/Compilers/CSharp/Portable/Declarations/DeclarationKind.cs
index 67a98d7fceb9f..0268495646d04 100644
--- a/src/Compilers/CSharp/Portable/Declarations/DeclarationKind.cs
+++ b/src/Compilers/CSharp/Portable/Declarations/DeclarationKind.cs
@@ -36,7 +36,9 @@ internal static DeclarationKind ToDeclarationKind(this SyntaxKind kind)
case SyntaxKind.ClassDeclaration: return DeclarationKind.Class;
case SyntaxKind.InterfaceDeclaration: return DeclarationKind.Interface;
case SyntaxKind.StructDeclaration: return DeclarationKind.Struct;
- case SyntaxKind.NamespaceDeclaration: return DeclarationKind.Namespace;
+ case SyntaxKind.NamespaceDeclaration:
+ case SyntaxKind.FileScopedNamespaceDeclaration:
+ return DeclarationKind.Namespace;
case SyntaxKind.EnumDeclaration: return DeclarationKind.Enum;
case SyntaxKind.DelegateDeclaration: return DeclarationKind.Delegate;
case SyntaxKind.RecordDeclaration: return DeclarationKind.Record;
diff --git a/src/Compilers/CSharp/Portable/Declarations/DeclarationTreeBuilder.cs b/src/Compilers/CSharp/Portable/Declarations/DeclarationTreeBuilder.cs
index 4164baf567b67..29b002c315b7a 100644
--- a/src/Compilers/CSharp/Portable/Declarations/DeclarationTreeBuilder.cs
+++ b/src/Compilers/CSharp/Portable/Declarations/DeclarationTreeBuilder.cs
@@ -44,7 +44,9 @@ private ImmutableArray VisitNamespaceChildren(
SyntaxList members,
CoreInternalSyntax.SyntaxList internalMembers)
{
- Debug.Assert(node.Kind() == SyntaxKind.NamespaceDeclaration || (node.Kind() == SyntaxKind.CompilationUnit && _syntaxTree.Options.Kind == SourceCodeKind.Regular));
+ Debug.Assert(
+ node.Kind() is SyntaxKind.NamespaceDeclaration or SyntaxKind.FileScopedNamespaceDeclaration ||
+ (node.Kind() == SyntaxKind.CompilationUnit && _syntaxTree.Options.Kind == SourceCodeKind.Regular));
if (members.Count == 0)
{
@@ -310,9 +312,15 @@ private RootSingleNamespaceDeclaration CreateRootSingleNamespaceDeclaration(Comp
diagnostics: diagnostics.ToReadOnlyAndFree());
}
+ public override SingleNamespaceOrTypeDeclaration VisitFileScopedNamespaceDeclaration(FileScopedNamespaceDeclarationSyntax node)
+ => this.VisitBaseNamespaceDeclaration(node);
+
public override SingleNamespaceOrTypeDeclaration VisitNamespaceDeclaration(NamespaceDeclarationSyntax node)
+ => this.VisitBaseNamespaceDeclaration(node);
+
+ private SingleNamespaceDeclaration VisitBaseNamespaceDeclaration(BaseNamespaceDeclarationSyntax node)
{
- var children = VisitNamespaceChildren(node, node.Members, node.Green.Members);
+ var children = VisitNamespaceChildren(node, node.Members, ((Syntax.InternalSyntax.BaseNamespaceDeclarationSyntax)node.Green).Members);
bool hasUsings = node.Usings.Any();
bool hasExterns = node.Externs.Any();
@@ -338,6 +346,57 @@ public override SingleNamespaceOrTypeDeclaration VisitNamespaceDeclaration(Names
}
var diagnostics = DiagnosticBag.GetInstance();
+
+ if (node is FileScopedNamespaceDeclarationSyntax)
+ {
+ if (node.Parent is FileScopedNamespaceDeclarationSyntax)
+ {
+ // Happens when user writes:
+ // namespace A.B;
+ // namespace X.Y;
+ diagnostics.Add(ErrorCode.ERR_MultipleFileScopedNamespace, node.Name.GetLocation());
+ }
+ else if (node.Parent is NamespaceDeclarationSyntax)
+ {
+ // Happens with:
+ //
+ // namespace A.B
+ // {
+ // namespace X.Y;
+ diagnostics.Add(ErrorCode.ERR_FileScopedAndNormalNamespace, node.Name.GetLocation());
+ }
+ else
+ {
+ // Happens with cases like:
+ //
+ // namespace A.B { }
+ // namespace X.Y;
+ //
+ // or even
+ //
+ // class C { }
+ // namespace X.Y;
+
+ Debug.Assert(node.Parent is CompilationUnitSyntax);
+ var compilationUnit = (CompilationUnitSyntax)node.Parent;
+ if (node != compilationUnit.Members[0])
+ {
+ diagnostics.Add(ErrorCode.ERR_FileScopedNamespaceNotBeforeAllMembers, node.Name.GetLocation());
+ }
+ }
+ }
+ else
+ {
+ Debug.Assert(node is NamespaceDeclarationSyntax);
+
+ // namespace X.Y;
+ // namespace A.B { }
+ if (node.Parent is FileScopedNamespaceDeclarationSyntax)
+ {
+ diagnostics.Add(ErrorCode.ERR_FileScopedAndNormalNamespace, node.Name.GetLocation());
+ }
+ }
+
if (ContainsGeneric(node.Name))
{
// We're not allowed to have generics.
diff --git a/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs b/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs
index 4fa4ab7024e84..38d21fdfa5b58 100644
--- a/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs
+++ b/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs
@@ -1207,7 +1207,7 @@ internal enum ErrorCode
//WRN_PDBConstantStringValueTooLong = 7063, gave up on this warning
ERR_CantOpenIcon = 7064,
ERR_ErrorBuildingWin32Resources = 7065,
- ERR_IteratorInInteractive = 7066,
+ // ERR_IteratorInInteractive = 7066,
ERR_BadAttributeParamDefaultArgument = 7067,
ERR_MissingTypeInSource = 7068,
ERR_MissingTypeInAssembly = 7069,
@@ -1468,7 +1468,7 @@ internal enum ErrorCode
ERR_PublicSignNetModule = 8202,
ERR_BadAssemblyName = 8203,
ERR_BadAsyncMethodBuilderTaskProperty = 8204,
- ERR_AttributesInLocalFuncDecl = 8205,
+ // ERR_AttributesInLocalFuncDecl = 8205,
ERR_TypeForwardedToMultipleAssemblies = 8206,
ERR_ExpressionTreeContainsDiscard = 8207,
ERR_PatternDynamicType = 8208,
@@ -1962,8 +1962,25 @@ internal enum ErrorCode
ERR_SimpleProgramIsEmpty = 8937,
ERR_LineSpanDirectiveInvalidValue = 8938,
ERR_LineSpanDirectiveEndLessThanStart = 8939,
-
- ERR_AttrTypeArgCannotBeTypeVar = 8940,
+ ERR_WrongArityAsyncReturn = 8940,
+
+ ERR_InterpolatedStringHandlerMethodReturnMalformed = 8941,
+ ERR_InterpolatedStringHandlerMethodReturnInconsistent = 8942,
+ ERR_NullInvalidInterpolatedStringHandlerArgumentName = 8943,
+ ERR_NotInstanceInvalidInterpolatedStringHandlerArgumentName = 8944,
+ ERR_InvalidInterpolatedStringHandlerArgumentName = 8945,
+ ERR_TypeIsNotAnInterpolatedStringHandlerType = 8946,
+ WRN_ParameterOccursAfterInterpolatedStringHandlerParameter = 8947,
+ ERR_CannotUseSelfAsInterpolatedStringHandlerArgument = 8948,
+ ERR_InterpolatedStringHandlerArgumentAttributeMalformed = 8949,
+ ERR_InterpolatedStringHandlerArgumentLocatedAfterInterpolatedString = 8950,
+ ERR_InterpolatedStringHandlerArgumentOptionalNotSpecified = 8951,
+ ERR_ExpressionTreeContainsInterpolatedStringHandlerConversion = 8952,
+ ERR_InterpolatedStringHandlerCreationCannotUseDynamic = 8953,
+ ERR_MultipleFileScopedNamespace = 8954,
+ ERR_FileScopedAndNormalNamespace = 8955,
+ ERR_FileScopedNamespaceNotBeforeAllMembers = 8956,
+ ERR_AttrTypeArgCannotBeTypeVar = 8957,
#endregion
diff --git a/src/Compilers/CSharp/Portable/Errors/ErrorFacts.cs b/src/Compilers/CSharp/Portable/Errors/ErrorFacts.cs
index 92526b2b489db..368793794dcf3 100644
--- a/src/Compilers/CSharp/Portable/Errors/ErrorFacts.cs
+++ b/src/Compilers/CSharp/Portable/Errors/ErrorFacts.cs
@@ -476,6 +476,7 @@ internal static int GetWarningLevel(ErrorCode code)
case ErrorCode.WRN_AnalyzerReferencesFramework:
case ErrorCode.WRN_UnreadRecordParameter:
case ErrorCode.WRN_DoNotCompareFunctionPointers:
+ case ErrorCode.WRN_ParameterOccursAfterInterpolatedStringHandlerParameter:
return 1;
default:
return 0;
diff --git a/src/Compilers/CSharp/Portable/Errors/MessageID.cs b/src/Compilers/CSharp/Portable/Errors/MessageID.cs
index d066f32cb78d3..b3273752e7006 100644
--- a/src/Compilers/CSharp/Portable/Errors/MessageID.cs
+++ b/src/Compilers/CSharp/Portable/Errors/MessageID.cs
@@ -223,6 +223,7 @@ internal enum MessageID
IDS_FeatureGlobalUsing = MessageBase + 12798,
IDS_FeatureInferredDelegateType = MessageBase + 12799,
IDS_FeatureLambdaAttributes = MessageBase + 12800,
+
IDS_FeatureWithOnAnonymousTypes = MessageBase + 12801,
IDS_FeatureExtendedPropertyPatterns = MessageBase + 12802,
IDS_FeatureStaticAbstractMembersInInterfaces = MessageBase + 12803,
@@ -230,7 +231,9 @@ internal enum MessageID
IDS_AsyncMethodBuilderOverride = MessageBase + 12805,
IDS_FeatureImplicitImplementationOfNonPublicMemebers = MessageBase + 12806,
IDS_FeatureLineSpanDirective = MessageBase + 12807,
- IDS_FeatureGenericAttributes = MessageBase + 12808,
+ IDS_FeatureImprovedInterpolatedStrings = MessageBase + 12808,
+ IDS_FeatureFileScopedNamespace = MessageBase + 12809,
+ IDS_FeatureGenericAttributes = MessageBase + 12810,
}
// Message IDs may refer to strings that need to be localized.
@@ -344,6 +347,7 @@ internal static LanguageVersion RequiredVersion(this MessageID feature)
// C# 10.0 features.
case MessageID.IDS_FeatureMixedDeclarationsAndExpressionsInDeconstruction: // semantic check
case MessageID.IDS_FeatureSealedToStringInRecord: // semantic check
+ case MessageID.IDS_FeatureImprovedInterpolatedStrings: // semantic check
case MessageID.IDS_FeatureRecordStructs:
case MessageID.IDS_FeatureWithOnStructs: // semantic check
case MessageID.IDS_FeatureWithOnAnonymousTypes: // semantic check
@@ -357,6 +361,7 @@ internal static LanguageVersion RequiredVersion(this MessageID feature)
case MessageID.IDS_FeatureConstantInterpolatedStrings: // semantic check
case MessageID.IDS_FeatureImplicitImplementationOfNonPublicMemebers: // semantic check
case MessageID.IDS_FeatureLineSpanDirective:
+ case MessageID.IDS_FeatureFileScopedNamespace: // syntax check
case MessageID.IDS_FeatureGenericAttributes: // semantic check
return LanguageVersion.CSharp10;
diff --git a/src/Compilers/CSharp/Portable/FlowAnalysis/AbstractFlowPass.cs b/src/Compilers/CSharp/Portable/FlowAnalysis/AbstractFlowPass.cs
index df4d53bdf8607..f74aab6458d45 100644
--- a/src/Compilers/CSharp/Portable/FlowAnalysis/AbstractFlowPass.cs
+++ b/src/Compilers/CSharp/Portable/FlowAnalysis/AbstractFlowPass.cs
@@ -4,6 +4,7 @@
#nullable disable
+using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Diagnostics;
@@ -1149,23 +1150,85 @@ public override BoundNode VisitDynamicInvocation(BoundDynamicInvocation node)
return null;
}
- protected BoundNode VisitInterpolatedStringBase(BoundInterpolatedStringBase node)
+ protected BoundNode VisitInterpolatedStringBase(BoundInterpolatedStringBase node, InterpolatedStringHandlerData? data)
{
- foreach (var expr in node.Parts)
+ // If there can be any branching, then we need to treat the expressions
+ // as optionally evaluated. Otherwise, we treat them as always evaluated
+ switch (data)
{
- VisitRvalue(expr);
+ case null:
+ visitParts();
+ break;
+ case { HasTrailingHandlerValidityParameter: false, UsesBoolReturns: false, Construction: var construction }:
+ VisitRvalue(construction);
+ visitParts();
+ break;
+ case { UsesBoolReturns: var usesBoolReturns, HasTrailingHandlerValidityParameter: var hasTrailingValidityParameter, Construction: var construction }:
+ VisitRvalue(construction);
+
+ if (node.Parts.IsEmpty)
+ {
+ break;
+ }
+
+ TLocalState beforePartsState;
+ ReadOnlySpan remainingParts;
+
+ if (hasTrailingValidityParameter)
+ {
+ beforePartsState = State.Clone();
+ remainingParts = node.Parts.AsSpan();
+ }
+ else
+ {
+ Visit(node.Parts[0]);
+ beforePartsState = State.Clone();
+ remainingParts = node.Parts.AsSpan()[1..];
+ }
+
+ foreach (var expr in remainingParts)
+ {
+ VisitRvalue(expr);
+ if (usesBoolReturns)
+ {
+ Join(ref beforePartsState, ref State);
+ }
+ }
+
+ if (usesBoolReturns)
+ {
+ // Already been joined after the last part, just assign
+ State = beforePartsState;
+ }
+ else
+ {
+ Debug.Assert(hasTrailingValidityParameter);
+ Join(ref State, ref beforePartsState);
+ }
+
+ break;
}
+
return null;
+
+ void visitParts()
+ {
+ foreach (var expr in node.Parts)
+ {
+ VisitRvalue(expr);
+ }
+ }
}
public override BoundNode VisitInterpolatedString(BoundInterpolatedString node)
{
- return VisitInterpolatedStringBase(node);
+ return VisitInterpolatedStringBase(node, node.InterpolationData);
}
public override BoundNode VisitUnconvertedInterpolatedString(BoundUnconvertedInterpolatedString node)
{
- return VisitInterpolatedStringBase(node);
+ // If the node is unconverted, we'll just treat it as if the contents are always evaluated
+ return VisitInterpolatedStringBase(node, data: null);
}
public override BoundNode VisitStringInsert(BoundStringInsert node)
@@ -1184,6 +1247,16 @@ public override BoundNode VisitStringInsert(BoundStringInsert node)
return null;
}
+ public override BoundNode VisitInterpolatedStringHandlerPlaceholder(BoundInterpolatedStringHandlerPlaceholder node)
+ {
+ return null;
+ }
+
+ public override BoundNode VisitInterpolatedStringArgumentPlaceholder(BoundInterpolatedStringArgumentPlaceholder node)
+ {
+ return null;
+ }
+
public override BoundNode VisitArgList(BoundArgList node)
{
// The "__arglist" expression that is legal inside a varargs method has no
diff --git a/src/Compilers/CSharp/Portable/FlowAnalysis/NullableWalker.DebugVerifier.cs b/src/Compilers/CSharp/Portable/FlowAnalysis/NullableWalker.DebugVerifier.cs
index 2ee0728aaca87..d10c77498e301 100644
--- a/src/Compilers/CSharp/Portable/FlowAnalysis/NullableWalker.DebugVerifier.cs
+++ b/src/Compilers/CSharp/Portable/FlowAnalysis/NullableWalker.DebugVerifier.cs
@@ -243,6 +243,16 @@ private void VisitBinaryOperatorChildren(BoundBinaryOperatorBase node)
// info is exposed to consumers.
return null;
}
+
+ public override BoundNode? VisitInterpolatedString(BoundInterpolatedString node)
+ {
+ if (node.InterpolationData is { Construction: var construction })
+ {
+ Visit(construction);
+ }
+ base.VisitInterpolatedString(node);
+ return null;
+ }
}
#endif
}
diff --git a/src/Compilers/CSharp/Portable/FlowAnalysis/NullableWalker.cs b/src/Compilers/CSharp/Portable/FlowAnalysis/NullableWalker.cs
index 6cad61e9557d2..73507e79b189c 100644
--- a/src/Compilers/CSharp/Portable/FlowAnalysis/NullableWalker.cs
+++ b/src/Compilers/CSharp/Portable/FlowAnalysis/NullableWalker.cs
@@ -6983,6 +6983,11 @@ private TypeWithState VisitConversion(
resultState = NullableFlowState.NotNull;
break;
+ case ConversionKind.InterpolatedStringHandler:
+ // https://github.com/dotnet/roslyn/issues/54583 Handle
+ resultState = NullableFlowState.NotNull;
+ break;
+
case ConversionKind.ObjectCreation:
case ConversionKind.SwitchExpression:
case ConversionKind.ConditionalExpression:
@@ -9764,6 +9769,8 @@ private static bool IsNullabilityMismatch(TypeSymbol type1, TypeSymbol type2)
public override BoundNode? VisitInterpolatedString(BoundInterpolatedString node)
{
+ // https://github.com/dotnet/roslyn/issues/54583
+ // Better handle the constructor propogation
var result = base.VisitInterpolatedString(node);
SetResultType(node, TypeWithState.Create(node.Type, NullableFlowState.NotNull));
return result;
@@ -9784,6 +9791,18 @@ private static bool IsNullabilityMismatch(TypeSymbol type1, TypeSymbol type2)
return result;
}
+ public override BoundNode? VisitInterpolatedStringHandlerPlaceholder(BoundInterpolatedStringHandlerPlaceholder node)
+ {
+ SetNotNullResult(node);
+ return null;
+ }
+
+ public override BoundNode? VisitInterpolatedStringArgumentPlaceholder(BoundInterpolatedStringArgumentPlaceholder node)
+ {
+ SetNotNullResult(node);
+ return null;
+ }
+
public override BoundNode? VisitConvertedStackAllocExpression(BoundConvertedStackAllocExpression node)
{
var result = base.VisitConvertedStackAllocExpression(node);
diff --git a/src/Compilers/CSharp/Portable/Generated/BoundNodes.xml.Generated.cs b/src/Compilers/CSharp/Portable/Generated/BoundNodes.xml.Generated.cs
index b6df30a1a81c0..fa2e11b51b2df 100644
--- a/src/Compilers/CSharp/Portable/Generated/BoundNodes.xml.Generated.cs
+++ b/src/Compilers/CSharp/Portable/Generated/BoundNodes.xml.Generated.cs
@@ -201,6 +201,8 @@ internal enum BoundKind : byte
NameOfOperator,
UnconvertedInterpolatedString,
InterpolatedString,
+ InterpolatedStringHandlerPlaceholder,
+ InterpolatedStringArgumentPlaceholder,
StringInsert,
IsPatternExpression,
ConstantPattern,
@@ -239,6 +241,7 @@ internal enum BoundKind : byte
+
internal abstract partial class BoundInitializer : BoundNode
{
protected BoundInitializer(BoundKind kind, SyntaxNode syntax, bool hasErrors)
@@ -5775,7 +5778,7 @@ public BoundEventAssignmentOperator Update(EventSymbol @event, bool isAddition,
internal sealed partial class BoundAttribute : BoundExpression
{
- public BoundAttribute(SyntaxNode syntax, MethodSymbol? constructor, ImmutableArray constructorArguments, ImmutableArray constructorArgumentNamesOpt, ImmutableArray constructorArgumentsToParamsOpt, bool constructorExpanded, ImmutableArray namedArguments, LookupResultKind resultKind, TypeSymbol type, bool hasErrors = false)
+ public BoundAttribute(SyntaxNode syntax, MethodSymbol? constructor, ImmutableArray constructorArguments, ImmutableArray constructorArgumentNamesOpt, ImmutableArray constructorArgumentsToParamsOpt, bool constructorExpanded, ImmutableArray namedArguments, LookupResultKind resultKind, TypeSymbol type, bool hasErrors = false)
: base(BoundKind.Attribute, syntax, type, hasErrors || constructorArguments.HasErrors() || namedArguments.HasErrors())
{
@@ -5799,7 +5802,7 @@ public BoundAttribute(SyntaxNode syntax, MethodSymbol? constructor, ImmutableArr
public ImmutableArray ConstructorArguments { get; }
- public ImmutableArray ConstructorArgumentNamesOpt { get; }
+ public ImmutableArray ConstructorArgumentNamesOpt { get; }
public ImmutableArray ConstructorArgumentsToParamsOpt { get; }
@@ -5812,7 +5815,7 @@ public BoundAttribute(SyntaxNode syntax, MethodSymbol? constructor, ImmutableArr
[DebuggerStepThrough]
public override BoundNode? Accept(BoundTreeVisitor visitor) => visitor.VisitAttribute(this);
- public BoundAttribute Update(MethodSymbol? constructor, ImmutableArray constructorArguments, ImmutableArray constructorArgumentNamesOpt, ImmutableArray constructorArgumentsToParamsOpt, bool constructorExpanded, ImmutableArray namedArguments, LookupResultKind resultKind, TypeSymbol type)
+ public BoundAttribute Update(MethodSymbol? constructor, ImmutableArray constructorArguments, ImmutableArray constructorArgumentNamesOpt, ImmutableArray constructorArgumentsToParamsOpt, bool constructorExpanded, ImmutableArray namedArguments, LookupResultKind resultKind, TypeSymbol type)
{
if (!Symbols.SymbolEqualityComparer.ConsiderEverything.Equals(constructor, this.Constructor) || constructorArguments != this.ConstructorArguments || constructorArgumentNamesOpt != this.ConstructorArgumentNamesOpt || constructorArgumentsToParamsOpt != this.ConstructorArgumentsToParamsOpt || constructorExpanded != this.ConstructorExpanded || namedArguments != this.NamedArguments || resultKind != this.ResultKind || !TypeSymbol.Equals(type, this.Type, TypeCompareKind.ConsiderEverything))
{
@@ -5826,7 +5829,7 @@ public BoundAttribute Update(MethodSymbol? constructor, ImmutableArray arguments, ImmutableArray argumentNamesOpt, ImmutableArray argumentRefKindsOpt, InitializerExpressionSyntax? initializerOpt, bool hasErrors = false)
+ public BoundUnconvertedObjectCreationExpression(SyntaxNode syntax, ImmutableArray arguments, ImmutableArray<(string Name, Location Location)?> argumentNamesOpt, ImmutableArray argumentRefKindsOpt, InitializerExpressionSyntax? initializerOpt, bool hasErrors = false)
: base(BoundKind.UnconvertedObjectCreationExpression, syntax, null, hasErrors || arguments.HasErrors())
{
@@ -5843,7 +5846,7 @@ public BoundUnconvertedObjectCreationExpression(SyntaxNode syntax, ImmutableArra
public ImmutableArray Arguments { get; }
- public ImmutableArray ArgumentNamesOpt { get; }
+ public ImmutableArray<(string Name, Location Location)?> ArgumentNamesOpt { get; }
public ImmutableArray ArgumentRefKindsOpt { get; }
@@ -5851,7 +5854,7 @@ public BoundUnconvertedObjectCreationExpression(SyntaxNode syntax, ImmutableArra
[DebuggerStepThrough]
public override BoundNode? Accept(BoundTreeVisitor visitor) => visitor.VisitUnconvertedObjectCreationExpression(this);
- public BoundUnconvertedObjectCreationExpression Update(ImmutableArray arguments, ImmutableArray argumentNamesOpt, ImmutableArray argumentRefKindsOpt, InitializerExpressionSyntax? initializerOpt)
+ public BoundUnconvertedObjectCreationExpression Update(ImmutableArray arguments, ImmutableArray<(string Name, Location Location)?> argumentNamesOpt, ImmutableArray argumentRefKindsOpt, InitializerExpressionSyntax? initializerOpt)
{
if (arguments != this.Arguments || argumentNamesOpt != this.ArgumentNamesOpt || argumentRefKindsOpt != this.ArgumentRefKindsOpt || initializerOpt != this.InitializerOpt)
{
@@ -7227,22 +7230,95 @@ public BoundUnconvertedInterpolatedString Update(ImmutableArray
internal sealed partial class BoundInterpolatedString : BoundInterpolatedStringBase
{
- public BoundInterpolatedString(SyntaxNode syntax, ImmutableArray parts, ConstantValue? constantValueOpt, TypeSymbol? type, bool hasErrors = false)
+ public BoundInterpolatedString(SyntaxNode syntax, InterpolatedStringHandlerData? interpolationData, ImmutableArray parts, ConstantValue? constantValueOpt, TypeSymbol? type, bool hasErrors = false)
: base(BoundKind.InterpolatedString, syntax, parts, constantValueOpt, type, hasErrors || parts.HasErrors())
{
RoslynDebug.Assert(!parts.IsDefault, "Field 'parts' cannot be null (use Null=\"allow\" in BoundNodes.xml to remove this check)");
+ this.InterpolationData = interpolationData;
}
+
+ public InterpolatedStringHandlerData? InterpolationData { get; }
[DebuggerStepThrough]
public override BoundNode? Accept(BoundTreeVisitor visitor) => visitor.VisitInterpolatedString(this);
- public BoundInterpolatedString Update(ImmutableArray parts, ConstantValue? constantValueOpt, TypeSymbol? type)
+ public BoundInterpolatedString Update(InterpolatedStringHandlerData? interpolationData, ImmutableArray parts, ConstantValue? constantValueOpt, TypeSymbol? type)
{
- if (parts != this.Parts || constantValueOpt != this.ConstantValueOpt || !TypeSymbol.Equals(type, this.Type, TypeCompareKind.ConsiderEverything))
+ if (interpolationData.Equals(this.InterpolationData) || parts != this.Parts || constantValueOpt != this.ConstantValueOpt || !TypeSymbol.Equals(type, this.Type, TypeCompareKind.ConsiderEverything))
+ {
+ var result = new BoundInterpolatedString(this.Syntax, interpolationData, parts, constantValueOpt, type, this.HasErrors);
+ result.CopyAttributes(this);
+ return result;
+ }
+ return this;
+ }
+ }
+
+ internal sealed partial class BoundInterpolatedStringHandlerPlaceholder : BoundValuePlaceholderBase
+ {
+ public BoundInterpolatedStringHandlerPlaceholder(SyntaxNode syntax, TypeSymbol? type, bool hasErrors)
+ : base(BoundKind.InterpolatedStringHandlerPlaceholder, syntax, type, hasErrors)
+ {
+ }
+
+ public BoundInterpolatedStringHandlerPlaceholder(SyntaxNode syntax, TypeSymbol? type)
+ : base(BoundKind.InterpolatedStringHandlerPlaceholder, syntax, type)
+ {
+ }
+
+ [DebuggerStepThrough]
+ public override BoundNode? Accept(BoundTreeVisitor visitor) => visitor.VisitInterpolatedStringHandlerPlaceholder(this);
+
+ public BoundInterpolatedStringHandlerPlaceholder Update(TypeSymbol? type)
+ {
+ if (!TypeSymbol.Equals(type, this.Type, TypeCompareKind.ConsiderEverything))
{
- var result = new BoundInterpolatedString(this.Syntax, parts, constantValueOpt, type, this.HasErrors);
+ var result = new BoundInterpolatedStringHandlerPlaceholder(this.Syntax, type, this.HasErrors);
+ result.CopyAttributes(this);
+ return result;
+ }
+ return this;
+ }
+ }
+
+ internal sealed partial class BoundInterpolatedStringArgumentPlaceholder : BoundValuePlaceholderBase
+ {
+ public BoundInterpolatedStringArgumentPlaceholder(SyntaxNode syntax, int argumentIndex, uint valSafeToEscape, TypeSymbol type, bool hasErrors)
+ : base(BoundKind.InterpolatedStringArgumentPlaceholder, syntax, type, hasErrors)
+ {
+
+ RoslynDebug.Assert(type is object, "Field 'type' cannot be null (make the type nullable in BoundNodes.xml to remove this check)");
+
+ this.ArgumentIndex = argumentIndex;
+ this.ValSafeToEscape = valSafeToEscape;
+ }
+
+ public BoundInterpolatedStringArgumentPlaceholder(SyntaxNode syntax, int argumentIndex, uint valSafeToEscape, TypeSymbol type)
+ : base(BoundKind.InterpolatedStringArgumentPlaceholder, syntax, type)
+ {
+
+ RoslynDebug.Assert(type is object, "Field 'type' cannot be null (make the type nullable in BoundNodes.xml to remove this check)");
+
+ this.ArgumentIndex = argumentIndex;
+ this.ValSafeToEscape = valSafeToEscape;
+ }
+
+
+ public new TypeSymbol Type => base.Type!;
+
+ public int ArgumentIndex { get; }
+
+ public uint ValSafeToEscape { get; }
+ [DebuggerStepThrough]
+ public override BoundNode? Accept(BoundTreeVisitor visitor) => visitor.VisitInterpolatedStringArgumentPlaceholder(this);
+
+ public BoundInterpolatedStringArgumentPlaceholder Update(int argumentIndex, uint valSafeToEscape, TypeSymbol type)
+ {
+ if (argumentIndex != this.ArgumentIndex || valSafeToEscape != this.ValSafeToEscape || !TypeSymbol.Equals(type, this.Type, TypeCompareKind.ConsiderEverything))
+ {
+ var result = new BoundInterpolatedStringArgumentPlaceholder(this.Syntax, argumentIndex, valSafeToEscape, type, this.HasErrors);
result.CopyAttributes(this);
return result;
}
@@ -7252,8 +7328,8 @@ public BoundInterpolatedString Update(ImmutableArray parts, Con
internal sealed partial class BoundStringInsert : BoundExpression
{
- public BoundStringInsert(SyntaxNode syntax, BoundExpression value, BoundExpression? alignment, BoundLiteral? format, TypeSymbol? type, bool hasErrors = false)
- : base(BoundKind.StringInsert, syntax, type, hasErrors || value.HasErrors() || alignment.HasErrors() || format.HasErrors())
+ public BoundStringInsert(SyntaxNode syntax, BoundExpression value, BoundExpression? alignment, BoundLiteral? format, bool isInterpolatedStringHandlerAppendCall, bool hasErrors = false)
+ : base(BoundKind.StringInsert, syntax, null, hasErrors || value.HasErrors() || alignment.HasErrors() || format.HasErrors())
{
RoslynDebug.Assert(value is object, "Field 'value' cannot be null (make the type nullable in BoundNodes.xml to remove this check)");
@@ -7261,22 +7337,27 @@ public BoundStringInsert(SyntaxNode syntax, BoundExpression value, BoundExpressi
this.Value = value;
this.Alignment = alignment;
this.Format = format;
+ this.IsInterpolatedStringHandlerAppendCall = isInterpolatedStringHandlerAppendCall;
}
+ public new TypeSymbol? Type => base.Type;
+
public BoundExpression Value { get; }
public BoundExpression? Alignment { get; }
public BoundLiteral? Format { get; }
+
+ public bool IsInterpolatedStringHandlerAppendCall { get; }
[DebuggerStepThrough]
public override BoundNode? Accept(BoundTreeVisitor visitor) => visitor.VisitStringInsert(this);
- public BoundStringInsert Update(BoundExpression value, BoundExpression? alignment, BoundLiteral? format, TypeSymbol? type)
+ public BoundStringInsert Update(BoundExpression value, BoundExpression? alignment, BoundLiteral? format, bool isInterpolatedStringHandlerAppendCall)
{
- if (value != this.Value || alignment != this.Alignment || format != this.Format || !TypeSymbol.Equals(type, this.Type, TypeCompareKind.ConsiderEverything))
+ if (value != this.Value || alignment != this.Alignment || format != this.Format || isInterpolatedStringHandlerAppendCall != this.IsInterpolatedStringHandlerAppendCall)
{
- var result = new BoundStringInsert(this.Syntax, value, alignment, format, type, this.HasErrors);
+ var result = new BoundStringInsert(this.Syntax, value, alignment, format, isInterpolatedStringHandlerAppendCall, this.HasErrors);
result.CopyAttributes(this);
return result;
}
@@ -8455,6 +8536,10 @@ internal R VisitInternal(BoundNode node, A arg)
return VisitUnconvertedInterpolatedString((BoundUnconvertedInterpolatedString)node, arg);
case BoundKind.InterpolatedString:
return VisitInterpolatedString((BoundInterpolatedString)node, arg);
+ case BoundKind.InterpolatedStringHandlerPlaceholder:
+ return VisitInterpolatedStringHandlerPlaceholder((BoundInterpolatedStringHandlerPlaceholder)node, arg);
+ case BoundKind.InterpolatedStringArgumentPlaceholder:
+ return VisitInterpolatedStringArgumentPlaceholder((BoundInterpolatedStringArgumentPlaceholder)node, arg);
case BoundKind.StringInsert:
return VisitStringInsert((BoundStringInsert)node, arg);
case BoundKind.IsPatternExpression:
@@ -8690,6 +8775,8 @@ internal abstract partial class BoundTreeVisitor
public virtual R VisitNameOfOperator(BoundNameOfOperator node, A arg) => this.DefaultVisit(node, arg);
public virtual R VisitUnconvertedInterpolatedString(BoundUnconvertedInterpolatedString node, A arg) => this.DefaultVisit(node, arg);
public virtual R VisitInterpolatedString(BoundInterpolatedString node, A arg) => this.DefaultVisit(node, arg);
+ public virtual R VisitInterpolatedStringHandlerPlaceholder(BoundInterpolatedStringHandlerPlaceholder node, A arg) => this.DefaultVisit(node, arg);
+ public virtual R VisitInterpolatedStringArgumentPlaceholder(BoundInterpolatedStringArgumentPlaceholder node, A arg) => this.DefaultVisit(node, arg);
public virtual R VisitStringInsert(BoundStringInsert node, A arg) => this.DefaultVisit(node, arg);
public virtual R VisitIsPatternExpression(BoundIsPatternExpression node, A arg) => this.DefaultVisit(node, arg);
public virtual R VisitConstantPattern(BoundConstantPattern node, A arg) => this.DefaultVisit(node, arg);
@@ -8898,6 +8985,8 @@ internal abstract partial class BoundTreeVisitor
public virtual BoundNode? VisitNameOfOperator(BoundNameOfOperator node) => this.DefaultVisit(node);
public virtual BoundNode? VisitUnconvertedInterpolatedString(BoundUnconvertedInterpolatedString node) => this.DefaultVisit(node);
public virtual BoundNode? VisitInterpolatedString(BoundInterpolatedString node) => this.DefaultVisit(node);
+ public virtual BoundNode? VisitInterpolatedStringHandlerPlaceholder(BoundInterpolatedStringHandlerPlaceholder node) => this.DefaultVisit(node);
+ public virtual BoundNode? VisitInterpolatedStringArgumentPlaceholder(BoundInterpolatedStringArgumentPlaceholder node) => this.DefaultVisit(node);
public virtual BoundNode? VisitStringInsert(BoundStringInsert node) => this.DefaultVisit(node);
public virtual BoundNode? VisitIsPatternExpression(BoundIsPatternExpression node) => this.DefaultVisit(node);
public virtual BoundNode? VisitConstantPattern(BoundConstantPattern node) => this.DefaultVisit(node);
@@ -9739,6 +9828,8 @@ internal abstract partial class BoundTreeWalker : BoundTreeVisitor
this.VisitList(node.Parts);
return null;
}
+ public override BoundNode? VisitInterpolatedStringHandlerPlaceholder(BoundInterpolatedStringHandlerPlaceholder node) => null;
+ public override BoundNode? VisitInterpolatedStringArgumentPlaceholder(BoundInterpolatedStringArgumentPlaceholder node) => null;
public override BoundNode? VisitStringInsert(BoundStringInsert node)
{
this.Visit(node.Value);
@@ -10917,7 +11008,17 @@ internal abstract partial class BoundTreeRewriter : BoundTreeVisitor
{
ImmutableArray parts = this.VisitList(node.Parts);
TypeSymbol? type = this.VisitType(node.Type);
- return node.Update(parts, node.ConstantValueOpt, type);
+ return node.Update(node.InterpolationData, parts, node.ConstantValueOpt, type);
+ }
+ public override BoundNode? VisitInterpolatedStringHandlerPlaceholder(BoundInterpolatedStringHandlerPlaceholder node)
+ {
+ TypeSymbol? type = this.VisitType(node.Type);
+ return node.Update(type);
+ }
+ public override BoundNode? VisitInterpolatedStringArgumentPlaceholder(BoundInterpolatedStringArgumentPlaceholder node)
+ {
+ TypeSymbol? type = this.VisitType(node.Type);
+ return node.Update(node.ArgumentIndex, node.ValSafeToEscape, type);
}
public override BoundNode? VisitStringInsert(BoundStringInsert node)
{
@@ -10925,7 +11026,7 @@ internal abstract partial class BoundTreeRewriter : BoundTreeVisitor
BoundExpression? alignment = (BoundExpression?)this.Visit(node.Alignment);
BoundLiteral? format = (BoundLiteral?)this.Visit(node.Format);
TypeSymbol? type = this.VisitType(node.Type);
- return node.Update(value, alignment, format, type);
+ return node.Update(value, alignment, format, node.IsInterpolatedStringHandlerAppendCall);
}
public override BoundNode? VisitIsPatternExpression(BoundIsPatternExpression node)
{
@@ -13203,16 +13304,40 @@ public NullabilityRewriter(ImmutableDictionary new TreeDumperNode("interpolatedString", null, new TreeDumperNode[]
{
+ new TreeDumperNode("interpolationData", node.InterpolationData, null),
new TreeDumperNode("parts", null, from x in node.Parts select Visit(x, null)),
new TreeDumperNode("constantValueOpt", node.ConstantValueOpt, null),
new TreeDumperNode("type", node.Type, null),
@@ -15143,11 +15269,28 @@ private BoundTreeDumperNodeProducer()
new TreeDumperNode("hasErrors", node.HasErrors, null)
}
);
+ public override TreeDumperNode VisitInterpolatedStringHandlerPlaceholder(BoundInterpolatedStringHandlerPlaceholder node, object? arg) => new TreeDumperNode("interpolatedStringHandlerPlaceholder", null, new TreeDumperNode[]
+ {
+ new TreeDumperNode("type", node.Type, null),
+ new TreeDumperNode("isSuppressed", node.IsSuppressed, null),
+ new TreeDumperNode("hasErrors", node.HasErrors, null)
+ }
+ );
+ public override TreeDumperNode VisitInterpolatedStringArgumentPlaceholder(BoundInterpolatedStringArgumentPlaceholder node, object? arg) => new TreeDumperNode("interpolatedStringArgumentPlaceholder", null, new TreeDumperNode[]
+ {
+ new TreeDumperNode("argumentIndex", node.ArgumentIndex, null),
+ new TreeDumperNode("valSafeToEscape", node.ValSafeToEscape, null),
+ new TreeDumperNode("type", node.Type, null),
+ new TreeDumperNode("isSuppressed", node.IsSuppressed, null),
+ new TreeDumperNode("hasErrors", node.HasErrors, null)
+ }
+ );
public override TreeDumperNode VisitStringInsert(BoundStringInsert node, object? arg) => new TreeDumperNode("stringInsert", null, new TreeDumperNode[]
{
new TreeDumperNode("value", null, new TreeDumperNode[] { Visit(node.Value, null) }),
new TreeDumperNode("alignment", null, new TreeDumperNode[] { Visit(node.Alignment, null) }),
new TreeDumperNode("format", null, new TreeDumperNode[] { Visit(node.Format, null) }),
+ new TreeDumperNode("isInterpolatedStringHandlerAppendCall", node.IsInterpolatedStringHandlerAppendCall, null),
new TreeDumperNode("type", node.Type, null),
new TreeDumperNode("isSuppressed", node.IsSuppressed, null),
new TreeDumperNode("hasErrors", node.HasErrors, null)
diff --git a/src/Compilers/CSharp/Portable/Generated/CSharp.Generated.g4 b/src/Compilers/CSharp/Portable/Generated/CSharp.Generated.g4
index 9450e00d62f58..331e0220160a7 100644
--- a/src/Compilers/CSharp/Portable/Generated/CSharp.Generated.g4
+++ b/src/Compilers/CSharp/Portable/Generated/CSharp.Generated.g4
@@ -76,13 +76,13 @@ name_colon
member_declaration
: base_field_declaration
| base_method_declaration
+ | base_namespace_declaration
| base_property_declaration
| base_type_declaration
| delegate_declaration
| enum_member_declaration
| global_statement
| incomplete_member
- | namespace_declaration
;
base_field_declaration
@@ -232,6 +232,19 @@ operator_declaration
: attribute_list* modifier* type explicit_interface_specifier? 'operator' ('+' | '-' | '!' | '~' | '++' | '--' | '*' | '/' | '%' | '<<' | '>>' | '|' | '&' | '^' | '==' | '!=' | '<' | '<=' | '>' | '>=' | 'false' | 'true' | 'is') parameter_list (block | (arrow_expression_clause ';'))
;
+base_namespace_declaration
+ : file_scoped_namespace_declaration
+ | namespace_declaration
+ ;
+
+file_scoped_namespace_declaration
+ : attribute_list* modifier* 'namespace' name ';' extern_alias_directive* using_directive* member_declaration*
+ ;
+
+namespace_declaration
+ : attribute_list* modifier* 'namespace' name '{' extern_alias_directive* using_directive* member_declaration* '}' ';'?
+ ;
+
base_property_declaration
: event_declaration
| indexer_declaration
@@ -327,10 +340,6 @@ incomplete_member
: attribute_list* modifier* type?
;
-namespace_declaration
- : attribute_list* modifier* 'namespace' name '{' extern_alias_directive* using_directive* member_declaration* '}' ';'?
- ;
-
type
: array_type
| function_pointer_type
diff --git a/src/Compilers/CSharp/Portable/Generated/CSharpSyntaxGenerator/CSharpSyntaxGenerator.SourceGenerator/Syntax.xml.Internal.Generated.cs b/src/Compilers/CSharp/Portable/Generated/CSharpSyntaxGenerator/CSharpSyntaxGenerator.SourceGenerator/Syntax.xml.Internal.Generated.cs
index 091928df6b8dc..c8656985fd5e1 100644
--- a/src/Compilers/CSharp/Portable/Generated/CSharpSyntaxGenerator/CSharpSyntaxGenerator.SourceGenerator/Syntax.xml.Internal.Generated.cs
+++ b/src/Compilers/CSharp/Portable/Generated/CSharpSyntaxGenerator/CSharpSyntaxGenerator.SourceGenerator/Syntax.xml.Internal.Generated.cs
@@ -19505,7 +19505,35 @@ protected MemberDeclarationSyntax(ObjectReader reader)
public abstract Microsoft.CodeAnalysis.Syntax.InternalSyntax.SyntaxList Modifiers { get; }
}
- internal sealed partial class NamespaceDeclarationSyntax : MemberDeclarationSyntax
+ internal abstract partial class BaseNamespaceDeclarationSyntax : MemberDeclarationSyntax
+ {
+ internal BaseNamespaceDeclarationSyntax(SyntaxKind kind, DiagnosticInfo[]? diagnostics, SyntaxAnnotation[]? annotations)
+ : base(kind, diagnostics, annotations)
+ {
+ }
+
+ internal BaseNamespaceDeclarationSyntax(SyntaxKind kind)
+ : base(kind)
+ {
+ }
+
+ protected BaseNamespaceDeclarationSyntax(ObjectReader reader)
+ : base(reader)
+ {
+ }
+
+ public abstract SyntaxToken NamespaceKeyword { get; }
+
+ public abstract NameSyntax Name { get; }
+
+ public abstract Microsoft.CodeAnalysis.Syntax.InternalSyntax.SyntaxList Externs { get; }
+
+ public abstract Microsoft.CodeAnalysis.Syntax.InternalSyntax.SyntaxList Usings { get; }
+
+ public abstract Microsoft.CodeAnalysis.Syntax.InternalSyntax.SyntaxList Members { get; }
+ }
+
+ internal sealed partial class NamespaceDeclarationSyntax : BaseNamespaceDeclarationSyntax
{
internal readonly GreenNode? attributeLists;
internal readonly GreenNode? modifiers;
@@ -19653,12 +19681,12 @@ internal NamespaceDeclarationSyntax(SyntaxKind kind, GreenNode? attributeLists,
public override Microsoft.CodeAnalysis.Syntax.InternalSyntax.SyntaxList AttributeLists => new Microsoft.CodeAnalysis.Syntax.InternalSyntax.SyntaxList(this.attributeLists);
public override Microsoft.CodeAnalysis.Syntax.InternalSyntax.SyntaxList Modifiers => new Microsoft.CodeAnalysis.Syntax.InternalSyntax.SyntaxList(this.modifiers);
- public SyntaxToken NamespaceKeyword => this.namespaceKeyword;
- public NameSyntax Name => this.name;
+ public override SyntaxToken NamespaceKeyword => this.namespaceKeyword;
+ public override NameSyntax Name => this.name;
public SyntaxToken OpenBraceToken => this.openBraceToken;
- public Microsoft.CodeAnalysis.Syntax.InternalSyntax.SyntaxList Externs => new Microsoft.CodeAnalysis.Syntax.InternalSyntax.SyntaxList(this.externs);
- public Microsoft.CodeAnalysis.Syntax.InternalSyntax.SyntaxList Usings => new Microsoft.CodeAnalysis.Syntax.InternalSyntax.SyntaxList(this.usings);
- public Microsoft.CodeAnalysis.Syntax.InternalSyntax.SyntaxList Members => new Microsoft.CodeAnalysis.Syntax.InternalSyntax.SyntaxList(this.members);
+ public override Microsoft.CodeAnalysis.Syntax.InternalSyntax.SyntaxList Externs => new Microsoft.CodeAnalysis.Syntax.InternalSyntax.SyntaxList(this.externs);
+ public override Microsoft.CodeAnalysis.Syntax.InternalSyntax.SyntaxList Usings => new Microsoft.CodeAnalysis.Syntax.InternalSyntax.SyntaxList(this.usings);
+ public override Microsoft.CodeAnalysis.Syntax.InternalSyntax.SyntaxList Members => new Microsoft.CodeAnalysis.Syntax.InternalSyntax.SyntaxList(this.members);
public SyntaxToken CloseBraceToken => this.closeBraceToken;
/// Gets the optional semicolon token.
public SyntaxToken? SemicolonToken => this.semicolonToken;
@@ -19782,6 +19810,244 @@ static NamespaceDeclarationSyntax()
}
}
+ internal sealed partial class FileScopedNamespaceDeclarationSyntax : BaseNamespaceDeclarationSyntax
+ {
+ internal readonly GreenNode? attributeLists;
+ internal readonly GreenNode? modifiers;
+ internal readonly SyntaxToken namespaceKeyword;
+ internal readonly NameSyntax name;
+ internal readonly SyntaxToken semicolonToken;
+ internal readonly GreenNode? externs;
+ internal readonly GreenNode? usings;
+ internal readonly GreenNode? members;
+
+ internal FileScopedNamespaceDeclarationSyntax(SyntaxKind kind, GreenNode? attributeLists, GreenNode? modifiers, SyntaxToken namespaceKeyword, NameSyntax name, SyntaxToken semicolonToken, GreenNode? externs, GreenNode? usings, GreenNode? members, DiagnosticInfo[]? diagnostics, SyntaxAnnotation[]? annotations)
+ : base(kind, diagnostics, annotations)
+ {
+ this.SlotCount = 8;
+ if (attributeLists != null)
+ {
+ this.AdjustFlagsAndWidth(attributeLists);
+ this.attributeLists = attributeLists;
+ }
+ if (modifiers != null)
+ {
+ this.AdjustFlagsAndWidth(modifiers);
+ this.modifiers = modifiers;
+ }
+ this.AdjustFlagsAndWidth(namespaceKeyword);
+ this.namespaceKeyword = namespaceKeyword;
+ this.AdjustFlagsAndWidth(name);
+ this.name = name;
+ this.AdjustFlagsAndWidth(semicolonToken);
+ this.semicolonToken = semicolonToken;
+ if (externs != null)
+ {
+ this.AdjustFlagsAndWidth(externs);
+ this.externs = externs;
+ }
+ if (usings != null)
+ {
+ this.AdjustFlagsAndWidth(usings);
+ this.usings = usings;
+ }
+ if (members != null)
+ {
+ this.AdjustFlagsAndWidth(members);
+ this.members = members;
+ }
+ }
+
+ internal FileScopedNamespaceDeclarationSyntax(SyntaxKind kind, GreenNode? attributeLists, GreenNode? modifiers, SyntaxToken namespaceKeyword, NameSyntax name, SyntaxToken semicolonToken, GreenNode? externs, GreenNode? usings, GreenNode? members, SyntaxFactoryContext context)
+ : base(kind)
+ {
+ this.SetFactoryContext(context);
+ this.SlotCount = 8;
+ if (attributeLists != null)
+ {
+ this.AdjustFlagsAndWidth(attributeLists);
+ this.attributeLists = attributeLists;
+ }
+ if (modifiers != null)
+ {
+ this.AdjustFlagsAndWidth(modifiers);
+ this.modifiers = modifiers;
+ }
+ this.AdjustFlagsAndWidth(namespaceKeyword);
+ this.namespaceKeyword = namespaceKeyword;
+ this.AdjustFlagsAndWidth(name);
+ this.name = name;
+ this.AdjustFlagsAndWidth(semicolonToken);
+ this.semicolonToken = semicolonToken;
+ if (externs != null)
+ {
+ this.AdjustFlagsAndWidth(externs);
+ this.externs = externs;
+ }
+ if (usings != null)
+ {
+ this.AdjustFlagsAndWidth(usings);
+ this.usings = usings;
+ }
+ if (members != null)
+ {
+ this.AdjustFlagsAndWidth(members);
+ this.members = members;
+ }
+ }
+
+ internal FileScopedNamespaceDeclarationSyntax(SyntaxKind kind, GreenNode? attributeLists, GreenNode? modifiers, SyntaxToken namespaceKeyword, NameSyntax name, SyntaxToken semicolonToken, GreenNode? externs, GreenNode? usings, GreenNode? members)
+ : base(kind)
+ {
+ this.SlotCount = 8;
+ if (attributeLists != null)
+ {
+ this.AdjustFlagsAndWidth(attributeLists);
+ this.attributeLists = attributeLists;
+ }
+ if (modifiers != null)
+ {
+ this.AdjustFlagsAndWidth(modifiers);
+ this.modifiers = modifiers;
+ }
+ this.AdjustFlagsAndWidth(namespaceKeyword);
+ this.namespaceKeyword = namespaceKeyword;
+ this.AdjustFlagsAndWidth(name);
+ this.name = name;
+ this.AdjustFlagsAndWidth(semicolonToken);
+ this.semicolonToken = semicolonToken;
+ if (externs != null)
+ {
+ this.AdjustFlagsAndWidth(externs);
+ this.externs = externs;
+ }
+ if (usings != null)
+ {
+ this.AdjustFlagsAndWidth(usings);
+ this.usings = usings;
+ }
+ if (members != null)
+ {
+ this.AdjustFlagsAndWidth(members);
+ this.members = members;
+ }
+ }
+
+ public override Microsoft.CodeAnalysis.Syntax.InternalSyntax.SyntaxList AttributeLists => new Microsoft.CodeAnalysis.Syntax.InternalSyntax.SyntaxList(this.attributeLists);
+ public override Microsoft.CodeAnalysis.Syntax.InternalSyntax.SyntaxList Modifiers => new Microsoft.CodeAnalysis.Syntax.InternalSyntax.SyntaxList(this.modifiers);
+ public override SyntaxToken NamespaceKeyword => this.namespaceKeyword;
+ public override NameSyntax Name => this.name;
+ public SyntaxToken SemicolonToken => this.semicolonToken;
+ public override Microsoft.CodeAnalysis.Syntax.InternalSyntax.SyntaxList Externs => new Microsoft.CodeAnalysis.Syntax.InternalSyntax.SyntaxList(this.externs);
+ public override Microsoft.CodeAnalysis.Syntax.InternalSyntax.SyntaxList Usings => new Microsoft.CodeAnalysis.Syntax.InternalSyntax.SyntaxList(this.usings);
+ public override Microsoft.CodeAnalysis.Syntax.InternalSyntax.SyntaxList Members => new Microsoft.CodeAnalysis.Syntax.InternalSyntax.SyntaxList(this.members);
+
+ internal override GreenNode? GetSlot(int index)
+ => index switch
+ {
+ 0 => this.attributeLists,
+ 1 => this.modifiers,
+ 2 => this.namespaceKeyword,
+ 3 => this.name,
+ 4 => this.semicolonToken,
+ 5 => this.externs,
+ 6 => this.usings,
+ 7 => this.members,
+ _ => null,
+ };
+
+ internal override SyntaxNode CreateRed(SyntaxNode? parent, int position) => new CSharp.Syntax.FileScopedNamespaceDeclarationSyntax(this, parent, position);
+
+ public override void Accept(CSharpSyntaxVisitor visitor) => visitor.VisitFileScopedNamespaceDeclaration(this);
+ public override TResult Accept(CSharpSyntaxVisitor visitor) => visitor.VisitFileScopedNamespaceDeclaration(this);
+
+ public FileScopedNamespaceDeclarationSyntax Update(Microsoft.CodeAnalysis.Syntax.InternalSyntax.SyntaxList attributeLists, Microsoft.CodeAnalysis.Syntax.InternalSyntax.SyntaxList modifiers, SyntaxToken namespaceKeyword, NameSyntax name, SyntaxToken semicolonToken, Microsoft.CodeAnalysis.Syntax.InternalSyntax.SyntaxList externs, Microsoft.CodeAnalysis.Syntax.InternalSyntax.SyntaxList usings, Microsoft.CodeAnalysis.Syntax.InternalSyntax.SyntaxList members)
+ {
+ if (attributeLists != this.AttributeLists || modifiers != this.Modifiers || namespaceKeyword != this.NamespaceKeyword || name != this.Name || semicolonToken != this.SemicolonToken || externs != this.Externs || usings != this.Usings || members != this.Members)
+ {
+ var newNode = SyntaxFactory.FileScopedNamespaceDeclaration(attributeLists, modifiers, namespaceKeyword, name, semicolonToken, externs, usings, members);
+ var diags = GetDiagnostics();
+ if (diags?.Length > 0)
+ newNode = newNode.WithDiagnosticsGreen(diags);
+ var annotations = GetAnnotations();
+ if (annotations?.Length > 0)
+ newNode = newNode.WithAnnotationsGreen(annotations);
+ return newNode;
+ }
+
+ return this;
+ }
+
+ internal override GreenNode SetDiagnostics(DiagnosticInfo[]? diagnostics)
+ => new FileScopedNamespaceDeclarationSyntax(this.Kind, this.attributeLists, this.modifiers, this.namespaceKeyword, this.name, this.semicolonToken, this.externs, this.usings, this.members, diagnostics, GetAnnotations());
+
+ internal override GreenNode SetAnnotations(SyntaxAnnotation[]? annotations)
+ => new FileScopedNamespaceDeclarationSyntax(this.Kind, this.attributeLists, this.modifiers, this.namespaceKeyword, this.name, this.semicolonToken, this.externs, this.usings, this.members, GetDiagnostics(), annotations);
+
+ internal FileScopedNamespaceDeclarationSyntax(ObjectReader reader)
+ : base(reader)
+ {
+ this.SlotCount = 8;
+ var attributeLists = (GreenNode?)reader.ReadValue();
+ if (attributeLists != null)
+ {
+ AdjustFlagsAndWidth(attributeLists);
+ this.attributeLists = attributeLists;
+ }
+ var modifiers = (GreenNode?)reader.ReadValue();
+ if (modifiers != null)
+ {
+ AdjustFlagsAndWidth(modifiers);
+ this.modifiers = modifiers;
+ }
+ var namespaceKeyword = (SyntaxToken)reader.ReadValue();
+ AdjustFlagsAndWidth(namespaceKeyword);
+ this.namespaceKeyword = namespaceKeyword;
+ var name = (NameSyntax)reader.ReadValue();
+ AdjustFlagsAndWidth(name);
+ this.name = name;
+ var semicolonToken = (SyntaxToken)reader.ReadValue();
+ AdjustFlagsAndWidth(semicolonToken);
+ this.semicolonToken = semicolonToken;
+ var externs = (GreenNode?)reader.ReadValue();
+ if (externs != null)
+ {
+ AdjustFlagsAndWidth(externs);
+ this.externs = externs;
+ }
+ var usings = (GreenNode?)reader.ReadValue();
+ if (usings != null)
+ {
+ AdjustFlagsAndWidth(usings);
+ this.usings = usings;
+ }
+ var members = (GreenNode?)reader.ReadValue();
+ if (members != null)
+ {
+ AdjustFlagsAndWidth(members);
+ this.members = members;
+ }
+ }
+
+ internal override void WriteTo(ObjectWriter writer)
+ {
+ base.WriteTo(writer);
+ writer.WriteValue(this.attributeLists);
+ writer.WriteValue(this.modifiers);
+ writer.WriteValue(this.namespaceKeyword);
+ writer.WriteValue(this.name);
+ writer.WriteValue(this.semicolonToken);
+ writer.WriteValue(this.externs);
+ writer.WriteValue(this.usings);
+ writer.WriteValue(this.members);
+ }
+
+ static FileScopedNamespaceDeclarationSyntax()
+ {
+ ObjectBinder.RegisterTypeReader(typeof(FileScopedNamespaceDeclarationSyntax), r => new FileScopedNamespaceDeclarationSyntax(r));
+ }
+ }
+
/// Class representing one or more attributes applied to a language construct.
internal sealed partial class AttributeListSyntax : CSharpSyntaxNode
{
@@ -33760,6 +34026,7 @@ internal partial class CSharpSyntaxVisitor
public virtual TResult VisitExternAliasDirective(ExternAliasDirectiveSyntax node) => this.DefaultVisit(node);
public virtual TResult VisitUsingDirective(UsingDirectiveSyntax node) => this.DefaultVisit(node);
public virtual TResult VisitNamespaceDeclaration(NamespaceDeclarationSyntax node) => this.DefaultVisit(node);
+ public virtual TResult VisitFileScopedNamespaceDeclaration(FileScopedNamespaceDeclarationSyntax node) => this.DefaultVisit(node);
public virtual TResult VisitAttributeList(AttributeListSyntax node) => this.DefaultVisit(node);
public virtual TResult VisitAttributeTargetSpecifier(AttributeTargetSpecifierSyntax node) => this.DefaultVisit(node);
public virtual TResult VisitAttribute(AttributeSyntax node) => this.DefaultVisit(node);
@@ -33998,6 +34265,7 @@ internal partial class CSharpSyntaxVisitor
public virtual void VisitExternAliasDirective(ExternAliasDirectiveSyntax node) => this.DefaultVisit(node);
public virtual void VisitUsingDirective(UsingDirectiveSyntax node) => this.DefaultVisit(node);
public virtual void VisitNamespaceDeclaration(NamespaceDeclarationSyntax node) => this.DefaultVisit(node);
+ public virtual void VisitFileScopedNamespaceDeclaration(FileScopedNamespaceDeclarationSyntax node) => this.DefaultVisit(node);
public virtual void VisitAttributeList(AttributeListSyntax node) => this.DefaultVisit(node);
public virtual void VisitAttributeTargetSpecifier(AttributeTargetSpecifierSyntax node) => this.DefaultVisit(node);
public virtual void VisitAttribute(AttributeSyntax node) => this.DefaultVisit(node);
@@ -34530,6 +34798,9 @@ public override CSharpSyntaxNode VisitUsingDirective(UsingDirectiveSyntax node)
public override CSharpSyntaxNode VisitNamespaceDeclaration(NamespaceDeclarationSyntax node)
=> node.Update(VisitList(node.AttributeLists), VisitList(node.Modifiers), (SyntaxToken)Visit(node.NamespaceKeyword), (NameSyntax)Visit(node.Name), (SyntaxToken)Visit(node.OpenBraceToken), VisitList(node.Externs), VisitList(node.Usings), VisitList(node.Members), (SyntaxToken)Visit(node.CloseBraceToken), (SyntaxToken)Visit(node.SemicolonToken));
+ public override CSharpSyntaxNode VisitFileScopedNamespaceDeclaration(FileScopedNamespaceDeclarationSyntax node)
+ => node.Update(VisitList(node.AttributeLists), VisitList(node.Modifiers), (SyntaxToken)Visit(node.NamespaceKeyword), (NameSyntax)Visit(node.Name), (SyntaxToken)Visit(node.SemicolonToken), VisitList(node.Externs), VisitList(node.Usings), VisitList(node.Members));
+
public override CSharpSyntaxNode VisitAttributeList(AttributeListSyntax node)
=> node.Update((SyntaxToken)Visit(node.OpenBracketToken), (AttributeTargetSpecifierSyntax)Visit(node.Target), VisitList(node.Attributes), (SyntaxToken)Visit(node.CloseBracketToken));
@@ -37920,6 +38191,19 @@ public NamespaceDeclarationSyntax NamespaceDeclaration(Microsoft.CodeAnalysis.Sy
return new NamespaceDeclarationSyntax(SyntaxKind.NamespaceDeclaration, attributeLists.Node, modifiers.Node, namespaceKeyword, name, openBraceToken, externs.Node, usings.Node, members.Node, closeBraceToken, semicolonToken, this.context);
}
+ public FileScopedNamespaceDeclarationSyntax FileScopedNamespaceDeclaration(Microsoft.CodeAnalysis.Syntax.InternalSyntax.SyntaxList attributeLists, Microsoft.CodeAnalysis.Syntax.InternalSyntax.SyntaxList modifiers, SyntaxToken namespaceKeyword, NameSyntax name, SyntaxToken semicolonToken, Microsoft.CodeAnalysis.Syntax.InternalSyntax.SyntaxList externs, Microsoft.CodeAnalysis.Syntax.InternalSyntax.SyntaxList usings, Microsoft.CodeAnalysis.Syntax.InternalSyntax.SyntaxList members)
+ {
+#if DEBUG
+ if (namespaceKeyword == null) throw new ArgumentNullException(nameof(namespaceKeyword));
+ if (namespaceKeyword.Kind != SyntaxKind.NamespaceKeyword) throw new ArgumentException(nameof(namespaceKeyword));
+ if (name == null) throw new ArgumentNullException(nameof(name));
+ if (semicolonToken == null) throw new ArgumentNullException(nameof(semicolonToken));
+ if (semicolonToken.Kind != SyntaxKind.SemicolonToken) throw new ArgumentException(nameof(semicolonToken));
+#endif
+
+ return new FileScopedNamespaceDeclarationSyntax(SyntaxKind.FileScopedNamespaceDeclaration, attributeLists.Node, modifiers.Node, namespaceKeyword, name, semicolonToken, externs.Node, usings.Node, members.Node, this.context);
+ }
+
public AttributeListSyntax AttributeList(SyntaxToken openBracketToken, AttributeTargetSpecifierSyntax? target, Microsoft.CodeAnalysis.Syntax.InternalSyntax.SeparatedSyntaxList attributes, SyntaxToken closeBracketToken)
{
#if DEBUG
@@ -42880,6 +43164,19 @@ public static NamespaceDeclarationSyntax NamespaceDeclaration(Microsoft.CodeAnal
return new NamespaceDeclarationSyntax(SyntaxKind.NamespaceDeclaration, attributeLists.Node, modifiers.Node, namespaceKeyword, name, openBraceToken, externs.Node, usings.Node, members.Node, closeBraceToken, semicolonToken);
}
+ public static FileScopedNamespaceDeclarationSyntax FileScopedNamespaceDeclaration(Microsoft.CodeAnalysis.Syntax.InternalSyntax.SyntaxList attributeLists, Microsoft.CodeAnalysis.Syntax.InternalSyntax.SyntaxList modifiers, SyntaxToken namespaceKeyword, NameSyntax name, SyntaxToken semicolonToken, Microsoft.CodeAnalysis.Syntax.InternalSyntax.SyntaxList externs, Microsoft.CodeAnalysis.Syntax.InternalSyntax.SyntaxList usings, Microsoft.CodeAnalysis.Syntax.InternalSyntax.SyntaxList members)
+ {
+#if DEBUG
+ if (namespaceKeyword == null) throw new ArgumentNullException(nameof(namespaceKeyword));
+ if (namespaceKeyword.Kind != SyntaxKind.NamespaceKeyword) throw new ArgumentException(nameof(namespaceKeyword));
+ if (name == null) throw new ArgumentNullException(nameof(name));
+ if (semicolonToken == null) throw new ArgumentNullException(nameof(semicolonToken));
+ if (semicolonToken.Kind != SyntaxKind.SemicolonToken) throw new ArgumentException(nameof(semicolonToken));
+#endif
+
+ return new FileScopedNamespaceDeclarationSyntax(SyntaxKind.FileScopedNamespaceDeclaration, attributeLists.Node, modifiers.Node, namespaceKeyword, name, semicolonToken, externs.Node, usings.Node, members.Node);
+ }
+
public static AttributeListSyntax AttributeList(SyntaxToken openBracketToken, AttributeTargetSpecifierSyntax? target, Microsoft.CodeAnalysis.Syntax.InternalSyntax.SeparatedSyntaxList attributes, SyntaxToken closeBracketToken)
{
#if DEBUG
@@ -44866,6 +45163,7 @@ internal static IEnumerable GetNodeTypes()
typeof(ExternAliasDirectiveSyntax),
typeof(UsingDirectiveSyntax),
typeof(NamespaceDeclarationSyntax),
+ typeof(FileScopedNamespaceDeclarationSyntax),
typeof(AttributeListSyntax),
typeof(AttributeTargetSpecifierSyntax),
typeof(AttributeSyntax),
diff --git a/src/Compilers/CSharp/Portable/Generated/CSharpSyntaxGenerator/CSharpSyntaxGenerator.SourceGenerator/Syntax.xml.Main.Generated.cs b/src/Compilers/CSharp/Portable/Generated/CSharpSyntaxGenerator/CSharpSyntaxGenerator.SourceGenerator/Syntax.xml.Main.Generated.cs
index 055f9fbf7187b..f5000e8684bfd 100644
--- a/src/Compilers/CSharp/Portable/Generated/CSharpSyntaxGenerator/CSharpSyntaxGenerator.SourceGenerator/Syntax.xml.Main.Generated.cs
+++ b/src/Compilers/CSharp/Portable/Generated/CSharpSyntaxGenerator/CSharpSyntaxGenerator.SourceGenerator/Syntax.xml.Main.Generated.cs
@@ -456,6 +456,9 @@ public partial class CSharpSyntaxVisitor
/// Called when the visitor visits a NamespaceDeclarationSyntax node.
public virtual TResult? VisitNamespaceDeclaration(NamespaceDeclarationSyntax node) => this.DefaultVisit(node);
+ /// Called when the visitor visits a FileScopedNamespaceDeclarationSyntax node.
+ public virtual TResult? VisitFileScopedNamespaceDeclaration(FileScopedNamespaceDeclarationSyntax node) => this.DefaultVisit(node);
+
/// Called when the visitor visits a AttributeListSyntax node.
public virtual TResult? VisitAttributeList(AttributeListSyntax node) => this.DefaultVisit(node);
@@ -1161,6 +1164,9 @@ public partial class CSharpSyntaxVisitor
/// Called when the visitor visits a NamespaceDeclarationSyntax node.
public virtual void VisitNamespaceDeclaration(NamespaceDeclarationSyntax node) => this.DefaultVisit(node);
+ /// Called when the visitor visits a FileScopedNamespaceDeclarationSyntax node.
+ public virtual void VisitFileScopedNamespaceDeclaration(FileScopedNamespaceDeclarationSyntax node) => this.DefaultVisit(node);
+
/// Called when the visitor visits a AttributeListSyntax node.
public virtual void VisitAttributeList(AttributeListSyntax node) => this.DefaultVisit(node);
@@ -1866,6 +1872,9 @@ public partial class CSharpSyntaxRewriter : CSharpSyntaxVisitor
public override SyntaxNode? VisitNamespaceDeclaration(NamespaceDeclarationSyntax node)
=> node.Update(VisitList(node.AttributeLists), VisitList(node.Modifiers), VisitToken(node.NamespaceKeyword), (NameSyntax?)Visit(node.Name) ?? throw new ArgumentNullException("name"), VisitToken(node.OpenBraceToken), VisitList(node.Externs), VisitList(node.Usings), VisitList(node.Members), VisitToken(node.CloseBraceToken), VisitToken(node.SemicolonToken));
+ public override SyntaxNode? VisitFileScopedNamespaceDeclaration(FileScopedNamespaceDeclarationSyntax node)
+ => node.Update(VisitList(node.AttributeLists), VisitList(node.Modifiers), VisitToken(node.NamespaceKeyword), (NameSyntax?)Visit(node.Name) ?? throw new ArgumentNullException("name"), VisitToken(node.SemicolonToken), VisitList(node.Externs), VisitList(node.Usings), VisitList(node.Members));
+
public override SyntaxNode? VisitAttributeList(AttributeListSyntax node)
=> node.Update(VisitToken(node.OpenBracketToken), (AttributeTargetSpecifierSyntax?)Visit(node.Target), VisitList(node.Attributes), VisitToken(node.CloseBracketToken));
@@ -4638,6 +4647,23 @@ public static NamespaceDeclarationSyntax NamespaceDeclaration(SyntaxList SyntaxFactory.NamespaceDeclaration(default, default(SyntaxTokenList), SyntaxFactory.Token(SyntaxKind.NamespaceKeyword), name, SyntaxFactory.Token(SyntaxKind.OpenBraceToken), default, default, default, SyntaxFactory.Token(SyntaxKind.CloseBraceToken), default);
+ /// Creates a new FileScopedNamespaceDeclarationSyntax instance.
+ public static FileScopedNamespaceDeclarationSyntax FileScopedNamespaceDeclaration(SyntaxList attributeLists, SyntaxTokenList modifiers, SyntaxToken namespaceKeyword, NameSyntax name, SyntaxToken semicolonToken, SyntaxList externs, SyntaxList usings, SyntaxList members)
+ {
+ if (namespaceKeyword.Kind() != SyntaxKind.NamespaceKeyword) throw new ArgumentException(nameof(namespaceKeyword));
+ if (name == null) throw new ArgumentNullException(nameof(name));
+ if (semicolonToken.Kind() != SyntaxKind.SemicolonToken) throw new ArgumentException(nameof(semicolonToken));
+ return (FileScopedNamespaceDeclarationSyntax)Syntax.InternalSyntax.SyntaxFactory.FileScopedNamespaceDeclaration(attributeLists.Node.ToGreenList(), modifiers.Node.ToGreenList(), (Syntax.InternalSyntax.SyntaxToken)namespaceKeyword.Node!, (Syntax.InternalSyntax.NameSyntax)name.Green, (Syntax.InternalSyntax.SyntaxToken)semicolonToken.Node!, externs.Node.ToGreenList(), usings.Node.ToGreenList(), members.Node.ToGreenList()).CreateRed();
+ }
+
+ /// Creates a new FileScopedNamespaceDeclarationSyntax instance.
+ public static FileScopedNamespaceDeclarationSyntax FileScopedNamespaceDeclaration(SyntaxList attributeLists, SyntaxTokenList modifiers, NameSyntax name, SyntaxList externs, SyntaxList usings, SyntaxList members)
+ => SyntaxFactory.FileScopedNamespaceDeclaration(attributeLists, modifiers, SyntaxFactory.Token(SyntaxKind.NamespaceKeyword), name, SyntaxFactory.Token(SyntaxKind.SemicolonToken), externs, usings, members);
+
+ /// Creates a new FileScopedNamespaceDeclarationSyntax instance.
+ public static FileScopedNamespaceDeclarationSyntax FileScopedNamespaceDeclaration(NameSyntax name)
+ => SyntaxFactory.FileScopedNamespaceDeclaration(default, default(SyntaxTokenList), SyntaxFactory.Token(SyntaxKind.NamespaceKeyword), name, SyntaxFactory.Token(SyntaxKind.SemicolonToken), default, default, default);
+
/// Creates a new AttributeListSyntax instance.
public static AttributeListSyntax AttributeList(SyntaxToken openBracketToken, AttributeTargetSpecifierSyntax? target, SeparatedSyntaxList attributes, SyntaxToken closeBracketToken)
{
diff --git a/src/Compilers/CSharp/Portable/Generated/CSharpSyntaxGenerator/CSharpSyntaxGenerator.SourceGenerator/Syntax.xml.Syntax.Generated.cs b/src/Compilers/CSharp/Portable/Generated/CSharpSyntaxGenerator/CSharpSyntaxGenerator.SourceGenerator/Syntax.xml.Syntax.Generated.cs
index 042ac762357c0..556e2b1b7e098 100644
--- a/src/Compilers/CSharp/Portable/Generated/CSharpSyntaxGenerator/CSharpSyntaxGenerator.SourceGenerator/Syntax.xml.Syntax.Generated.cs
+++ b/src/Compilers/CSharp/Portable/Generated/CSharpSyntaxGenerator/CSharpSyntaxGenerator.SourceGenerator/Syntax.xml.Syntax.Generated.cs
@@ -9128,13 +9128,57 @@ internal MemberDeclarationSyntax(InternalSyntax.CSharpSyntaxNode green, SyntaxNo
internal abstract MemberDeclarationSyntax AddModifiersCore(params SyntaxToken[] items);
}
+ public abstract partial class BaseNamespaceDeclarationSyntax : MemberDeclarationSyntax
+ {
+ internal BaseNamespaceDeclarationSyntax(InternalSyntax.CSharpSyntaxNode green, SyntaxNode? parent, int position)
+ : base(green, parent, position)
+ {
+ }
+
+ public abstract SyntaxToken NamespaceKeyword { get; }
+ public BaseNamespaceDeclarationSyntax WithNamespaceKeyword(SyntaxToken namespaceKeyword) => WithNamespaceKeywordCore(namespaceKeyword);
+ internal abstract BaseNamespaceDeclarationSyntax WithNamespaceKeywordCore(SyntaxToken namespaceKeyword);
+
+ public abstract NameSyntax Name { get; }
+ public BaseNamespaceDeclarationSyntax WithName(NameSyntax name) => WithNameCore(name);
+ internal abstract BaseNamespaceDeclarationSyntax WithNameCore(NameSyntax name);
+
+ public abstract SyntaxList Externs { get; }
+ public BaseNamespaceDeclarationSyntax WithExterns(SyntaxList externs) => WithExternsCore(externs);
+ internal abstract BaseNamespaceDeclarationSyntax WithExternsCore(SyntaxList externs);
+
+ public BaseNamespaceDeclarationSyntax AddExterns(params ExternAliasDirectiveSyntax[] items) => AddExternsCore(items);
+ internal abstract BaseNamespaceDeclarationSyntax AddExternsCore(params ExternAliasDirectiveSyntax[] items);
+
+ public abstract SyntaxList Usings { get; }
+ public BaseNamespaceDeclarationSyntax WithUsings(SyntaxList usings) => WithUsingsCore(usings);
+ internal abstract BaseNamespaceDeclarationSyntax WithUsingsCore(SyntaxList usings);
+
+ public BaseNamespaceDeclarationSyntax AddUsings(params UsingDirectiveSyntax[] items) => AddUsingsCore(items);
+ internal abstract BaseNamespaceDeclarationSyntax AddUsingsCore(params UsingDirectiveSyntax[] items);
+
+ public abstract SyntaxList Members { get; }
+ public BaseNamespaceDeclarationSyntax WithMembers(SyntaxList members) => WithMembersCore(members);
+ internal abstract BaseNamespaceDeclarationSyntax WithMembersCore(SyntaxList members);
+
+ public BaseNamespaceDeclarationSyntax AddMembers(params MemberDeclarationSyntax[] items) => AddMembersCore(items);
+ internal abstract BaseNamespaceDeclarationSyntax AddMembersCore(params MemberDeclarationSyntax[] items);
+
+ public new BaseNamespaceDeclarationSyntax WithAttributeLists(SyntaxList attributeLists) => (BaseNamespaceDeclarationSyntax)WithAttributeListsCore(attributeLists);
+ public new BaseNamespaceDeclarationSyntax WithModifiers(SyntaxTokenList modifiers) => (BaseNamespaceDeclarationSyntax)WithModifiersCore(modifiers);
+
+ public new BaseNamespaceDeclarationSyntax AddAttributeLists(params AttributeListSyntax[] items) => (BaseNamespaceDeclarationSyntax)AddAttributeListsCore(items);
+
+ public new BaseNamespaceDeclarationSyntax AddModifiers(params SyntaxToken[] items) => (BaseNamespaceDeclarationSyntax)AddModifiersCore(items);
+ }
+
///
/// This node is associated with the following syntax kinds:
///
///
///
///
- public sealed partial class NamespaceDeclarationSyntax : MemberDeclarationSyntax
+ public sealed partial class NamespaceDeclarationSyntax : BaseNamespaceDeclarationSyntax
{
private SyntaxNode? attributeLists;
private NameSyntax? name;
@@ -9158,17 +9202,17 @@ public override SyntaxTokenList Modifiers
}
}
- public SyntaxToken NamespaceKeyword => new SyntaxToken(this, ((Syntax.InternalSyntax.NamespaceDeclarationSyntax)this.Green).namespaceKeyword, GetChildPosition(2), GetChildIndex(2));
+ public override SyntaxToken NamespaceKeyword => new SyntaxToken(this, ((Syntax.InternalSyntax.NamespaceDeclarationSyntax)this.Green).namespaceKeyword, GetChildPosition(2), GetChildIndex(2));
- public NameSyntax Name => GetRed(ref this.name, 3)!;
+ public override NameSyntax Name => GetRed(ref this.name, 3)!;
public SyntaxToken OpenBraceToken => new SyntaxToken(this, ((Syntax.InternalSyntax.NamespaceDeclarationSyntax)this.Green).openBraceToken, GetChildPosition(4), GetChildIndex(4));
- public SyntaxList Externs => new SyntaxList(GetRed(ref this.externs, 5));
+ public override SyntaxList Externs => new SyntaxList(GetRed(ref this.externs, 5));
- public SyntaxList Usings => new SyntaxList(GetRed(ref this.usings, 6));
+ public override SyntaxList Usings => new SyntaxList(GetRed(ref this.usings, 6));
- public SyntaxList Members => new SyntaxList(GetRed(ref this.members, 7));
+ public override SyntaxList Members => new SyntaxList