diff --git a/eng/Versions.props b/eng/Versions.props
index 12cffd628b7f5..106d12fb72c13 100644
--- a/eng/Versions.props
+++ b/eng/Versions.props
@@ -28,7 +28,7 @@
3.0.0-beta2.20059.3+77df2220
3.3.1
- 1.0.1-beta1.20067.1
+ 1.0.1-beta1.20114.4
3.5.0-beta3-20078-04
16.4.248
5.0.0-alpha1.19409.1
@@ -97,7 +97,7 @@
15.8.27812-alpha
1.1.20180503.2
16.0.198-g52de9c2988
- 15.5.23
+ 15.6.36
$(VisualStudioEditorPackagesVersion)
16.0.29431.108
16.4.1091102-preview
diff --git a/src/EditorFeatures/CSharpTest/AddAccessibilityModifiers/AddAccessibilityModifiersTests.cs b/src/EditorFeatures/CSharpTest/AddAccessibilityModifiers/AddAccessibilityModifiersTests.cs
index 526e07bc16666..20376ba845d19 100644
--- a/src/EditorFeatures/CSharpTest/AddAccessibilityModifiers/AddAccessibilityModifiersTests.cs
+++ b/src/EditorFeatures/CSharpTest/AddAccessibilityModifiers/AddAccessibilityModifiersTests.cs
@@ -2,74 +2,70 @@
// 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.Generic;
using System.Threading.Tasks;
-using Microsoft.CodeAnalysis.CodeFixes;
using Microsoft.CodeAnalysis.CodeStyle;
-using Microsoft.CodeAnalysis.CSharp.AddAccessibilityModifiers;
-using Microsoft.CodeAnalysis.Diagnostics;
-using Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.Diagnostics;
-using Microsoft.CodeAnalysis.Options;
using Microsoft.CodeAnalysis.Test.Utilities;
using Xunit;
+using VerifyCS = Microsoft.CodeAnalysis.Editor.UnitTests.CodeActions.CSharpCodeFixVerifier<
+ Microsoft.CodeAnalysis.CSharp.AddAccessibilityModifiers.CSharpAddAccessibilityModifiersDiagnosticAnalyzer,
+ Microsoft.CodeAnalysis.CSharp.AddAccessibilityModifiers.CSharpAddAccessibilityModifiersCodeFixProvider>;
namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.AddAccessibilityModifiers
{
- public partial class AddAccessibilityModifiersTests : AbstractCSharpDiagnosticProviderBasedUserDiagnosticTest
+ public class AddAccessibilityModifiersTests
{
- internal override (DiagnosticAnalyzer, CodeFixProvider) CreateDiagnosticProviderAndFixer(Workspace workspace)
- => (new CSharpAddAccessibilityModifiersDiagnosticAnalyzer(), new CSharpAddAccessibilityModifiersCodeFixProvider());
-
- private IDictionary OmitDefaultModifiers =>
- OptionsSet(SingleOption(CodeStyleOptions.RequireAccessibilityModifiers, AccessibilityModifiersRequired.OmitIfDefault, NotificationOption.Suggestion));
+ [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsAddAccessibilityModifiers)]
+ public void TestStandardProperties()
+ => VerifyCS.VerifyStandardProperties();
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsAddAccessibilityModifiers)]
public async Task TestAllConstructs()
{
- await TestInRegularAndScriptAsync(
-@"
+ await VerifyCS.VerifyCodeFixAsync(
+ @"using System;
namespace Outer
{
namespace Inner1.Inner2
{
- class {|FixAllInDocument:C|}
+ partial class [|C|] : I
{
- class NestedClass { }
+ class [|NestedClass|] { }
- struct NestedStruct { }
+ struct [|NestedStruct|] { }
- int f1;
- int f2, f3;
+ int [|f1|];
+ int [|f2|], f3;
public int f4;
- event Action e1, e2;
+ event Action [|e1|], e2;
public event Action e3;
- event Action e4 { add { } remove { } }
+ event Action [|e4|] { add { } remove { } }
public event Action e5 { add { } remove { } }
- event Action I.e6 { add { } remote { } }
+ event Action I.e6 { add { } remove { } }
static C() { }
- C() { }
+ [|C|]() { }
public C(int i) { }
~C() { }
- void M1() { }
+ void [|M1|]() { }
public void M2() { }
void I.M3() { }
+ partial void M4();
partial void M4() { }
- int P1 { get; }
+ int [|P1|] { get; }
public int P2 { get; }
int I.P3 { get; }
- int this[int i] { get; }
- public int this[string s] { get; }
- int I.this[bool b] { get; }
+ int [|this|][int i] => throw null;
+ public int this[string s] => throw null;
+ int I.this[bool b] => throw null;
}
- interface I
+ interface [|I|]
{
event Action e6;
void M3();
@@ -77,20 +73,20 @@ interface I
int this[bool b] { get; }
}
- delegate void D();
+ delegate void [|D|]();
- enum E
+ enum [|E|]
{
EMember
}
}
}",
-@"
+ @"using System;
namespace Outer
{
namespace Inner1.Inner2
{
- internal class {|FixAllInDocument:C|}
+ internal partial class C : I
{
private class NestedClass { }
@@ -105,7 +101,7 @@ private struct NestedStruct { }
private event Action e4 { add { } remove { } }
public event Action e5 { add { } remove { } }
- event Action I.e6 { add { } remote { } }
+ event Action I.e6 { add { } remove { } }
static C() { }
@@ -117,15 +113,16 @@ public C(int i) { }
private void M1() { }
public void M2() { }
void I.M3() { }
+ partial void M4();
partial void M4() { }
private int P1 { get; }
public int P2 { get; }
int I.P3 { get; }
- private int this[int i] { get; }
- public int this[string s] { get; }
- int I.this[bool b] { get; }
+ private int this[int i] => throw null;
+ public int this[string s] => throw null;
+ int I.this[bool b] => throw null;
}
internal interface I
@@ -149,7 +146,7 @@ internal enum E
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsAddAccessibilityModifiers)]
public async Task TestRefStructs()
{
- await TestInRegularAndScriptAsync(@"
+ await VerifyCS.VerifyCodeFixAsync(@"
namespace Test
{
ref struct [|S1|] { }
@@ -163,7 +160,7 @@ internal ref struct S1 { }
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsAddAccessibilityModifiers)]
public async Task TestReadOnlyStructs()
{
- await TestInRegularAndScriptAsync(@"
+ await VerifyCS.VerifyCodeFixAsync(@"
namespace Test
{
readonly struct [|S1|] { }
@@ -177,51 +174,57 @@ internal readonly struct S1 { }
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsAddAccessibilityModifiers)]
public async Task TestAllConstructsWithOmit()
{
- await TestInRegularAndScriptAsync(
-@"
+ await new VerifyCS.Test
+ {
+ TestState =
+ {
+ Sources =
+ {
+ @"using System;
namespace Outer
{
namespace Inner1.Inner2
{
- internal class {|FixAllInDocument:C|}
+ internal partial class [|C|] : I
{
- private class NestedClass { }
+ private class [|NestedClass|] { }
- private struct NestedStruct { }
+ private struct [|NestedStruct|] { }
- private int f1;
- private int f2, f3;
+ private int [|f1|];
+ private int [|f2|], f3;
public int f4;
- private event Action e1, e2;
+ private event Action [|e1|], e2;
public event Action e3;
- private event Action e4 { add { } remove { } }
+ private event Action [|e4|] { add { } remove { } }
public event Action e5 { add { } remove { } }
- event Action I.e6 { add { } remote { } }
+ event Action I.e6 { add { } remove { } }
static C() { }
- private C() { }
+ private [|C|]() { }
public C(int i) { }
~C() { }
- private void M1() { }
+ private void [|M1|]() { }
public void M2() { }
void I.M3() { }
+ partial void M4();
partial void M4() { }
- private int P1 { get; }
+ private int [|P1|] { get; }
public int P2 { get; }
int I.P3 { get; }
- private int this[int i] { get; }
- public int this[string s] { get; }
- int I.this[bool b] { get; }
+ private int [|this|][int i] => throw null;
+ public int this[string s] => throw null;
+ int I.this[bool b] => throw null;
}
- internal interface I
+ internal interface [|I|]
{
event Action e6;
void M3();
@@ -229,20 +232,26 @@ internal interface I
int this[bool b] { get; }
}
- internal delegate void D();
+ internal delegate void [|D|]();
- internal enum E
+ internal enum [|E|]
{
EMember
}
}
}",
-@"
+ },
+ },
+ FixedState =
+ {
+ Sources =
+ {
+ @"using System;
namespace Outer
{
namespace Inner1.Inner2
{
- class {|FixAllInDocument:C|}
+ partial class C : I
{
class NestedClass { }
@@ -257,7 +266,7 @@ struct NestedStruct { }
event Action e4 { add { } remove { } }
public event Action e5 { add { } remove { } }
- event Action I.e6 { add { } remote { } }
+ event Action I.e6 { add { } remove { } }
static C() { }
@@ -269,15 +278,16 @@ public C(int i) { }
void M1() { }
public void M2() { }
void I.M3() { }
+ partial void M4();
partial void M4() { }
int P1 { get; }
public int P2 { get; }
int I.P3 { get; }
- int this[int i] { get; }
- public int this[string s] { get; }
- int I.this[bool b] { get; }
+ int this[int i] => throw null;
+ public int this[string s] => throw null;
+ int I.this[bool b] => throw null;
}
interface I
@@ -295,43 +305,74 @@ enum E
EMember
}
}
-}", options: OmitDefaultModifiers);
+}",
+ },
+ },
+ Options =
+ {
+ { CodeStyleOptions.RequireAccessibilityModifiers, AccessibilityModifiersRequired.OmitIfDefault },
+ },
+ }.RunAsync();
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsAddAccessibilityModifiers)]
public async Task TestRefStructsWithOmit()
{
- await TestInRegularAndScriptAsync(@"
+ await new VerifyCS.Test
+ {
+ TestCode = @"
namespace Test
{
internal ref struct [|S1|] { }
-}", @"
+}",
+ FixedCode = @"
namespace Test
{
ref struct S1 { }
-}", options: OmitDefaultModifiers);
+}",
+ Options =
+ {
+ { CodeStyleOptions.RequireAccessibilityModifiers, AccessibilityModifiersRequired.OmitIfDefault },
+ },
+ }.RunAsync();
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsAddAccessibilityModifiers)]
public async Task TestReadOnlyStructsWithOmit()
{
- await TestInRegularAndScriptAsync(@"
+ await new VerifyCS.Test
+ {
+ TestCode = @"
namespace Test
{
internal readonly struct [|S1|] { }
-}", @"
+}",
+ FixedCode = @"
namespace Test
{
readonly struct S1 { }
-}", options: OmitDefaultModifiers);
+}",
+ Options =
+ {
+ { CodeStyleOptions.RequireAccessibilityModifiers, AccessibilityModifiersRequired.OmitIfDefault },
+ },
+ }.RunAsync();
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsAddAccessibilityModifiers)]
public async Task TestClassOutsideNamespace()
{
- await TestInRegularAndScriptAsync(@"
-internal class [|C1|] { }", @"
-class C1 { }", options: OmitDefaultModifiers);
+ await new VerifyCS.Test
+ {
+ TestCode = @"
+internal class [|C1|] { }",
+ FixedCode = @"
+class C1 { }",
+ Options =
+ {
+ { CodeStyleOptions.RequireAccessibilityModifiers, AccessibilityModifiersRequired.OmitIfDefault },
+ },
+ }.RunAsync();
}
}
}
diff --git a/src/EditorFeatures/TestUtilities/CodeActions/CSharpCodeFixVerifier`2+Test.cs b/src/EditorFeatures/TestUtilities/CodeActions/CSharpCodeFixVerifier`2+Test.cs
new file mode 100644
index 0000000000000..b2e46bba43ec0
--- /dev/null
+++ b/src/EditorFeatures/TestUtilities/CodeActions/CSharpCodeFixVerifier`2+Test.cs
@@ -0,0 +1,88 @@
+// 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.Immutable;
+using Microsoft.CodeAnalysis.CodeFixes;
+using Microsoft.CodeAnalysis.CSharp;
+using Microsoft.CodeAnalysis.CSharp.Testing;
+using Microsoft.CodeAnalysis.Diagnostics;
+using Microsoft.CodeAnalysis.Testing.Verifiers;
+using Roslyn.Utilities;
+
+namespace Microsoft.CodeAnalysis.Editor.UnitTests.CodeActions
+{
+ public static partial class CSharpCodeFixVerifier
+ where TAnalyzer : DiagnosticAnalyzer, new()
+ where TCodeFix : CodeFixProvider, new()
+ {
+ public class Test : CSharpCodeFixTest
+ {
+ ///
+ /// By default, the compiler reports diagnostics for nullable reference types at
+ /// , and the analyzer test framework defaults to only validating
+ /// diagnostics at . This map contains all compiler diagnostic IDs
+ /// related to nullability mapped to , which is then used to enable all
+ /// of these warnings for default validation during analyzer and code fix tests.
+ ///
+ private static readonly ImmutableDictionary s_nullableWarnings = GetNullableWarningsFromCompiler();
+
+ public Test()
+ {
+ MarkupOptions = Testing.MarkupOptions.UseFirstDescriptor;
+
+ SolutionTransforms.Add((solution, projectId) =>
+ {
+ var parseOptions = (CSharpParseOptions)solution.GetProject(projectId).ParseOptions;
+ solution = solution.WithProjectParseOptions(projectId, parseOptions.WithLanguageVersion(LanguageVersion));
+
+ var compilationOptions = solution.GetProject(projectId).CompilationOptions;
+ compilationOptions = compilationOptions.WithSpecificDiagnosticOptions(compilationOptions.SpecificDiagnosticOptions.SetItems(s_nullableWarnings));
+ solution = solution.WithProjectCompilationOptions(projectId, compilationOptions);
+
+ var options = solution.Options;
+ foreach (var (key, value) in Options)
+ {
+ options = options.WithChangedOption(key, value);
+ }
+
+ solution = solution.WithOptions(options);
+
+ return solution;
+ });
+ }
+
+ private static ImmutableDictionary GetNullableWarningsFromCompiler()
+ {
+ string[] args = { "/warnaserror:nullable" };
+ var commandLineArguments = CSharpCommandLineParser.Default.Parse(args, baseDirectory: Environment.CurrentDirectory, sdkDirectory: Environment.CurrentDirectory);
+ var nullableWarnings = commandLineArguments.CompilationOptions.SpecificDiagnosticOptions;
+
+ // Workaround for https://github.com/dotnet/roslyn/issues/41610
+ nullableWarnings = nullableWarnings
+ .SetItem("CS8632", ReportDiagnostic.Error)
+ .SetItem("CS8669", ReportDiagnostic.Error);
+
+ return nullableWarnings;
+ }
+
+ ///
+ /// Gets or sets the language version to use for the test. The default value is
+ /// .
+ ///
+ public LanguageVersion LanguageVersion { get; set; } = LanguageVersion.CSharp8;
+
+ ///
+ /// Gets a collection of options to apply to for testing. Values may be added
+ /// using a collection initializer.
+ ///
+ public OptionsCollection Options { get; } = new OptionsCollection(LanguageNames.CSharp);
+
+ protected override AnalyzerOptions GetAnalyzerOptions(Project project)
+ {
+ return new WorkspaceAnalyzerOptions(base.GetAnalyzerOptions(project), project.Solution);
+ }
+ }
+ }
+}
diff --git a/src/EditorFeatures/TestUtilities/CodeActions/CSharpCodeFixVerifier`2.cs b/src/EditorFeatures/TestUtilities/CodeActions/CSharpCodeFixVerifier`2.cs
new file mode 100644
index 0000000000000..630e6df217b49
--- /dev/null
+++ b/src/EditorFeatures/TestUtilities/CodeActions/CSharpCodeFixVerifier`2.cs
@@ -0,0 +1,74 @@
+// 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.Threading.Tasks;
+using Microsoft.CodeAnalysis.CodeFixes;
+using Microsoft.CodeAnalysis.CSharp.Testing;
+using Microsoft.CodeAnalysis.Diagnostics;
+using Microsoft.CodeAnalysis.Testing;
+using Microsoft.CodeAnalysis.Testing.Verifiers;
+
+namespace Microsoft.CodeAnalysis.Editor.UnitTests.CodeActions
+{
+ public static partial class CSharpCodeFixVerifier
+ where TAnalyzer : DiagnosticAnalyzer, new()
+ where TCodeFix : CodeFixProvider, new()
+ {
+ ///
+ public static DiagnosticResult Diagnostic()
+ => CSharpCodeFixVerifier.Diagnostic();
+
+ ///
+ public static DiagnosticResult Diagnostic(string diagnosticId)
+ => CSharpCodeFixVerifier.Diagnostic(diagnosticId);
+
+ ///
+ public static DiagnosticResult Diagnostic(DiagnosticDescriptor descriptor)
+ => CSharpCodeFixVerifier.Diagnostic(descriptor);
+
+ ///
+ /// Verify standard properties of .
+ ///
+ ///
+ /// This validation method is largely specific to dotnet/roslyn scenarios.
+ ///
+ /// to verify
+ /// property of supported diagnostics; otherwise, to skip this validation.
+ public static void VerifyStandardProperties(bool verifyHelpLink = false)
+ => CodeFixVerifierHelper.VerifyStandardProperties(new TAnalyzer(), verifyHelpLink);
+
+ ///
+ public static async Task VerifyAnalyzerAsync(string source, params DiagnosticResult[] expected)
+ {
+ var test = new Test
+ {
+ TestCode = source,
+ };
+
+ test.ExpectedDiagnostics.AddRange(expected);
+ await test.RunAsync();
+ }
+
+ ///
+ public static async Task VerifyCodeFixAsync(string source, string fixedSource)
+ => await VerifyCodeFixAsync(source, DiagnosticResult.EmptyDiagnosticResults, fixedSource);
+
+ ///
+ public static async Task VerifyCodeFixAsync(string source, DiagnosticResult expected, string fixedSource)
+ => await VerifyCodeFixAsync(source, new[] { expected }, fixedSource);
+
+ ///
+ public static async Task VerifyCodeFixAsync(string source, DiagnosticResult[] expected, string fixedSource)
+ {
+ var test = new Test
+ {
+ TestCode = source,
+ FixedCode = fixedSource,
+ };
+
+ test.ExpectedDiagnostics.AddRange(expected);
+ await test.RunAsync();
+ }
+ }
+}
diff --git a/src/EditorFeatures/TestUtilities/CodeActions/CodeFixVerifierHelper.cs b/src/EditorFeatures/TestUtilities/CodeActions/CodeFixVerifierHelper.cs
new file mode 100644
index 0000000000000..922759fd1a997
--- /dev/null
+++ b/src/EditorFeatures/TestUtilities/CodeActions/CodeFixVerifierHelper.cs
@@ -0,0 +1,77 @@
+// 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.Linq;
+using Microsoft.CodeAnalysis.Diagnostics;
+using Xunit;
+
+namespace Microsoft.CodeAnalysis.Editor.UnitTests.CodeActions
+{
+ internal static class CodeFixVerifierHelper
+ {
+ public static void VerifyStandardProperties(DiagnosticAnalyzer analyzer, bool verifyHelpLink = false)
+ {
+ VerifyMessageTitle(analyzer);
+ VerifyMessageDescription(analyzer);
+
+ if (verifyHelpLink)
+ {
+ VerifyMessageHelpLinkUri(analyzer);
+ }
+ }
+
+ private static void VerifyMessageTitle(DiagnosticAnalyzer analyzer)
+ {
+ foreach (var descriptor in analyzer.SupportedDiagnostics)
+ {
+ if (descriptor.CustomTags.Contains(WellKnownDiagnosticTags.NotConfigurable))
+ {
+ // The title only displayed for rule configuration
+ continue;
+ }
+
+ Assert.NotEqual("", descriptor.Title?.ToString() ?? "");
+ }
+ }
+
+ private static void VerifyMessageDescription(DiagnosticAnalyzer analyzer)
+ {
+ foreach (var descriptor in analyzer.SupportedDiagnostics)
+ {
+ if (ShouldSkipMessageDescriptionVerification(descriptor))
+ {
+ continue;
+ }
+
+ Assert.NotEqual("", descriptor.MessageFormat?.ToString() ?? "");
+ }
+
+ return;
+
+ // Local function
+ static bool ShouldSkipMessageDescriptionVerification(DiagnosticDescriptor descriptor)
+ {
+ if (descriptor.CustomTags.Contains(WellKnownDiagnosticTags.NotConfigurable))
+ {
+ if (!descriptor.IsEnabledByDefault || descriptor.DefaultSeverity == DiagnosticSeverity.Hidden)
+ {
+ // The message only displayed if either enabled and not hidden, or configurable
+ return true;
+ }
+ }
+
+ return false;
+ }
+ }
+
+ private static void VerifyMessageHelpLinkUri(DiagnosticAnalyzer analyzer)
+ {
+ foreach (var descriptor in analyzer.SupportedDiagnostics)
+ {
+ Assert.NotEqual("", descriptor.HelpLinkUri ?? "");
+ }
+ }
+ }
+}
diff --git a/src/EditorFeatures/TestUtilities/CodeActions/OptionsCollection.cs b/src/EditorFeatures/TestUtilities/CodeActions/OptionsCollection.cs
new file mode 100644
index 0000000000000..99ac6de7263a2
--- /dev/null
+++ b/src/EditorFeatures/TestUtilities/CodeActions/OptionsCollection.cs
@@ -0,0 +1,43 @@
+// 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.Collections;
+using System.Collections.Generic;
+using Microsoft.CodeAnalysis.CodeStyle;
+using Microsoft.CodeAnalysis.Options;
+
+namespace Microsoft.CodeAnalysis.Editor.UnitTests.CodeActions
+{
+ public sealed class OptionsCollection : IEnumerable>
+ {
+ private readonly Dictionary _options = new Dictionary();
+ private readonly string _languageName;
+
+ public OptionsCollection(string languageName)
+ {
+ _languageName = languageName;
+ }
+
+ public void Add(Option option, T value)
+ => _options.Add(new OptionKey(option), value);
+
+ public void Add(Option> option, T value, NotificationOption notification)
+ => _options.Add(new OptionKey(option), new CodeStyleOption(value, notification));
+
+ public void Add(PerLanguageOption option, T value)
+ => _options.Add(new OptionKey(option, _languageName), value);
+
+ public void Add(PerLanguageOption> option, T value)
+ => Add(option, value, option.DefaultValue.Notification);
+
+ public void Add(PerLanguageOption> option, T value, NotificationOption notification)
+ => _options.Add(new OptionKey(option, _languageName), new CodeStyleOption(value, notification));
+
+ public IEnumerator> GetEnumerator()
+ => _options.GetEnumerator();
+
+ IEnumerator IEnumerable.GetEnumerator()
+ => GetEnumerator();
+ }
+}
diff --git a/src/EditorFeatures/TestUtilities/CodeActions/VisualBasicCodeFixVerifier`2+Test.cs b/src/EditorFeatures/TestUtilities/CodeActions/VisualBasicCodeFixVerifier`2+Test.cs
new file mode 100644
index 0000000000000..030264a2764d7
--- /dev/null
+++ b/src/EditorFeatures/TestUtilities/CodeActions/VisualBasicCodeFixVerifier`2+Test.cs
@@ -0,0 +1,59 @@
+// 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 Microsoft.CodeAnalysis.CodeFixes;
+using Microsoft.CodeAnalysis.Diagnostics;
+using Microsoft.CodeAnalysis.Testing.Verifiers;
+using Microsoft.CodeAnalysis.VisualBasic;
+using Microsoft.CodeAnalysis.VisualBasic.Testing;
+using Roslyn.Utilities;
+
+namespace Microsoft.CodeAnalysis.Editor.UnitTests.CodeActions
+{
+ public static partial class VisualBasicCodeFixVerifier
+ where TAnalyzer : DiagnosticAnalyzer, new()
+ where TCodeFix : CodeFixProvider, new()
+ {
+ public class Test : VisualBasicCodeFixTest
+ {
+ public Test()
+ {
+ MarkupOptions = Testing.MarkupOptions.UseFirstDescriptor;
+
+ SolutionTransforms.Add((solution, projectId) =>
+ {
+ var parseOptions = (VisualBasicParseOptions)solution.GetProject(projectId).ParseOptions;
+ solution = solution.WithProjectParseOptions(projectId, parseOptions.WithLanguageVersion(LanguageVersion));
+
+ var options = solution.Options;
+ foreach (var (key, value) in Options)
+ {
+ options = options.WithChangedOption(key, value);
+ }
+
+ solution = solution.WithOptions(options);
+
+ return solution;
+ });
+ }
+
+ ///
+ /// Gets or sets the language version to use for the test. The default value is
+ /// .
+ ///
+ public LanguageVersion LanguageVersion { get; set; } = LanguageVersion.VisualBasic16;
+
+ ///
+ /// Gets a collection of options to apply to for testing. Values may be added
+ /// using a collection initializer.
+ ///
+ public OptionsCollection Options { get; } = new OptionsCollection(LanguageNames.VisualBasic);
+
+ protected override AnalyzerOptions GetAnalyzerOptions(Project project)
+ {
+ return new WorkspaceAnalyzerOptions(base.GetAnalyzerOptions(project), project.Solution);
+ }
+ }
+ }
+}
diff --git a/src/EditorFeatures/TestUtilities/CodeActions/VisualBasicCodeFixVerifier`2.cs b/src/EditorFeatures/TestUtilities/CodeActions/VisualBasicCodeFixVerifier`2.cs
new file mode 100644
index 0000000000000..47a3848eacf67
--- /dev/null
+++ b/src/EditorFeatures/TestUtilities/CodeActions/VisualBasicCodeFixVerifier`2.cs
@@ -0,0 +1,74 @@
+// 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.Threading.Tasks;
+using Microsoft.CodeAnalysis.CodeFixes;
+using Microsoft.CodeAnalysis.Diagnostics;
+using Microsoft.CodeAnalysis.Testing;
+using Microsoft.CodeAnalysis.Testing.Verifiers;
+using Microsoft.CodeAnalysis.VisualBasic.Testing;
+
+namespace Microsoft.CodeAnalysis.Editor.UnitTests.CodeActions
+{
+ public static partial class VisualBasicCodeFixVerifier
+ where TAnalyzer : DiagnosticAnalyzer, new()
+ where TCodeFix : CodeFixProvider, new()
+ {
+ ///
+ public static DiagnosticResult Diagnostic()
+ => VisualBasicCodeFixVerifier.Diagnostic();
+
+ ///
+ public static DiagnosticResult Diagnostic(string diagnosticId)
+ => VisualBasicCodeFixVerifier.Diagnostic(diagnosticId);
+
+ ///
+ public static DiagnosticResult Diagnostic(DiagnosticDescriptor descriptor)
+ => VisualBasicCodeFixVerifier.Diagnostic(descriptor);
+
+ ///
+ /// Verify standard properties of .
+ ///
+ ///
+ /// This validation method is largely specific to dotnet/roslyn scenarios.
+ ///
+ /// to verify
+ /// property of supported diagnostics; otherwise, to skip this validation.
+ public static void VerifyStandardProperties(bool verifyHelpLink = false)
+ => CodeFixVerifierHelper.VerifyStandardProperties(new TAnalyzer(), verifyHelpLink);
+
+ ///
+ public static async Task VerifyAnalyzerAsync(string source, params DiagnosticResult[] expected)
+ {
+ var test = new Test
+ {
+ TestCode = source,
+ };
+
+ test.ExpectedDiagnostics.AddRange(expected);
+ await test.RunAsync();
+ }
+
+ ///
+ public static async Task VerifyCodeFixAsync(string source, string fixedSource)
+ => await VerifyCodeFixAsync(source, DiagnosticResult.EmptyDiagnosticResults, fixedSource);
+
+ ///
+ public static async Task VerifyCodeFixAsync(string source, DiagnosticResult expected, string fixedSource)
+ => await VerifyCodeFixAsync(source, new[] { expected }, fixedSource);
+
+ ///
+ public static async Task VerifyCodeFixAsync(string source, DiagnosticResult[] expected, string fixedSource)
+ {
+ var test = new Test
+ {
+ TestCode = source,
+ FixedCode = fixedSource,
+ };
+
+ test.ExpectedDiagnostics.AddRange(expected);
+ await test.RunAsync();
+ }
+ }
+}
diff --git a/src/EditorFeatures/TestUtilities/Roslyn.Services.Test.Utilities.csproj b/src/EditorFeatures/TestUtilities/Roslyn.Services.Test.Utilities.csproj
index 9b15252cf1be4..1e0ea1173fd2a 100644
--- a/src/EditorFeatures/TestUtilities/Roslyn.Services.Test.Utilities.csproj
+++ b/src/EditorFeatures/TestUtilities/Roslyn.Services.Test.Utilities.csproj
@@ -57,6 +57,8 @@
+
+