From 9d3f7a7c08afce248dbd3ef3e387fcb8a06bd1ae Mon Sep 17 00:00:00 2001 From: CyrusNajmabadi Date: Sun, 9 Oct 2016 15:20:32 -0700 Subject: [PATCH] Use expression bodied methods if desired. --- .../CSharp/Portable/CSharpWorkspace.csproj | 3 +- .../CSharpCodeGenerationService.cs | 11 ++-- .../CodeGeneration/CodeGenerationHelpers.cs | 50 +++++++++++++++++ .../CodeGeneration/MethodGenerator.cs | 50 ++++++++++++++--- .../CodeGeneration/PropertyGenerator.cs | 56 ++++++------------- 5 files changed, 118 insertions(+), 52 deletions(-) create mode 100644 src/Workspaces/CSharp/Portable/CodeGeneration/CodeGenerationHelpers.cs diff --git a/src/Workspaces/CSharp/Portable/CSharpWorkspace.csproj b/src/Workspaces/CSharp/Portable/CSharpWorkspace.csproj index 15b4d2afe76..126c26c83a6 100644 --- a/src/Workspaces/CSharp/Portable/CSharpWorkspace.csproj +++ b/src/Workspaces/CSharp/Portable/CSharpWorkspace.csproj @@ -65,6 +65,7 @@ + @@ -244,4 +245,4 @@ - + \ No newline at end of file diff --git a/src/Workspaces/CSharp/Portable/CodeGeneration/CSharpCodeGenerationService.cs b/src/Workspaces/CSharp/Portable/CodeGeneration/CSharpCodeGenerationService.cs index 15a58acc55f..f82578ba4b8 100644 --- a/src/Workspaces/CSharp/Portable/CodeGeneration/CSharpCodeGenerationService.cs +++ b/src/Workspaces/CSharp/Portable/CodeGeneration/CSharpCodeGenerationService.cs @@ -161,7 +161,8 @@ protected override TDeclarationNode AddMethod(TDeclarationNode return Cast(OperatorGenerator.AddOperatorTo(typeDeclaration, method, options, availableIndices)); } - return Cast(MethodGenerator.AddMethodTo(typeDeclaration, method, options, availableIndices)); + return Cast(MethodGenerator.AddMethodTo( + typeDeclaration, method, Workspace, options, availableIndices)); } if (method.IsConstructor() || @@ -173,11 +174,13 @@ protected override TDeclarationNode AddMethod(TDeclarationNode var compilationUnit = destination as CompilationUnitSyntax; if (compilationUnit != null) { - return Cast(MethodGenerator.AddMethodTo(compilationUnit, method, options, availableIndices)); + return Cast( + MethodGenerator.AddMethodTo(compilationUnit, method, Workspace, options, availableIndices)); } var ns = Cast(destination); - return Cast(MethodGenerator.AddMethodTo(ns, method, options, availableIndices)); + return Cast( + MethodGenerator.AddMethodTo(ns, method, Workspace, options, availableIndices)); } protected override TDeclarationNode AddProperty(TDeclarationNode destination, IPropertySymbol property, CodeGenerationOptions options, IList availableIndices) @@ -629,7 +632,7 @@ public override SyntaxNode CreateFieldDeclaration(IFieldSymbol field, CodeGenera } else { - return MethodGenerator.GenerateMethodDeclaration(method, destination, options); + return MethodGenerator.GenerateMethodDeclaration(method, destination, Workspace, options); } } diff --git a/src/Workspaces/CSharp/Portable/CodeGeneration/CodeGenerationHelpers.cs b/src/Workspaces/CSharp/Portable/CodeGeneration/CodeGenerationHelpers.cs new file mode 100644 index 00000000000..247614b277b --- /dev/null +++ b/src/Workspaces/CSharp/Portable/CodeGeneration/CodeGenerationHelpers.cs @@ -0,0 +1,50 @@ +// 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 Microsoft.CodeAnalysis.CSharp.Syntax; + +namespace Microsoft.CodeAnalysis.CSharp.CodeGeneration +{ + internal static class CodeGenerationHelpers + { + public static ArrowExpressionClauseSyntax TryConvertToExpressionBody(BlockSyntax block) + { + if (block != null && block.Statements.Count == 1) + { + var firstStatement = block.Statements[0]; + var expression = TryGetExpression(firstStatement); + if (expression != null) + { + return SyntaxFactory.ArrowExpressionClause(expression); + } + } + + return null; + } + + private static ExpressionSyntax TryGetExpression(StatementSyntax firstStatement) + { + if (firstStatement.Kind() == SyntaxKind.ExpressionStatement) + { + return ((ExpressionStatementSyntax)firstStatement).Expression; + } + else if (firstStatement.Kind() == SyntaxKind.ReturnStatement) + { + var returnStatement = (ReturnStatementSyntax)firstStatement; + if (returnStatement.Expression != null) + { + return returnStatement.Expression; + } + } + else if (firstStatement.Kind() == SyntaxKind.ThrowStatement) + { + var throwStatement = (ThrowStatementSyntax)firstStatement; + if (throwStatement.Expression != null) + { + return SyntaxFactory.ThrowExpression(throwStatement.ThrowKeyword, throwStatement.Expression); + } + } + + return null; + } + } +} \ No newline at end of file diff --git a/src/Workspaces/CSharp/Portable/CodeGeneration/MethodGenerator.cs b/src/Workspaces/CSharp/Portable/CodeGeneration/MethodGenerator.cs index bba77d7fbfa..09ead9a1844 100644 --- a/src/Workspaces/CSharp/Portable/CodeGeneration/MethodGenerator.cs +++ b/src/Workspaces/CSharp/Portable/CodeGeneration/MethodGenerator.cs @@ -1,8 +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; using System.Collections.Generic; using System.Linq; using Microsoft.CodeAnalysis.CodeGeneration; +using Microsoft.CodeAnalysis.CSharp.CodeStyle; using Microsoft.CodeAnalysis.CSharp.Extensions; using Microsoft.CodeAnalysis.CSharp.Symbols; using Microsoft.CodeAnalysis.CSharp.Syntax; @@ -17,10 +19,12 @@ internal static class MethodGenerator internal static NamespaceDeclarationSyntax AddMethodTo( NamespaceDeclarationSyntax destination, IMethodSymbol method, + Workspace workspace, CodeGenerationOptions options, IList availableIndices) { - var declaration = GenerateMethodDeclaration(method, CodeGenerationDestination.Namespace, options); + var declaration = GenerateMethodDeclaration( + method, CodeGenerationDestination.Namespace, workspace, options); var members = Insert(destination.Members, declaration, options, availableIndices, after: LastMethod); return destination.WithMembers(members.ToSyntaxList()); } @@ -28,10 +32,12 @@ internal static class MethodGenerator internal static CompilationUnitSyntax AddMethodTo( CompilationUnitSyntax destination, IMethodSymbol method, + Workspace workspace, CodeGenerationOptions options, IList availableIndices) { - var declaration = GenerateMethodDeclaration(method, CodeGenerationDestination.CompilationUnit, options); + var declaration = GenerateMethodDeclaration( + method, CodeGenerationDestination.CompilationUnit, workspace, options); var members = Insert(destination.Members, declaration, options, availableIndices, after: LastMethod); return destination.WithMembers(members.ToSyntaxList()); } @@ -39,10 +45,12 @@ internal static class MethodGenerator internal static TypeDeclarationSyntax AddMethodTo( TypeDeclarationSyntax destination, IMethodSymbol method, + Workspace workspace, CodeGenerationOptions options, IList availableIndices) { - var methodDeclaration = GenerateMethodDeclaration(method, GetDestination(destination), options); + var methodDeclaration = GenerateMethodDeclaration( + method, GetDestination(destination), workspace, options); // Create a clone of the original type with the new method inserted. var members = Insert(destination.Members, methodDeclaration, options, availableIndices, after: LastMethod); @@ -51,7 +59,8 @@ internal static class MethodGenerator } public static MethodDeclarationSyntax GenerateMethodDeclaration( - IMethodSymbol method, CodeGenerationDestination destination, CodeGenerationOptions options) + IMethodSymbol method, CodeGenerationDestination destination, + Workspace workspace, CodeGenerationOptions options) { options = options ?? CodeGenerationOptions.Default; @@ -61,14 +70,15 @@ internal static class MethodGenerator return reusableSyntax; } - var declaration = GenerateMethodDeclarationWorker(method, destination, options); + var declaration = GenerateMethodDeclarationWorker(method, destination, workspace, options); return AddAnnotationsTo(method, ConditionallyAddDocumentationCommentTo(declaration, method, options)); } private static MethodDeclarationSyntax GenerateMethodDeclarationWorker( - IMethodSymbol method, CodeGenerationDestination destination, CodeGenerationOptions options) + IMethodSymbol method, CodeGenerationDestination destination, + Workspace workspace, CodeGenerationOptions options) { var hasNoBody = !options.GenerateMethodBodies || destination == CodeGenerationDestination.InterfaceType || @@ -80,7 +90,7 @@ internal static class MethodGenerator ? method.ReturnType.GenerateRefTypeSyntax() : method.ReturnType.GenerateTypeSyntax(); - return AddCleanupAnnotationsTo(SyntaxFactory.MethodDeclaration( + var methodDeclaration = SyntaxFactory.MethodDeclaration( attributeLists: GenerateAttributes(method, options, explicitInterfaceSpecifier != null), modifiers: GenerateModifiers(method, destination, options), returnType: returnType, @@ -91,7 +101,31 @@ internal static class MethodGenerator constraintClauses: GenerateConstraintClauses(method), body: hasNoBody ? null : StatementGenerator.GenerateBlock(method), expressionBody: default(ArrowExpressionClauseSyntax), - semicolonToken: hasNoBody ? SyntaxFactory.Token(SyntaxKind.SemicolonToken) : new SyntaxToken())); + semicolonToken: hasNoBody ? SyntaxFactory.Token(SyntaxKind.SemicolonToken) : new SyntaxToken()); + + methodDeclaration = UseExpressionBodyIfDesired(workspace, methodDeclaration); + + return AddCleanupAnnotationsTo(methodDeclaration); + } + + private static MethodDeclarationSyntax UseExpressionBodyIfDesired( + Workspace workspace, MethodDeclarationSyntax methodDeclaration) + { + if (methodDeclaration.ExpressionBody == null) + { + var preferExpressionBody = workspace.Options.GetOption(CSharpCodeStyleOptions.PreferExpressionBodiedMethods).Value; + if (preferExpressionBody) + { + var expressionBody = CodeGenerationHelpers.TryConvertToExpressionBody(methodDeclaration.Body); + if (expressionBody != null) + { + return methodDeclaration.WithBody(null) + .WithExpressionBody(expressionBody); + } + } + } + + return methodDeclaration; } private static SyntaxList GenerateAttributes( diff --git a/src/Workspaces/CSharp/Portable/CodeGeneration/PropertyGenerator.cs b/src/Workspaces/CSharp/Portable/CodeGeneration/PropertyGenerator.cs index cbd2815695f..b4736b73e24 100644 --- a/src/Workspaces/CSharp/Portable/CodeGeneration/PropertyGenerator.cs +++ b/src/Workspaces/CSharp/Portable/CodeGeneration/PropertyGenerator.cs @@ -132,21 +132,24 @@ public static bool CanBeGenerated(IPropertySymbol property) private static PropertyDeclarationSyntax UseExpressionBodyIfDesired( Workspace workspace, PropertyDeclarationSyntax propertyDeclaration) { - var preferExpressionBody = workspace.Options.GetOption(CSharpCodeStyleOptions.PreferExpressionBodiedProperties).Value; - if (preferExpressionBody) + if (propertyDeclaration.ExpressionBody == null) { - if (propertyDeclaration.Initializer == null && - propertyDeclaration.AccessorList.Accessors.Count == 1) + var preferExpressionBody = workspace.Options.GetOption(CSharpCodeStyleOptions.PreferExpressionBodiedProperties).Value; + if (preferExpressionBody) { - var accessor = propertyDeclaration.AccessorList.Accessors[0]; - if (accessor.IsKind(SyntaxKind.GetAccessorDeclaration)) + if (propertyDeclaration.Initializer == null && + propertyDeclaration.AccessorList.Accessors.Count == 1) { - var expressionBody = TryGetExpressionBody(accessor); - if (expressionBody != null) + var accessor = propertyDeclaration.AccessorList.Accessors[0]; + if (accessor.IsKind(SyntaxKind.GetAccessorDeclaration)) { - propertyDeclaration = propertyDeclaration.WithAccessorList(null) - .WithExpressionBody(expressionBody) - .WithSemicolonToken(SyntaxFactory.Token(SyntaxKind.SemicolonToken)); + var expressionBody = TryGetExpressionBody(accessor); + if (expressionBody != null) + { + propertyDeclaration = propertyDeclaration.WithAccessorList(null) + .WithExpressionBody(expressionBody) + .WithSemicolonToken(SyntaxFactory.Token(SyntaxKind.SemicolonToken)); + } } } } @@ -159,34 +162,9 @@ private static ArrowExpressionClauseSyntax TryGetExpressionBody(AccessorDeclarat { // If the accessor has an expression body already, then use that as the expression body // for the property. - if (accessor.ExpressionBody != null) - { - return accessor.ExpressionBody; - } - - if (accessor.Body != null) - { - if (accessor.Body.Statements.Count == 1) - { - var firstStatement = accessor.Body.Statements[0]; - if (firstStatement.Kind() == SyntaxKind.ReturnStatement) - { - var returnStatement = (ReturnStatementSyntax)firstStatement; - if (returnStatement.Expression != null) - { - return SyntaxFactory.ArrowExpressionClause(returnStatement.Expression); - } - } - else if (firstStatement.Kind() == SyntaxKind.ThrowStatement) - { - var throwStatement = (ThrowStatementSyntax)firstStatement; - return SyntaxFactory.ArrowExpressionClause( - SyntaxFactory.ThrowExpression(throwStatement.ThrowKeyword, throwStatement.Expression)); - } - } - } - - return null; + return accessor.ExpressionBody != null + ? accessor.ExpressionBody + : CodeGenerationHelpers.TryConvertToExpressionBody(accessor.Body); } private static AccessorListSyntax GenerateAccessorList( -- GitLab