diff --git a/src/EditorFeatures/Test/MetadataAsSource/MetadataAsSourceTests.cs b/src/EditorFeatures/Test/MetadataAsSource/MetadataAsSourceTests.cs index 7c8fb731e215a2feac426e698e820cf3cd71b21d..9cf7a324ad0ea698d76bb43b2b8ffaf68272535d 100644 --- a/src/EditorFeatures/Test/MetadataAsSource/MetadataAsSourceTests.cs +++ b/src/EditorFeatures/Test/MetadataAsSource/MetadataAsSourceTests.cs @@ -2970,6 +2970,80 @@ public class TestType context.VerifyResult(metadataAsSourceFile, expected); } + [Fact, Trait(Traits.Feature, Traits.Features.MetadataAsSource)] + public async Task TestNullableEnableDisable13() + { + var metadata = @" +#nullable enable + +using System; + +public class TestType +{ + public void M1(string s) + { + } + +#nullable disable + + public class Nested + { + public void NestedM(string s) + { + } + } + +#nullable enable + + public void M2(string s) + { + } +}"; + var sourceWithSymbolReference = @" +class C +{ + void M() + { + var obj = new TestType().[|M1|](null); + } +}"; + var expected = $@"#region {FeaturesResources.Assembly} ReferencedAssembly, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null +// {CodeAnalysisResources.InMemoryAssembly} +#endregion + +#nullable enable + +public class TestType +{{ + public TestType(); + + public void [|M1|](string s); + public void M2(string s); + + public class Nested + {{ + public Nested(); + +#nullable disable + public void NestedM(string s); + +#nullable enable + }} +}}"; + + using var context = TestContext.Create( + LanguageNames.CSharp, + SpecializedCollections.SingletonEnumerable(metadata), + includeXmlDocComments: false, + languageVersion: "CSharp8", + sourceWithSymbolReference: sourceWithSymbolReference, + metadataLanguageVersion: "CSharp8"); + + var navigationSymbol = await context.GetNavigationSymbolAsync(); + var metadataAsSourceFile = await context.GenerateSourceAsync(navigationSymbol); + context.VerifyResult(metadataAsSourceFile, expected); + } + [Fact, Trait(Traits.Feature, Traits.Features.MetadataAsSource)] public async Task TestDynamic1() { diff --git a/src/Features/CSharp/Portable/MetadataAsSource/CSharpMetadataAsSourceService.cs b/src/Features/CSharp/Portable/MetadataAsSource/CSharpMetadataAsSourceService.cs index 1bca978c9a2b4277835fe75f9536787c18271657..a24fc06bf6dd649324d61125a9dc06bb71a45694 100644 --- a/src/Features/CSharp/Portable/MetadataAsSource/CSharpMetadataAsSourceService.cs +++ b/src/Features/CSharp/Portable/MetadataAsSource/CSharpMetadataAsSourceService.cs @@ -143,13 +143,14 @@ private static SyntaxTrivia[] CreateNullableTrivia(bool enable) }; } - private SyntaxNode AddNullableRegions(SyntaxNode node, CancellationToken cancellationToken) + private TSyntax AddNullableRegions(TSyntax node, CancellationToken cancellationToken) + where TSyntax : SyntaxNode { return node switch { - CompilationUnitSyntax compilationUnit => compilationUnit.WithMembers(AddNullableRegions(compilationUnit.Members, cancellationToken)), - NamespaceDeclarationSyntax ns => ns.WithMembers(AddNullableRegions(ns.Members, cancellationToken)), - TypeDeclarationSyntax type => AddNullableRegionsAroundTypeMembers(type, cancellationToken), + CompilationUnitSyntax compilationUnit => (TSyntax)(object)compilationUnit.WithMembers(AddNullableRegions(compilationUnit.Members, cancellationToken)), + NamespaceDeclarationSyntax ns => (TSyntax)(object)ns.WithMembers(AddNullableRegions(ns.Members, cancellationToken)), + TypeDeclarationSyntax type => (TSyntax)(object)AddNullableRegionsAroundTypeMembers(type, cancellationToken), _ => node, }; } @@ -161,7 +162,7 @@ private SyntaxNode AddNullableRegions(SyntaxNode node, CancellationToken cancell using var _ = ArrayBuilder.GetInstance(out var builder); foreach (var member in members) - builder.Add((MemberDeclarationSyntax)AddNullableRegions(member, cancellationToken)); + builder.Add(AddNullableRegions(member, cancellationToken)); return SyntaxFactory.List(builder); } @@ -181,7 +182,7 @@ private SyntaxNode AddNullableRegions(SyntaxNode node, CancellationToken cancell { // if we hit a type, and we're currently disabled, then switch us back to enabled for that type. // This ensures whenever we walk into a type-decl, we're always in the enabled-state. - builder.Add(TransitionTo(member, enabled: true, ref currentlyEnabled)); + builder.Add(TransitionTo(AddNullableRegions(member, cancellationToken), enabled: true, ref currentlyEnabled)); continue; }