Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,9 @@ internal sealed override uint RefEscapeScope
{
return _refEscapeScope;
}
return Binder.TopLevelScope;
return _scope == DeclarationScope.RefScoped ?
_scopeBinder.LocalScopeDepth :
Binder.TopLevelScope;
}
}

Expand All @@ -143,7 +145,7 @@ internal sealed override uint ValEscapeScope
return _valEscapeScope;
}
return _scope == DeclarationScope.ValueScoped ?
Binder.TopLevelScope :
_scopeBinder.LocalScopeDepth :
Binder.ExternalScope;
}
}
Expand Down
113 changes: 113 additions & 0 deletions src/Compilers/CSharp/Test/Semantic/Semantics/RefFieldTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9273,6 +9273,119 @@ static void Test(ref int x)
);
}

[WorkItem(64009, "https://github.com/dotnet/roslyn/issues/64009")]
[Fact]
public void LocalScope_09()
{
var source =
@"{
scoped s1 = default;
scoped ref @scoped s2 = ref s1;
}
ref struct @scoped { }
";
var comp = CreateCompilation(source);
comp.VerifyDiagnostics();
}

[Fact]
public void LocalScope_10()
{
var source =
@"{
int i = 0;
S s1 = new S(ref i);
scoped S s2 = s1;
}
ref struct S
{
public S(ref int i) { }
}
";
var comp = CreateCompilation(source);
comp.VerifyDiagnostics();
}

[Fact]
public void LocalScope_11()
{
var source =
@"class Program
{
static void Main()
{
S s0 = default;
scoped ref S r0 = ref s0;
{
scoped ref S r1 = ref s0;
r0 = ref r1; // 1
}
{
scoped ref S r2 = ref r0;
r0 = ref r2; // 2
}
{
ref S r3 = ref s0;
r0 = ref r3;
}
{
ref S r4 = ref r0;
r0 = ref r4;
}
}
}
ref struct S { }
";
var comp = CreateCompilation(source);
comp.VerifyDiagnostics(
// (9,13): error CS8374: Cannot ref-assign 'r1' to 'r0' because 'r1' has a narrower escape scope than 'r0'.
// r0 = ref r1; // 1
Diagnostic(ErrorCode.ERR_RefAssignNarrower, "r0 = ref r1").WithArguments("r0", "r1").WithLocation(9, 13),
// (13,13): error CS8374: Cannot ref-assign 'r2' to 'r0' because 'r2' has a narrower escape scope than 'r0'.
// r0 = ref r2; // 2
Diagnostic(ErrorCode.ERR_RefAssignNarrower, "r0 = ref r2").WithArguments("r0", "r2").WithLocation(13, 13));
}

[Fact]
public void LocalScope_12()
{
var source =
@"class Program
{
static void Main()
{
int i0 = 0;
S s0 = new S(ref i0);
{
int i1 = 1;
S s1 = new S(ref i1);
s0 = s1; // 1
}
{
scoped S s2 = s0;
s0 = s2; // 2
}
{
S s3 = s0;
s0 = s3;
}
}
}
ref struct S
{
public S(ref int i) { }
}
";
var comp = CreateCompilation(source);
comp.VerifyDiagnostics(
// (10,18): error CS8352: Cannot use variable 's1' in this context because it may expose referenced variables outside of their declaration scope
// s0 = s1; // 1
Diagnostic(ErrorCode.ERR_EscapeVariable, "s1").WithArguments("s1").WithLocation(10, 18),
// (14,18): error CS8352: Cannot use variable 's2' in this context because it may expose referenced variables outside of their declaration scope
// s0 = s2; // 2
Diagnostic(ErrorCode.ERR_EscapeVariable, "s2").WithArguments("s2").WithLocation(14, 18));
}

[Fact]
public void LocalScopeAndInitializer_01()
{
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,239 @@
// 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.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.Test.Utilities;
using Roslyn.Test.Utilities;
using Xunit;

namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.Completion.CompletionProviders.Snippets
{
[Trait(Traits.Feature, Traits.Features.Completion)]
public class CSharpInterfaceSnippetCompletionProviderTests : AbstractCSharpSnippetCompletionProviderTests
{
protected override string ItemToCommit => "interface";

[WpfFact]
public async Task InsertInterfaceSnippetInNamespaceTest()
{
var markupBeforeCommit =
@"namespace Namespace
{
$$
}";

var expectedCodeAfterCommit =
@"namespace Namespace
{
interface MyInterface
{
$$
}
}";
await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit);
}

[WpfFact]
public async Task InsertInterfaceSnippetInFileScopedNamespaceTest()
{
var markupBeforeCommit =
@"namespace Namespace;

$$";

var expectedCodeAfterCommit =
@"namespace Namespace;

interface MyInterface
{
$$
}";
await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit);
}

[WpfFact]
public async Task InsertInterfaceSnippetTest()
{
var markupBeforeCommit =
@"$$";

var expectedCodeAfterCommit =
@"interface MyInterface
{
$$
}";
await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit);
}

[WpfFact]
public async Task InsertInterfaceTopLevelSnippetTest()
{
var markupBeforeCommit =
@"System.Console.WriteLine();
$$";

var expectedCodeAfterCommit =
@"System.Console.WriteLine();

interface MyInterface
{
$$
}";
await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit);
}

[WpfFact]
public async Task InsertInterfaceSnippetInClassTest()
{
var markupBeforeCommit =
@"class MyClass
{
$$
}";

var expectedCodeAfterCommit =
@"class MyClass
{
interface MyInterface
{
$$
}
}";
await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit);
}

[WpfFact]
public async Task InsertInterfaceSnippetInRecordTest()
{
var markupBeforeCommit =
@"record MyRecord
{
$$
}";

var expectedCodeAfterCommit =
@"record MyRecord
{
interface MyInterface
{
$$
}
}";
await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit);
}

[WpfFact]
public async Task InsertInterfaceSnippetInStructTest()
{
var markupBeforeCommit =
@"struct MyStruct
{
$$
}";

var expectedCodeAfterCommit =
@"struct MyStruct
{
interface MyInterface
{
$$
}
}";
await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit);
}

[WpfFact]
public async Task InsertInterfaceSnippetInInterfaceTest()
{
var markupBeforeCommit =
@"interface MyInterface
{
$$
}";

var expectedCodeAfterCommit =
@"interface MyInterface
{
interface MyInterface1
{
$$
}
}";
await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit);
}

[WpfFact]
public async Task InsertInterfaceSnippetWithModifiersTest()
{
var markupBeforeCommit =
$@"
<Workspace>
<Project Language=""C#"" AssemblyName=""Assembly1"" CommonReferences=""true"">
<Document FilePath=""/0/Test0.cs"">
$$
</Document>
<AnalyzerConfigDocument FilePath=""/.editorconfig"">
root = true

[*]
# IDE0008: Use explicit type
dotnet_style_require_accessibility_modifiers = always
</AnalyzerConfigDocument>
</Project>
</Workspace>";
var expectedCodeAfterCommit =
$@"
public interface MyInterface
{{
$$
}}
";
await VerifyCustomCommitProviderAsync(markupBeforeCommit, ItemToCommit, expectedCodeAfterCommit);
}

[WpfFact]
public async Task NoInterfaceSnippetInEnumTest()
{
var markupBeforeCommit =
@"enum MyEnum
{
$$
}";

await VerifyItemIsAbsentAsync(markupBeforeCommit, ItemToCommit);
}

[WpfFact]
public async Task NoInteraceSnippetInMethodTest()
{
var markupBeforeCommit =
@"class Program
{
public void Method()
{
$$
}
}";
await VerifyItemIsAbsentAsync(markupBeforeCommit, ItemToCommit);
}

[WpfFact]
public async Task NoInterfaceSnippetInConstructorTest()
{
var markupBeforeCommit =
@"class Program
{
public Program()
{
$$
}
}";
await VerifyItemIsAbsentAsync(markupBeforeCommit, ItemToCommit);
}
}
}
Loading