diff --git a/src/EditorFeatures/CSharpTest/CodeActions/UseExplicitType/UseExplicitTypeRefactoringTests.cs b/src/EditorFeatures/CSharpTest/CodeActions/UseExplicitType/UseExplicitTypeRefactoringTests.cs deleted file mode 100644 index 9f89b62035b209875b847576b65398c4e91a920b..0000000000000000000000000000000000000000 --- a/src/EditorFeatures/CSharpTest/CodeActions/UseExplicitType/UseExplicitTypeRefactoringTests.cs +++ /dev/null @@ -1,327 +0,0 @@ -// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System.Collections.Generic; -using System.Threading.Tasks; -using Microsoft.CodeAnalysis.CodeRefactorings; -using Microsoft.CodeAnalysis.CodeStyle; -using Microsoft.CodeAnalysis.CSharp.CodeRefactorings.UseExplicitType; -using Microsoft.CodeAnalysis.CSharp.CodeStyle; -using Microsoft.CodeAnalysis.Options; -using Microsoft.CodeAnalysis.Test.Utilities; -using Roslyn.Test.Utilities; -using Xunit; - -namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.CodeRefactorings.UseExplicitType -{ - [Trait(Traits.Feature, Traits.Features.CodeActionsUseExplicitType)] - public class UseExplicitTypeRefactoringTests : AbstractCSharpCodeActionTest - { - protected override CodeRefactoringProvider CreateCodeRefactoringProvider(Workspace workspace, TestParameters parameters) - => new UseExplicitTypeCodeRefactoringProvider(); - - private readonly CodeStyleOption onWithSilent = new CodeStyleOption(true, NotificationOption.Silent); - private readonly CodeStyleOption offWithSilent = new CodeStyleOption(false, NotificationOption.Silent); - private readonly CodeStyleOption onWithInfo = new CodeStyleOption(true, NotificationOption.Suggestion); - private readonly CodeStyleOption offWithInfo = new CodeStyleOption(false, NotificationOption.Suggestion); - - private IDictionary PreferExplicitTypeWithInfo() => OptionsSet( - SingleOption(CSharpCodeStyleOptions.UseImplicitTypeWherePossible, offWithInfo), - SingleOption(CSharpCodeStyleOptions.UseImplicitTypeWhereApparent, offWithInfo), - SingleOption(CSharpCodeStyleOptions.UseImplicitTypeForIntrinsicTypes, offWithInfo)); - - private IDictionary PreferExplicitTypeWithSilent() => OptionsSet( - SingleOption(CSharpCodeStyleOptions.UseImplicitTypeWherePossible, offWithSilent), - SingleOption(CSharpCodeStyleOptions.UseImplicitTypeWhereApparent, offWithSilent), - SingleOption(CSharpCodeStyleOptions.UseImplicitTypeForIntrinsicTypes, offWithSilent)); - - private IDictionary PreferImplicitTypeWithInfo() => OptionsSet( - SingleOption(CSharpCodeStyleOptions.UseImplicitTypeWherePossible, onWithInfo), - SingleOption(CSharpCodeStyleOptions.UseImplicitTypeWhereApparent, onWithInfo), - SingleOption(CSharpCodeStyleOptions.UseImplicitTypeForIntrinsicTypes, onWithInfo)); - - private IDictionary PreferImplicitTypeWithSilent() => OptionsSet( - SingleOption(CSharpCodeStyleOptions.UseImplicitTypeWherePossible, onWithSilent), - SingleOption(CSharpCodeStyleOptions.UseImplicitTypeWhereApparent, onWithSilent), - SingleOption(CSharpCodeStyleOptions.UseImplicitTypeForIntrinsicTypes, onWithSilent)); - - [Fact] - public async Task TestIntLocalDeclaration() - { - var code = @" -class C -{ - static void Main() - { - var[||] i = 0; - } -}"; - - var expected = @" -class C -{ - static void Main() - { - int i = 0; - } -}"; - - await TestInRegularAndScriptAsync(code, expected, options: PreferImplicitTypeWithSilent()); - await TestInRegularAndScriptAsync(code, expected, options: PreferExplicitTypeWithSilent()); - await TestMissingInRegularAndScriptAsync(code, PreferExplicitTypeWithInfo()); - } - - [Fact] - public async Task TestForeachInsideLocalDeclaration() - { - var code = @" -class C -{ - static void Main() - { - System.Action notThisLocal = () => { foreach (var[||] i in new int[0]) { } }; - } -}"; - - var expected = @" -class C -{ - static void Main() - { - System.Action notThisLocal = () => { foreach (int[||] i in new int[0]) { } }; - } -}"; - - await TestInRegularAndScriptAsync(code, expected, options: PreferImplicitTypeWithSilent()); - } - - [Fact] - public async Task TestInVarPattern() - { - var code = @" -class C -{ - static void Main() - { - _ = 0 is var[||] i; - } -}"; - - await TestMissingInRegularAndScriptAsync(code, PreferImplicitTypeWithSilent()); - await TestMissingInRegularAndScriptAsync(code, PreferExplicitTypeWithSilent()); - await TestMissingInRegularAndScriptAsync(code, PreferExplicitTypeWithInfo()); - } - - [Fact] - public async Task TestIntLocalDeclaration_Multiple() - { - var code = @" -class C -{ - static void Main() - { - var[||] i = 0, j = j; - } -}"; - - - await TestMissingInRegularAndScriptAsync(code, PreferImplicitTypeWithSilent()); - await TestMissingInRegularAndScriptAsync(code, PreferExplicitTypeWithSilent()); - await TestMissingInRegularAndScriptAsync(code, PreferExplicitTypeWithInfo()); - } - - [Fact] - public async Task TestIntLocalDeclaration_NoInitializer() - { - var code = @" -class C -{ - static void Main() - { - var[||] i; - } -}"; - - await TestMissingInRegularAndScriptAsync(code); - } - - [Fact] - public async Task TestIntForLoop() - { - var code = @" -class C -{ - static void Main() - { - for (var[||] i = 0;;) { } - } -}"; - - var expected = @" -class C -{ - static void Main() - { - for (int i = 0;;) { } - } -}"; - - await TestInRegularAndScriptAsync(code, expected, options: PreferImplicitTypeWithSilent()); - } - - [Fact] - public async Task TestInDispose() - { - var code = @" -class C : System.IDisposable -{ - static void Main() - { - using (var[||] c = new C()) { } - } -}"; - - var expected = @" -class C : System.IDisposable -{ - static void Main() - { - using (C c = new C()) { } - } -}"; - - await TestInRegularAndScriptAsync(code, expected, options: PreferImplicitTypeWithSilent()); - } - - [Fact] - public async Task TestTypelessVarLocalDeclaration() - { - var code = @" -class var -{ - static void Main() - { - var[||] i = null; - } -}"; - await TestMissingInRegularAndScriptAsync(code, options: PreferImplicitTypeWithSilent()); - } - - [Fact] - public async Task TestIntForeachLoop() - { - var code = @" -class C -{ - static void Main() - { - foreach (var[||] i in new[] { 0 }) { } - } -}"; - - var expected = @" -class C -{ - static void Main() - { - foreach (int i in new[] { 0 }) { } - } -}"; - - await TestInRegularAndScriptAsync(code, expected, options: PreferImplicitTypeWithSilent()); - } - - [Fact] - public async Task TestIntDeconstruction() - { - var code = @" -class C -{ - static void Main() - { - var[||] (i, j) = (0, 1); - } -}"; - - var expected = @" -class C -{ - static void Main() - { - (int i, int j) = (0, 1); - } -}"; - - await TestInRegularAndScriptAsync(code, expected, options: PreferImplicitTypeWithSilent()); - } - - [Fact] - public async Task TestIntDeconstruction2() - { - var code = @" -class C -{ - static void Main() - { - (var[||] i, var j) = (0, 1); - } -}"; - - var expected = @" -class C -{ - static void Main() - { - (int i, var j) = (0, 1); - } -}"; - - await TestInRegularAndScriptAsync(code, expected, options: PreferImplicitTypeWithSilent()); - await TestInRegularAndScriptAsync(code, expected, options: PreferExplicitTypeWithSilent()); - await TestMissingInRegularAndScriptAsync(code, PreferExplicitTypeWithInfo()); - } - - [Fact] - public async Task TestWithAnonymousType() - { - var code = @" -class C -{ - static void Main() - { - [|var|] x = new { Amount = 108, Message = ""Hello"" }; - } -}"; - - await TestMissingInRegularAndScriptAsync(code, options: PreferImplicitTypeWithSilent()); - } - - [Fact, WorkItem(26923, "https://github.com/dotnet/roslyn/issues/26923")] - public async Task NoSuggestionOnForeachCollectionExpression() - { - var code = @"using System; -using System.Collections.Generic; - -class Program -{ - void Method(List var) - { - foreach (int value in [|var|]) - { - Console.WriteLine(value.Value); - } - } -}"; - - // We never want to get offered here under any circumstances. - await TestMissingInRegularAndScriptAsync(code, PreferImplicitTypeWithSilent()); - await TestMissingInRegularAndScriptAsync(code, PreferExplicitTypeWithSilent()); - await TestMissingInRegularAndScriptAsync(code, PreferImplicitTypeWithInfo()); - await TestMissingInRegularAndScriptAsync(code, PreferExplicitTypeWithInfo()); - } - - private Task TestMissingInRegularAndScriptAsync(string initialMarkup, IDictionary options) - { - return TestMissingInRegularAndScriptAsync(initialMarkup, parameters: new TestParameters(options: options)); - } - } -} diff --git a/src/EditorFeatures/CSharpTest/CodeActions/UseImplicitType/UseImplicitTypeRefactoringTests.cs b/src/EditorFeatures/CSharpTest/CodeActions/UseImplicitType/UseImplicitTypeRefactoringTests.cs deleted file mode 100644 index 701a483c6ac6ac74c16d1731f7e568c5d7282b9b..0000000000000000000000000000000000000000 --- a/src/EditorFeatures/CSharpTest/CodeActions/UseImplicitType/UseImplicitTypeRefactoringTests.cs +++ /dev/null @@ -1,301 +0,0 @@ -// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System.Collections.Generic; -using System.Threading.Tasks; -using Microsoft.CodeAnalysis.CodeRefactorings; -using Microsoft.CodeAnalysis.CodeStyle; -using Microsoft.CodeAnalysis.CSharp.CodeRefactorings.UseImplicitType; -using Microsoft.CodeAnalysis.CSharp.CodeStyle; -using Microsoft.CodeAnalysis.Options; -using Microsoft.CodeAnalysis.Test.Utilities; -using Roslyn.Test.Utilities; -using Xunit; - -namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.CodeRefactorings.UseExplicitType -{ - [Trait(Traits.Feature, Traits.Features.CodeActionsUseImplicitType)] - public class UseImplicitTypeRefactoringTests : AbstractCSharpCodeActionTest - { - protected override CodeRefactoringProvider CreateCodeRefactoringProvider(Workspace workspace, TestParameters parameters) - => new UseImplicitTypeCodeRefactoringProvider(); - - private readonly CodeStyleOption onWithSilent = new CodeStyleOption(true, NotificationOption.Silent); - private readonly CodeStyleOption offWithSilent = new CodeStyleOption(false, NotificationOption.Silent); - private readonly CodeStyleOption onWithInfo = new CodeStyleOption(true, NotificationOption.Suggestion); - private readonly CodeStyleOption offWithInfo = new CodeStyleOption(false, NotificationOption.Suggestion); - - private IDictionary PreferExplicitTypeWithInfo() => OptionsSet( - SingleOption(CSharpCodeStyleOptions.UseImplicitTypeWherePossible, offWithInfo), - SingleOption(CSharpCodeStyleOptions.UseImplicitTypeWhereApparent, offWithInfo), - SingleOption(CSharpCodeStyleOptions.UseImplicitTypeForIntrinsicTypes, offWithInfo)); - - private IDictionary PreferImplicitTypeWithInfo() => OptionsSet( - SingleOption(CSharpCodeStyleOptions.UseImplicitTypeWherePossible, onWithInfo), - SingleOption(CSharpCodeStyleOptions.UseImplicitTypeWhereApparent, onWithInfo), - SingleOption(CSharpCodeStyleOptions.UseImplicitTypeForIntrinsicTypes, onWithInfo)); - - private IDictionary PreferExplicitTypeWithSilent() => OptionsSet( - SingleOption(CSharpCodeStyleOptions.UseImplicitTypeWherePossible, offWithSilent), - SingleOption(CSharpCodeStyleOptions.UseImplicitTypeWhereApparent, offWithSilent), - SingleOption(CSharpCodeStyleOptions.UseImplicitTypeForIntrinsicTypes, offWithSilent)); - - private IDictionary PreferImplicitTypeWithSilent() => OptionsSet( - SingleOption(CSharpCodeStyleOptions.UseImplicitTypeWherePossible, onWithSilent), - SingleOption(CSharpCodeStyleOptions.UseImplicitTypeWhereApparent, onWithSilent), - SingleOption(CSharpCodeStyleOptions.UseImplicitTypeForIntrinsicTypes, onWithSilent)); - - [Fact] - public async Task TestIntLocalDeclaration() - { - var code = @" -class C -{ - static void Main() - { - int[||] i = 0; - } -}"; - - var expected = @" -class C -{ - static void Main() - { - var i = 0; - } -}"; - - await TestInRegularAndScriptAsync(code, expected, options: PreferImplicitTypeWithSilent()); - await TestInRegularAndScriptAsync(code, expected, options: PreferExplicitTypeWithSilent()); - await TestInRegularAndScriptAsync(code, expected, options: PreferExplicitTypeWithInfo()); - await TestMissingInRegularAndScriptAsync(code, PreferImplicitTypeWithInfo()); - } - - [Fact] - public async Task TestForeachInsideLocalDeclaration() - { - var code = @" -class C -{ - static void Main() - { - System.Action notThisLocal = () => { foreach (int[||] i in new int[0]) { } }; - } -}"; - - var expected = @" -class C -{ - static void Main() - { - System.Action notThisLocal = () => { foreach (var[||] i in new int[0]) { } }; - } -}"; - - await TestInRegularAndScriptAsync(code, expected, options: PreferImplicitTypeWithSilent()); - } - - [Fact] - public async Task TestInIntPattern() - { - var code = @" -class C -{ - static void Main() - { - _ = 0 is int[||] i; - } -}"; - - await TestMissingInRegularAndScriptAsync(code, PreferImplicitTypeWithSilent()); - await TestMissingInRegularAndScriptAsync(code, PreferExplicitTypeWithSilent()); - await TestMissingInRegularAndScriptAsync(code, PreferExplicitTypeWithInfo()); - await TestMissingInRegularAndScriptAsync(code, PreferImplicitTypeWithInfo()); - } - - [Fact] - public async Task TestIntLocalDeclaration_Multiple() - { - var code = @" -class C -{ - static void Main() - { - int[||] i = 0, j = j; - } -}"; - - - await TestMissingInRegularAndScriptAsync(code, PreferImplicitTypeWithSilent()); - await TestMissingInRegularAndScriptAsync(code, PreferExplicitTypeWithSilent()); - await TestMissingInRegularAndScriptAsync(code, PreferExplicitTypeWithInfo()); - await TestMissingInRegularAndScriptAsync(code, PreferImplicitTypeWithInfo()); - } - - [Fact] - public async Task TestIntLocalDeclaration_NoInitializer() - { - var code = @" -class C -{ - static void Main() - { - int[||] i; - } -}"; - - await TestMissingInRegularAndScriptAsync(code); - } - - [Fact] - public async Task TestIntForLoop() - { - var code = @" -class C -{ - static void Main() - { - for (int[||] i = 0;;) { } - } -}"; - - var expected = @" -class C -{ - static void Main() - { - for (var i = 0;;) { } - } -}"; - - await TestInRegularAndScriptAsync(code, expected, options: PreferImplicitTypeWithSilent()); - } - - [Fact] - public async Task TestInDispose() - { - var code = @" -class C : System.IDisposable -{ - static void Main() - { - using (C[||] c = new C()) { } - } -}"; - - var expected = @" -class C : System.IDisposable -{ - static void Main() - { - using (var c = new C()) { } - } -}"; - - await TestInRegularAndScriptAsync(code, expected, options: PreferImplicitTypeWithSilent()); - } - - [Fact] - public async Task TestIntForeachLoop() - { - var code = @" -class C -{ - static void Main() - { - foreach (int[||] i in new[] { 0 }) { } - } -}"; - - var expected = @" -class C -{ - static void Main() - { - foreach (var i in new[] { 0 }) { } - } -}"; - - await TestInRegularAndScriptAsync(code, expected, options: PreferImplicitTypeWithSilent()); - } - - [Fact] - public async Task TestIntDeconstruction() - { - var code = @" -class C -{ - static void Main() - { - (int[||] i, var j) = (0, 1); - } -}"; - - var expected = @" -class C -{ - static void Main() - { - (var i, var j) = (0, 1); - } -}"; - - await TestInRegularAndScriptAsync(code, expected, options: PreferImplicitTypeWithSilent()); - } - - [Fact] - public async Task TestIntDeconstruction2() - { - var code = @" -class C -{ - static void Main() - { - (int[||] i, var j) = (0, 1); - } -}"; - - var expected = @" -class C -{ - static void Main() - { - (var i, var j) = (0, 1); - } -}"; - - await TestInRegularAndScriptAsync(code, expected, options: PreferImplicitTypeWithSilent()); - await TestInRegularAndScriptAsync(code, expected, options: PreferExplicitTypeWithSilent()); - await TestMissingInRegularAndScriptAsync(code, PreferImplicitTypeWithInfo()); - } - - [Fact, WorkItem(26923, "https://github.com/dotnet/roslyn/issues/26923")] - public async Task NoSuggestionOnForeachCollectionExpression() - { - var code = @"using System; -using System.Collections.Generic; - -class C -{ - static void Main(string[] args) - { - foreach (string arg in [|args|]) - { - - } - } -}"; - - // We never want to get offered here under any circumstances. - await TestMissingInRegularAndScriptAsync(code, PreferImplicitTypeWithSilent()); - await TestMissingInRegularAndScriptAsync(code, PreferExplicitTypeWithSilent()); - await TestMissingInRegularAndScriptAsync(code, PreferImplicitTypeWithInfo()); - await TestMissingInRegularAndScriptAsync(code, PreferExplicitTypeWithInfo()); - } - - private Task TestMissingInRegularAndScriptAsync(string initialMarkup, IDictionary options) - { - return TestMissingInRegularAndScriptAsync(initialMarkup, parameters: new TestParameters(options: options)); - } - } -} diff --git a/src/EditorFeatures/CSharpTest/CodeRefactorings/UseExplicitOrImplicitType/AbstractUseTypeRefactoringTests.cs b/src/EditorFeatures/CSharpTest/CodeRefactorings/UseExplicitOrImplicitType/AbstractUseTypeRefactoringTests.cs new file mode 100644 index 0000000000000000000000000000000000000000..e3023085038c23b55de7a88e1f5371801c062c2d --- /dev/null +++ b/src/EditorFeatures/CSharpTest/CodeRefactorings/UseExplicitOrImplicitType/AbstractUseTypeRefactoringTests.cs @@ -0,0 +1,73 @@ +// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System.Collections.Generic; +using Microsoft.CodeAnalysis.CodeStyle; +using Microsoft.CodeAnalysis.CSharp.CodeStyle; +using Microsoft.CodeAnalysis.Options; + +namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.CodeRefactorings.UseExplicitOrImplicitType +{ + public abstract class AbstractUseTypeRefactoringTests : AbstractCSharpCodeActionTest + { + private readonly CodeStyleOption onWithNone = new CodeStyleOption(true, NotificationOption.None); + private readonly CodeStyleOption offWithNone = new CodeStyleOption(false, NotificationOption.None); + private readonly CodeStyleOption onWithSilent = new CodeStyleOption(true, NotificationOption.Silent); + private readonly CodeStyleOption offWithSilent = new CodeStyleOption(false, NotificationOption.Silent); + private readonly CodeStyleOption onWithInfo = new CodeStyleOption(true, NotificationOption.Suggestion); + private readonly CodeStyleOption offWithInfo = new CodeStyleOption(false, NotificationOption.Suggestion); + private readonly CodeStyleOption onWithWarning = new CodeStyleOption(true, NotificationOption.Warning); + private readonly CodeStyleOption offWithWarning = new CodeStyleOption(false, NotificationOption.Warning); + private readonly CodeStyleOption offWithError = new CodeStyleOption(false, NotificationOption.Error); + private readonly CodeStyleOption onWithError = new CodeStyleOption(true, NotificationOption.Error); + + protected IDictionary PreferExplicitTypeWithError() => OptionsSet( + SingleOption(CSharpCodeStyleOptions.UseImplicitTypeWherePossible, offWithError), + SingleOption(CSharpCodeStyleOptions.UseImplicitTypeWhereApparent, offWithError), + SingleOption(CSharpCodeStyleOptions.UseImplicitTypeForIntrinsicTypes, offWithError)); + + protected IDictionary PreferImplicitTypeWithError() => OptionsSet( + SingleOption(CSharpCodeStyleOptions.UseImplicitTypeWherePossible, onWithError), + SingleOption(CSharpCodeStyleOptions.UseImplicitTypeWhereApparent, onWithError), + SingleOption(CSharpCodeStyleOptions.UseImplicitTypeForIntrinsicTypes, onWithError)); + + protected IDictionary PreferExplicitTypeWithWarning() => OptionsSet( + SingleOption(CSharpCodeStyleOptions.UseImplicitTypeWherePossible, offWithWarning), + SingleOption(CSharpCodeStyleOptions.UseImplicitTypeWhereApparent, offWithWarning), + SingleOption(CSharpCodeStyleOptions.UseImplicitTypeForIntrinsicTypes, offWithWarning)); + + protected IDictionary PreferImplicitTypeWithWarning() => OptionsSet( + SingleOption(CSharpCodeStyleOptions.UseImplicitTypeWherePossible, onWithWarning), + SingleOption(CSharpCodeStyleOptions.UseImplicitTypeWhereApparent, onWithWarning), + SingleOption(CSharpCodeStyleOptions.UseImplicitTypeForIntrinsicTypes, onWithWarning)); + + protected IDictionary PreferExplicitTypeWithInfo() => OptionsSet( + SingleOption(CSharpCodeStyleOptions.UseImplicitTypeWherePossible, offWithInfo), + SingleOption(CSharpCodeStyleOptions.UseImplicitTypeWhereApparent, offWithInfo), + SingleOption(CSharpCodeStyleOptions.UseImplicitTypeForIntrinsicTypes, offWithInfo)); + + protected IDictionary PreferImplicitTypeWithInfo() => OptionsSet( + SingleOption(CSharpCodeStyleOptions.UseImplicitTypeWherePossible, onWithInfo), + SingleOption(CSharpCodeStyleOptions.UseImplicitTypeWhereApparent, onWithInfo), + SingleOption(CSharpCodeStyleOptions.UseImplicitTypeForIntrinsicTypes, onWithInfo)); + + protected IDictionary PreferExplicitTypeWithSilent() => OptionsSet( + SingleOption(CSharpCodeStyleOptions.UseImplicitTypeWherePossible, offWithSilent), + SingleOption(CSharpCodeStyleOptions.UseImplicitTypeWhereApparent, offWithSilent), + SingleOption(CSharpCodeStyleOptions.UseImplicitTypeForIntrinsicTypes, offWithSilent)); + + protected IDictionary PreferImplicitTypeWithSilent() => OptionsSet( + SingleOption(CSharpCodeStyleOptions.UseImplicitTypeWherePossible, onWithSilent), + SingleOption(CSharpCodeStyleOptions.UseImplicitTypeWhereApparent, onWithSilent), + SingleOption(CSharpCodeStyleOptions.UseImplicitTypeForIntrinsicTypes, onWithSilent)); + + protected IDictionary PreferExplicitTypeWithNone() => OptionsSet( + SingleOption(CSharpCodeStyleOptions.UseImplicitTypeWherePossible, offWithNone), + SingleOption(CSharpCodeStyleOptions.UseImplicitTypeWhereApparent, offWithNone), + SingleOption(CSharpCodeStyleOptions.UseImplicitTypeForIntrinsicTypes, offWithNone)); + + protected IDictionary PreferImplicitTypeWithNone() => OptionsSet( + SingleOption(CSharpCodeStyleOptions.UseImplicitTypeWherePossible, onWithNone), + SingleOption(CSharpCodeStyleOptions.UseImplicitTypeWhereApparent, onWithNone), + SingleOption(CSharpCodeStyleOptions.UseImplicitTypeForIntrinsicTypes, onWithNone)); + } +} diff --git a/src/EditorFeatures/CSharpTest/CodeRefactorings/UseExplicitOrImplicitType/UseExplicitTypeRefactoringTests.cs b/src/EditorFeatures/CSharpTest/CodeRefactorings/UseExplicitOrImplicitType/UseExplicitTypeRefactoringTests.cs new file mode 100644 index 0000000000000000000000000000000000000000..31e5123fd5ccb5dbd5f1fd6b815485ba27b97e53 --- /dev/null +++ b/src/EditorFeatures/CSharpTest/CodeRefactorings/UseExplicitOrImplicitType/UseExplicitTypeRefactoringTests.cs @@ -0,0 +1,317 @@ +// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.CodeRefactorings; +using Microsoft.CodeAnalysis.CSharp.CodeRefactorings.UseExplicitType; +using Microsoft.CodeAnalysis.Test.Utilities; +using Roslyn.Test.Utilities; +using Xunit; + +namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.CodeRefactorings.UseExplicitOrImplicitType +{ + [Trait(Traits.Feature, Traits.Features.CodeActionsUseExplicitType)] + public class UseExplicitTypeRefactoringTests : AbstractUseTypeRefactoringTests + { + protected override CodeRefactoringProvider CreateCodeRefactoringProvider(Workspace workspace, TestParameters parameters) + => new UseExplicitTypeCodeRefactoringProvider(); + + [Fact] + public async Task TestIntLocalDeclaration() + { + var code = @" +class C +{ + static void Main() + { + var[||] i = 0; + } +}"; + + var expected = @" +class C +{ + static void Main() + { + int i = 0; + } +}"; + + await TestInRegularAndScriptWhenDiagnosticNotAppliedAsync(code, expected); + } + + [Fact] + public async Task TestForeachInsideLocalDeclaration() + { + var code = @" +class C +{ + static void Main() + { + System.Action notThisLocal = () => { foreach (var[||] i in new int[0]) { } }; + } +}"; + + var expected = @" +class C +{ + static void Main() + { + System.Action notThisLocal = () => { foreach (int[||] i in new int[0]) { } }; + } +}"; + + await TestInRegularAndScriptWhenDiagnosticNotAppliedAsync(code, expected); + } + + [Fact] + public async Task TestInVarPattern() + { + var code = @" +class C +{ + static void Main() + { + _ = 0 is var[||] i; + } +}"; + + await TestMissingInRegularAndScriptAsync(code); + } + + [Fact] + public async Task TestIntLocalDeclaration_Multiple() + { + var code = @" +class C +{ + static void Main() + { + var[||] i = 0, j = j; + } +}"; + + + await TestMissingInRegularAndScriptAsync(code); + } + + [Fact] + public async Task TestIntLocalDeclaration_NoInitializer() + { + var code = @" +class C +{ + static void Main() + { + var[||] i; + } +}"; + + await TestMissingInRegularAndScriptAsync(code); + } + + [Fact] + public async Task TestIntForLoop() + { + var code = @" +class C +{ + static void Main() + { + for (var[||] i = 0;;) { } + } +}"; + + var expected = @" +class C +{ + static void Main() + { + for (int i = 0;;) { } + } +}"; + + await TestInRegularAndScriptWhenDiagnosticNotAppliedAsync(code, expected); + } + + [Fact] + public async Task TestInDispose() + { + var code = @" +class C : System.IDisposable +{ + static void Main() + { + using (var[||] c = new C()) { } + } +}"; + + var expected = @" +class C : System.IDisposable +{ + static void Main() + { + using (C c = new C()) { } + } +}"; + + await TestInRegularAndScriptWhenDiagnosticNotAppliedAsync(code, expected); + } + + [Fact] + public async Task TestTypelessVarLocalDeclaration() + { + var code = @" +class var +{ + static void Main() + { + var[||] i = null; + } +}"; + await TestMissingInRegularAndScriptAsync(code); + } + + [Fact] + public async Task TestIntForeachLoop() + { + var code = @" +class C +{ + static void Main() + { + foreach (var[||] i in new[] { 0 }) { } + } +}"; + + var expected = @" +class C +{ + static void Main() + { + foreach (int i in new[] { 0 }) { } + } +}"; + + await TestInRegularAndScriptWhenDiagnosticNotAppliedAsync(code, expected); + } + + [Fact] + public async Task TestIntDeconstruction() + { + var code = @" +class C +{ + static void Main() + { + var[||] (i, j) = (0, 1); + } +}"; + + var expected = @" +class C +{ + static void Main() + { + (int i, int j) = (0, 1); + } +}"; + + await TestInRegularAndScriptWhenDiagnosticNotAppliedAsync(code, expected); + } + + [Fact] + public async Task TestIntDeconstruction2() + { + var code = @" +class C +{ + static void Main() + { + (var[||] i, var j) = (0, 1); + } +}"; + + var expected = @" +class C +{ + static void Main() + { + (int i, var j) = (0, 1); + } +}"; + + await TestInRegularAndScriptWhenDiagnosticNotAppliedAsync(code, expected); + } + + [Fact] + public async Task TestWithAnonymousType() + { + var code = @" +class C +{ + static void Main() + { + [|var|] x = new { Amount = 108, Message = ""Hello"" }; + } +}"; + + await TestMissingInRegularAndScriptAsync(code); + } + + [Fact, WorkItem(26923, "https://github.com/dotnet/roslyn/issues/26923")] + public async Task NoSuggestionOnForeachCollectionExpression() + { + var code = @"using System; +using System.Collections.Generic; + +class Program +{ + void Method(List var) + { + foreach (int value in [|var|]) + { + Console.WriteLine(value.Value); + } + } +}"; + + // We never want to get offered here under any circumstances. + await TestMissingInRegularAndScriptAsync(code); + } + + private async Task TestInRegularAndScriptWhenDiagnosticNotAppliedAsync(string initialMarkup, string expectedMarkup) + { + // Enabled because the diagnostic is disabled + await TestInRegularAndScriptAsync(initialMarkup, expectedMarkup, options: PreferExplicitTypeWithNone()); + + // Enabled because the diagnostic is checking for the other direction + await TestInRegularAndScriptAsync(initialMarkup, expectedMarkup, options: PreferImplicitTypeWithNone()); + await TestInRegularAndScriptAsync(initialMarkup, expectedMarkup, options: PreferImplicitTypeWithSilent()); + await TestInRegularAndScriptAsync(initialMarkup, expectedMarkup, options: PreferImplicitTypeWithInfo()); + + // Disabled because the diagnostic will report it instead + await TestMissingInRegularAndScriptAsync(initialMarkup, parameters: new TestParameters(options: PreferExplicitTypeWithSilent())); + await TestMissingInRegularAndScriptAsync(initialMarkup, parameters: new TestParameters(options: PreferExplicitTypeWithInfo())); + await TestMissingInRegularAndScriptAsync(initialMarkup, parameters: new TestParameters(options: PreferExplicitTypeWithWarning())); + await TestMissingInRegularAndScriptAsync(initialMarkup, parameters: new TestParameters(options: PreferExplicitTypeWithError())); + + // Currently this refactoring is still enabled in cases where it would cause a warning or error + await TestInRegularAndScriptAsync(initialMarkup, expectedMarkup, options: PreferImplicitTypeWithWarning()); + await TestInRegularAndScriptAsync(initialMarkup, expectedMarkup, options: PreferImplicitTypeWithError()); + } + + private async Task TestMissingInRegularAndScriptAsync(string initialMarkup) + { + await TestMissingInRegularAndScriptAsync(initialMarkup, parameters: new TestParameters(options: PreferImplicitTypeWithNone())); + await TestMissingInRegularAndScriptAsync(initialMarkup, parameters: new TestParameters(options: PreferExplicitTypeWithNone())); + await TestMissingInRegularAndScriptAsync(initialMarkup, parameters: new TestParameters(options: PreferImplicitTypeWithSilent())); + await TestMissingInRegularAndScriptAsync(initialMarkup, parameters: new TestParameters(options: PreferExplicitTypeWithSilent())); + await TestMissingInRegularAndScriptAsync(initialMarkup, parameters: new TestParameters(options: PreferImplicitTypeWithInfo())); + await TestMissingInRegularAndScriptAsync(initialMarkup, parameters: new TestParameters(options: PreferExplicitTypeWithInfo())); + await TestMissingInRegularAndScriptAsync(initialMarkup, parameters: new TestParameters(options: PreferImplicitTypeWithWarning())); + await TestMissingInRegularAndScriptAsync(initialMarkup, parameters: new TestParameters(options: PreferExplicitTypeWithWarning())); + await TestMissingInRegularAndScriptAsync(initialMarkup, parameters: new TestParameters(options: PreferImplicitTypeWithError())); + await TestMissingInRegularAndScriptAsync(initialMarkup, parameters: new TestParameters(options: PreferExplicitTypeWithError())); + } + } +} diff --git a/src/EditorFeatures/CSharpTest/CodeRefactorings/UseExplicitOrImplicitType/UseImplicitTypeRefactoringTests.cs b/src/EditorFeatures/CSharpTest/CodeRefactorings/UseExplicitOrImplicitType/UseImplicitTypeRefactoringTests.cs new file mode 100644 index 0000000000000000000000000000000000000000..d03e861b901feaabd219cad2bcfb783dadbe9c9d --- /dev/null +++ b/src/EditorFeatures/CSharpTest/CodeRefactorings/UseExplicitOrImplicitType/UseImplicitTypeRefactoringTests.cs @@ -0,0 +1,288 @@ +// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.CodeRefactorings; +using Microsoft.CodeAnalysis.CSharp.CodeRefactorings.UseImplicitType; +using Microsoft.CodeAnalysis.Test.Utilities; +using Roslyn.Test.Utilities; +using Xunit; + +namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.CodeRefactorings.UseExplicitOrImplicitType +{ + [Trait(Traits.Feature, Traits.Features.CodeActionsUseImplicitType)] + public class UseImplicitTypeRefactoringTests : AbstractUseTypeRefactoringTests + { + protected override CodeRefactoringProvider CreateCodeRefactoringProvider(Workspace workspace, TestParameters parameters) + => new UseImplicitTypeCodeRefactoringProvider(); + + [Fact] + public async Task TestIntLocalDeclaration() + { + var code = @" +class C +{ + static void Main() + { + int[||] i = 0; + } +}"; + + var expected = @" +class C +{ + static void Main() + { + var i = 0; + } +}"; + + await TestInRegularAndScriptWhenDiagnosticNotAppliedAsync(code, expected); + } + + [Fact] + public async Task TestForeachInsideLocalDeclaration() + { + var code = @" +class C +{ + static void Main() + { + System.Action notThisLocal = () => { foreach (int[||] i in new int[0]) { } }; + } +}"; + + var expected = @" +class C +{ + static void Main() + { + System.Action notThisLocal = () => { foreach (var[||] i in new int[0]) { } }; + } +}"; + + await TestInRegularAndScriptWhenDiagnosticNotAppliedAsync(code, expected); + } + + [Fact] + public async Task TestInIntPattern() + { + var code = @" +class C +{ + static void Main() + { + _ = 0 is int[||] i; + } +}"; + + await TestMissingInRegularAndScriptAsync(code); + } + + [Fact] + public async Task TestIntLocalDeclaration_Multiple() + { + var code = @" +class C +{ + static void Main() + { + int[||] i = 0, j = j; + } +}"; + + + await TestMissingInRegularAndScriptAsync(code); + } + + [Fact] + public async Task TestIntLocalDeclaration_NoInitializer() + { + var code = @" +class C +{ + static void Main() + { + int[||] i; + } +}"; + + await TestMissingInRegularAndScriptAsync(code); + } + + [Fact] + public async Task TestIntForLoop() + { + var code = @" +class C +{ + static void Main() + { + for (int[||] i = 0;;) { } + } +}"; + + var expected = @" +class C +{ + static void Main() + { + for (var i = 0;;) { } + } +}"; + + await TestInRegularAndScriptWhenDiagnosticNotAppliedAsync(code, expected); + } + + [Fact] + public async Task TestInDispose() + { + var code = @" +class C : System.IDisposable +{ + static void Main() + { + using (C[||] c = new C()) { } + } +}"; + + var expected = @" +class C : System.IDisposable +{ + static void Main() + { + using (var c = new C()) { } + } +}"; + + await TestInRegularAndScriptWhenDiagnosticNotAppliedAsync(code, expected); + } + + [Fact] + public async Task TestIntForeachLoop() + { + var code = @" +class C +{ + static void Main() + { + foreach (int[||] i in new[] { 0 }) { } + } +}"; + + var expected = @" +class C +{ + static void Main() + { + foreach (var i in new[] { 0 }) { } + } +}"; + + await TestInRegularAndScriptWhenDiagnosticNotAppliedAsync(code, expected); + } + + [Fact] + public async Task TestIntDeconstruction() + { + var code = @" +class C +{ + static void Main() + { + (int[||] i, var j) = (0, 1); + } +}"; + + var expected = @" +class C +{ + static void Main() + { + (var i, var j) = (0, 1); + } +}"; + + await TestInRegularAndScriptWhenDiagnosticNotAppliedAsync(code, expected); + } + + [Fact] + public async Task TestIntDeconstruction2() + { + var code = @" +class C +{ + static void Main() + { + (int[||] i, var j) = (0, 1); + } +}"; + + var expected = @" +class C +{ + static void Main() + { + (var i, var j) = (0, 1); + } +}"; + + await TestInRegularAndScriptWhenDiagnosticNotAppliedAsync(code, expected); + } + + [Fact, WorkItem(26923, "https://github.com/dotnet/roslyn/issues/26923")] + public async Task NoSuggestionOnForeachCollectionExpression() + { + var code = @"using System; +using System.Collections.Generic; + +class C +{ + static void Main(string[] args) + { + foreach (string arg in [|args|]) + { + + } + } +}"; + + // We never want to get offered here under any circumstances. + await TestMissingInRegularAndScriptAsync(code); + } + + private async Task TestInRegularAndScriptWhenDiagnosticNotAppliedAsync(string initialMarkup, string expectedMarkup) + { + // Enabled because the diagnostic is disabled + await TestInRegularAndScriptAsync(initialMarkup, expectedMarkup, options: PreferImplicitTypeWithNone()); + + // Enabled because the diagnostic is checking for the other direction + await TestInRegularAndScriptAsync(initialMarkup, expectedMarkup, options: PreferExplicitTypeWithNone()); + await TestInRegularAndScriptAsync(initialMarkup, expectedMarkup, options: PreferExplicitTypeWithSilent()); + await TestInRegularAndScriptAsync(initialMarkup, expectedMarkup, options: PreferExplicitTypeWithInfo()); + + // Disabled because the diagnostic will report it instead + await TestMissingInRegularAndScriptAsync(initialMarkup, parameters: new TestParameters(options: PreferImplicitTypeWithSilent())); + await TestMissingInRegularAndScriptAsync(initialMarkup, parameters: new TestParameters(options: PreferImplicitTypeWithInfo())); + await TestMissingInRegularAndScriptAsync(initialMarkup, parameters: new TestParameters(options: PreferImplicitTypeWithWarning())); + await TestMissingInRegularAndScriptAsync(initialMarkup, parameters: new TestParameters(options: PreferImplicitTypeWithError())); + + // Currently this refactoring is still enabled in cases where it would cause a warning or error + await TestInRegularAndScriptAsync(initialMarkup, expectedMarkup, options: PreferExplicitTypeWithWarning()); + await TestInRegularAndScriptAsync(initialMarkup, expectedMarkup, options: PreferExplicitTypeWithError()); + } + + private async Task TestMissingInRegularAndScriptAsync(string initialMarkup) + { + await TestMissingInRegularAndScriptAsync(initialMarkup, parameters: new TestParameters(options: PreferImplicitTypeWithNone())); + await TestMissingInRegularAndScriptAsync(initialMarkup, parameters: new TestParameters(options: PreferExplicitTypeWithNone())); + await TestMissingInRegularAndScriptAsync(initialMarkup, parameters: new TestParameters(options: PreferImplicitTypeWithSilent())); + await TestMissingInRegularAndScriptAsync(initialMarkup, parameters: new TestParameters(options: PreferExplicitTypeWithSilent())); + await TestMissingInRegularAndScriptAsync(initialMarkup, parameters: new TestParameters(options: PreferImplicitTypeWithInfo())); + await TestMissingInRegularAndScriptAsync(initialMarkup, parameters: new TestParameters(options: PreferExplicitTypeWithInfo())); + await TestMissingInRegularAndScriptAsync(initialMarkup, parameters: new TestParameters(options: PreferImplicitTypeWithWarning())); + await TestMissingInRegularAndScriptAsync(initialMarkup, parameters: new TestParameters(options: PreferExplicitTypeWithWarning())); + await TestMissingInRegularAndScriptAsync(initialMarkup, parameters: new TestParameters(options: PreferImplicitTypeWithError())); + await TestMissingInRegularAndScriptAsync(initialMarkup, parameters: new TestParameters(options: PreferExplicitTypeWithError())); + } + } +} diff --git a/src/EditorFeatures/CSharpTest/Diagnostics/PreferFrameworkType/PreferFrameworkTypeTests.cs b/src/EditorFeatures/CSharpTest/Diagnostics/PreferFrameworkType/PreferFrameworkTypeTests.cs index 3a7d133aec30cc5f67187966962b51cafb4c2734..99384eeb8680c1b5e493efeb207cae8c30aa34a5 100644 --- a/src/EditorFeatures/CSharpTest/Diagnostics/PreferFrameworkType/PreferFrameworkTypeTests.cs +++ b/src/EditorFeatures/CSharpTest/Diagnostics/PreferFrameworkType/PreferFrameworkTypeTests.cs @@ -3,11 +3,11 @@ using System.Collections.Generic; using System.Threading.Tasks; using Microsoft.CodeAnalysis.CodeFixes; -using Microsoft.CodeAnalysis.CodeFixes.PreferFrameworkType; using Microsoft.CodeAnalysis.CodeStyle; using Microsoft.CodeAnalysis.CSharp.Diagnostics.Analyzers; using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.Options; +using Microsoft.CodeAnalysis.PreferFrameworkType; using Microsoft.CodeAnalysis.Test.Utilities; using Xunit; diff --git a/src/EditorFeatures/CSharpTest/Diagnostics/PreferFrameworkType/PreferFrameworkTypeTests_FixAllTests.cs b/src/EditorFeatures/CSharpTest/Diagnostics/PreferFrameworkType/PreferFrameworkTypeTests_FixAllTests.cs index b035bbfa9e02998549910d639663babb95c1a14b..1b38290b579061422e3b015555d13b978573d2bd 100644 --- a/src/EditorFeatures/CSharpTest/Diagnostics/PreferFrameworkType/PreferFrameworkTypeTests_FixAllTests.cs +++ b/src/EditorFeatures/CSharpTest/Diagnostics/PreferFrameworkType/PreferFrameworkTypeTests_FixAllTests.cs @@ -412,9 +412,9 @@ private System.Int32 F(System.Int32 p1, System.Int16 p2) using System; class ProgramA { - private int x = 0; - private int y = 0; - private int z = 0; + private Int32 x = 0; + private Int32 y = 0; + private Int32 z = 0; private System.Int32 F(System.Int32 p1, System.Int16 p2) { @@ -432,9 +432,9 @@ private System.Int32 F(System.Int32 p1, System.Int16 p2) using System; class ProgramA2 { - private int x = 0; - private int y = 0; - private int z = 0; + private Int32 x = 0; + private Int32 y = 0; + private Int32 z = 0; private System.Int32 F(System.Int32 p1, System.Int16 p2) { @@ -454,9 +454,9 @@ private System.Int32 F(System.Int32 p1, System.Int16 p2) using System; class ProgramA3 { - private int x = 0; - private int y = 0; - private int z = 0; + private Int32 x = 0; + private Int32 y = 0; + private Int32 z = 0; private System.Int32 F(System.Int32 p1, System.Int16 p2) { diff --git a/src/EditorFeatures/CSharpTest/Diagnostics/UseImplicitOrExplicitType/UseExplicitTypeTests.cs b/src/EditorFeatures/CSharpTest/Diagnostics/UseImplicitOrExplicitType/UseExplicitTypeTests.cs index 020cc9f85227b0a4800022c525b6225b1026037b..681284d2736d95c7e80433ce5a8a94a40ffeec7e 100644 --- a/src/EditorFeatures/CSharpTest/Diagnostics/UseImplicitOrExplicitType/UseExplicitTypeTests.cs +++ b/src/EditorFeatures/CSharpTest/Diagnostics/UseImplicitOrExplicitType/UseExplicitTypeTests.cs @@ -1539,8 +1539,10 @@ static void M() [|var|] n1 = new C(); } }"; - await TestMissingInRegularAndScriptAsync(source, - new TestParameters(options: ExplicitTypeSilentEnforcement())); + await TestDiagnosticInfoAsync(source, + options: ExplicitTypeSilentEnforcement(), + diagnosticId: IDEDiagnosticIds.UseExplicitTypeDiagnosticId, + diagnosticSeverity: DiagnosticSeverity.Hidden); } [WpfFact, Trait(Traits.Feature, Traits.Features.CodeActionsUseImplicitType)] diff --git a/src/EditorFeatures/CSharpTest/Diagnostics/UseImplicitOrExplicitType/UseImplicitTypeTests.cs b/src/EditorFeatures/CSharpTest/Diagnostics/UseImplicitOrExplicitType/UseImplicitTypeTests.cs index d5225e0ab4edc859817c35cd7eb1de6590fe715d..032aee67614cc35af6328cebbe577d000becc04a 100644 --- a/src/EditorFeatures/CSharpTest/Diagnostics/UseImplicitOrExplicitType/UseImplicitTypeTests.cs +++ b/src/EditorFeatures/CSharpTest/Diagnostics/UseImplicitOrExplicitType/UseImplicitTypeTests.cs @@ -1524,8 +1524,10 @@ static void M() [|C|] n1 = new C(); } }"; - await TestMissingInRegularAndScriptAsync(source, - new TestParameters(options: ImplicitTypeSilentEnforcement())); + await TestDiagnosticInfoAsync(source, + options: ImplicitTypeSilentEnforcement(), + diagnosticId: IDEDiagnosticIds.UseImplicitTypeDiagnosticId, + diagnosticSeverity: DiagnosticSeverity.Hidden); } [WpfFact, Trait(Traits.Feature, Traits.Features.CodeActionsUseImplicitType)] diff --git a/src/EditorFeatures/CSharpTest/Formatting/CodeCleanupTests.cs b/src/EditorFeatures/CSharpTest/Formatting/CodeCleanupTests.cs index 69a4f96760d35973c064b64bcd53d06b73ffb977..aeb2099bcf3b1825dd456481121f14418d6a4595 100644 --- a/src/EditorFeatures/CSharpTest/Formatting/CodeCleanupTests.cs +++ b/src/EditorFeatures/CSharpTest/Formatting/CodeCleanupTests.cs @@ -8,12 +8,9 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.CodeCleanup; -using Microsoft.CodeAnalysis.CSharp.Diagnostics.SimplifyTypeNames; -using Microsoft.CodeAnalysis.CSharp.TypeStyle; using Microsoft.CodeAnalysis.CSharp.UseExpressionBody; using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.Diagnostics.CSharp; -using Microsoft.CodeAnalysis.Diagnostics.SimplifyTypeNames; using Microsoft.CodeAnalysis.Editor.UnitTests; using Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces; using Microsoft.CodeAnalysis.Options; @@ -87,6 +84,7 @@ static void Main(string[] args) return AssertCodeCleanupResult(expected, code, (CodeCleanupOptions.AreCodeCleanupRulesConfigured, enabled: true), (CodeCleanupOptions.SortImports, enabled: true), + (CodeCleanupOptions.ApplyImplicitExplicitTypePreferences, enabled: false), (CodeCleanupOptions.AddAccessibilityModifiers, enabled: false)); } diff --git a/src/EditorFeatures/CSharpTest/QualifyMemberAccess/QualifyMemberAccessTests.cs b/src/EditorFeatures/CSharpTest/QualifyMemberAccess/QualifyMemberAccessTests.cs index e90158f1572381e625a3e69814f3be163708bd06..84682e6d143d29793072deb7c2c663d12386ee33 100644 --- a/src/EditorFeatures/CSharpTest/QualifyMemberAccess/QualifyMemberAccessTests.cs +++ b/src/EditorFeatures/CSharpTest/QualifyMemberAccess/QualifyMemberAccessTests.cs @@ -888,9 +888,9 @@ void Handler(object sender, EventArgs args) } [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsQualifyMemberAccess)] - public async Task QualifyMemberAccessNotPresentOnNotificationOptionSilent() + public async Task QualifyMemberAccessOnNotificationOptionSilent() { - await TestMissingAsyncWithOptionAndNotificationOption( + await TestAsyncWithOptionAndNotificationOption( @"class Class { int Property { get; set; }; @@ -900,6 +900,15 @@ void M() [|Property|] = 1; } }", +@"class Class +{ + int Property { get; set; }; + + void M() + { + this.Property = 1; + } +}", CodeStyleOptions.QualifyPropertyAccess, NotificationOption.Silent); } diff --git a/src/EditorFeatures/CSharpTest/QuickInfo/SyntacticQuickInfoSourceTests.cs b/src/EditorFeatures/CSharpTest/QuickInfo/SyntacticQuickInfoSourceTests.cs index ff2cef22f2149cc09cd709b83129f13d6743920d..8ac45b26d90ff58c49d5191de2a4e489e23ef4d0 100644 --- a/src/EditorFeatures/CSharpTest/QuickInfo/SyntacticQuickInfoSourceTests.cs +++ b/src/EditorFeatures/CSharpTest/QuickInfo/SyntacticQuickInfoSourceTests.cs @@ -1,14 +1,19 @@ // Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. +using System.Collections.Immutable; using System.Linq; using System.Threading; using System.Threading.Tasks; +using Microsoft.CodeAnalysis.Classification; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.QuickInfo; +using Microsoft.CodeAnalysis.Editor.Implementation.IntelliSense.QuickInfo; using Microsoft.CodeAnalysis.Editor.UnitTests.QuickInfo; using Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces; using Microsoft.CodeAnalysis.QuickInfo; using Microsoft.CodeAnalysis.Test.Utilities; +using Microsoft.VisualStudio.Text; +using Moq; using Roslyn.Test.Utilities; using Xunit; @@ -287,8 +292,10 @@ private QuickInfoProvider CreateProvider(TestWorkspace workspace) Assert.NotEqual(0, info.RelatedSpans.Length); var tabSize = document.Project.Solution.Workspace.Options.GetOption(Microsoft.CodeAnalysis.Formatting.FormattingOptions.TabSize, document.Project.Language); var text = await document.GetTextAsync(); - var spans = IndentationHelper.GetSpansWithAlignedIndentation(text, info.RelatedSpans, tabSize); - var actualText = string.Concat(spans.Select(s => text.GetSubText(s).ToString())); + + var classifiedSpans = info.RelatedSpans.Select(s => new ClassifiedSpan(ClassificationTypeNames.Text, s)); + var spans = IndentationHelper.GetSpansWithAlignedIndentation(text, classifiedSpans.ToImmutableArray(), tabSize); + var actualText = string.Concat(spans.Select(s => text.GetSubText(s.TextSpan).ToString())); Assert.Equal(expectedContent, actualText); } diff --git a/src/EditorFeatures/CSharpTest/SimplifyTypeNames/SimplifyTypeNamesTests.cs b/src/EditorFeatures/CSharpTest/SimplifyTypeNames/SimplifyTypeNamesTests.cs index d8f4925ac516231f47817f616afb6647310be351..72f57d43934a60ca778ee508e0e1be4ac0955105 100644 --- a/src/EditorFeatures/CSharpTest/SimplifyTypeNames/SimplifyTypeNamesTests.cs +++ b/src/EditorFeatures/CSharpTest/SimplifyTypeNames/SimplifyTypeNamesTests.cs @@ -1189,9 +1189,9 @@ static void Main(string[] args) [WorkItem(995168, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/995168"), WorkItem(1073099, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/1073099")] [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsSimplifyTypeNames)] - public async Task SimplifyToPredefinedTypeNameShouldNotBeOfferedInsideNameOf4() + public async Task SimplifyToPredefinedTypeNameShouldBeOfferedInsideFunctionCalledNameOf() { - await TestMissingInRegularAndScriptAsync( + await TestInRegularAndScriptAsync( @"using System; class Program @@ -1201,6 +1201,20 @@ static void Main(string[] args) var x = nameof(typeof([|Int32|])); } + static string nameof(Type t) + { + return string.Empty; + } +}", +@"using System; + +class Program +{ + static void Main(string[] args) + { + var x = nameof(typeof(int)); + } + static string nameof(Type t) { return string.Empty; diff --git a/src/EditorFeatures/CSharpTest/UseExpressionBody/Refactoring/UseExpressionBodyForAccessorsRefactoringTests.cs b/src/EditorFeatures/CSharpTest/UseExpressionBody/Refactoring/UseExpressionBodyForAccessorsRefactoringTests.cs index 2ce8b07729532f58a4cfd5eaf5d0969986289ada..9eee4339f2f4f5cb5b9815049ad3175b9c6a6f77 100644 --- a/src/EditorFeatures/CSharpTest/UseExpressionBody/Refactoring/UseExpressionBodyForAccessorsRefactoringTests.cs +++ b/src/EditorFeatures/CSharpTest/UseExpressionBody/Refactoring/UseExpressionBodyForAccessorsRefactoringTests.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Threading.Tasks; using Microsoft.CodeAnalysis.CodeRefactorings; +using Microsoft.CodeAnalysis.CodeStyle; using Microsoft.CodeAnalysis.CSharp.CodeStyle; using Microsoft.CodeAnalysis.CSharp.UseExpressionBody; using Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.CodeRefactorings; @@ -23,21 +24,41 @@ protected override CodeRefactoringProvider CreateCodeRefactoringProvider(Workspa this.SingleOption(CSharpCodeStyleOptions.PreferExpressionBodiedAccessors, CSharpCodeStyleOptions.WhenPossibleWithSilentEnforcement), this.SingleOption(CSharpCodeStyleOptions.PreferExpressionBodiedProperties, CSharpCodeStyleOptions.NeverWithSilentEnforcement)); + private IDictionary UseExpressionBodyForAccessors_BlockBodyForProperties_DisabledDiagnostic => + OptionsSet( + this.SingleOption(CSharpCodeStyleOptions.PreferExpressionBodiedAccessors, new CodeStyleOption(ExpressionBodyPreference.WhenPossible, NotificationOption.None)), + this.SingleOption(CSharpCodeStyleOptions.PreferExpressionBodiedProperties, new CodeStyleOption(ExpressionBodyPreference.Never, NotificationOption.None))); + private IDictionary UseExpressionBodyForAccessors_ExpressionBodyForProperties => OptionsSet( this.SingleOption(CSharpCodeStyleOptions.PreferExpressionBodiedAccessors, CSharpCodeStyleOptions.WhenPossibleWithSilentEnforcement), this.SingleOption(CSharpCodeStyleOptions.PreferExpressionBodiedProperties, CSharpCodeStyleOptions.WhenPossibleWithSilentEnforcement)); + private IDictionary UseExpressionBodyForAccessors_ExpressionBodyForProperties_DisabledDiagnostic => + OptionsSet( + this.SingleOption(CSharpCodeStyleOptions.PreferExpressionBodiedAccessors, new CodeStyleOption(ExpressionBodyPreference.WhenPossible, NotificationOption.None)), + this.SingleOption(CSharpCodeStyleOptions.PreferExpressionBodiedProperties, new CodeStyleOption(ExpressionBodyPreference.WhenPossible, NotificationOption.None))); + private IDictionary UseBlockBodyForAccessors_ExpressionBodyForProperties => OptionsSet( this.SingleOption(CSharpCodeStyleOptions.PreferExpressionBodiedAccessors, CSharpCodeStyleOptions.NeverWithSilentEnforcement), this.SingleOption(CSharpCodeStyleOptions.PreferExpressionBodiedProperties, CSharpCodeStyleOptions.WhenPossibleWithSilentEnforcement)); + private IDictionary UseBlockBodyForAccessors_ExpressionBodyForProperties_DisabledDiagnostic => + OptionsSet( + this.SingleOption(CSharpCodeStyleOptions.PreferExpressionBodiedAccessors, new CodeStyleOption(ExpressionBodyPreference.Never, NotificationOption.None)), + this.SingleOption(CSharpCodeStyleOptions.PreferExpressionBodiedProperties, new CodeStyleOption(ExpressionBodyPreference.WhenPossible, NotificationOption.None))); + private IDictionary UseBlockBodyForAccessors_BlockBodyForProperties => OptionsSet( this.SingleOption(CSharpCodeStyleOptions.PreferExpressionBodiedAccessors, CSharpCodeStyleOptions.NeverWithSilentEnforcement), this.SingleOption(CSharpCodeStyleOptions.PreferExpressionBodiedProperties, CSharpCodeStyleOptions.NeverWithSilentEnforcement)); + private IDictionary UseBlockBodyForAccessors_BlockBodyForProperties_DisabledDiagnostic => + OptionsSet( + this.SingleOption(CSharpCodeStyleOptions.PreferExpressionBodiedAccessors, new CodeStyleOption(ExpressionBodyPreference.Never, NotificationOption.None)), + this.SingleOption(CSharpCodeStyleOptions.PreferExpressionBodiedProperties, new CodeStyleOption(ExpressionBodyPreference.Never, NotificationOption.None))); + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseExpressionBody)] public async Task TestUpdatePropertyIfPropertyWantsBlockAndAccessorWantsExpression() { @@ -74,6 +95,46 @@ int Goo }", parameters: new TestParameters(options: UseExpressionBodyForAccessors_ExpressionBodyForProperties)); } + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseExpressionBody)] + public async Task TestOfferedIfUserPrefersExpressionBodiesWithoutDiagnosticAndInBlockBody() + { + await TestInRegularAndScript1Async( +@"class C +{ + int Goo + { + get + { + return [||]Bar(); + } + } +}", +@"class C +{ + int Goo => Bar(); +}", parameters: new TestParameters(options: UseExpressionBodyForAccessors_BlockBodyForProperties_DisabledDiagnostic)); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseExpressionBody)] + public async Task TestOfferedIfUserPrefersExpressionBodiesWithoutDiagnosticAndInBlockBody2() + { + await TestInRegularAndScript1Async( +@"class C +{ + int Goo + { + get + { + return [||]Bar(); + } + } +}", +@"class C +{ + int Goo => Bar(); +}", parameters: new TestParameters(options: UseExpressionBodyForAccessors_ExpressionBodyForProperties_DisabledDiagnostic)); + } + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseExpressionBody)] public async Task TestOfferedIfUserPrefersBlockBodiesAndInBlockBody() { @@ -127,6 +188,36 @@ public async Task TestNotOfferedIfUserPrefersBlockBodiesAndInExpressionBody() }", parameters: new TestParameters(options: UseBlockBodyForAccessors_ExpressionBodyForProperties)); } + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseExpressionBody)] + public async Task TestOfferedIfUserPrefersBlockBodiesWithoutDiagnosticAndInExpressionBody() + { + await TestInRegularAndScript1Async( +@"class C +{ + int Goo { get => [||]Bar(); } +}", + +@"class C +{ + int Goo => Bar(); +}", parameters: new TestParameters(options: UseBlockBodyForAccessors_BlockBodyForProperties_DisabledDiagnostic)); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseExpressionBody)] + public async Task TestOfferedIfUserPrefersBlockBodiesWithoutDiagnosticAndInExpressionBody2() + { + await TestInRegularAndScript1Async( +@"class C +{ + int Goo { get => [||]Bar(); } +}", + +@"class C +{ + int Goo => Bar(); +}", parameters: new TestParameters(options: UseBlockBodyForAccessors_ExpressionBodyForProperties_DisabledDiagnostic)); + } + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseExpressionBody)] public async Task TestOfferedForPropertyIfUserPrefersBlockPropertiesAndHasBlockProperty() { diff --git a/src/EditorFeatures/CSharpTest/UseExpressionBody/Refactoring/UseExpressionBodyForConstructorsRefactoringTests.cs b/src/EditorFeatures/CSharpTest/UseExpressionBody/Refactoring/UseExpressionBodyForConstructorsRefactoringTests.cs index 567677d47ab0910a77ce9f5ae3cf1e3bf06dd565..acff7ae4fe0a0a21c91168cffc71e4122558fa20 100644 --- a/src/EditorFeatures/CSharpTest/UseExpressionBody/Refactoring/UseExpressionBodyForConstructorsRefactoringTests.cs +++ b/src/EditorFeatures/CSharpTest/UseExpressionBody/Refactoring/UseExpressionBodyForConstructorsRefactoringTests.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Threading.Tasks; using Microsoft.CodeAnalysis.CodeRefactorings; +using Microsoft.CodeAnalysis.CodeStyle; using Microsoft.CodeAnalysis.CSharp.CodeStyle; using Microsoft.CodeAnalysis.CSharp.UseExpressionBody; using Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.CodeRefactorings; @@ -20,9 +21,15 @@ protected override CodeRefactoringProvider CreateCodeRefactoringProvider(Workspa private IDictionary UseExpressionBody => this.Option(CSharpCodeStyleOptions.PreferExpressionBodiedConstructors, CSharpCodeStyleOptions.WhenPossibleWithSilentEnforcement); + private IDictionary UseExpressionBodyDisabledDiagnostic => + this.Option(CSharpCodeStyleOptions.PreferExpressionBodiedConstructors, new CodeStyleOption(ExpressionBodyPreference.WhenPossible, NotificationOption.None)); + private IDictionary UseBlockBody => this.Option(CSharpCodeStyleOptions.PreferExpressionBodiedConstructors, CSharpCodeStyleOptions.NeverWithSilentEnforcement); + private IDictionary UseBlockBodyDisabledDiagnostic => + this.Option(CSharpCodeStyleOptions.PreferExpressionBodiedConstructors, new CodeStyleOption(ExpressionBodyPreference.Never, NotificationOption.None)); + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseExpressionBody)] public async Task TestNotOfferedIfUserPrefersExpressionBodiesAndInBlockBody() { @@ -36,6 +43,23 @@ public C() }", parameters: new TestParameters(options: UseExpressionBody)); } + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseExpressionBody)] + public async Task TestOfferedIfUserPrefersExpressionBodiesWithoutDiagnosticAndInBlockBody() + { + await TestInRegularAndScript1Async( +@"class C +{ + public C() + { + [||]Bar(); + } +}", +@"class C +{ + public C() => Bar(); +}", parameters: new TestParameters(options: UseExpressionBodyDisabledDiagnostic)); + } + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseExpressionBody)] public async Task TestOfferedIfUserPrefersBlockBodiesAndInBlockBody() { @@ -76,6 +100,23 @@ public async Task TestNotOfferedIfUserPrefersBlockBodiesAndInExpressionBody() }", parameters: new TestParameters(options: UseBlockBody)); } + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseExpressionBody)] + public async Task TestOfferedIfUserPrefersBlockBodiesWithoutDiagnosticAndInExpressionBody() + { + await TestInRegularAndScript1Async( +@"class C +{ + public C() => [||]Bar(); +}", +@"class C +{ + public C() + { + Bar(); + } +}", parameters: new TestParameters(options: UseBlockBodyDisabledDiagnostic)); + } + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseExpressionBody)] public async Task TestOfferedIfUserPrefersExpressionBodiesAndInExpressionBody() { diff --git a/src/EditorFeatures/CSharpTest/UseExpressionBody/Refactoring/UseExpressionBodyForConversionOperatorsRefactoringTests.cs b/src/EditorFeatures/CSharpTest/UseExpressionBody/Refactoring/UseExpressionBodyForConversionOperatorsRefactoringTests.cs index 927238cb06906540a376b33a1504b4a650da8376..a45779f6c939400bf6e4b437ff55088191a126fd 100644 --- a/src/EditorFeatures/CSharpTest/UseExpressionBody/Refactoring/UseExpressionBodyForConversionOperatorsRefactoringTests.cs +++ b/src/EditorFeatures/CSharpTest/UseExpressionBody/Refactoring/UseExpressionBodyForConversionOperatorsRefactoringTests.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Threading.Tasks; using Microsoft.CodeAnalysis.CodeRefactorings; +using Microsoft.CodeAnalysis.CodeStyle; using Microsoft.CodeAnalysis.CSharp.CodeStyle; using Microsoft.CodeAnalysis.CSharp.UseExpressionBody; using Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.CodeRefactorings; @@ -20,9 +21,15 @@ protected override CodeRefactoringProvider CreateCodeRefactoringProvider(Workspa private IDictionary UseExpressionBody => this.Option(CSharpCodeStyleOptions.PreferExpressionBodiedOperators, CSharpCodeStyleOptions.WhenPossibleWithSilentEnforcement); + private IDictionary UseExpressionBodyDisabledDiagnostic => + this.Option(CSharpCodeStyleOptions.PreferExpressionBodiedOperators, new CodeStyleOption(ExpressionBodyPreference.WhenPossible, NotificationOption.None)); + private IDictionary UseBlockBody => this.Option(CSharpCodeStyleOptions.PreferExpressionBodiedOperators, CSharpCodeStyleOptions.NeverWithSilentEnforcement); + private IDictionary UseBlockBodyDisabledDiagnostic => + this.Option(CSharpCodeStyleOptions.PreferExpressionBodiedOperators, new CodeStyleOption(ExpressionBodyPreference.Never, NotificationOption.None)); + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseExpressionBody)] public async Task TestNotOfferedIfUserPrefersExpressionBodiesAndInBlockBody() { @@ -36,6 +43,23 @@ public async Task TestNotOfferedIfUserPrefersExpressionBodiesAndInBlockBody() }", parameters: new TestParameters(options: UseExpressionBody)); } + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseExpressionBody)] + public async Task TestOfferedIfUserPrefersExpressionBodiesWithoutDiagnosticAndInBlockBody() + { + await TestInRegularAndScript1Async( +@"class C +{ + public static implicit operator bool(C c1) + { + [||]Bar(); + } +}", +@"class C +{ + public static implicit operator bool(C c1) => Bar(); +}", parameters: new TestParameters(options: UseExpressionBodyDisabledDiagnostic)); + } + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseExpressionBody)] public async Task TestOfferedIfUserPrefersBlockBodiesAndInBlockBody() { @@ -76,6 +100,23 @@ public async Task TestNotOfferedIfUserPrefersBlockBodiesAndInExpressionBody() }", parameters: new TestParameters(options: UseBlockBody)); } + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseExpressionBody)] + public async Task TestOfferedIfUserPrefersBlockBodiesWithoutDiagnosticAndInExpressionBody() + { + await TestInRegularAndScript1Async( +@"class C +{ + public static implicit operator bool(C c1) => [||]Bar(); +}", +@"class C +{ + public static implicit operator bool(C c1) + { + return Bar(); + } +}", parameters: new TestParameters(options: UseBlockBodyDisabledDiagnostic)); + } + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseExpressionBody)] public async Task TestOfferedIfUserPrefersExpressionBodiesAndInExpressionBody() { diff --git a/src/EditorFeatures/CSharpTest/UseExpressionBody/Refactoring/UseExpressionBodyForIndexersRefactoringTests.cs b/src/EditorFeatures/CSharpTest/UseExpressionBody/Refactoring/UseExpressionBodyForIndexersRefactoringTests.cs index 1ef46a398c7b425a57355eb35f659127c9f254dc..ec9e14b0e87970beb76b6191678aed9a22180bb5 100644 --- a/src/EditorFeatures/CSharpTest/UseExpressionBody/Refactoring/UseExpressionBodyForIndexersRefactoringTests.cs +++ b/src/EditorFeatures/CSharpTest/UseExpressionBody/Refactoring/UseExpressionBodyForIndexersRefactoringTests.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Threading.Tasks; using Microsoft.CodeAnalysis.CodeRefactorings; +using Microsoft.CodeAnalysis.CodeStyle; using Microsoft.CodeAnalysis.CSharp.CodeStyle; using Microsoft.CodeAnalysis.CSharp.UseExpressionBody; using Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.CodeRefactorings; @@ -21,9 +22,15 @@ protected override CodeRefactoringProvider CreateCodeRefactoringProvider(Workspa private IDictionary UseExpressionBody => this.Option(CSharpCodeStyleOptions.PreferExpressionBodiedIndexers, CSharpCodeStyleOptions.WhenPossibleWithSilentEnforcement); + private IDictionary UseExpressionBodyDisabledDiagnostic => + this.Option(CSharpCodeStyleOptions.PreferExpressionBodiedIndexers, new CodeStyleOption(ExpressionBodyPreference.WhenPossible, NotificationOption.None)); + private IDictionary UseBlockBody => this.Option(CSharpCodeStyleOptions.PreferExpressionBodiedIndexers, CSharpCodeStyleOptions.NeverWithSilentEnforcement); + private IDictionary UseBlockBodyDisabledDiagnostic => + this.Option(CSharpCodeStyleOptions.PreferExpressionBodiedIndexers, new CodeStyleOption(ExpressionBodyPreference.Never, NotificationOption.None)); + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseExpressionBody)] public async Task TestNotOfferedIfUserPrefersExpressionBodiesAndInBlockBody() { @@ -40,6 +47,26 @@ public async Task TestNotOfferedIfUserPrefersExpressionBodiesAndInBlockBody() }", parameters: new TestParameters(options: UseExpressionBody)); } + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseExpressionBody)] + public async Task TestOfferedIfUserPrefersExpressionBodiesWithoutDiagnosticAndInBlockBody() + { + await TestInRegularAndScript1Async( +@"class C +{ + int this[int i] + { + get + { + [||]return Bar(); + } + } +}", +@"class C +{ + int this[int i] => Bar(); +}", parameters: new TestParameters(options: UseExpressionBodyDisabledDiagnostic)); + } + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseExpressionBody)] public async Task TestOfferedIfUserPrefersBlockBodiesAndInBlockBody() { @@ -86,6 +113,26 @@ public async Task TestNotOfferedIfUserPrefersBlockBodiesAndInExpressionBody() }", parameters: new TestParameters(options: UseBlockBody)); } + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseExpressionBody)] + public async Task TestOfferedIfUserPrefersBlockBodiesWithoutDiagnosticAndInExpressionBody() + { + await TestInRegularAndScript1Async( +@"class C +{ + int this[int i] => [||]Bar(); +}", +@"class C +{ + int this[int i] + { + get + { + return Bar(); + } + } +}", parameters: new TestParameters(options: UseBlockBodyDisabledDiagnostic)); + } + [WorkItem(20363, "https://github.com/dotnet/roslyn/issues/20363")] [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseExpressionBody)] public async Task TestOfferedIfUserPrefersExpressionBodiesAndInExpressionBody() diff --git a/src/EditorFeatures/CSharpTest/UseExpressionBody/Refactoring/UseExpressionBodyForMethodsRefactoringTests.cs b/src/EditorFeatures/CSharpTest/UseExpressionBody/Refactoring/UseExpressionBodyForMethodsRefactoringTests.cs index a71f5fef84e518fb6f85e69378cc851b7759d07f..6bb14d25d9bd3833841e069a7b84589d4ab0c3b7 100644 --- a/src/EditorFeatures/CSharpTest/UseExpressionBody/Refactoring/UseExpressionBodyForMethodsRefactoringTests.cs +++ b/src/EditorFeatures/CSharpTest/UseExpressionBody/Refactoring/UseExpressionBodyForMethodsRefactoringTests.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Threading.Tasks; using Microsoft.CodeAnalysis.CodeRefactorings; +using Microsoft.CodeAnalysis.CodeStyle; using Microsoft.CodeAnalysis.CSharp.CodeStyle; using Microsoft.CodeAnalysis.CSharp.UseExpressionBody; using Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.CodeRefactorings; @@ -20,9 +21,15 @@ protected override CodeRefactoringProvider CreateCodeRefactoringProvider(Workspa private IDictionary UseExpressionBody => this.Option(CSharpCodeStyleOptions.PreferExpressionBodiedMethods, CSharpCodeStyleOptions.WhenPossibleWithSilentEnforcement); + private IDictionary UseExpressionBodyDisabledDiagnostic => + this.Option(CSharpCodeStyleOptions.PreferExpressionBodiedMethods, new CodeStyleOption(ExpressionBodyPreference.WhenPossible, NotificationOption.None)); + private IDictionary UseBlockBody => this.Option(CSharpCodeStyleOptions.PreferExpressionBodiedMethods, CSharpCodeStyleOptions.NeverWithSilentEnforcement); + private IDictionary UseBlockBodyDisabledDiagnostic => + this.Option(CSharpCodeStyleOptions.PreferExpressionBodiedMethods, new CodeStyleOption(ExpressionBodyPreference.Never, NotificationOption.None)); + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseExpressionBody)] public async Task TestNotOfferedIfUserPrefersExpressionBodiesAndInBlockBody() { @@ -36,6 +43,23 @@ void Goo() }", parameters: new TestParameters(options: UseExpressionBody)); } + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseExpressionBody)] + public async Task TestOfferedIfUserPrefersExpressionBodiesWithoutDiagnosticAndInBlockBody() + { + await TestInRegularAndScript1Async( +@"class C +{ + void Goo() + { + [||]Bar(); + } +}", +@"class C +{ + void Goo() => Bar(); +}", parameters: new TestParameters(options: UseExpressionBodyDisabledDiagnostic)); + } + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseExpressionBody)] public async Task TestOfferedIfUserPrefersBlockBodiesAndInBlockBody() { @@ -76,6 +100,23 @@ public async Task TestNotOfferedIfUserPrefersBlockBodiesAndInExpressionBody() }", parameters: new TestParameters(options: UseBlockBody)); } + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseExpressionBody)] + public async Task TestOfferedIfUserPrefersBlockBodiesWithoutDiagnosticAndInExpressionBody() + { + await TestInRegularAndScript1Async( +@"class C +{ + void Goo() => [||]Bar(); +}", +@"class C +{ + void Goo() + { + Bar(); + } +}", parameters: new TestParameters(options: UseBlockBodyDisabledDiagnostic)); + } + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseExpressionBody)] public async Task TestOfferedIfUserPrefersExpressionBodiesAndInExpressionBody() { diff --git a/src/EditorFeatures/CSharpTest/UseExpressionBody/Refactoring/UseExpressionBodyForOperatorsRefactoringTests.cs b/src/EditorFeatures/CSharpTest/UseExpressionBody/Refactoring/UseExpressionBodyForOperatorsRefactoringTests.cs index ea0cb3518f4a0370dec51ca7faaa9a6bc0999737..1293c4bcfabff716e7635890de5db92d84a4c382 100644 --- a/src/EditorFeatures/CSharpTest/UseExpressionBody/Refactoring/UseExpressionBodyForOperatorsRefactoringTests.cs +++ b/src/EditorFeatures/CSharpTest/UseExpressionBody/Refactoring/UseExpressionBodyForOperatorsRefactoringTests.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Threading.Tasks; using Microsoft.CodeAnalysis.CodeRefactorings; +using Microsoft.CodeAnalysis.CodeStyle; using Microsoft.CodeAnalysis.CSharp.CodeStyle; using Microsoft.CodeAnalysis.CSharp.UseExpressionBody; using Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.CodeRefactorings; @@ -20,9 +21,15 @@ protected override CodeRefactoringProvider CreateCodeRefactoringProvider(Workspa private IDictionary UseExpressionBody => this.Option(CSharpCodeStyleOptions.PreferExpressionBodiedOperators, CSharpCodeStyleOptions.WhenPossibleWithSilentEnforcement); + private IDictionary UseExpressionBodyDisabledDiagnostic => + this.Option(CSharpCodeStyleOptions.PreferExpressionBodiedOperators, new CodeStyleOption(ExpressionBodyPreference.WhenPossible, NotificationOption.None)); + private IDictionary UseBlockBody => this.Option(CSharpCodeStyleOptions.PreferExpressionBodiedOperators, CSharpCodeStyleOptions.NeverWithSilentEnforcement); + private IDictionary UseBlockBodyDisabledDiagnostic => + this.Option(CSharpCodeStyleOptions.PreferExpressionBodiedOperators, new CodeStyleOption(ExpressionBodyPreference.Never, NotificationOption.None)); + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseExpressionBody)] public async Task TestNotOfferedIfUserPrefersExpressionBodiesAndInBlockBody() { @@ -36,6 +43,23 @@ public async Task TestNotOfferedIfUserPrefersExpressionBodiesAndInBlockBody() }", parameters: new TestParameters(options: UseExpressionBody)); } + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseExpressionBody)] + public async Task TestOfferedIfUserPrefersExpressionBodiesWithoutDiagnosticAndInBlockBody() + { + await TestInRegularAndScript1Async( +@"class C +{ + public static bool operator +(C c1, C c2) + { + [||]Bar(); + } +}", +@"class C +{ + public static bool operator +(C c1, C c2) => Bar(); +}", parameters: new TestParameters(options: UseExpressionBodyDisabledDiagnostic)); + } + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseExpressionBody)] public async Task TestOfferedIfUserPrefersBlockBodiesAndInBlockBody() { @@ -76,6 +100,23 @@ public async Task TestNotOfferedIfUserPrefersBlockBodiesAndInExpressionBody() }", parameters: new TestParameters(options: UseBlockBody)); } + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseExpressionBody)] + public async Task TestOfferedIfUserPrefersBlockBodiesWithoutDiagnosticAndInExpressionBody() + { + await TestInRegularAndScript1Async( +@"class C +{ + public static bool operator +(C c1, C c2) => [||]Bar(); +}", +@"class C +{ + public static bool operator +(C c1, C c2) + { + return Bar(); + } +}", parameters: new TestParameters(options: UseBlockBodyDisabledDiagnostic)); + } + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseExpressionBody)] public async Task TestOfferedIfUserPrefersExpressionBodiesAndInExpressionBody() { diff --git a/src/EditorFeatures/CSharpTest/UseExpressionBody/Refactoring/UseExpressionBodyForPropertiesRefactoringTests.cs b/src/EditorFeatures/CSharpTest/UseExpressionBody/Refactoring/UseExpressionBodyForPropertiesRefactoringTests.cs index 49ac45f55a48f02f428e8f73ceb825a99693fe13..b6b91ec120dffb15254b6bcea890e25c8d760126 100644 --- a/src/EditorFeatures/CSharpTest/UseExpressionBody/Refactoring/UseExpressionBodyForPropertiesRefactoringTests.cs +++ b/src/EditorFeatures/CSharpTest/UseExpressionBody/Refactoring/UseExpressionBodyForPropertiesRefactoringTests.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Threading.Tasks; using Microsoft.CodeAnalysis.CodeRefactorings; +using Microsoft.CodeAnalysis.CodeStyle; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.CodeStyle; using Microsoft.CodeAnalysis.CSharp.UseExpressionBody; @@ -24,21 +25,41 @@ protected override CodeRefactoringProvider CreateCodeRefactoringProvider(Workspa this.SingleOption(CSharpCodeStyleOptions.PreferExpressionBodiedAccessors, CSharpCodeStyleOptions.WhenPossibleWithSilentEnforcement), this.SingleOption(CSharpCodeStyleOptions.PreferExpressionBodiedProperties, CSharpCodeStyleOptions.NeverWithSilentEnforcement)); + private IDictionary UseExpressionBodyForAccessors_BlockBodyForProperties_DisabledDiagnostic => + OptionsSet( + this.SingleOption(CSharpCodeStyleOptions.PreferExpressionBodiedAccessors, new CodeStyleOption(ExpressionBodyPreference.WhenPossible, NotificationOption.None)), + this.SingleOption(CSharpCodeStyleOptions.PreferExpressionBodiedProperties, new CodeStyleOption(ExpressionBodyPreference.Never, NotificationOption.None))); + private IDictionary UseExpressionBodyForAccessors_ExpressionBodyForProperties => OptionsSet( this.SingleOption(CSharpCodeStyleOptions.PreferExpressionBodiedAccessors, CSharpCodeStyleOptions.WhenPossibleWithSilentEnforcement), this.SingleOption(CSharpCodeStyleOptions.PreferExpressionBodiedProperties, CSharpCodeStyleOptions.WhenPossibleWithSilentEnforcement)); + private IDictionary UseExpressionBodyForAccessors_ExpressionBodyForProperties_DisabledDiagnostic => + OptionsSet( + this.SingleOption(CSharpCodeStyleOptions.PreferExpressionBodiedAccessors, new CodeStyleOption(ExpressionBodyPreference.WhenPossible, NotificationOption.None)), + this.SingleOption(CSharpCodeStyleOptions.PreferExpressionBodiedProperties, new CodeStyleOption(ExpressionBodyPreference.WhenPossible, NotificationOption.None))); + private IDictionary UseBlockBodyForAccessors_ExpressionBodyForProperties => OptionsSet( this.SingleOption(CSharpCodeStyleOptions.PreferExpressionBodiedAccessors, CSharpCodeStyleOptions.NeverWithSilentEnforcement), this.SingleOption(CSharpCodeStyleOptions.PreferExpressionBodiedProperties, CSharpCodeStyleOptions.WhenPossibleWithSilentEnforcement)); + private IDictionary UseBlockBodyForAccessors_ExpressionBodyForProperties_DisabledDiagnostic => + OptionsSet( + this.SingleOption(CSharpCodeStyleOptions.PreferExpressionBodiedAccessors, new CodeStyleOption(ExpressionBodyPreference.Never, NotificationOption.None)), + this.SingleOption(CSharpCodeStyleOptions.PreferExpressionBodiedProperties, new CodeStyleOption(ExpressionBodyPreference.WhenPossible, NotificationOption.None))); + private IDictionary UseBlockBodyForAccessors_BlockBodyForProperties => OptionsSet( this.SingleOption(CSharpCodeStyleOptions.PreferExpressionBodiedAccessors, CSharpCodeStyleOptions.NeverWithSilentEnforcement), this.SingleOption(CSharpCodeStyleOptions.PreferExpressionBodiedProperties, CSharpCodeStyleOptions.NeverWithSilentEnforcement)); + private IDictionary UseBlockBodyForAccessors_BlockBodyForProperties_DisabledDiagnostic => + OptionsSet( + this.SingleOption(CSharpCodeStyleOptions.PreferExpressionBodiedAccessors, new CodeStyleOption(ExpressionBodyPreference.Never, NotificationOption.None)), + this.SingleOption(CSharpCodeStyleOptions.PreferExpressionBodiedProperties, new CodeStyleOption(ExpressionBodyPreference.Never, NotificationOption.None))); + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseExpressionBody)] public async Task TestNotOfferedIfUserPrefersExpressionBodiesAndInBlockBody() { @@ -55,6 +76,26 @@ int Goo }", parameters: new TestParameters(options: UseExpressionBodyForAccessors_ExpressionBodyForProperties)); } + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseExpressionBody)] + public async Task TestOfferedIfUserPrefersExpressionBodiesWithoutDiagnosticAndInBlockBody() + { + await TestInRegularAndScript1Async( +@"class C +{ + int Goo + { + get + { + [||]return Bar(); + } + } +}", +@"class C +{ + int Goo => Bar(); +}", parameters: new TestParameters(options: UseExpressionBodyForAccessors_ExpressionBodyForProperties_DisabledDiagnostic)); + } + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseExpressionBody)] public async Task TestUpdateAccessorIfAccessWantsBlockAndPropertyWantsExpression() { @@ -154,6 +195,46 @@ public async Task TestNotOfferedIfUserPrefersBlockBodiesAndInExpressionBody2() }", parameters: new TestParameters(options: UseBlockBodyForAccessors_BlockBodyForProperties)); } + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseExpressionBody)] + public async Task TestOfferedIfUserPrefersBlockBodiesWithoutDiagnosticAndInExpressionBody() + { + await TestInRegularAndScript1Async( +@"class C +{ + int Goo => [||]Bar(); +}", +@"class C +{ + int Goo + { + get + { + return Bar(); + } + } +}", parameters: new TestParameters(options: UseExpressionBodyForAccessors_BlockBodyForProperties_DisabledDiagnostic)); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseExpressionBody)] + public async Task TestOfferedIfUserPrefersBlockBodiesWithoutDiagnosticAndInExpressionBody2() + { + await TestInRegularAndScript1Async( +@"class C +{ + int Goo => [||]Bar(); +}", +@"class C +{ + int Goo + { + get + { + return Bar(); + } + } +}", parameters: new TestParameters(options: UseBlockBodyForAccessors_BlockBodyForProperties_DisabledDiagnostic)); + } + [WorkItem(20363, "https://github.com/dotnet/roslyn/issues/20363")] [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseExpressionBody)] public async Task TestOfferedIfUserPrefersExpressionBodiesAndInExpressionBody() diff --git a/src/EditorFeatures/Core/FindUsages/ClassifiedSpansAndHighlightSpanFactory.cs b/src/EditorFeatures/Core/FindUsages/ClassifiedSpansAndHighlightSpanFactory.cs index 3460eca9c89b64012183ffc2687f93d2534db560..22d2a73d8f6776406b1c254e5f24a96135ff32f5 100644 --- a/src/EditorFeatures/Core/FindUsages/ClassifiedSpansAndHighlightSpanFactory.cs +++ b/src/EditorFeatures/Core/FindUsages/ClassifiedSpansAndHighlightSpanFactory.cs @@ -1,16 +1,13 @@ // Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. -using System.Collections.Generic; using System.Collections.Immutable; using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.Classification; using Microsoft.CodeAnalysis.FindUsages; -using Microsoft.CodeAnalysis.Formatting; -using Microsoft.CodeAnalysis.Host; -using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Text; +using Microsoft.CodeAnalysis.Text.Shared.Extensions; namespace Microsoft.CodeAnalysis.Editor.FindUsages { @@ -80,13 +77,8 @@ private static TextSpan GetLineSpanForReference(SourceText sourceText, TextSpan private static async Task> GetClassifiedSpansAsync( Document document, TextSpan narrowSpan, TextSpan widenedSpan, CancellationToken cancellationToken) { - var result = await GetClassifiedSpansAsync(document, narrowSpan, widenedSpan, WorkspaceClassificationDelegationService.Instance, cancellationToken).ConfigureAwait(false); - if (!result.IsDefault) - { - return result; - } - - result = await GetClassifiedSpansAsync(document, narrowSpan, widenedSpan, EditorClassificationDelegationService.Instance, cancellationToken).ConfigureAwait(false); + var result = await EditorClassifier.GetClassifiedSpansAsync( + document, widenedSpan, cancellationToken).ConfigureAwait(false); if (!result.IsDefault) { return result; @@ -100,194 +92,5 @@ private static TextSpan GetLineSpanForReference(SourceText sourceText, TextSpan new ClassifiedSpan(ClassificationTypeNames.Text, narrowSpan), new ClassifiedSpan(ClassificationTypeNames.Text, TextSpan.FromBounds(narrowSpan.End, widenedSpan.End))); } - - - private static async Task> GetClassifiedSpansAsync( - Document document, TextSpan narrowSpan, TextSpan widenedSpan, - IClassificationDelegationService delegationService, - CancellationToken cancellationToken) where TClassificationService : class, ILanguageService - { - var classificationService = document.GetLanguageService(); - if (classificationService == null) - { - return default; - } - - // Call out to the individual language to classify the chunk of text around the - // reference. We'll get both the syntactic and semantic spans for this region. - // Because the semantic tags may override the semantic ones (for example, - // "DateTime" might be syntactically an identifier, but semantically a struct - // name), we'll do a later merging step to get the final correct list of - // classifications. For tagging, normally the editor handles this. But as - // we're producing the list of Inlines ourselves, we have to handles this here. - var syntaxSpans = ListPool.Allocate(); - var semanticSpans = ListPool.Allocate(); - try - { - var sourceText = await document.GetTextAsync(cancellationToken).ConfigureAwait(false); - - await delegationService.AddSyntacticClassificationsAsync( - classificationService, document, widenedSpan, syntaxSpans, cancellationToken).ConfigureAwait(false); - await delegationService.AddSemanticClassificationsAsync( - classificationService, document, widenedSpan, semanticSpans, cancellationToken).ConfigureAwait(false); - - var classifiedSpans = MergeClassifiedSpans( - syntaxSpans, semanticSpans, widenedSpan, sourceText); - return classifiedSpans; - } - finally - { - ListPool.Free(syntaxSpans); - ListPool.Free(semanticSpans); - } - } - - private static ImmutableArray MergeClassifiedSpans( - List syntaxSpans, List semanticSpans, - TextSpan widenedSpan, SourceText sourceText) - { - // The spans produced by the language services may not be ordered - // (indeed, this happens with semantic classification as different - // providers produce different results in an arbitrary order). Order - // them first before proceeding. - Order(syntaxSpans); - Order(semanticSpans); - - // It's possible for us to get classified spans that occur *before* - // or after the span we want to present. This happens because the calls to - // AddSyntacticClassificationsAsync and AddSemanticClassificationsAsync - // may return more spans than the range asked for. While bad form, - // it's never been a requirement that implementation not do that. - // For example, the span may be the non-full-span of a node, but the - // classifiers may still return classifications for leading/trailing - // trivia even if it's out of the bounds of that span. - // - // To deal with that, we adjust all spans so that they don't go outside - // of the range we care about. - AdjustSpans(syntaxSpans, widenedSpan); - AdjustSpans(semanticSpans, widenedSpan); - - // The classification service will only produce classifications for - // things it knows about. i.e. there will be gaps in what it produces. - // Fill in those gaps so we have *all* parts of the span - // classified properly. - var filledInSyntaxSpans = ArrayBuilder.GetInstance(); - var filledInSemanticSpans = ArrayBuilder.GetInstance(); - - try - { - FillInClassifiedSpanGaps(sourceText, widenedSpan.Start, syntaxSpans, filledInSyntaxSpans); - FillInClassifiedSpanGaps(sourceText, widenedSpan.Start, semanticSpans, filledInSemanticSpans); - - // Now merge the lists together, taking all the results from syntaxParts - // unless they were overridden by results in semanticParts. - return MergeParts(filledInSyntaxSpans, filledInSemanticSpans); - } - finally - { - filledInSyntaxSpans.Free(); - filledInSemanticSpans.Free(); - } - } - - private static void Order(List syntaxSpans) - => syntaxSpans.Sort((s1, s2) => s1.TextSpan.Start - s2.TextSpan.Start); - - private static void AdjustSpans(List spans, TextSpan widenedSpan) - { - for (var i = 0; i < spans.Count; i++) - { - var span = spans[i]; - - // Make sure the span actually intersects 'widenedSpan'. If it - // does not, just put in an empty length span. It will get ignored later - // when we walk through this list. - var intersection = span.TextSpan.Intersection(widenedSpan); - - if (i > 0 && intersection != null) - { - if (spans[i - 1].TextSpan.End > intersection.Value.Start) - { - // This span isn't strictly after the previous span. Ignore it. - intersection = null; - } - } - - var newSpan = new ClassifiedSpan(span.ClassificationType, - intersection ?? new TextSpan()); - spans[i] = newSpan; - } - } - - private static void FillInClassifiedSpanGaps( - SourceText sourceText, int startPosition, - List classifiedSpans, ArrayBuilder result) - { - foreach (var span in classifiedSpans) - { - // Ignore empty spans. We can get those when the classification service - // returns spans outside of the range of the span we asked to classify. - if (span.TextSpan.Length == 0) - { - continue; - } - - // If there is space between this span and the last one, then add a space. - if (startPosition != span.TextSpan.Start) - { - result.Add(new ClassifiedSpan(ClassificationTypeNames.Text, - TextSpan.FromBounds( - startPosition, span.TextSpan.Start))); - } - - result.Add(span); - startPosition = span.TextSpan.End; - } - } - - private static ImmutableArray MergeParts( - ArrayBuilder syntaxParts, - ArrayBuilder semanticParts) - { - // Take all the syntax parts. However, if any have been overridden by a - // semantic part, then choose that one. - - var finalParts = ArrayBuilder.GetInstance(); - var lastReplacementIndex = 0; - for (int i = 0, n = syntaxParts.Count; i < n; i++) - { - var syntaxPartAndSpan = syntaxParts[i]; - - // See if we can find a semantic part to replace this syntax part. - var replacementIndex = semanticParts.FindIndex( - lastReplacementIndex, t => t.TextSpan == syntaxPartAndSpan.TextSpan); - - // Take the semantic part if it's just 'text'. We want to keep it if - // the semantic classifier actually produced an interesting result - // (as opposed to it just being a 'gap' classification). - var part = replacementIndex >= 0 && !IsClassifiedAsText(semanticParts[replacementIndex]) - ? semanticParts[replacementIndex] - : syntaxPartAndSpan; - finalParts.Add(part); - - if (replacementIndex >= 0) - { - // If we found a semantic replacement, update the lastIndex. - // That way we can start searching from that point instead - // of checking all the elements each time. - lastReplacementIndex = replacementIndex + 1; - } - } - - return finalParts.ToImmutableAndFree(); - } - - private static bool IsClassifiedAsText(ClassifiedSpan partAndSpan) - { - // Don't take 'text' from the semantic parts. We'll get those for the - // spaces between the actual interesting semantic spans, and we don't - // want them to override actual good syntax spans. - return partAndSpan.ClassificationType == ClassificationTypeNames.Text; - } } } diff --git a/src/EditorFeatures/Core/Implementation/Classification/EditorClassifier.cs b/src/EditorFeatures/Core/Implementation/Classification/EditorClassifier.cs new file mode 100644 index 0000000000000000000000000000000000000000..a477591cf1ef04c6d22a581615fe53d95ba51aa9 --- /dev/null +++ b/src/EditorFeatures/Core/Implementation/Classification/EditorClassifier.cs @@ -0,0 +1,234 @@ +// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.Classification; +using Microsoft.CodeAnalysis.Formatting; +using Microsoft.CodeAnalysis.Host; +using Microsoft.CodeAnalysis.PooledObjects; +using Microsoft.CodeAnalysis.Shared.Extensions; +using Microsoft.CodeAnalysis.Text; + +namespace Microsoft.CodeAnalysis.Editor +{ + internal static class EditorClassifier + { + /// + /// Classifies the provided in the given . + /// This will first try to do this using an appropriate + /// if it can be found, followed by an appropriate + /// if that can be found. will be returned if this + /// fails. + /// + public static async Task> GetClassifiedSpansAsync( + Document document, TextSpan span, CancellationToken cancellationToken) + { + var result = await GetClassifiedSpansAsync( + WorkspaceClassificationDelegationService.Instance, + document, span, cancellationToken).ConfigureAwait(false); + if (!result.IsDefault) + { + return result; + } + + result = await GetClassifiedSpansAsync( + EditorClassificationDelegationService.Instance, + document, span, cancellationToken).ConfigureAwait(false); + if (!result.IsDefault) + { + return result; + } + + return default; + } + + private static async Task> GetClassifiedSpansAsync( + IClassificationDelegationService delegationService, + Document document, TextSpan widenedSpan, CancellationToken cancellationToken) where TClassificationService : class, ILanguageService + { + var classificationService = document.GetLanguageService(); + if (classificationService == null) + { + return default; + } + + // Call out to the individual language to classify the chunk of text around the + // reference. We'll get both the syntactic and semantic spans for this region. + // Because the semantic tags may override the semantic ones (for example, + // "DateTime" might be syntactically an identifier, but semantically a struct + // name), we'll do a later merging step to get the final correct list of + // classifications. For tagging, normally the editor handles this. But as + // we're producing the list of Inlines ourselves, we have to handles this here. + var syntaxSpans = ListPool.Allocate(); + var semanticSpans = ListPool.Allocate(); + try + { + var sourceText = await document.GetTextAsync(cancellationToken).ConfigureAwait(false); + + await delegationService.AddSyntacticClassificationsAsync( + classificationService, document, widenedSpan, syntaxSpans, cancellationToken).ConfigureAwait(false); + await delegationService.AddSemanticClassificationsAsync( + classificationService, document, widenedSpan, semanticSpans, cancellationToken).ConfigureAwait(false); + + var classifiedSpans = MergeClassifiedSpans( + syntaxSpans, semanticSpans, widenedSpan, sourceText); + return classifiedSpans; + } + finally + { + ListPool.Free(syntaxSpans); + ListPool.Free(semanticSpans); + } + } + + private static ImmutableArray MergeClassifiedSpans( + List syntaxSpans, List semanticSpans, + TextSpan widenedSpan, SourceText sourceText) + { + // The spans produced by the language services may not be ordered + // (indeed, this happens with semantic classification as different + // providers produce different results in an arbitrary order). Order + // them first before proceeding. + Order(syntaxSpans); + Order(semanticSpans); + + // It's possible for us to get classified spans that occur *before* + // or after the span we want to present. This happens because the calls to + // AddSyntacticClassificationsAsync and AddSemanticClassificationsAsync + // may return more spans than the range asked for. While bad form, + // it's never been a requirement that implementation not do that. + // For example, the span may be the non-full-span of a node, but the + // classifiers may still return classifications for leading/trailing + // trivia even if it's out of the bounds of that span. + // + // To deal with that, we adjust all spans so that they don't go outside + // of the range we care about. + AdjustSpans(syntaxSpans, widenedSpan); + AdjustSpans(semanticSpans, widenedSpan); + + // The classification service will only produce classifications for + // things it knows about. i.e. there will be gaps in what it produces. + // Fill in those gaps so we have *all* parts of the span + // classified properly. + var filledInSyntaxSpans = ArrayBuilder.GetInstance(); + var filledInSemanticSpans = ArrayBuilder.GetInstance(); + + try + { + FillInClassifiedSpanGaps(sourceText, widenedSpan.Start, syntaxSpans, filledInSyntaxSpans); + FillInClassifiedSpanGaps(sourceText, widenedSpan.Start, semanticSpans, filledInSemanticSpans); + + // Now merge the lists together, taking all the results from syntaxParts + // unless they were overridden by results in semanticParts. + return MergeParts(filledInSyntaxSpans, filledInSemanticSpans); + } + finally + { + filledInSyntaxSpans.Free(); + filledInSemanticSpans.Free(); + } + } + + private static void Order(List syntaxSpans) + => syntaxSpans.Sort((s1, s2) => s1.TextSpan.Start - s2.TextSpan.Start); + + private static void AdjustSpans(List spans, TextSpan widenedSpan) + { + for (var i = 0; i < spans.Count; i++) + { + var span = spans[i]; + + // Make sure the span actually intersects 'widenedSpan'. If it + // does not, just put in an empty length span. It will get ignored later + // when we walk through this list. + var intersection = span.TextSpan.Intersection(widenedSpan); + + if (i > 0 && intersection != null) + { + if (spans[i - 1].TextSpan.End > intersection.Value.Start) + { + // This span isn't strictly after the previous span. Ignore it. + intersection = null; + } + } + + var newSpan = new ClassifiedSpan(span.ClassificationType, + intersection ?? new TextSpan()); + spans[i] = newSpan; + } + } + + private static void FillInClassifiedSpanGaps( + SourceText sourceText, int startPosition, + List classifiedSpans, ArrayBuilder result) + { + foreach (var span in classifiedSpans) + { + // Ignore empty spans. We can get those when the classification service + // returns spans outside of the range of the span we asked to classify. + if (span.TextSpan.Length == 0) + { + continue; + } + + // If there is space between this span and the last one, then add a space. + if (startPosition != span.TextSpan.Start) + { + result.Add(new ClassifiedSpan(ClassificationTypeNames.Text, + TextSpan.FromBounds( + startPosition, span.TextSpan.Start))); + } + + result.Add(span); + startPosition = span.TextSpan.End; + } + } + + private static ImmutableArray MergeParts( + ArrayBuilder syntaxParts, + ArrayBuilder semanticParts) + { + // Take all the syntax parts. However, if any have been overridden by a + // semantic part, then choose that one. + + var finalParts = ArrayBuilder.GetInstance(); + var lastReplacementIndex = 0; + for (int i = 0, n = syntaxParts.Count; i < n; i++) + { + var syntaxPartAndSpan = syntaxParts[i]; + + // See if we can find a semantic part to replace this syntax part. + var replacementIndex = semanticParts.FindIndex( + lastReplacementIndex, t => t.TextSpan == syntaxPartAndSpan.TextSpan); + + // Take the semantic part if it's just 'text'. We want to keep it if + // the semantic classifier actually produced an interesting result + // (as opposed to it just being a 'gap' classification). + var part = replacementIndex >= 0 && !IsClassifiedAsText(semanticParts[replacementIndex]) + ? semanticParts[replacementIndex] + : syntaxPartAndSpan; + finalParts.Add(part); + + if (replacementIndex >= 0) + { + // If we found a semantic replacement, update the lastIndex. + // That way we can start searching from that point instead + // of checking all the elements each time. + lastReplacementIndex = replacementIndex + 1; + } + } + + return finalParts.ToImmutableAndFree(); + } + + private static bool IsClassifiedAsText(ClassifiedSpan partAndSpan) + { + // Don't take 'text' from the semantic parts. We'll get those for the + // spaces between the actual interesting semantic spans, and we don't + // want them to override actual good syntax spans. + return partAndSpan.ClassificationType == ClassificationTypeNames.Text; + } + } +} diff --git a/src/EditorFeatures/Core/Implementation/IntelliSense/Completion/Controller_Commit.cs b/src/EditorFeatures/Core/Implementation/IntelliSense/Completion/Controller_Commit.cs index ea8dc00abaf6c59de67e08991acb96a75f3e1924..c329db6fec30ea655309eda4d4ea6a72ada711ff 100644 --- a/src/EditorFeatures/Core/Implementation/IntelliSense/Completion/Controller_Commit.cs +++ b/src/EditorFeatures/Core/Implementation/IntelliSense/Completion/Controller_Commit.cs @@ -7,6 +7,7 @@ using Microsoft.CodeAnalysis.Completion; using Microsoft.CodeAnalysis.Editor.Shared.Extensions; using Microsoft.CodeAnalysis.Editor.Shared.Utilities; +using Microsoft.CodeAnalysis.Internal.Log; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Text; using Microsoft.CodeAnalysis.Text.Shared.Extensions; @@ -186,6 +187,7 @@ private CompletionProvider GetCompletionProvider(CompletionItem item) } transaction.Complete(); + Logger.Log(FunctionId.Intellisense_Completion_Commit, KeyValueLogMessage.NoProperty); } // Let the completion rules know that this item was committed. diff --git a/src/EditorFeatures/Core/Implementation/IntelliSense/QuickInfo/IntellisenseQuickInfoBuilder.cs b/src/EditorFeatures/Core/Implementation/IntelliSense/QuickInfo/IntellisenseQuickInfoBuilder.cs index 5ab0493cd82aa4f24d97e79779951f7f9bb0dda4..4f0dc5e958b37c1af73e6beecc477c321eb5ea5b 100644 --- a/src/EditorFeatures/Core/Implementation/IntelliSense/QuickInfo/IntellisenseQuickInfoBuilder.cs +++ b/src/EditorFeatures/Core/Implementation/IntelliSense/QuickInfo/IntellisenseQuickInfoBuilder.cs @@ -1,9 +1,15 @@ // Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System.Collections.Generic; +using System.Collections.Immutable; using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.Classification; using Microsoft.CodeAnalysis.Editor.Shared.Extensions; +using Microsoft.CodeAnalysis.Formatting; using Microsoft.CodeAnalysis.QuickInfo; +using Microsoft.CodeAnalysis.Text.Shared.Extensions; using Microsoft.VisualStudio.Text; using Microsoft.VisualStudio.Text.Adornments; @@ -14,7 +20,11 @@ namespace Microsoft.CodeAnalysis.Editor.Implementation.IntelliSense.QuickInfo { internal static class IntellisenseQuickInfoBuilder { - internal static IntellisenseQuickInfoItem BuildItem(ITrackingSpan trackingSpan, CodeAnalysisQuickInfoItem quickInfoItem) + internal static async Task BuildItemAsync(ITrackingSpan trackingSpan, + CodeAnalysisQuickInfoItem quickInfoItem, + ITextSnapshot snapshot, + Document document, + CancellationToken cancellationToken) { // Build the first line of QuickInfo item, the images and the Description section should be on the first line with Wrapped style var glyphs = quickInfoItem.Tags.GetGlyphs(); @@ -47,6 +57,27 @@ internal static IntellisenseQuickInfoItem BuildItem(ITrackingSpan trackingSpan, quickInfoItem.Sections.Where(s => s.Kind != QuickInfoSectionKinds.Description) .Select(BuildClassifiedTextElement)); + // build text for RelatedSpan + if (quickInfoItem.RelatedSpans.Any()) + { + var classifiedSpanList = new List(); + foreach (var span in quickInfoItem.RelatedSpans) + { + var classifiedSpans = await EditorClassifier.GetClassifiedSpansAsync(document, span, cancellationToken).ConfigureAwait(false); + classifiedSpanList.AddRange(classifiedSpans); + } + + var tabSize = document.Project.Solution.Workspace.Options.GetOption(FormattingOptions.TabSize, document.Project.Language); + var text = await document.GetTextAsync().ConfigureAwait(false); + var spans = IndentationHelper.GetSpansWithAlignedIndentation(text, classifiedSpanList.ToImmutableArray(), tabSize); + var textRuns = spans.Select(s => new ClassifiedTextRun(s.ClassificationType, snapshot.GetText(s.TextSpan.ToSpan()))); + + if (textRuns.Any()) + { + elements.Add(new ClassifiedTextElement(textRuns)); + } + } + var content = new ContainerElement( ContainerElementStyle.Stacked, elements); @@ -59,6 +90,5 @@ private static ClassifiedTextElement BuildClassifiedTextElement(QuickInfoSection return new ClassifiedTextElement(section.TaggedParts.Select( part => new ClassifiedTextRun(part.Tag.ToClassificationTypeName(), part.Text))); } - } } diff --git a/src/EditorFeatures/Core/Implementation/IntelliSense/QuickInfo/QuickInfoSourceProvider.QuickInfoSource.cs b/src/EditorFeatures/Core/Implementation/IntelliSense/QuickInfo/QuickInfoSourceProvider.QuickInfoSource.cs index 5df2906d2610fb8fef28916bba9f623ceac4ac03..2adff626eb67d00e7606fe1862f74c8b1abd7a03 100644 --- a/src/EditorFeatures/Core/Implementation/IntelliSense/QuickInfo/QuickInfoSourceProvider.QuickInfoSource.cs +++ b/src/EditorFeatures/Core/Implementation/IntelliSense/QuickInfo/QuickInfoSourceProvider.QuickInfoSource.cs @@ -59,7 +59,7 @@ public async Task GetQuickInfoItemAsync(IAsyncQuickIn { var textVersion = snapshot.Version; var trackingSpan = textVersion.CreateTrackingSpan(item.Span.ToSpan(), SpanTrackingMode.EdgeInclusive); - return IntellisenseQuickInfoBuilder.BuildItem(trackingSpan, item); + return await IntellisenseQuickInfoBuilder.BuildItemAsync(trackingSpan, item, snapshot, document, cancellationToken).ConfigureAwait(false); } return null; diff --git a/src/EditorFeatures/Test2/IntelliSense/IntellisenseQuickInfoBuilderTests.vb b/src/EditorFeatures/Test2/IntelliSense/IntellisenseQuickInfoBuilderTests.vb index 8133bb7960fb702bc6767d023999159d473ea299..ffa3fe24a15c1915f02477560df987290e80aaa1 100644 --- a/src/EditorFeatures/Test2/IntelliSense/IntellisenseQuickInfoBuilderTests.vb +++ b/src/EditorFeatures/Test2/IntelliSense/IntellisenseQuickInfoBuilderTests.vb @@ -14,7 +14,7 @@ Namespace Microsoft.CodeAnalysis.Editor.UnitTests.IntelliSense Public Class IntellisenseQuickInfoBuilderTests - Public Sub BuildQuickInfoItem() + Public Async Sub BuildQuickInfoItem() Dim codeAnalysisQuickInfoItem _ = QuickInfoItem.Create(New Text.TextSpan(0, 0), ImmutableArray.Create({"Method", "Public"}), @@ -56,7 +56,7 @@ Namespace Microsoft.CodeAnalysis.Editor.UnitTests.IntelliSense .DefaultValue = DefaultValue.Mock } - Dim intellisenseQuickInfo = IntellisenseQuickInfoBuilder.BuildItem(trackingSpan.Object, codeAnalysisQuickInfoItem) + Dim intellisenseQuickInfo = Await IntellisenseQuickInfoBuilder.BuildItemAsync(trackingSpan.Object, codeAnalysisQuickInfoItem, Nothing, Nothing, Threading.CancellationToken.None) Assert.NotNull(intellisenseQuickInfo) diff --git a/src/EditorFeatures/VisualBasicTest/Diagnostics/PreferFrameworkType/PreferFrameworkTypeTests.vb b/src/EditorFeatures/VisualBasicTest/Diagnostics/PreferFrameworkType/PreferFrameworkTypeTests.vb index 7e133694ce0f7d7efc6208855783b06310b28cd3..b94843be0e6d60fd65a0bc9bf7f0e1d1fea9c2c8 100644 --- a/src/EditorFeatures/VisualBasicTest/Diagnostics/PreferFrameworkType/PreferFrameworkTypeTests.vb +++ b/src/EditorFeatures/VisualBasicTest/Diagnostics/PreferFrameworkType/PreferFrameworkTypeTests.vb @@ -3,10 +3,10 @@ Option Strict On Imports Microsoft.CodeAnalysis.CodeFixes -Imports Microsoft.CodeAnalysis.CodeFixes.PreferFrameworkType Imports Microsoft.CodeAnalysis.CodeStyle Imports Microsoft.CodeAnalysis.Diagnostics Imports Microsoft.CodeAnalysis.Options +Imports Microsoft.CodeAnalysis.PreferFrameworkType Imports Microsoft.CodeAnalysis.VisualBasic.Diagnostics.Analyzers Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.Diagnostics.PreferFrameworkTypeTests diff --git a/src/EditorFeatures/VisualBasicTest/Diagnostics/PreferFrameworkType/PreferFrameworkTypeTests_FixAllTests.vb b/src/EditorFeatures/VisualBasicTest/Diagnostics/PreferFrameworkType/PreferFrameworkTypeTests_FixAllTests.vb index 25604fab33f5b4b5410b7011a71c4f0ba9524f6c..0ca1c5e7e6b6debecae343f761b81a6da8b77cd3 100644 --- a/src/EditorFeatures/VisualBasicTest/Diagnostics/PreferFrameworkType/PreferFrameworkTypeTests_FixAllTests.vb +++ b/src/EditorFeatures/VisualBasicTest/Diagnostics/PreferFrameworkType/PreferFrameworkTypeTests_FixAllTests.vb @@ -346,9 +346,9 @@ End Class]]> - Public Async Function QualifyMemberAccessNotPresentOnNotificationOptionSilent() As Task - Await TestMissingAsyncWithOptionAndNotification( + Public Async Function QualifyMemberAccessOnNotificationOptionSilent() As Task + Await TestAsyncWithOptionAndNotification( "Class C : Property I As Integer : Sub M() : [|I|] = 1 : End Sub : End Class", +"Class C : Property I As Integer : Sub M() : Me.I = 1 : End Sub : End Class", CodeStyleOptions.QualifyPropertyAccess, NotificationOption.Silent) End Function diff --git a/src/EditorFeatures/VisualBasicTest/SimplifyTypeNames/SimplifyTypeNamesTests.vb b/src/EditorFeatures/VisualBasicTest/SimplifyTypeNames/SimplifyTypeNamesTests.vb index 80c8f2d36a6edfdd7616f0a2fc0445f02e2e801c..21f028795c7293cf50d8654c9f4f1134fa8fbde4 100644 --- a/src/EditorFeatures/VisualBasicTest/SimplifyTypeNames/SimplifyTypeNamesTests.vb +++ b/src/EditorFeatures/VisualBasicTest/SimplifyTypeNames/SimplifyTypeNamesTests.vb @@ -2417,7 +2417,7 @@ End Module Dim parameters2 As New TestParameters() Using workspace = CreateWorkspaceFromFile(source.ToString(), parameters2) workspace.ApplyOptions(PreferIntrinsicPredefinedTypeEverywhere()) - Dim diagnostics = (Await GetDiagnosticsAsync(workspace, parameters2)).Where(Function(d) d.Id = IDEDiagnosticIds.PreferIntrinsicPredefinedTypeInDeclarationsDiagnosticId) + Dim diagnostics = (Await GetDiagnosticsAsync(workspace, parameters2)).Where(Function(d) d.Id = IDEDiagnosticIds.PreferBuiltInOrFrameworkTypeDiagnosticId) Assert.Equal(1, diagnostics.Count) End Using diff --git a/src/Features/CSharp/Portable/CodeCleanup/CSharpCodeCleanupService.cs b/src/Features/CSharp/Portable/CodeCleanup/CSharpCodeCleanupService.cs index bc51bba23bad2689461a8dca3dd6e24642b85dfb..200acfbb692feaef7107e4fe6901b21f134cb6e3 100644 --- a/src/Features/CSharp/Portable/CodeCleanup/CSharpCodeCleanupService.cs +++ b/src/Features/CSharp/Portable/CodeCleanup/CSharpCodeCleanupService.cs @@ -43,8 +43,7 @@ internal class CSharpCodeCleanupService : ICodeCleanupService private static ImmutableArray, ImmutableArray>> GetCodeCleanupOptionMapping() { - return ImmutableArray.Create, ImmutableArray>> - ( + return ImmutableArray.Create( Tuple.Create( CodeCleanupOptions.ApplyImplicitExplicitTypePreferences, ImmutableArray.Create(IDEDiagnosticIds.UseImplicitTypeDiagnosticId, @@ -57,8 +56,7 @@ internal class CSharpCodeCleanupService : ICodeCleanupService ), Tuple.Create( CodeCleanupOptions.ApplyLanguageFrameworkTypePreferences, - ImmutableArray.Create(IDEDiagnosticIds.PreferFrameworkTypeInDeclarationsDiagnosticId, - IDEDiagnosticIds.PreferFrameworkTypeInMemberAccessDiagnosticId) + ImmutableArray.Create(IDEDiagnosticIds.PreferBuiltInOrFrameworkTypeDiagnosticId) ), Tuple.Create( CodeCleanupOptions.AddRemoveBracesForSingleLineControlStatements, diff --git a/src/Features/CSharp/Portable/CodeRefactorings/UseExplicitOrImplicitType/AbstractUseTypeCodeRefactoringProvider.cs b/src/Features/CSharp/Portable/CodeRefactorings/UseExplicitOrImplicitType/AbstractUseTypeCodeRefactoringProvider.cs index bb6e68561e2e2c09a57a14de8d829611c07b209c..336d7424925633229f52bf978402be32ed25b6f0 100644 --- a/src/Features/CSharp/Portable/CodeRefactorings/UseExplicitOrImplicitType/AbstractUseTypeCodeRefactoringProvider.cs +++ b/src/Features/CSharp/Portable/CodeRefactorings/UseExplicitOrImplicitType/AbstractUseTypeCodeRefactoringProvider.cs @@ -69,7 +69,7 @@ public override async Task ComputeRefactoringsAsync(CodeRefactoringContext conte } var typeStyle = AnalyzeTypeName(declaredType, semanticModel, optionSet, cancellationToken); - if (typeStyle.IsStylePreferred && typeStyle.Severity.WithDefaultSeverity(DiagnosticSeverity.Hidden) < ReportDiagnostic.Hidden) + if (typeStyle.IsStylePreferred && typeStyle.Severity != ReportDiagnostic.Suppress) { // the analyzer would handle this. So we do not. return; diff --git a/src/Features/CSharp/Portable/Diagnostics/Analyzers/CSharpPreferFrameworkTypeDiagnosticAnalyzer.cs b/src/Features/CSharp/Portable/Diagnostics/Analyzers/CSharpPreferFrameworkTypeDiagnosticAnalyzer.cs index ff0bd5abd555777b9db9c61edfa02aab251777bf..8d9edaea930ec4c2855d9cdc55a7037de52e0b65 100644 --- a/src/Features/CSharp/Portable/Diagnostics/Analyzers/CSharpPreferFrameworkTypeDiagnosticAnalyzer.cs +++ b/src/Features/CSharp/Portable/Diagnostics/Analyzers/CSharpPreferFrameworkTypeDiagnosticAnalyzer.cs @@ -4,7 +4,7 @@ using Microsoft.CodeAnalysis.CSharp.Extensions; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Diagnostics; -using Microsoft.CodeAnalysis.Diagnostics.PreferFrameworkType; +using Microsoft.CodeAnalysis.PreferFrameworkType; namespace Microsoft.CodeAnalysis.CSharp.Diagnostics.Analyzers { diff --git a/src/Features/CSharp/Portable/Diagnostics/Analyzers/CSharpSimplifyTypeNamesDiagnosticAnalyzer.cs b/src/Features/CSharp/Portable/Diagnostics/Analyzers/CSharpSimplifyTypeNamesDiagnosticAnalyzer.cs index 21482127b3b5b394db2c342731928c3455c979d5..bdd01f6bf1b5f2daeb8b7a3a1a0bde67db0a4ed2 100644 --- a/src/Features/CSharp/Portable/Diagnostics/Analyzers/CSharpSimplifyTypeNamesDiagnosticAnalyzer.cs +++ b/src/Features/CSharp/Portable/Diagnostics/Analyzers/CSharpSimplifyTypeNamesDiagnosticAnalyzer.cs @@ -1,7 +1,5 @@ // Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. -using System; -using System.Collections.Generic; using System.Collections.Immutable; using System.Linq; using System.Threading; @@ -9,8 +7,8 @@ using Microsoft.CodeAnalysis.CSharp.Extensions; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Diagnostics; -using Microsoft.CodeAnalysis.Diagnostics.SimplifyTypeNames; using Microsoft.CodeAnalysis.Options; +using Microsoft.CodeAnalysis.SimplifyTypeNames; using Microsoft.CodeAnalysis.Text; namespace Microsoft.CodeAnalysis.CSharp.Diagnostics.SimplifyTypeNames @@ -93,13 +91,23 @@ private static bool IsCrefCandidate(SyntaxNode node) return node is QualifiedCrefSyntax; } - protected sealed override bool CanSimplifyTypeNameExpressionCore(SemanticModel model, SyntaxNode node, OptionSet optionSet, out TextSpan issueSpan, out string diagnosticId, CancellationToken cancellationToken) + protected sealed override bool CanSimplifyTypeNameExpressionCore( + SemanticModel model, SyntaxNode node, OptionSet optionSet, + out TextSpan issueSpan, out string diagnosticId, out bool inDeclaration, + CancellationToken cancellationToken) { - return CanSimplifyTypeNameExpression(model, node, optionSet, out issueSpan, out diagnosticId, cancellationToken); + return CanSimplifyTypeNameExpression( + model, node, optionSet, + out issueSpan, out diagnosticId, out inDeclaration, + cancellationToken); } - internal override bool CanSimplifyTypeNameExpression(SemanticModel model, SyntaxNode node, OptionSet optionSet, out TextSpan issueSpan, out string diagnosticId, CancellationToken cancellationToken) + internal override bool CanSimplifyTypeNameExpression( + SemanticModel model, SyntaxNode node, OptionSet optionSet, + out TextSpan issueSpan, out string diagnosticId, out bool inDeclaration, + CancellationToken cancellationToken) { + inDeclaration = false; issueSpan = default; diagnosticId = IDEDiagnosticIds.SimplifyNamesDiagnosticId; @@ -138,11 +146,13 @@ internal override bool CanSimplifyTypeNameExpression(SemanticModel model, Syntax // set proper diagnostic ids. if (replacementSyntax.HasAnnotations(nameof(CodeStyleOptions.PreferIntrinsicPredefinedTypeKeywordInDeclaration))) { - diagnosticId = IDEDiagnosticIds.PreferIntrinsicPredefinedTypeInDeclarationsDiagnosticId; + inDeclaration = true; + diagnosticId = IDEDiagnosticIds.PreferBuiltInOrFrameworkTypeDiagnosticId; } else if (replacementSyntax.HasAnnotations(nameof(CodeStyleOptions.PreferIntrinsicPredefinedTypeKeywordInMemberAccess))) { - diagnosticId = IDEDiagnosticIds.PreferIntrinsicPredefinedTypeInMemberAccessDiagnosticId; + inDeclaration = false; + diagnosticId = IDEDiagnosticIds.PreferBuiltInOrFrameworkTypeDiagnosticId; } else if (expression.Kind() == SyntaxKind.SimpleMemberAccessExpression) { diff --git a/src/Features/CSharp/Portable/Diagnostics/Analyzers/CSharpTypeStyleDiagnosticAnalyzerBase.cs b/src/Features/CSharp/Portable/Diagnostics/Analyzers/CSharpTypeStyleDiagnosticAnalyzerBase.cs index c3afdcf684f4ae2197006b3b3157892c2071469d..6157dabd9daa77fe5e63bb14f732047844c76a3d 100644 --- a/src/Features/CSharp/Portable/Diagnostics/Analyzers/CSharpTypeStyleDiagnosticAnalyzerBase.cs +++ b/src/Features/CSharp/Portable/Diagnostics/Analyzers/CSharpTypeStyleDiagnosticAnalyzerBase.cs @@ -1,14 +1,10 @@ // Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. -using System.Diagnostics; -using System.Threading; using Microsoft.CodeAnalysis.CodeStyle; using Microsoft.CodeAnalysis.CSharp.CodeStyle; using Microsoft.CodeAnalysis.CSharp.Extensions; -using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.CSharp.Utilities; using Microsoft.CodeAnalysis.Diagnostics; -using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Text; namespace Microsoft.CodeAnalysis.CSharp.Diagnostics.TypeStyle @@ -62,9 +58,7 @@ private void HandleVariableDeclaration(SyntaxNodeAnalysisContext context) var typeStyle = Helper.AnalyzeTypeName( declaredType, semanticModel, optionSet, cancellationToken); - if (!typeStyle.IsStylePreferred || - typeStyle.Severity.WithDefaultSeverity(DiagnosticSeverity.Hidden) >= ReportDiagnostic.Hidden || - !typeStyle.CanConvert()) + if (!typeStyle.IsStylePreferred || !typeStyle.CanConvert()) { return; } diff --git a/src/Features/CSharp/Portable/SimplifyTypeNames/SimplifyTypeNamesCodeFixProvider.cs b/src/Features/CSharp/Portable/SimplifyTypeNames/SimplifyTypeNamesCodeFixProvider.cs index dc4c5973c1f9a17b61f31b7bef3f451570063f48..17bea1a0b0ee7af8810c447bf429c52e9fddddc9 100644 --- a/src/Features/CSharp/Portable/SimplifyTypeNames/SimplifyTypeNamesCodeFixProvider.cs +++ b/src/Features/CSharp/Portable/SimplifyTypeNames/SimplifyTypeNamesCodeFixProvider.cs @@ -26,11 +26,10 @@ protected override string GetTitle(string diagnosticId, string nodeText) switch (diagnosticId) { case IDEDiagnosticIds.SimplifyNamesDiagnosticId: - case IDEDiagnosticIds.PreferIntrinsicPredefinedTypeInDeclarationsDiagnosticId: + case IDEDiagnosticIds.PreferBuiltInOrFrameworkTypeDiagnosticId: return string.Format(CSharpFeaturesResources.Simplify_name_0, nodeText); case IDEDiagnosticIds.SimplifyMemberAccessDiagnosticId: - case IDEDiagnosticIds.PreferIntrinsicPredefinedTypeInMemberAccessDiagnosticId: return string.Format(CSharpFeaturesResources.Simplify_member_access_0, nodeText); case IDEDiagnosticIds.RemoveQualificationDiagnosticId: diff --git a/src/Features/CSharp/Portable/UseExpressionBody/Helpers/UseExpressionBodyHelper`1.cs b/src/Features/CSharp/Portable/UseExpressionBody/Helpers/UseExpressionBodyHelper`1.cs index 59ac364687a319b87373148e14320a83b049b853..539470c3ead8426dedf5e5068f94a61a14289e53 100644 --- a/src/Features/CSharp/Portable/UseExpressionBody/Helpers/UseExpressionBodyHelper`1.cs +++ b/src/Features/CSharp/Portable/UseExpressionBody/Helpers/UseExpressionBodyHelper`1.cs @@ -5,7 +5,6 @@ using System.Linq; using Microsoft.CodeAnalysis.CodeRefactorings; using Microsoft.CodeAnalysis.CodeStyle; -using Microsoft.CodeAnalysis.CSharp.CodeStyle; using Microsoft.CodeAnalysis.CSharp.Extensions; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Diagnostics; @@ -82,12 +81,15 @@ protected virtual Location GetDiagnosticLocation(TDeclaration declaration) public bool CanOfferUseExpressionBody( OptionSet optionSet, TDeclaration declaration, bool forAnalyzer) { - var preference = optionSet.GetOption(this.Option).Value; + var currentOptionValue = optionSet.GetOption(Option); + var preference = currentOptionValue.Value; var userPrefersExpressionBodies = preference != ExpressionBodyPreference.Never; + var analyzerDisabled = currentOptionValue.Notification.Severity == ReportDiagnostic.Suppress; // If the user likes expression bodies, then we offer expression bodies from the diagnostic analyzer. // If the user does not like expression bodies then we offer expression bodies from the refactoring provider. - if (userPrefersExpressionBodies == forAnalyzer) + // If the analyzer is disabled completely, the refactoring is enabled in both directions. + if (userPrefersExpressionBodies == forAnalyzer || (!forAnalyzer && analyzerDisabled)) { var expressionBody = this.GetExpressionBody(declaration); if (expressionBody == null) @@ -156,8 +158,10 @@ protected virtual Location GetDiagnosticLocation(TDeclaration declaration) public (bool canOffer, bool fixesError) CanOfferUseBlockBody( OptionSet optionSet, TDeclaration declaration, bool forAnalyzer) { - var preference = optionSet.GetOption(this.Option).Value; + var currentOptionValue = optionSet.GetOption(Option); + var preference = currentOptionValue.Value; var userPrefersBlockBodies = preference == ExpressionBodyPreference.Never; + var analyzerDisabled = currentOptionValue.Notification.Severity == ReportDiagnostic.Suppress; var expressionBodyOpt = this.GetExpressionBody(declaration); var canOffer = expressionBodyOpt?.TryConvertToBlock( @@ -197,7 +201,9 @@ protected virtual Location GetDiagnosticLocation(TDeclaration declaration) // If the user likes block bodies, then we offer block bodies from the diagnostic analyzer. // If the user does not like block bodies then we offer block bodies from the refactoring provider. - return (userPrefersBlockBodies == forAnalyzer, fixesError: false); + // If the analyzer is disabled completely, the refactoring is enabled in both directions. + canOffer = userPrefersBlockBodies == forAnalyzer || (!forAnalyzer && analyzerDisabled); + return (canOffer, fixesError: false); } public TDeclaration Update( diff --git a/src/Features/CSharp/Portable/UseExpressionBody/UseExpressionBodyCodeFixProvider.cs b/src/Features/CSharp/Portable/UseExpressionBody/UseExpressionBodyCodeFixProvider.cs index a2d0f579cfbfd9b0ffba24b7cbf729019f9eedc6..309fd7337cb4b9faa5c6ac1957b50f1798ed65d7 100644 --- a/src/Features/CSharp/Portable/UseExpressionBody/UseExpressionBodyCodeFixProvider.cs +++ b/src/Features/CSharp/Portable/UseExpressionBody/UseExpressionBodyCodeFixProvider.cs @@ -31,7 +31,7 @@ public UseExpressionBodyCodeFixProvider() } protected override bool IncludeDiagnosticDuringFixAll(Diagnostic diagnostic) - => diagnostic.Severity != DiagnosticSeverity.Hidden || + => !diagnostic.IsSuppressed || diagnostic.Properties.ContainsKey(UseExpressionBodyDiagnosticAnalyzer.FixesError); public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context) diff --git a/src/Features/CSharp/Portable/UseLocalFunction/CSharpUseLocalFunctionCodeFixProvider.cs b/src/Features/CSharp/Portable/UseLocalFunction/CSharpUseLocalFunctionCodeFixProvider.cs index 53c224dd162ad120b40130709e38d124a8d305bb..4f119121c495dcaa2a0b9567a13da0ae7e5d6ac8 100644 --- a/src/Features/CSharp/Portable/UseLocalFunction/CSharpUseLocalFunctionCodeFixProvider.cs +++ b/src/Features/CSharp/Portable/UseLocalFunction/CSharpUseLocalFunctionCodeFixProvider.cs @@ -30,7 +30,7 @@ public override ImmutableArray FixableDiagnosticIds => ImmutableArray.Create(IDEDiagnosticIds.UseLocalFunctionDiagnosticId); protected override bool IncludeDiagnosticDuringFixAll(Diagnostic diagnostic) - => diagnostic.Severity != DiagnosticSeverity.Hidden && !diagnostic.IsSuppressed; + => !diagnostic.IsSuppressed; public override Task RegisterCodeFixesAsync(CodeFixContext context) { diff --git a/src/Features/Core/Portable/Diagnostics/Analyzers/IDEDiagnosticIds.cs b/src/Features/Core/Portable/Diagnostics/Analyzers/IDEDiagnosticIds.cs index 513991c59e8b95c391699dee4295253f986d163f..68df2773a9d6bacf97a3b1f5bd7f603c3ae1da64 100644 --- a/src/Features/Core/Portable/Diagnostics/Analyzers/IDEDiagnosticIds.cs +++ b/src/Features/Core/Portable/Diagnostics/Analyzers/IDEDiagnosticIds.cs @@ -15,10 +15,13 @@ internal static class IDEDiagnosticIds public const string AddQualificationDiagnosticId = "IDE0009"; public const string PopulateSwitchDiagnosticId = "IDE0010"; public const string AddBracesDiagnosticId = "IDE0011"; - public const string PreferIntrinsicPredefinedTypeInDeclarationsDiagnosticId = "IDE0012"; - public const string PreferIntrinsicPredefinedTypeInMemberAccessDiagnosticId = "IDE0013"; - public const string PreferFrameworkTypeInDeclarationsDiagnosticId = "IDE0014"; - public const string PreferFrameworkTypeInMemberAccessDiagnosticId = "IDE0015"; + + // IDE0012-IDE0015 deprecated and replaced with PreferBuiltInOrFrameworkTypeDiagnosticId (IDE0049) + // public const string PreferIntrinsicPredefinedTypeInDeclarationsDiagnosticId = "IDE0012"; + // public const string PreferIntrinsicPredefinedTypeInMemberAccessDiagnosticId = "IDE0013"; + // public const string PreferFrameworkTypeInDeclarationsDiagnosticId = "IDE0014"; + // public const string PreferFrameworkTypeInMemberAccessDiagnosticId = "IDE0015"; + public const string UseThrowExpressionDiagnosticId = "IDE0016"; public const string UseObjectInitializerDiagnosticId = "IDE0017"; public const string InlineDeclarationDiagnosticId = "IDE0018"; @@ -72,6 +75,9 @@ internal static class IDEDiagnosticIds public const string RemoveUnnecessaryParenthesesDiagnosticId = "IDE0047"; public const string AddRequiredParenthesesDiagnosticId = "IDE0048"; + public const string PreferBuiltInOrFrameworkTypeDiagnosticId = "IDE0049"; + + // Analyzer error Ids public const string AnalyzerChangedId = "IDE1001"; public const string AnalyzerDependencyConflictId = "IDE1002"; diff --git a/src/Features/Core/Portable/Diagnostics/Analyzers/NamingStyleDiagnosticAnalyzerBase.cs b/src/Features/Core/Portable/Diagnostics/Analyzers/NamingStyleDiagnosticAnalyzerBase.cs index c621452852f0b79b3eb1c2e1e3d7085b3d40627a..c4f8c28c8510fdf834fc728ba21f92131aedbde6 100644 --- a/src/Features/Core/Portable/Diagnostics/Analyzers/NamingStyleDiagnosticAnalyzerBase.cs +++ b/src/Features/Core/Portable/Diagnostics/Analyzers/NamingStyleDiagnosticAnalyzerBase.cs @@ -2,7 +2,6 @@ using System; using System.Collections.Concurrent; -using System.Collections.Generic; using System.Collections.Immutable; using System.Linq; using System.Threading; @@ -118,7 +117,7 @@ void SyntaxNodeAction(SyntaxNodeAnalysisContext syntaxContext) var namingStyleRules = namingPreferences.Rules; if (!namingStyleRules.TryGetApplicableRule(symbol, out var applicableRule) || - applicableRule.EnforcementLevel.WithDefaultSeverity(DiagnosticSeverity.Hidden) >= ReportDiagnostic.Hidden) + applicableRule.EnforcementLevel == ReportDiagnostic.Suppress) { return null; } diff --git a/src/Features/Core/Portable/CodeFixes/PreferFrameworkType/PreferFrameworkTypeCodeFixProvider.cs b/src/Features/Core/Portable/PreferFrameworkType/PreferFrameworkTypeCodeFixProvider.cs similarity index 70% rename from src/Features/Core/Portable/CodeFixes/PreferFrameworkType/PreferFrameworkTypeCodeFixProvider.cs rename to src/Features/Core/Portable/PreferFrameworkType/PreferFrameworkTypeCodeFixProvider.cs index dd193752dbe5ee3b585c6b7ed17fde89f0bbb811..398ea270b21b9d35f0456da5e1ca6f14da2bce2c 100644 --- a/src/Features/Core/Portable/CodeFixes/PreferFrameworkType/PreferFrameworkTypeCodeFixProvider.cs +++ b/src/Features/Core/Portable/PreferFrameworkType/PreferFrameworkTypeCodeFixProvider.cs @@ -6,34 +6,31 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.CodeActions; +using Microsoft.CodeAnalysis.CodeFixes; using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.Editing; using Microsoft.CodeAnalysis.Shared.Extensions; using Roslyn.Utilities; -namespace Microsoft.CodeAnalysis.CodeFixes.PreferFrameworkType +namespace Microsoft.CodeAnalysis.PreferFrameworkType { [ExportCodeFixProvider(LanguageNames.CSharp, LanguageNames.VisualBasic, Name = PredefinedCodeFixProviderNames.PreferFrameworkType), Shared] internal class PreferFrameworkTypeCodeFixProvider : SyntaxEditorBasedCodeFixProvider { - public const string EquivalenceKey = nameof(EquivalenceKey); - public const string DeclarationsEquivalenceKey = nameof(DeclarationsEquivalenceKey); - public const string MemberAccessEquivalenceKey = nameof(MemberAccessEquivalenceKey); - - public sealed override ImmutableArray FixableDiagnosticIds => ImmutableArray.Create( - IDEDiagnosticIds.PreferFrameworkTypeInDeclarationsDiagnosticId, - IDEDiagnosticIds.PreferFrameworkTypeInMemberAccessDiagnosticId); + public sealed override ImmutableArray FixableDiagnosticIds { get; } = ImmutableArray.Create( + IDEDiagnosticIds.PreferBuiltInOrFrameworkTypeDiagnosticId); public override Task RegisterCodeFixesAsync(CodeFixContext context) { var diagnostic = context.Diagnostics[0]; - var equivalenceKey = diagnostic.Properties[EquivalenceKey]; - context.RegisterCodeFix( - new PreferFrameworkTypeCodeAction( - c => this.FixAsync(context.Document, context.Diagnostics[0], c), - equivalenceKey), - context.Diagnostics); + if (diagnostic.Properties.ContainsKey(PreferFrameworkTypeConstants.PreferFrameworkType)) + { + context.RegisterCodeFix( + new PreferFrameworkTypeCodeAction( + c => this.FixAsync(context.Document, diagnostic, c)), + context.Diagnostics); + } return Task.CompletedTask; } @@ -60,13 +57,13 @@ public override Task RegisterCodeFixesAsync(CodeFixContext context) } protected override bool IncludeDiagnosticDuringFixAll(FixAllState state, Diagnostic diagnostic) - => diagnostic.Properties[EquivalenceKey] == state.CodeActionEquivalenceKey; + => diagnostic.Properties.ContainsKey(PreferFrameworkTypeConstants.PreferFrameworkType); private class PreferFrameworkTypeCodeAction : CodeAction.DocumentChangeAction { public PreferFrameworkTypeCodeAction( - Func> createChangedDocument, string equivalenceKey) - : base(FeaturesResources.Use_framework_type, createChangedDocument, equivalenceKey) + Func> createChangedDocument) + : base(FeaturesResources.Use_framework_type, createChangedDocument, FeaturesResources.Use_framework_type) { } } diff --git a/src/Features/Core/Portable/PreferFrameworkType/PreferFrameworkTypeConstants.cs b/src/Features/Core/Portable/PreferFrameworkType/PreferFrameworkTypeConstants.cs new file mode 100644 index 0000000000000000000000000000000000000000..7a8bca6b1e99c6a75c8d4e405b2ddc34baab9c8e --- /dev/null +++ b/src/Features/Core/Portable/PreferFrameworkType/PreferFrameworkTypeConstants.cs @@ -0,0 +1,13 @@ +// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System.Collections.Immutable; + +namespace Microsoft.CodeAnalysis.PreferFrameworkType +{ + internal static class PreferFrameworkTypeConstants + { + public const string PreferFrameworkType = nameof(PreferFrameworkType); + public static readonly ImmutableDictionary Properties = + ImmutableDictionary.Empty.Add(PreferFrameworkType, ""); + } +} diff --git a/src/Features/Core/Portable/Diagnostics/Analyzers/PreferFrameworkTypeDiagnosticAnalyzerBase.cs b/src/Features/Core/Portable/PreferFrameworkType/PreferFrameworkTypeDiagnosticAnalyzerBase.cs similarity index 84% rename from src/Features/Core/Portable/Diagnostics/Analyzers/PreferFrameworkTypeDiagnosticAnalyzerBase.cs rename to src/Features/Core/Portable/PreferFrameworkType/PreferFrameworkTypeDiagnosticAnalyzerBase.cs index e1766e31e1f441930e016d1119ccb615d5276fc3..b208be1d2ef1584f0adbf7ca526da9efec9934ae 100644 --- a/src/Features/Core/Portable/Diagnostics/Analyzers/PreferFrameworkTypeDiagnosticAnalyzerBase.cs +++ b/src/Features/Core/Portable/PreferFrameworkType/PreferFrameworkTypeDiagnosticAnalyzerBase.cs @@ -1,11 +1,11 @@ // Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System.Collections.Immutable; -using Microsoft.CodeAnalysis.CodeFixes.PreferFrameworkType; using Microsoft.CodeAnalysis.CodeStyle; +using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.Options; -namespace Microsoft.CodeAnalysis.Diagnostics.PreferFrameworkType +namespace Microsoft.CodeAnalysis.PreferFrameworkType { internal abstract class PreferFrameworkTypeDiagnosticAnalyzerBase : AbstractCodeStyleDiagnosticAnalyzer @@ -13,13 +13,8 @@ internal abstract class PreferFrameworkTypeDiagnosticAnalyzerBase DeclarationsEquivalenceKey = ImmutableDictionary.Empty.Add( - PreferFrameworkTypeCodeFixProvider.EquivalenceKey, PreferFrameworkTypeCodeFixProvider.DeclarationsEquivalenceKey); - private static readonly ImmutableDictionary MemberAccessEquivalenceKey = ImmutableDictionary.Empty.Add( - PreferFrameworkTypeCodeFixProvider.EquivalenceKey, PreferFrameworkTypeCodeFixProvider.MemberAccessEquivalenceKey); - protected PreferFrameworkTypeDiagnosticAnalyzerBase() - : base(IDEDiagnosticIds.PreferFrameworkTypeInDeclarationsDiagnosticId, + : base(IDEDiagnosticIds.PreferBuiltInOrFrameworkTypeDiagnosticId, new LocalizableResourceString(nameof(FeaturesResources.Use_framework_type), FeaturesResources.ResourceManager, typeof(FeaturesResources)), new LocalizableResourceString(nameof(FeaturesResources.Use_framework_type), FeaturesResources.ResourceManager, typeof(FeaturesResources))) { @@ -87,14 +82,16 @@ protected void AnalyzeNode(SyntaxNodeAnalysisContext context) { return; } + // earlier we did a context insensitive check to see if this style was preferred in *any* context at all. // now, we have to make a context sensitive check to see if options settings for our context requires us to report a diagnostic. if (ShouldReportDiagnostic(predefinedTypeNode, optionSet, language, - out var severity, out var properties)) + out var diagnosticSeverity)) { context.ReportDiagnostic(DiagnosticHelper.Create( Descriptor, predefinedTypeNode.GetLocation(), - severity, additionalLocations: null, properties)); + diagnosticSeverity, additionalLocations: null, + PreferFrameworkTypeConstants.Properties)); } } @@ -102,8 +99,8 @@ protected void AnalyzeNode(SyntaxNodeAnalysisContext context) /// Detects the context of this occurrence of predefined type and determines if we should report it. /// private bool ShouldReportDiagnostic( - TPredefinedTypeSyntax predefinedTypeNode, OptionSet optionSet, string language, - out ReportDiagnostic severity, out ImmutableDictionary properties) + TPredefinedTypeSyntax predefinedTypeNode, OptionSet optionSet, + string language, out ReportDiagnostic severity) { // we have a predefined type syntax that is either in a member access context or a declaration context. // check the appropriate option and determine if we should report a diagnostic. @@ -113,7 +110,6 @@ protected void AnalyzeNode(SyntaxNodeAnalysisContext context) var optionValue = optionSet.GetOption(option, language); severity = optionValue.Notification.Severity; - properties = isMemberAccessOrCref ? MemberAccessEquivalenceKey : DeclarationsEquivalenceKey; return OptionSettingPrefersFrameworkType(optionValue, severity); } @@ -132,6 +128,6 @@ private bool IsFrameworkTypePreferred(OptionSet optionSet, PerLanguageOption /// if predefined type is not preferred, it implies the preference is framework type. private static bool OptionSettingPrefersFrameworkType(CodeStyleOption optionValue, ReportDiagnostic severity) - => !optionValue.Value && severity.WithDefaultSeverity(DiagnosticSeverity.Hidden) < ReportDiagnostic.Hidden; + => !optionValue.Value && severity != ReportDiagnostic.Suppress; } } diff --git a/src/Features/Core/Portable/QualifyMemberAccess/AbstractQualifyMemberAccessDiagnosticAnalyzer.cs b/src/Features/Core/Portable/QualifyMemberAccess/AbstractQualifyMemberAccessDiagnosticAnalyzer.cs index 347876ba087176e12f4d410b8f56cb1f063bf10c..d35a411344b1543dd7c13186cac44d5c40c3978e 100644 --- a/src/Features/Core/Portable/QualifyMemberAccess/AbstractQualifyMemberAccessDiagnosticAnalyzer.cs +++ b/src/Features/Core/Portable/QualifyMemberAccess/AbstractQualifyMemberAccessDiagnosticAnalyzer.cs @@ -121,19 +121,20 @@ private void AnalyzeOperation(OperationAnalysisContext context, IOperation opera var optionValue = optionSet.GetOption(applicableOption, context.Operation.Syntax.Language); var shouldOptionBePresent = optionValue.Value; - var isQualificationPresent = IsAlreadyQualifiedMemberAccess(simpleName); - if (shouldOptionBePresent && !isQualificationPresent) + var severity = optionValue.Notification.Severity; + if (!shouldOptionBePresent || severity == ReportDiagnostic.Suppress) { - var severity = optionValue.Notification.Severity; - if (severity.WithDefaultSeverity(DiagnosticSeverity.Hidden) < ReportDiagnostic.Hidden) - { - context.ReportDiagnostic(DiagnosticHelper.Create( - Descriptor, - GetLocation(operation), - severity, - additionalLocations: null, - properties: null)); - } + return; + } + + if (!IsAlreadyQualifiedMemberAccess(simpleName)) + { + context.ReportDiagnostic(DiagnosticHelper.Create( + Descriptor, + GetLocation(operation), + severity, + additionalLocations: null, + properties: null)); } } diff --git a/src/Features/Core/Portable/QuickInfo/IndentationHelper.cs b/src/Features/Core/Portable/QuickInfo/IndentationHelper.cs index 2f8571e11cd5f39a335a0b16513980d0f752381e..d70375c801f9d7646d237c2c9986c692528ea987 100644 --- a/src/Features/Core/Portable/QuickInfo/IndentationHelper.cs +++ b/src/Features/Core/Portable/QuickInfo/IndentationHelper.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; using System.Collections.Immutable; +using Microsoft.CodeAnalysis.Classification; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Text; @@ -18,25 +19,29 @@ internal static class IndentationHelper /// This operation will potentially split spans that cover multiple lines into separate spans. /// /// - /// The initial set of spans to align. + /// The initial set of spans to align. /// The number of spaces to /// - public static ImmutableArray GetSpansWithAlignedIndentation( + public static ImmutableArray GetSpansWithAlignedIndentation( SourceText text, - ImmutableArray spans, + ImmutableArray classifiedSpans, int tabSize) { - if (!spans.IsDefault && spans.Length > 0) + if (!classifiedSpans.IsDefault && classifiedSpans.Length > 0) { // We need to figure out the shortest indentation level of the exposed lines. We'll // then remove that indentation from all lines. - var indentationColumn = DetermineIndentationColumn(text, spans, tabSize); + var indentationColumn = DetermineIndentationColumn(text, classifiedSpans, tabSize); - var adjustedSpans = new List(); + string spanClassificationType = null; + var adjustedClassifiedSpans = new List(); - for (var i = 0; i < spans.Length; i++) + for (var i = 0; i < classifiedSpans.Length; i++) { - var span = spans[i]; + var classifiedSpan = classifiedSpans[i]; + spanClassificationType = classifiedSpan.ClassificationType; + var span = classifiedSpan.TextSpan; + var startLineNumber = text.Lines.GetLineFromPosition(span.Start).LineNumber; var endLineNumber = text.Lines.GetLineFromPosition(span.End).LineNumber; @@ -52,7 +57,7 @@ internal static class IndentationHelper var spanBeforeDeletion = TextSpan.FromBounds(span.Start, Math.Min(span.End, deletion.Start)); if (spanBeforeDeletion.Length > 0) { - adjustedSpans.Add(spanBeforeDeletion); + adjustedClassifiedSpans.Add(new ClassifiedSpan(spanClassificationType, spanBeforeDeletion)); } } @@ -64,28 +69,28 @@ internal static class IndentationHelper if (span.Length > 0) { - adjustedSpans.Add(span); + adjustedClassifiedSpans.Add(new ClassifiedSpan(spanClassificationType, span)); } } - return adjustedSpans.ToImmutableArray(); + return adjustedClassifiedSpans.ToImmutableArray(); } else { - return ImmutableArray.Empty; + return ImmutableArray.Empty; } } private static int DetermineIndentationColumn( SourceText text, - ImmutableArray spans, + ImmutableArray spans, int tabSize) { int? indentationColumn = null; foreach (var span in spans) { - var startLineNumber = text.Lines.GetLineFromPosition(span.Start).LineNumber; - var endLineNumber = text.Lines.GetLineFromPosition(span.End).LineNumber; + var startLineNumber = text.Lines.GetLineFromPosition(span.TextSpan.Start).LineNumber; + var endLineNumber = text.Lines.GetLineFromPosition(span.TextSpan.End).LineNumber; // If the span starts after the first non-whitespace of the first line, we'll // exclude that line to avoid throwing off the calculation. Otherwise, the @@ -102,7 +107,7 @@ internal static class IndentationHelper // Without throwing out the first line in the example above, the indentation column // used will be 4, rather than 8. var startLineFirstNonWhitespace = text.Lines[startLineNumber].GetFirstNonWhitespacePosition(); - if (startLineFirstNonWhitespace.HasValue && startLineFirstNonWhitespace.Value < span.Start) + if (startLineFirstNonWhitespace.HasValue && startLineFirstNonWhitespace.Value < span.TextSpan.Start) { startLineNumber++; } diff --git a/src/Features/Core/Portable/SimplifyTypeNames/AbstractSimplifyTypeNamesCodeFixProvider.cs b/src/Features/Core/Portable/SimplifyTypeNames/AbstractSimplifyTypeNamesCodeFixProvider.cs index 2ee027aa7487bf861e60551fe5d16f6215444d01..3626b7b9c01c9dfd384c6b725507c2ed56608cf4 100644 --- a/src/Features/Core/Portable/SimplifyTypeNames/AbstractSimplifyTypeNamesCodeFixProvider.cs +++ b/src/Features/Core/Portable/SimplifyTypeNames/AbstractSimplifyTypeNamesCodeFixProvider.cs @@ -7,7 +7,6 @@ using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeFixes; using Microsoft.CodeAnalysis.Diagnostics; -using Microsoft.CodeAnalysis.Diagnostics.SimplifyTypeNames; using Microsoft.CodeAnalysis.Editing; using Microsoft.CodeAnalysis.LanguageServices; using Microsoft.CodeAnalysis.Options; @@ -36,8 +35,7 @@ internal abstract partial class AbstractSimplifyTypeNamesCodeFixProvider : DiagnosticAnalyzer, IBuiltInAnalyzer where TLanguageKindEnum : struct { @@ -43,32 +44,26 @@ internal abstract class SimplifyTypeNamesDiagnosticAnalyzerBase SupportedDiagnostics { get; } = ImmutableArray.Create( s_descriptorSimplifyNames, s_descriptorSimplifyMemberAccess, s_descriptorRemoveThisOrMe, - s_descriptorPreferIntrinsicTypeInDeclarations, - s_descriptorPreferIntrinsicTypeInMemberAccess); + s_descriptorPreferBuiltinOrFrameworkType); private readonly ImmutableArray _kindsOfInterest; @@ -98,7 +93,10 @@ public sealed override void Initialize(AnalysisContext context) protected abstract void AnalyzeNode(SyntaxNodeAnalysisContext context); - protected abstract bool CanSimplifyTypeNameExpressionCore(SemanticModel model, SyntaxNode node, OptionSet optionSet, out TextSpan issueSpan, out string diagnosticId, CancellationToken cancellationToken); + protected abstract bool CanSimplifyTypeNameExpressionCore( + SemanticModel model, SyntaxNode node, OptionSet optionSet, + out TextSpan issueSpan, out string diagnosticId, out bool inDeclaration, + CancellationToken cancellationToken); protected abstract string GetLanguageName(); @@ -113,7 +111,10 @@ protected bool TrySimplifyTypeNameExpression(SemanticModel model, SyntaxNode nod return false; } - if (!CanSimplifyTypeNameExpressionCore(model, node, optionSet, out var issueSpan, out string diagnosticId, cancellationToken)) + if (!CanSimplifyTypeNameExpressionCore( + model, node, optionSet, + out var issueSpan, out var diagnosticId, out var inDeclaration, + cancellationToken)) { return false; } @@ -142,18 +143,15 @@ protected bool TrySimplifyTypeNameExpression(SemanticModel model, SyntaxNode nod (descriptor, severity) = GetRemoveQualificationDiagnosticDescriptor(model, node, optionSet, cancellationToken); break; - case IDEDiagnosticIds.PreferIntrinsicPredefinedTypeInDeclarationsDiagnosticId: - option = CodeStyleOptions.PreferIntrinsicPredefinedTypeKeywordInDeclaration; - (descriptor, severity) = GetApplicablePredefinedTypeDiagnosticDescriptor( - IDEDiagnosticIds.PreferIntrinsicPredefinedTypeInDeclarationsDiagnosticId, option, optionSet); - break; + case IDEDiagnosticIds.PreferBuiltInOrFrameworkTypeDiagnosticId: + option = inDeclaration + ? CodeStyleOptions.PreferIntrinsicPredefinedTypeKeywordInDeclaration + : CodeStyleOptions.PreferIntrinsicPredefinedTypeKeywordInMemberAccess; + descriptor = s_descriptorPreferBuiltinOrFrameworkType; - case IDEDiagnosticIds.PreferIntrinsicPredefinedTypeInMemberAccessDiagnosticId: - option = CodeStyleOptions.PreferIntrinsicPredefinedTypeKeywordInMemberAccess; - (descriptor, severity) = GetApplicablePredefinedTypeDiagnosticDescriptor( - IDEDiagnosticIds.PreferIntrinsicPredefinedTypeInMemberAccessDiagnosticId, option, optionSet); + var optionValue = optionSet.GetOption(option, GetLanguageName()); + severity = optionValue.Notification.Severity; break; - default: throw ExceptionUtilities.UnexpectedValue(diagnosticId); } @@ -171,31 +169,6 @@ protected bool TrySimplifyTypeNameExpression(SemanticModel model, SyntaxNode nod return true; } - private (DiagnosticDescriptor descriptor, ReportDiagnostic severity) GetApplicablePredefinedTypeDiagnosticDescriptor(string id, PerLanguageOption option, OptionSet optionSet) where T : CodeStyleOption - { - var optionValue = optionSet.GetOption(option, GetLanguageName()); - - DiagnosticDescriptor descriptor = null; - if (optionValue.Notification.Severity.WithDefaultSeverity(DiagnosticSeverity.Hidden) < ReportDiagnostic.Hidden) - { - switch (id) - { - case IDEDiagnosticIds.PreferIntrinsicPredefinedTypeInDeclarationsDiagnosticId: - descriptor = s_descriptorPreferIntrinsicTypeInDeclarations; - break; - - case IDEDiagnosticIds.PreferIntrinsicPredefinedTypeInMemberAccessDiagnosticId: - descriptor = s_descriptorPreferIntrinsicTypeInMemberAccess; - break; - - default: - throw ExceptionUtilities.UnexpectedValue(id); - } - } - - return (descriptor, optionValue.Notification.Severity); - } - private (DiagnosticDescriptor descriptor, ReportDiagnostic severity) GetRemoveQualificationDiagnosticDescriptor(SemanticModel model, SyntaxNode node, OptionSet optionSet, CancellationToken cancellationToken) { var symbolInfo = model.GetSymbolInfo(node, cancellationToken); diff --git a/src/Features/Core/Portable/UseExplicitTupleName/UseExplicitTupleNameDiagnosticAnalyzer.cs b/src/Features/Core/Portable/UseExplicitTupleName/UseExplicitTupleNameDiagnosticAnalyzer.cs index f5d0386d72b64a4109044d92b45cb94489cca79a..71f24d61d57082b6af32281c357d2c76850dacc6 100644 --- a/src/Features/Core/Portable/UseExplicitTupleName/UseExplicitTupleNameDiagnosticAnalyzer.cs +++ b/src/Features/Core/Portable/UseExplicitTupleName/UseExplicitTupleNameDiagnosticAnalyzer.cs @@ -1,9 +1,7 @@ // Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. -using System; using System.Collections.Immutable; using System.Linq; -using System.Reflection; using System.Threading; using Microsoft.CodeAnalysis.CodeStyle; using Microsoft.CodeAnalysis.Diagnostics; @@ -41,7 +39,7 @@ private void AnalyzeOperation(OperationAnalysisContext context) var option = optionSet.GetOption(CodeStyleOptions.PreferExplicitTupleNames, context.Compilation.Language); var severity = option.Notification.Severity; - if (severity.WithDefaultSeverity(DiagnosticSeverity.Hidden) >= ReportDiagnostic.Hidden) + if (severity == ReportDiagnostic.Suppress) { return; } diff --git a/src/Features/VisualBasic/Portable/Diagnostics/Analyzers/VisualBasicPreferFrameworkTypeDiagnosticAnalyzer.vb b/src/Features/VisualBasic/Portable/Diagnostics/Analyzers/VisualBasicPreferFrameworkTypeDiagnosticAnalyzer.vb index 30345a13ccd62dc220d1d8c62163c3c680359850..9c04b7e7d15ee45d9fef09db0c14299d1d061f40 100644 --- a/src/Features/VisualBasic/Portable/Diagnostics/Analyzers/VisualBasicPreferFrameworkTypeDiagnosticAnalyzer.vb +++ b/src/Features/VisualBasic/Portable/Diagnostics/Analyzers/VisualBasicPreferFrameworkTypeDiagnosticAnalyzer.vb @@ -2,7 +2,7 @@ Imports System.Collections.Immutable Imports Microsoft.CodeAnalysis.Diagnostics -Imports Microsoft.CodeAnalysis.Diagnostics.PreferFrameworkType +Imports Microsoft.CodeAnalysis.PreferFrameworkType Imports Microsoft.CodeAnalysis.VisualBasic.Syntax Namespace Microsoft.CodeAnalysis.VisualBasic.Diagnostics.Analyzers diff --git a/src/Features/VisualBasic/Portable/Diagnostics/Analyzers/VisualBasicSimplifyTypeNamesDiagnosticAnalyzer.vb b/src/Features/VisualBasic/Portable/Diagnostics/Analyzers/VisualBasicSimplifyTypeNamesDiagnosticAnalyzer.vb index 0e1633dd4ba8a21c79be720e58acb032495e5690..738a117a4229c89956488f184557ed5b30cbdd0d 100644 --- a/src/Features/VisualBasic/Portable/Diagnostics/Analyzers/VisualBasicSimplifyTypeNamesDiagnosticAnalyzer.vb +++ b/src/Features/VisualBasic/Portable/Diagnostics/Analyzers/VisualBasicSimplifyTypeNamesDiagnosticAnalyzer.vb @@ -4,8 +4,8 @@ Imports System.Collections.Immutable Imports System.Threading Imports Microsoft.CodeAnalysis.CodeStyle Imports Microsoft.CodeAnalysis.Diagnostics -Imports Microsoft.CodeAnalysis.Diagnostics.SimplifyTypeNames Imports Microsoft.CodeAnalysis.Options +Imports Microsoft.CodeAnalysis.SimplifyTypeNames Imports Microsoft.CodeAnalysis.Text Imports Microsoft.CodeAnalysis.VisualBasic.Syntax @@ -57,11 +57,18 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.CodeFixes.SimplifyTypeNames Return node IsNot Nothing AndAlso IsNodeKindInteresting(node) End Function - Protected Overrides Function CanSimplifyTypeNameExpressionCore(model As SemanticModel, node As SyntaxNode, optionSet As OptionSet, ByRef issueSpan As TextSpan, ByRef diagnosticId As String, cancellationToken As CancellationToken) As Boolean - Return CanSimplifyTypeNameExpression(model, node, optionSet, issueSpan, diagnosticId, cancellationToken) + Protected Overrides Function CanSimplifyTypeNameExpressionCore( + model As SemanticModel, node As SyntaxNode, optionSet As OptionSet, + ByRef issueSpan As TextSpan, ByRef diagnosticId As String, ByRef inDeclaration As Boolean, + cancellationToken As CancellationToken) As Boolean + Return CanSimplifyTypeNameExpression( + model, node, optionSet, issueSpan, diagnosticId, inDeclaration, cancellationToken) End Function - Friend Overrides Function CanSimplifyTypeNameExpression(model As SemanticModel, node As SyntaxNode, optionSet As OptionSet, ByRef issueSpan As TextSpan, ByRef diagnosticId As String, cancellationToken As CancellationToken) As Boolean + Friend Overrides Function CanSimplifyTypeNameExpression( + model As SemanticModel, node As SyntaxNode, optionSet As OptionSet, + ByRef issueSpan As TextSpan, ByRef diagnosticId As String, ByRef inDeclaration As Boolean, + cancellationToken As CancellationToken) As Boolean issueSpan = Nothing diagnosticId = IDEDiagnosticIds.SimplifyNamesDiagnosticId @@ -77,9 +84,11 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.CodeFixes.SimplifyTypeNames ' set proper diagnostic ids. If replacementSyntax.HasAnnotations(NameOf(CodeStyleOptions.PreferIntrinsicPredefinedTypeKeywordInDeclaration)) Then - diagnosticId = IDEDiagnosticIds.PreferIntrinsicPredefinedTypeInDeclarationsDiagnosticId + inDeclaration = True + diagnosticId = IDEDiagnosticIds.PreferBuiltInOrFrameworkTypeDiagnosticId ElseIf replacementSyntax.HasAnnotations(NameOf(CodeStyleOptions.PreferIntrinsicPredefinedTypeKeywordInMemberAccess)) Then - diagnosticId = IDEDiagnosticIds.PreferIntrinsicPredefinedTypeInMemberAccessDiagnosticId + inDeclaration = False + diagnosticId = IDEDiagnosticIds.PreferBuiltInOrFrameworkTypeDiagnosticId ElseIf expression.Kind = SyntaxKind.SimpleMemberAccessExpression Then Dim memberAccess = DirectCast(expression, MemberAccessExpressionSyntax) Dim method = model.GetMemberGroup(expression) diff --git a/src/Features/VisualBasic/Portable/SimplifyTypeNames/SimplifyTypeNamesCodeFixProvider.vb b/src/Features/VisualBasic/Portable/SimplifyTypeNames/SimplifyTypeNamesCodeFixProvider.vb index 0896fecede0d32221876bef5443bc8f2cff1e35b..dd81e1d63ea8f86bca559e4b81921ec720880b36 100644 --- a/src/Features/VisualBasic/Portable/SimplifyTypeNames/SimplifyTypeNamesCodeFixProvider.vb +++ b/src/Features/VisualBasic/Portable/SimplifyTypeNames/SimplifyTypeNamesCodeFixProvider.vb @@ -21,11 +21,10 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.SimplifyTypeNames Protected Overrides Function GetTitle(simplifyDiagnosticId As String, nodeText As String) As String Select Case simplifyDiagnosticId Case IDEDiagnosticIds.SimplifyNamesDiagnosticId, - IDEDiagnosticIds.PreferIntrinsicPredefinedTypeInDeclarationsDiagnosticId + IDEDiagnosticIds.PreferBuiltInOrFrameworkTypeDiagnosticId Return String.Format(VBFeaturesResources.Simplify_name_0, nodeText) - Case IDEDiagnosticIds.SimplifyMemberAccessDiagnosticId, - IDEDiagnosticIds.PreferIntrinsicPredefinedTypeInMemberAccessDiagnosticId + Case IDEDiagnosticIds.SimplifyMemberAccessDiagnosticId Return String.Format(VBFeaturesResources.Simplify_member_access_0, nodeText) Case IDEDiagnosticIds.RemoveQualificationDiagnosticId diff --git a/src/VisualStudio/Core/Def/Implementation/AnalyzerDependency/AnalyzerFileWatcherService.cs b/src/VisualStudio/Core/Def/Implementation/AnalyzerDependency/AnalyzerFileWatcherService.cs index e9969d138fa1f822043588cfe4277781489a6b18..d11978d2fc6603b964c766c0924de945f2357128 100644 --- a/src/VisualStudio/Core/Def/Implementation/AnalyzerDependency/AnalyzerFileWatcherService.cs +++ b/src/VisualStudio/Core/Def/Implementation/AnalyzerDependency/AnalyzerFileWatcherService.cs @@ -25,6 +25,11 @@ internal sealed class AnalyzerFileWatcherService private readonly IVsFileChangeEx _fileChangeService; private readonly Dictionary _fileChangeTrackers = new Dictionary(StringComparer.OrdinalIgnoreCase); + + /// + /// Holds a list of assembly modified times that we can use to detect a file change prior to the being in place. + /// Once it's in place and subscribed, we'll remove the entry because any further changes will be detected that way. + /// private readonly Dictionary _assemblyUpdatedTimesUtc = new Dictionary(StringComparer.OrdinalIgnoreCase); private readonly object _guard = new object(); @@ -47,27 +52,6 @@ internal sealed class AnalyzerFileWatcherService _updateSource = hostDiagnosticUpdateSource; _fileChangeService = (IVsFileChangeEx)serviceProvider.GetService(typeof(SVsFileChangeEx)); } - - internal void ErrorIfAnalyzerAlreadyLoaded(ProjectId projectId, string analyzerPath) - { - DateTime loadedAssemblyUpdateTimeUtc; - lock (_guard) - { - if (!_assemblyUpdatedTimesUtc.TryGetValue(analyzerPath, out loadedAssemblyUpdateTimeUtc)) - { - return; - } - } - - DateTime? fileUpdateTimeUtc = GetLastUpdateTimeUtc(analyzerPath); - - if (fileUpdateTimeUtc != null && - loadedAssemblyUpdateTimeUtc != fileUpdateTimeUtc) - { - RaiseAnalyzerChangedWarning(projectId, analyzerPath); - } - } - internal void RemoveAnalyzerAlreadyLoadedDiagnostics(ProjectId projectId, string analyzerPath) { _updateSource.ClearDiagnosticsForProject(projectId, Tuple.Create(s_analyzerChangedErrorId, analyzerPath)); @@ -101,7 +85,7 @@ private void RaiseAnalyzerChangedWarning(ProjectId projectId, string analyzerPat } } - internal void AddPath(string filePath) + internal void TrackFilePathAndReportErrorIfChanged(string filePath, ProjectId projectId) { lock (_guard) { @@ -114,11 +98,39 @@ internal void AddPath(string filePath) _fileChangeTrackers.Add(filePath, tracker); } - DateTime? fileUpdateTime = GetLastUpdateTimeUtc(filePath); + DateTime assemblyUpdatedTime; - if (fileUpdateTime.HasValue) + if (_assemblyUpdatedTimesUtc.TryGetValue(filePath, out assemblyUpdatedTime)) + { + DateTime? currentFileUpdateTime = GetLastUpdateTimeUtc(filePath); + + if (currentFileUpdateTime != null) + { + if (currentFileUpdateTime != assemblyUpdatedTime) + { + RaiseAnalyzerChangedWarning(projectId, filePath); + } + + // If the the tracker is in place, at this point we can stop checking any further for this assembly + if (tracker.PreviousCallToStartFileChangeHasAsynchronouslyCompleted) + { + _assemblyUpdatedTimesUtc.Remove(filePath); + } + } + } + else { - _assemblyUpdatedTimesUtc[filePath] = fileUpdateTime.Value; + // We don't have an assembly updated time. This means we either haven't ever checked it, or we have a file watcher in place. + // If the file watcher is in place, then nothing further to do. Otherwise we'll add the update time to the map for future checking + if (!tracker.PreviousCallToStartFileChangeHasAsynchronouslyCompleted) + { + DateTime? currentFileUpdateTime = GetLastUpdateTimeUtc(filePath); + + if (currentFileUpdateTime != null) + { + _assemblyUpdatedTimesUtc[filePath] = currentFileUpdateTime.Value; + } + } } } } diff --git a/src/VisualStudio/Core/Def/Implementation/Diagnostics/DiagnosticProgressReporter.cs b/src/VisualStudio/Core/Def/Implementation/Diagnostics/DiagnosticProgressReporter.cs index 6219d7e60cbe0666941476f4ffbfcae9fc75b5a4..b84b6bfca7a3126b34376d884f2e547f507a1b4b 100644 --- a/src/VisualStudio/Core/Def/Implementation/Diagnostics/DiagnosticProgressReporter.cs +++ b/src/VisualStudio/Core/Def/Implementation/Diagnostics/DiagnosticProgressReporter.cs @@ -40,6 +40,12 @@ internal sealed class DiagnosticProgressReporter _taskCenterService = (IVsTaskStatusCenterService)serviceProvider.GetService(typeof(SVsTaskStatusCenterService)); _diagnosticService = diagnosticService; + _options = new TaskHandlerOptions() + { + Title = ServicesVSResources.Live_code_analysis, + ActionsAfterCompletion = CompletionActions.None + }; + var crawlerService = workspace.Services.GetService(); var reporter = crawlerService.GetProgressReporter(workspace); @@ -48,12 +54,6 @@ internal sealed class DiagnosticProgressReporter // no event unsubscription since it will remain alive until VS shutdown reporter.ProgressChanged += OnSolutionCrawlerProgressChanged; _diagnosticService.DiagnosticsUpdated += OnDiagnosticsUpdated; - - _options = new TaskHandlerOptions() - { - Title = ServicesVSResources.Live_code_analysis, - ActionsAfterCompletion = CompletionActions.None - }; } private void OnDiagnosticsUpdated(object sender, DiagnosticsUpdatedArgs e) diff --git a/src/VisualStudio/Core/Def/Implementation/ProjectSystem/AbstractProject_Analyzers.cs b/src/VisualStudio/Core/Def/Implementation/ProjectSystem/AbstractProject_Analyzers.cs index 2967fd455cc9d16a143263fdcf12e8080c5c124a..e66cf3250bc171b7d8ea784be14298bcf0b81acc 100644 --- a/src/VisualStudio/Core/Def/Implementation/ProjectSystem/AbstractProject_Analyzers.cs +++ b/src/VisualStudio/Core/Def/Implementation/ProjectSystem/AbstractProject_Analyzers.cs @@ -61,8 +61,7 @@ public void AddAnalyzerReference(string analyzerAssemblyFullPath) if (File.Exists(analyzerAssemblyFullPath)) { - GetAnalyzerFileWatcherService().AddPath(analyzerAssemblyFullPath); - GetAnalyzerFileWatcherService().ErrorIfAnalyzerAlreadyLoaded(Id, analyzerAssemblyFullPath); + GetAnalyzerFileWatcherService().TrackFilePathAndReportErrorIfChanged(analyzerAssemblyFullPath, projectId: Id); } else { diff --git a/src/VisualStudio/Core/Def/Implementation/ProjectSystem/DocumentProvider.StandardTextDocument.cs b/src/VisualStudio/Core/Def/Implementation/ProjectSystem/DocumentProvider.StandardTextDocument.cs index e28048f69d2e5f21897bf7471216ba39d5adf280..26bf9a64ce0525cf8433c1f855cc7d790e28af45 100644 --- a/src/VisualStudio/Core/Def/Implementation/ProjectSystem/DocumentProvider.StandardTextDocument.cs +++ b/src/VisualStudio/Core/Def/Implementation/ProjectSystem/DocumentProvider.StandardTextDocument.cs @@ -5,6 +5,8 @@ using System.Collections.Immutable; using System.Diagnostics; using System.IO; +using System.Threading; +using System.Threading.Tasks; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Editor.Shared.Extensions; using Microsoft.CodeAnalysis.Editor.Shared.Utilities; @@ -82,7 +84,7 @@ private class StandardTextDocument : ForegroundThreadAffinitizedObject, IVisualS // The project system does not tell us the CodePage specified in the proj file, so // we use null to auto-detect. - _doNotAccessDirectlyLoader = new FileTextLoader(documentKey.Moniker, defaultEncoding: null); + _doNotAccessDirectlyLoader = new FileChangeTrackingTextLoader(_fileChangeTracker, new FileTextLoader(documentKey.Moniker, defaultEncoding: null)); // If we aren't already open in the editor, then we should create a file change notification if (openTextBuffer == null) @@ -135,7 +137,6 @@ public TextLoader Loader { get { - _fileChangeTracker.EnsureSubscription(); return _doNotAccessDirectlyLoader; } } @@ -237,6 +238,33 @@ public uint GetItemId() return Project.Hierarchy.TryGetItemId(_itemMoniker); } + + /// + /// A wrapper for a that ensures we are watching file contents prior to reading the file. + /// + private sealed class FileChangeTrackingTextLoader : TextLoader + { + private readonly FileChangeTracker _fileChangeTracker; + private readonly TextLoader _innerTextLoader; + + public FileChangeTrackingTextLoader(FileChangeTracker fileChangeTracker, TextLoader innerTextLoader) + { + _fileChangeTracker = fileChangeTracker; + _innerTextLoader = innerTextLoader; + } + + public override Task LoadTextAndVersionAsync(Workspace workspace, DocumentId documentId, CancellationToken cancellationToken) + { + _fileChangeTracker.EnsureSubscription(); + return _innerTextLoader.LoadTextAndVersionAsync(workspace, documentId, cancellationToken); + } + + internal override TextAndVersion LoadTextAndVersionSynchronously(Workspace workspace, DocumentId documentId, CancellationToken cancellationToken) + { + _fileChangeTracker.EnsureSubscription(); + return _innerTextLoader.LoadTextAndVersionSynchronously(workspace, documentId, cancellationToken); + } + } } } } diff --git a/src/VisualStudio/Core/Def/Implementation/ProjectSystem/FileChangeTracker.cs b/src/VisualStudio/Core/Def/Implementation/ProjectSystem/FileChangeTracker.cs index e5de6fdc4596e7efa7f658522e1ff92fa2d457b4..1728e2a4b1435408901f1e0a46264ed88fc0c2f2 100644 --- a/src/VisualStudio/Core/Def/Implementation/ProjectSystem/FileChangeTracker.cs +++ b/src/VisualStudio/Core/Def/Implementation/ProjectSystem/FileChangeTracker.cs @@ -67,6 +67,18 @@ public string FilePath get { return _filePath; } } + /// + /// Returns true if a previous call to has completed. + /// + public bool PreviousCallToStartFileChangeHasAsynchronouslyCompleted + { + get + { + var cookie = _fileChangeCookie; + return cookie != s_none && cookie.IsValueCreated; + } + } + public void AssertUnsubscription() { // We must have been disposed properly. diff --git a/src/VisualStudio/Core/Def/Implementation/ProjectSystem/MetadataReferences/VisualStudioMetadataReference.Snapshot.cs b/src/VisualStudio/Core/Def/Implementation/ProjectSystem/MetadataReferences/VisualStudioMetadataReference.Snapshot.cs index ef977368d234e3aa6c75eb8b884734fb3e76dd8c..5338963261d1921c5e5dd2f5dc9b84eb895046c6 100644 --- a/src/VisualStudio/Core/Def/Implementation/ProjectSystem/MetadataReferences/VisualStudioMetadataReference.Snapshot.cs +++ b/src/VisualStudio/Core/Def/Implementation/ProjectSystem/MetadataReferences/VisualStudioMetadataReference.Snapshot.cs @@ -4,6 +4,7 @@ using System.Collections.Generic; using System.Diagnostics; using System.IO; +using System.Threading; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Execution; using Microsoft.CodeAnalysis.Host; @@ -31,7 +32,7 @@ internal partial class VisualStudioMetadataReference internal sealed class Snapshot : PortableExecutableReference, ISupportTemporaryStorage { private readonly VisualStudioMetadataReferenceManager _provider; - private readonly DateTime _timestamp; + private readonly Lazy _timestamp; private Exception _error; internal Snapshot(VisualStudioMetadataReferenceManager provider, MetadataReferenceProperties properties, string fullPath) @@ -40,20 +41,29 @@ internal Snapshot(VisualStudioMetadataReferenceManager provider, MetadataReferen Contract.Requires(Properties.Kind == MetadataImageKind.Assembly); _provider = provider; - try - { - _timestamp = FileUtilities.GetFileTimeStamp(this.FilePath); - } - catch (IOException e) - { - // Reading timestamp of a file might fail. - // Let's remember the failure and report it to the compiler when it asks for metadata. - _error = e; - } + _timestamp = new Lazy(() => { + try + { + return FileUtilities.GetFileTimeStamp(this.FilePath); + } + catch (IOException e) + { + // Reading timestamp of a file might fail. + // Let's remember the failure and report it to the compiler when it asks for metadata. + // We could let the Lazy hold onto this (since it knows how to rethrow exceptions), but + // our support of GetStorages needs to gracefully handle the case where we have no timestamp. + // If Lazy had a "IsValueFaulted" we could be cleaner here. + _error = e; + return DateTime.MinValue; + } + }, LazyThreadSafetyMode.PublicationOnly); } protected override Metadata GetMetadataImpl() { + // Fetch the timestamp first, so as to populate _error if needed + var timestamp = _timestamp.Value; + if (_error != null) { throw _error; @@ -61,7 +71,7 @@ protected override Metadata GetMetadataImpl() try { - return _provider.GetMetadata(this.FilePath, _timestamp); + return _provider.GetMetadata(this.FilePath, timestamp); } catch (Exception e) when (SaveMetadataReadingException(e)) { @@ -98,7 +108,7 @@ private string GetDebuggerDisplay() public IEnumerable GetStorages() { - return _provider.GetStorages(this.FilePath, _timestamp); + return _provider.GetStorages(this.FilePath, _timestamp.Value); } } } diff --git a/src/VisualStudio/Core/Test.Next/Services/VisualStudioDiagnosticAnalyzerExecutorTests.cs b/src/VisualStudio/Core/Test.Next/Services/VisualStudioDiagnosticAnalyzerExecutorTests.cs index dccc493c099d3df14ce874d0c465666ef54998d2..d6b367e27ffc59130e07096bd83bdd60005d6fc9 100644 --- a/src/VisualStudio/Core/Test.Next/Services/VisualStudioDiagnosticAnalyzerExecutorTests.cs +++ b/src/VisualStudio/Core/Test.Next/Services/VisualStudioDiagnosticAnalyzerExecutorTests.cs @@ -48,14 +48,17 @@ void Method() var analyzerType = typeof(CSharpUseExplicitTypeDiagnosticAnalyzer); var analyzerResult = await AnalyzeAsync(workspace, workspace.CurrentSolution.ProjectIds.First(), analyzerType); - Assert.True(analyzerResult.IsEmpty); + var diagnostics = analyzerResult.SemanticLocals[analyzerResult.DocumentIds.First()]; + Assert.Equal(IDEDiagnosticIds.UseExplicitTypeDiagnosticId, diagnostics[0].Id); + Assert.Equal(DiagnosticSeverity.Hidden, diagnostics[0].Severity); // set option workspace.Options = workspace.Options.WithChangedOption(CSharpCodeStyleOptions.UseImplicitTypeWhereApparent, new CodeStyleOption(false, NotificationOption.Suggestion)); analyzerResult = await AnalyzeAsync(workspace, workspace.CurrentSolution.ProjectIds.First(), analyzerType); - var diagnostics = analyzerResult.SemanticLocals[analyzerResult.DocumentIds.First()]; + diagnostics = analyzerResult.SemanticLocals[analyzerResult.DocumentIds.First()]; Assert.Equal(IDEDiagnosticIds.UseExplicitTypeDiagnosticId, diagnostics[0].Id); + Assert.Equal(DiagnosticSeverity.Info, diagnostics[0].Severity); } } diff --git a/src/Workspaces/CSharp/Portable/Utilities/CSharpTypeStyleHelper.cs b/src/Workspaces/CSharp/Portable/Utilities/CSharpTypeStyleHelper.cs index d9b6a077e4c632b6209741bd58fca3677ad52c63..a3ef2a55aa9b2c1193b6c747986006045e4b24ec 100644 --- a/src/Workspaces/CSharp/Portable/Utilities/CSharpTypeStyleHelper.cs +++ b/src/Workspaces/CSharp/Portable/Utilities/CSharpTypeStyleHelper.cs @@ -18,16 +18,17 @@ internal struct TypeStyleResult private readonly CancellationToken _cancellationToken; /// - /// Whether or not converting would transition the code to the style the user prefers. i.e. - /// if the user likes 'var' for everything, and you have 'int i = 0' then IsStylePreffered - /// will be true. however, if the user likes 'var' for everything and you have 'var i = 0', - /// then it's still possible to convert that, it would just be 'false' for IsStylePreferred - /// because it goes against the user's preferences. - /// - /// In general, most features should only convert the type if IsStylePreferred is true. The - /// one exception is the refactoring, which is explicitly there to still let people convert - /// things quickly, even if it's going against their stated style. + /// Whether or not converting would transition the code to the style the user prefers. i.e. if the user likes + /// var for everything, and you have int i = 0 then will be + /// . However, if the user likes var for everything and you have var i = 0, + /// then it's still possible to convert that, it would just be for + /// because it goes against the user's preferences. /// + /// + /// In general, most features should only convert the type if is + /// . The one exception is the refactoring, which is explicitly there to still let people + /// convert things quickly, even if it's going against their stated style. + /// public readonly bool IsStylePreferred; public readonly ReportDiagnostic Severity; diff --git a/src/Workspaces/Core/Portable/CodeStyle/CodeStyleHelpers.cs b/src/Workspaces/Core/Portable/CodeStyle/CodeStyleHelpers.cs index a57810cc67953346fc0128950e752bc00df0db65..f91a237848d891edd849cad20bb6f77d2d8d3c21 100644 --- a/src/Workspaces/Core/Portable/CodeStyle/CodeStyleHelpers.cs +++ b/src/Workspaces/Core/Portable/CodeStyle/CodeStyleHelpers.cs @@ -98,6 +98,7 @@ public static bool TryParseNotification(string value, out NotificationOption not notification = NotificationOption.None; return true; + case EditorConfigSeverityStrings.Refactoring: case EditorConfigSeverityStrings.Silent: notification = NotificationOption.Silent; return true; diff --git a/src/Workspaces/Core/Portable/CodeStyle/NotificationOption.cs b/src/Workspaces/Core/Portable/CodeStyle/NotificationOption.cs index a57024de419b9117bf8ca4371610fc6b73807924..3d6fe7d875d48e058359ed068450d948c8c43652 100644 --- a/src/Workspaces/Core/Portable/CodeStyle/NotificationOption.cs +++ b/src/Workspaces/Core/Portable/CodeStyle/NotificationOption.cs @@ -31,7 +31,7 @@ public DiagnosticSeverity Value } public static readonly NotificationOption None = new NotificationOption(WorkspacesResources.None, ReportDiagnostic.Suppress); - public static readonly NotificationOption Silent = new NotificationOption(WorkspacesResources.None, ReportDiagnostic.Hidden); + public static readonly NotificationOption Silent = new NotificationOption(WorkspacesResources.Refactoring_Only, ReportDiagnostic.Hidden); public static readonly NotificationOption Suggestion = new NotificationOption(WorkspacesResources.Suggestion, ReportDiagnostic.Info); public static readonly NotificationOption Warning = new NotificationOption(WorkspacesResources.Warning, ReportDiagnostic.Warn); public static readonly NotificationOption Error = new NotificationOption(WorkspacesResources.Error, ReportDiagnostic.Error); diff --git a/src/Workspaces/Core/Portable/Log/FunctionId.cs b/src/Workspaces/Core/Portable/Log/FunctionId.cs index daca6c05c2137053dbad0b4f4ef7f45bcff11574..00058d93140452d3cdfc434f217440f118b7cbf8 100644 --- a/src/Workspaces/Core/Portable/Log/FunctionId.cs +++ b/src/Workspaces/Core/Portable/Log/FunctionId.cs @@ -416,6 +416,7 @@ internal enum FunctionId RemoteHostService_SynchronizeTextAsync, SymbolFinder_Solution_Pattern_FindSourceDeclarationsAsync, - SymbolFinder_Project_Pattern_FindSourceDeclarationsAsync + SymbolFinder_Project_Pattern_FindSourceDeclarationsAsync, + Intellisense_Completion_Commit, } } diff --git a/src/Workspaces/Core/Portable/NamingStyles/EditorConfig/EditorConfigNamingStyleParser_NamingRule.cs b/src/Workspaces/Core/Portable/NamingStyles/EditorConfig/EditorConfigNamingStyleParser_NamingRule.cs index 4ba279e854f67287779d2e52567b93dfd66a2360..8a8e118770043de3c3b87d2cbd7ed3a88106f3ca 100644 --- a/src/Workspaces/Core/Portable/NamingStyles/EditorConfig/EditorConfigNamingStyleParser_NamingRule.cs +++ b/src/Workspaces/Core/Portable/NamingStyles/EditorConfig/EditorConfigNamingStyleParser_NamingRule.cs @@ -52,6 +52,7 @@ private static ReportDiagnostic ParseEnforcementLevel(string ruleSeverity) case EditorConfigSeverityStrings.None: return ReportDiagnostic.Suppress; + case EditorConfigSeverityStrings.Refactoring: case EditorConfigSeverityStrings.Silent: return ReportDiagnostic.Hidden; diff --git a/src/Workspaces/Core/Portable/NamingStyles/EditorConfig/EditorConfigSeverityStrings.cs b/src/Workspaces/Core/Portable/NamingStyles/EditorConfig/EditorConfigSeverityStrings.cs index 8dc1d15dd0c96cbdd493b55de939eae6f866fa5f..de3803eaee432ef72ff4e9d2d405082f24e6323b 100644 --- a/src/Workspaces/Core/Portable/NamingStyles/EditorConfig/EditorConfigSeverityStrings.cs +++ b/src/Workspaces/Core/Portable/NamingStyles/EditorConfig/EditorConfigSeverityStrings.cs @@ -5,6 +5,7 @@ namespace Microsoft.CodeAnalysis internal static class EditorConfigSeverityStrings { public const string None = "none"; + public const string Refactoring = "refactoring"; public const string Silent = "silent"; public const string Suggestion = "suggestion"; public const string Warning = "warning"; diff --git a/src/Workspaces/Core/Portable/WorkspacesResources.Designer.cs b/src/Workspaces/Core/Portable/WorkspacesResources.Designer.cs index 15a84c3dd8bb3b7328ba7df4d01fdd328c750a99..700fb28f8c3bdc39a979f7ee10426ebb8cae35ae 100644 --- a/src/Workspaces/Core/Portable/WorkspacesResources.Designer.cs +++ b/src/Workspaces/Core/Portable/WorkspacesResources.Designer.cs @@ -1052,6 +1052,15 @@ internal class WorkspacesResources { } } + /// + /// Looks up a localized string similar to Refactoring Only. + /// + internal static string Refactoring_Only { + get { + return ResourceManager.GetString("Refactoring_Only", resourceCulture); + } + } + /// /// Looks up a localized string similar to Removed:. /// diff --git a/src/Workspaces/Core/Portable/WorkspacesResources.resx b/src/Workspaces/Core/Portable/WorkspacesResources.resx index acb00e35c50f32b7958822689257196368e817b3..fe1cb1ebbad4d07189d4565ecb28e0e1f6807531 100644 --- a/src/Workspaces/Core/Portable/WorkspacesResources.resx +++ b/src/Workspaces/Core/Portable/WorkspacesResources.resx @@ -616,4 +616,7 @@ Changing document properties is not supported + + Refactoring Only + \ No newline at end of file diff --git a/src/Workspaces/Core/Portable/xlf/WorkspacesResources.cs.xlf b/src/Workspaces/Core/Portable/xlf/WorkspacesResources.cs.xlf index 92f1e2dfb509ed4fa7d626b78a75690648a7732b..0753052923faa332abfc6e2a54d962f0dc89b406 100644 --- a/src/Workspaces/Core/Portable/xlf/WorkspacesResources.cs.xlf +++ b/src/Workspaces/Core/Portable/xlf/WorkspacesResources.cs.xlf @@ -7,6 +7,11 @@ Došlo k chybě při čtení zadaného konfiguračního souboru: {0} + + Refactoring Only + Refactoring Only + + Symbol "{0}" is not from source. Symbol {0} nepochází ze zdroje. diff --git a/src/Workspaces/Core/Portable/xlf/WorkspacesResources.de.xlf b/src/Workspaces/Core/Portable/xlf/WorkspacesResources.de.xlf index d08d0641c00c6621ee12d0325bd0cb8b539e20ee..6fc9d5813edcb6215cd3cd7eabf27445abfc3c24 100644 --- a/src/Workspaces/Core/Portable/xlf/WorkspacesResources.de.xlf +++ b/src/Workspaces/Core/Portable/xlf/WorkspacesResources.de.xlf @@ -7,6 +7,11 @@ Beim Lesen der angegebenen Konfigurationsdatei ist ein Fehler aufgetreten: {0} + + Refactoring Only + Refactoring Only + + Symbol "{0}" is not from source. Symbol "{0}" ist nicht aus Quelle. diff --git a/src/Workspaces/Core/Portable/xlf/WorkspacesResources.es.xlf b/src/Workspaces/Core/Portable/xlf/WorkspacesResources.es.xlf index 453c56a7027ce29ee697884cabbde8bb2ddf8478..016ff3b13a6349918ab0180c80abc3ff5bffbb91 100644 --- a/src/Workspaces/Core/Portable/xlf/WorkspacesResources.es.xlf +++ b/src/Workspaces/Core/Portable/xlf/WorkspacesResources.es.xlf @@ -7,6 +7,11 @@ Error al leer el archivo de configuración especificado: {0} + + Refactoring Only + Refactoring Only + + Symbol "{0}" is not from source. El símbolo "{0}" no procede del código fuente. diff --git a/src/Workspaces/Core/Portable/xlf/WorkspacesResources.fr.xlf b/src/Workspaces/Core/Portable/xlf/WorkspacesResources.fr.xlf index 86e876e15b415be5476687b86278f1cbe532266c..1db9a2a0a251164f84fbbaf64a700856276edaf6 100644 --- a/src/Workspaces/Core/Portable/xlf/WorkspacesResources.fr.xlf +++ b/src/Workspaces/Core/Portable/xlf/WorkspacesResources.fr.xlf @@ -7,6 +7,11 @@ Une erreur s'est produite lors de la lecture du fichier de configuration spécifié : {0} + + Refactoring Only + Refactoring Only + + Symbol "{0}" is not from source. Le symbole "{0}" ne provient pas de la source. diff --git a/src/Workspaces/Core/Portable/xlf/WorkspacesResources.it.xlf b/src/Workspaces/Core/Portable/xlf/WorkspacesResources.it.xlf index 98356795f24041d9b7ad15e874cf08d40af21ca0..9779a548788c2364d493205965ba316c04e733b6 100644 --- a/src/Workspaces/Core/Portable/xlf/WorkspacesResources.it.xlf +++ b/src/Workspaces/Core/Portable/xlf/WorkspacesResources.it.xlf @@ -7,6 +7,11 @@ Si è verificato un errore durante la lettura del file di configurazione specificato: {0} + + Refactoring Only + Refactoring Only + + Symbol "{0}" is not from source. Il simbolo "{0}" non proviene dall'origine. diff --git a/src/Workspaces/Core/Portable/xlf/WorkspacesResources.ja.xlf b/src/Workspaces/Core/Portable/xlf/WorkspacesResources.ja.xlf index 90310c17b4fc71bff62145cd13fbb9e5acf33e5b..c3499c3dc1bcf572869d3e5d162fae2f3e46b168 100644 --- a/src/Workspaces/Core/Portable/xlf/WorkspacesResources.ja.xlf +++ b/src/Workspaces/Core/Portable/xlf/WorkspacesResources.ja.xlf @@ -7,6 +7,11 @@ 指定した構成ファイルの読み取り中にエラーが発生しました: {0} + + Refactoring Only + Refactoring Only + + Symbol "{0}" is not from source. シンボル "{0}" は、ソースからではありません。 diff --git a/src/Workspaces/Core/Portable/xlf/WorkspacesResources.ko.xlf b/src/Workspaces/Core/Portable/xlf/WorkspacesResources.ko.xlf index 34b91d971c0f83b523ab44d87061187961d2d0e5..de90cfed2bcb3cd5f923c76036718a2a0fa254ea 100644 --- a/src/Workspaces/Core/Portable/xlf/WorkspacesResources.ko.xlf +++ b/src/Workspaces/Core/Portable/xlf/WorkspacesResources.ko.xlf @@ -7,6 +7,11 @@ 지정한 구성 파일을 읽는 동안 오류가 발생했습니다({0}). + + Refactoring Only + Refactoring Only + + Symbol "{0}" is not from source. "{0}" 기호가 소스에 없습니다. diff --git a/src/Workspaces/Core/Portable/xlf/WorkspacesResources.pl.xlf b/src/Workspaces/Core/Portable/xlf/WorkspacesResources.pl.xlf index 757392fe54de6cd9e7e678f2906ebdde4f98d2b5..69909972e3055f73a8bfc2698dbf526098470ebe 100644 --- a/src/Workspaces/Core/Portable/xlf/WorkspacesResources.pl.xlf +++ b/src/Workspaces/Core/Portable/xlf/WorkspacesResources.pl.xlf @@ -7,6 +7,11 @@ Wystąpił błąd podczas odczytywania określonego pliku konfiguracji: {0} + + Refactoring Only + Refactoring Only + + Symbol "{0}" is not from source. Symbol „{0}” nie pochodzi ze źródła. diff --git a/src/Workspaces/Core/Portable/xlf/WorkspacesResources.pt-BR.xlf b/src/Workspaces/Core/Portable/xlf/WorkspacesResources.pt-BR.xlf index 668bf6698c45b8ddf4dbbe527c114be293e8f570..ab54002cf5ae52deb14e87b9fbe3f98e9370b785 100644 --- a/src/Workspaces/Core/Portable/xlf/WorkspacesResources.pt-BR.xlf +++ b/src/Workspaces/Core/Portable/xlf/WorkspacesResources.pt-BR.xlf @@ -7,6 +7,11 @@ Ocorreu um erro ao ler o arquivo de configuração especificado: {0} + + Refactoring Only + Refactoring Only + + Symbol "{0}" is not from source. Símbolo "{0}" não é da fonte. diff --git a/src/Workspaces/Core/Portable/xlf/WorkspacesResources.ru.xlf b/src/Workspaces/Core/Portable/xlf/WorkspacesResources.ru.xlf index 66c6cd2723170a80e2bb19999dc39678a6f80573..1b2f799d50b3d29f344e0680d1b5ced33ce9b053 100644 --- a/src/Workspaces/Core/Portable/xlf/WorkspacesResources.ru.xlf +++ b/src/Workspaces/Core/Portable/xlf/WorkspacesResources.ru.xlf @@ -7,6 +7,11 @@ Произошла ошибка при чтении указанного файла конфигурации: {0} + + Refactoring Only + Refactoring Only + + Symbol "{0}" is not from source. Символ "{0}" не из источника. diff --git a/src/Workspaces/Core/Portable/xlf/WorkspacesResources.tr.xlf b/src/Workspaces/Core/Portable/xlf/WorkspacesResources.tr.xlf index 6f2fe04e95a06902d3250cf9fb05f741b105d910..8250b8e1b4d4813a9806c51b85216b30a8112c54 100644 --- a/src/Workspaces/Core/Portable/xlf/WorkspacesResources.tr.xlf +++ b/src/Workspaces/Core/Portable/xlf/WorkspacesResources.tr.xlf @@ -7,6 +7,11 @@ Belirtilen yapılandırma dosyası okunurken bir hata oluştu: {0} + + Refactoring Only + Refactoring Only + + Symbol "{0}" is not from source. "{0}" sembolü kaynağa ait değil. diff --git a/src/Workspaces/Core/Portable/xlf/WorkspacesResources.zh-Hans.xlf b/src/Workspaces/Core/Portable/xlf/WorkspacesResources.zh-Hans.xlf index 9220b88041cb4624e097680262d4097c6fd01020..802b52ac38ee87486c7aa7f595b66c436947af21 100644 --- a/src/Workspaces/Core/Portable/xlf/WorkspacesResources.zh-Hans.xlf +++ b/src/Workspaces/Core/Portable/xlf/WorkspacesResources.zh-Hans.xlf @@ -7,6 +7,11 @@ 读取指定的配置文件时出错: {0} + + Refactoring Only + Refactoring Only + + Symbol "{0}" is not from source. 符号“{0}”不是来自源。 diff --git a/src/Workspaces/Core/Portable/xlf/WorkspacesResources.zh-Hant.xlf b/src/Workspaces/Core/Portable/xlf/WorkspacesResources.zh-Hant.xlf index b880785ee64c65cca8278bd77ad54003a561068d..5c2a5bc990ac1ab53ecbab10b977f5ba9e771ec0 100644 --- a/src/Workspaces/Core/Portable/xlf/WorkspacesResources.zh-Hant.xlf +++ b/src/Workspaces/Core/Portable/xlf/WorkspacesResources.zh-Hant.xlf @@ -7,6 +7,11 @@ 讀取指定的組態檔時發生錯誤: {0} + + Refactoring Only + Refactoring Only + + Symbol "{0}" is not from source. 符號 "{0}" 非來自來源。 diff --git a/src/Workspaces/CoreTest/CodeStyle/EditorConfigCodeStyleParserTests.cs b/src/Workspaces/CoreTest/CodeStyle/EditorConfigCodeStyleParserTests.cs index 2245639057b460a88f07e0347349e90af63b9769..90b6eeaaf0a04ad1bfd3bce1808f814b43e15aa4 100644 --- a/src/Workspaces/CoreTest/CodeStyle/EditorConfigCodeStyleParserTests.cs +++ b/src/Workspaces/CoreTest/CodeStyle/EditorConfigCodeStyleParserTests.cs @@ -14,12 +14,14 @@ public class EditorConfigCodeStyleParserTests { [Theory] [InlineData("true:none", true, ReportDiagnostic.Suppress)] + [InlineData("true:refactoring", true, ReportDiagnostic.Hidden)] [InlineData("true:silent", true, ReportDiagnostic.Hidden)] [InlineData("true:suggestion", true, ReportDiagnostic.Info)] [InlineData("true:warning", true, ReportDiagnostic.Warn)] [InlineData("true:error", true, ReportDiagnostic.Error)] [InlineData("true", false, ReportDiagnostic.Hidden)] [InlineData("false:none", false, ReportDiagnostic.Suppress)] + [InlineData("false:refactoring", false, ReportDiagnostic.Hidden)] [InlineData("false:silent", false, ReportDiagnostic.Hidden)] [InlineData("false:suggestion", false, ReportDiagnostic.Info)] [InlineData("false:warning", false, ReportDiagnostic.Warn)]