Browse Source

Add expression body syntax for getter-only properties.

pull/1087/head
Siegfried Pammer 8 years ago
parent
commit
c382989904
  1. 36
      ICSharpCode.Decompiler/CSharp/OutputVisitor/CSharpOutputVisitor.cs
  2. 3
      ICSharpCode.Decompiler/CSharp/Syntax/Expressions/LambdaExpression.cs
  3. 1
      ICSharpCode.Decompiler/CSharp/Syntax/Roles.cs
  4. 11
      ICSharpCode.Decompiler/CSharp/Syntax/TypeMembers/PropertyDeclaration.cs
  5. 24
      ICSharpCode.Decompiler/CSharp/Transforms/NormalizeBlockStatements.cs
  6. 15
      ICSharpCode.Decompiler/DecompilerSettings.cs

36
ICSharpCode.Decompiler/CSharp/OutputVisitor/CSharpOutputVisitor.cs

@ -866,7 +866,7 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor @@ -866,7 +866,7 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor
lambdaExpression.Parameters.Single().AcceptVisitor(this);
}
Space();
WriteToken(LambdaExpression.ArrowRole);
WriteToken(Roles.Arrow);
if (lambdaExpression.Body is BlockStatement) {
WriteBlock((BlockStatement)lambdaExpression.Body, policy.AnonymousMethodBraceStyle);
} else {
@ -2179,22 +2179,30 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor @@ -2179,22 +2179,30 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor
Space();
WritePrivateImplementationType(propertyDeclaration.PrivateImplementationType);
WriteIdentifier(propertyDeclaration.NameToken);
OpenBrace(policy.PropertyBraceStyle);
// output get/set in their original order
foreach (AstNode node in propertyDeclaration.Children) {
if (node.Role == IndexerDeclaration.GetterRole || node.Role == IndexerDeclaration.SetterRole) {
node.AcceptVisitor(this);
if (propertyDeclaration.ExpressionBody.IsNull) {
OpenBrace(policy.PropertyBraceStyle);
// output get/set in their original order
foreach (AstNode node in propertyDeclaration.Children) {
if (node.Role == IndexerDeclaration.GetterRole || node.Role == IndexerDeclaration.SetterRole) {
node.AcceptVisitor(this);
}
}
}
CloseBrace(policy.PropertyBraceStyle);
if (!propertyDeclaration.Initializer.IsNull) {
Space(policy.SpaceAroundAssignment);
WriteToken(Roles.Assign);
Space(policy.SpaceAroundAssignment);
propertyDeclaration.Initializer.AcceptVisitor(this);
CloseBrace(policy.PropertyBraceStyle);
if (!propertyDeclaration.Initializer.IsNull) {
Space(policy.SpaceAroundAssignment);
WriteToken(Roles.Assign);
Space(policy.SpaceAroundAssignment);
propertyDeclaration.Initializer.AcceptVisitor(this);
Semicolon();
}
NewLine();
} else {
Space();
WriteToken(Roles.Arrow);
Space();
propertyDeclaration.ExpressionBody.AcceptVisitor(this);
Semicolon();
}
NewLine();
EndNode(propertyDeclaration);
}

3
ICSharpCode.Decompiler/CSharp/Syntax/Expressions/LambdaExpression.cs

@ -32,7 +32,6 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -32,7 +32,6 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
public class LambdaExpression : Expression
{
public readonly static TokenRole AsyncModifierRole = new TokenRole ("async");
public readonly static TokenRole ArrowRole = new TokenRole ("=>");
public static readonly Role<AstNode> BodyRole = new Role<AstNode>("Body", AstNode.Null);
bool isAsync;
@ -55,7 +54,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -55,7 +54,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
}
public CSharpTokenNode ArrowToken {
get { return GetChildByRole (ArrowRole); }
get { return GetChildByRole (Roles.Arrow); }
}
public AstNode Body {

1
ICSharpCode.Decompiler/CSharp/Syntax/Roles.cs

@ -66,6 +66,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -66,6 +66,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
public static readonly TokenRole Assign = new TokenRole ("=");
public static readonly TokenRole Colon = new TokenRole (":");
public static readonly TokenRole DoubleColon = new TokenRole ("::");
public static readonly TokenRole Arrow = new TokenRole("=>");
public static readonly Role<Comment> Comment = new Role<Comment> ("Comment");
public static readonly Role<NewLineNode> NewLine = new Role<NewLineNode> ("NewLine");
public static readonly Role<WhitespaceNode> Whitespace = new Role<WhitespaceNode> ("Whitespace");

11
ICSharpCode.Decompiler/CSharp/Syntax/TypeMembers/PropertyDeclaration.cs

@ -34,7 +34,8 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -34,7 +34,8 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
public static readonly TokenRole SetKeywordRole = new TokenRole ("set");
public static readonly Role<Accessor> GetterRole = new Role<Accessor>("Getter", Accessor.Null);
public static readonly Role<Accessor> SetterRole = new Role<Accessor>("Setter", Accessor.Null);
public static readonly Role<Expression> ExpressionBodyRole = new Role<Expression>("ExpressionBody", Expression.Null);
public override SymbolKind SymbolKind {
get { return SymbolKind.Property; }
}
@ -75,6 +76,11 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -75,6 +76,11 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
set { SetChildByRole(Roles.Expression, value); }
}
public Expression ExpressionBody {
get { return GetChildByRole(ExpressionBodyRole); }
set { SetChildByRole(ExpressionBodyRole, value); }
}
public override void AcceptVisitor (IAstVisitor visitor)
{
visitor.VisitPropertyDeclaration (this);
@ -97,7 +103,8 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -97,7 +103,8 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
&& this.MatchAttributesAndModifiers(o, match) && this.ReturnType.DoMatch(o.ReturnType, match)
&& this.PrivateImplementationType.DoMatch(o.PrivateImplementationType, match)
&& this.Getter.DoMatch(o.Getter, match) && this.Setter.DoMatch(o.Setter, match)
&& this.Initializer.DoMatch(o.Initializer, match);
&& this.Initializer.DoMatch(o.Initializer, match)
&& this.ExpressionBody.DoMatch(o.ExpressionBody, match);
}
}
}

24
ICSharpCode.Decompiler/CSharp/Transforms/NormalizeBlockStatements.cs

@ -3,6 +3,7 @@ using System.Collections.Generic; @@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Linq;
using System.Text;
using ICSharpCode.Decompiler.CSharp.Syntax;
using ICSharpCode.Decompiler.CSharp.Syntax.PatternMatching;
namespace ICSharpCode.Decompiler.CSharp.Transforms
{
@ -116,5 +117,28 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -116,5 +117,28 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
this.context = context;
rootNode.AcceptVisitor(this);
}
public override void VisitPropertyDeclaration(PropertyDeclaration propertyDeclaration)
{
if (context.Settings.UseExpressionBodyForCalculatedGetterOnlyProperties) {
SimplifyPropertyDeclaration(propertyDeclaration);
}
base.VisitPropertyDeclaration(propertyDeclaration);
}
static readonly PropertyDeclaration CalculatedGetterOnlyPropertyPattern = new PropertyDeclaration() {
Modifiers = Modifiers.Any,
Name = Pattern.AnyString,
ReturnType = new AnyNode(),
Getter = new Accessor() { Body = new BlockStatement() { new ReturnStatement(new AnyNode("expression")) } }
};
void SimplifyPropertyDeclaration(PropertyDeclaration propertyDeclaration)
{
var m = CalculatedGetterOnlyPropertyPattern.Match(propertyDeclaration);
if (!m.Success)
return;
propertyDeclaration.ExpressionBody = m.Get<Expression>("expression").Single().Detach();
}
}
}

15
ICSharpCode.Decompiler/DecompilerSettings.cs

@ -421,6 +421,21 @@ namespace ICSharpCode.Decompiler @@ -421,6 +421,21 @@ namespace ICSharpCode.Decompiler
}
}
bool useExpressionBodyForCalculatedGetterOnlyProperties = true;
/// <summary>
/// Gets/Sets whether simple calculated getter-only property declarations should use expression body syntax.
/// </summary>
public bool UseExpressionBodyForCalculatedGetterOnlyProperties {
get { return useExpressionBodyForCalculatedGetterOnlyProperties; }
set {
if (useExpressionBodyForCalculatedGetterOnlyProperties != value) {
useExpressionBodyForCalculatedGetterOnlyProperties = value;
OnPropertyChanged();
}
}
}
#region Options to aid VB decompilation
bool introduceIncrementAndDecrement = true;

Loading…
Cancel
Save