diff --git a/src/Analyzers/CSharp/Analyzers/UseExpressionBodyForLambda/UseExpressionBodyForLambdaHelpers.cs b/src/Analyzers/CSharp/Analyzers/UseExpressionBodyForLambda/UseExpressionBodyForLambdaHelpers.cs index bb2a81c2f53ba..f2ddccdc64584 100644 --- a/src/Analyzers/CSharp/Analyzers/UseExpressionBodyForLambda/UseExpressionBodyForLambdaHelpers.cs +++ b/src/Analyzers/CSharp/Analyzers/UseExpressionBodyForLambda/UseExpressionBodyForLambdaHelpers.cs @@ -3,6 +3,7 @@ // See the LICENSE file in the project root for more information. using System.Diagnostics.CodeAnalysis; +using System.Linq; using System.Threading; using Microsoft.CodeAnalysis.CodeStyle; using Microsoft.CodeAnalysis.CSharp.Extensions; @@ -112,6 +113,33 @@ internal static bool TryConvertToExpressionBody( { var body = declaration.Body as BlockSyntax; - return body.TryConvertToExpressionBody(languageVersion, conversionPreference, cancellationToken, out expression, out _); + if (!body.TryConvertToExpressionBody(languageVersion, conversionPreference, cancellationToken, out expression, out var semicolonToken)) + return false; + + // If we have directives, we have something like: + // + // X(c => + // { + // #if DEBUG + // Y(); + // #else + // Z(); + // #endif + // }); + // + // Converting this to an expression body is a little too complex for us to support currently. We'd have to grab + // out the parts of the #else/#elif blocks, grab out their expressions, and rewrite into a form like so: + // + // X(c => + // #if DEBUG + // Y() + // #else + // Z() + // #endif + // ); + if (semicolonToken.TrailingTrivia.Any(t => t.IsDirective)) + return false; + + return true; } } diff --git a/src/Features/CSharp/Portable/UseExpressionBody/UseExpressionBodyCodeRefactoringProvider.cs b/src/Features/CSharp/Portable/UseExpressionBody/UseExpressionBodyCodeRefactoringProvider.cs index 70ab88f8b6b8c..56b6366f8a0c5 100644 --- a/src/Features/CSharp/Portable/UseExpressionBody/UseExpressionBodyCodeRefactoringProvider.cs +++ b/src/Features/CSharp/Portable/UseExpressionBody/UseExpressionBodyCodeRefactoringProvider.cs @@ -28,19 +28,15 @@ namespace Microsoft.CodeAnalysis.CSharp.UseExpressionBody; [ExportCodeRefactoringProvider(LanguageNames.CSharp, Name = PredefinedCodeRefactoringProviderNames.UseExpressionBody), Shared] [ExtensionOrder(Before = PredefinedCodeRefactoringProviderNames.ExtractClass)] -internal class UseExpressionBodyCodeRefactoringProvider : SyntaxEditorBasedCodeRefactoringProvider +[method: ImportingConstructor] +[method: SuppressMessage("RoslynDiagnosticsReliability", "RS0033:Importing constructor should be [Obsolete]", Justification = "Used in test code: https://github.com/dotnet/roslyn/issues/42814")] +internal sealed class UseExpressionBodyCodeRefactoringProvider() : SyntaxEditorBasedCodeRefactoringProvider { private static readonly ImmutableArray _helpers = UseExpressionBodyHelper.Helpers; private static readonly BidirectionalMap<(UseExpressionBodyHelper helper, bool useExpressionBody), string> s_equivalenceKeyMap = CreateEquivalanceKeyMap(UseExpressionBodyHelper.Helpers); - [ImportingConstructor] - [SuppressMessage("RoslynDiagnosticsReliability", "RS0033:Importing constructor should be [Obsolete]", Justification = "Used in test code: https://github.com/dotnet/roslyn/issues/42814")] - public UseExpressionBodyCodeRefactoringProvider() - { - } - private static BidirectionalMap<(UseExpressionBodyHelper helper, bool useExpressionBody), string> CreateEquivalanceKeyMap( ImmutableArray helpers) { @@ -127,9 +123,9 @@ private static bool TryComputeRefactoring( context.RegisterRefactoring( CodeAction.Create( helper.UseExpressionBodyTitle.ToString(), - c => UpdateDocumentAsync( + cancellationToken => UpdateDocumentAsync( document, root, declaration, helper, - useExpressionBody: true, cancellationToken: c), + useExpressionBody: true, cancellationToken), s_equivalenceKeyMap[(helper, useExpressionBody: true)]), declaration.Span); succeeded = true; @@ -140,9 +136,9 @@ private static bool TryComputeRefactoring( context.RegisterRefactoring( CodeAction.Create( helper.UseBlockBodyTitle.ToString(), - c => UpdateDocumentAsync( + cancellationToken => UpdateDocumentAsync( document, root, declaration, helper, - useExpressionBody: false, cancellationToken: c), + useExpressionBody: false, cancellationToken), s_equivalenceKeyMap[(helper, useExpressionBody: false)]), declaration.Span); succeeded = true; diff --git a/src/Features/CSharp/Portable/UseExpressionBodyForLambda/UseExpressionBodyForLambdaCodeRefactoringProvider.cs b/src/Features/CSharp/Portable/UseExpressionBodyForLambda/UseExpressionBodyForLambdaCodeRefactoringProvider.cs index 124e0daf8ad2e..4b4f7d5970f22 100644 --- a/src/Features/CSharp/Portable/UseExpressionBodyForLambda/UseExpressionBodyForLambdaCodeRefactoringProvider.cs +++ b/src/Features/CSharp/Portable/UseExpressionBodyForLambda/UseExpressionBodyForLambdaCodeRefactoringProvider.cs @@ -22,14 +22,10 @@ namespace Microsoft.CodeAnalysis.CSharp.UseExpressionBodyForLambda; [ExportCodeRefactoringProvider(LanguageNames.CSharp, Name = PredefinedCodeRefactoringProviderNames.UseExpressionBodyForLambda), Shared] -internal sealed class UseExpressionBodyForLambdaCodeRefactoringProvider : CodeRefactoringProvider +[method: ImportingConstructor] +[method: SuppressMessage("RoslynDiagnosticsReliability", "RS0033:Importing constructor should be [Obsolete]", Justification = "Used in test code: https://github.com/dotnet/roslyn/issues/42814")] +internal sealed class UseExpressionBodyForLambdaCodeRefactoringProvider() : CodeRefactoringProvider { - [ImportingConstructor] - [SuppressMessage("RoslynDiagnosticsReliability", "RS0033:Importing constructor should be [Obsolete]", Justification = "Used in test code: https://github.com/dotnet/roslyn/issues/42814")] - public UseExpressionBodyForLambdaCodeRefactoringProvider() - { - } - public override async Task ComputeRefactoringsAsync(CodeRefactoringContext context) { var document = context.Document; diff --git a/src/Features/CSharpTest/UseExpressionBodyForLambda/UseExpressionBodyForLambdasRefactoringTests.cs b/src/Features/CSharpTest/UseExpressionBodyForLambda/UseExpressionBodyForLambdasRefactoringTests.cs index ebe2273829beb..fed4ea0b006aa 100644 --- a/src/Features/CSharpTest/UseExpressionBodyForLambda/UseExpressionBodyForLambdasRefactoringTests.cs +++ b/src/Features/CSharpTest/UseExpressionBodyForLambda/UseExpressionBodyForLambdasRefactoringTests.cs @@ -11,12 +11,13 @@ using Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.CodeRefactorings; using Microsoft.CodeAnalysis.Editor.UnitTests.CodeActions; using Microsoft.CodeAnalysis.Test.Utilities; +using Roslyn.Test.Utilities; using Xunit; namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.UseExpressionBody; [Trait(Traits.Feature, Traits.Features.CodeActionsUseExpressionBody)] -public class UseExpressionBodyForLambdasRefactoringTests : AbstractCSharpCodeActionTest_NoEditor +public sealed class UseExpressionBodyForLambdasRefactoringTests : AbstractCSharpCodeActionTest_NoEditor { protected override CodeRefactoringProvider CreateCodeRefactoringProvider(TestWorkspace workspace, TestParameters parameters) => new UseExpressionBodyForLambdaCodeRefactoringProvider(); @@ -208,4 +209,20 @@ void Goo() } """, parameters: new TestParameters(options: UseExpressionBody)); } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/74137")] + public async Task TestNotWithPreprocessorDirectives() + { + await TestMissingAsync( + """ + app.UseSwaggerUI(c [||]=> + { + #if DEBUG + c.SwaggerEndpoint("/swagger/v1/swagger.json", "API V1"); + #else + c.SwaggerEndpoint("/api/swagger/v1/swagger.json", "API V1"); + #endif + }); + """, parameters: new TestParameters(options: UseExpressionBodyDisabledDiagnostic)); + } }