Browse Source

add transformation of decimal literals and decimal constants

pull/728/head
Siegfried Pammer 10 years ago
parent
commit
62fe21fb9f
  1. 2
      ICSharpCode.Decompiler/CSharp/CSharpDecompiler.cs
  2. 7
      ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs
  3. 19
      ICSharpCode.Decompiler/CSharp/Transforms/DecimalConstantTransform.cs
  4. 1
      ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj
  5. 46
      ICSharpCode.Decompiler/IL/Instructions.cs
  6. 2
      ICSharpCode.Decompiler/IL/Instructions.tt
  7. 45
      ICSharpCode.Decompiler/IL/Transforms/ExpressionTransforms.cs
  8. 1
      ICSharpCode.Decompiler/Tests/ICSharpCode.Decompiler.Tests.csproj
  9. 42
      ICSharpCode.Decompiler/Tests/TestCases/DecimalFields.cs
  10. 6
      ICSharpCode.Decompiler/Tests/TestRunner.cs

2
ICSharpCode.Decompiler/CSharp/CSharpDecompiler.cs

@ -67,7 +67,7 @@ namespace ICSharpCode.Decompiler.CSharp
new AddCheckedBlocks(), new AddCheckedBlocks(),
//new DeclareVariables(context), // should run after most transforms that modify statements //new DeclareVariables(context), // should run after most transforms that modify statements
new ConvertConstructorCallIntoInitializer(), // must run after DeclareVariables new ConvertConstructorCallIntoInitializer(), // must run after DeclareVariables
//new DecimalConstantTransform(), new DecimalConstantTransform(),
new IntroduceUsingDeclarations(), new IntroduceUsingDeclarations(),
//new IntroduceExtensionMethods(context), // must run after IntroduceUsingDeclarations //new IntroduceExtensionMethods(context), // must run after IntroduceUsingDeclarations
//new IntroduceQueryExpressions(context), // must run after IntroduceExtensionMethods //new IntroduceQueryExpressions(context), // must run after IntroduceExtensionMethods

7
ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs

@ -177,6 +177,13 @@ namespace ICSharpCode.Decompiler.CSharp
.WithRR(new ConstantResolveResult(compilation.FindType(KnownTypeCode.Double), inst.Value)); .WithRR(new ConstantResolveResult(compilation.FindType(KnownTypeCode.Double), inst.Value));
} }
protected internal override TranslatedExpression VisitLdcDecimal(LdcDecimal inst)
{
return new PrimitiveExpression(inst.Value)
.WithILInstruction(inst)
.WithRR(new ConstantResolveResult(compilation.FindType(KnownTypeCode.Decimal), inst.Value));
}
protected internal override TranslatedExpression VisitLdStr(LdStr inst) protected internal override TranslatedExpression VisitLdStr(LdStr inst)
{ {
return new PrimitiveExpression(inst.Value) return new PrimitiveExpression(inst.Value)

19
ICSharpCode.Decompiler/CSharp/Transforms/DecimalConstantTransform.cs

@ -19,40 +19,39 @@
using System; using System;
using ICSharpCode.NRefactory.CSharp; using ICSharpCode.NRefactory.CSharp;
using ICSharpCode.NRefactory.PatternMatching; using ICSharpCode.NRefactory.PatternMatching;
using Mono.Cecil; using ICSharpCode.NRefactory.TypeSystem;
namespace ICSharpCode.Decompiler.CSharp.Transforms namespace ICSharpCode.Decompiler.CSharp.Transforms
{ {
/// <summary> /// <summary>
/// Transforms decimal constant fields. /// Transforms decimal constant fields.
/// </summary> /// </summary>
public class DecimalConstantTransform : DepthFirstAstVisitor<object, object>, IAstTransform public class DecimalConstantTransform : DepthFirstAstVisitor, IAstTransform
{ {
static readonly PrimitiveType decimalType = new PrimitiveType("decimal"); static readonly PrimitiveType decimalType = new PrimitiveType("decimal");
public override object VisitFieldDeclaration(FieldDeclaration fieldDeclaration, object data) public override void VisitFieldDeclaration(FieldDeclaration fieldDeclaration)
{ {
const Modifiers staticReadOnly = Modifiers.Static | Modifiers.Readonly; const Modifiers staticReadOnly = Modifiers.Static | Modifiers.Readonly;
if ((fieldDeclaration.Modifiers & staticReadOnly) == staticReadOnly && decimalType.IsMatch(fieldDeclaration.ReturnType)) { if ((fieldDeclaration.Modifiers & staticReadOnly) == staticReadOnly && decimalType.IsMatch(fieldDeclaration.ReturnType)) {
foreach (var attributeSection in fieldDeclaration.Attributes) { foreach (var attributeSection in fieldDeclaration.Attributes) {
foreach (var attribute in attributeSection.Attributes) { foreach (var attribute in attributeSection.Attributes) {
TypeReference tr = attribute.Type.Annotation<TypeReference>(); var t = attribute.Type.GetSymbol() as IType;
if (tr != null && tr.Name == "DecimalConstantAttribute" && tr.Namespace == "System.Runtime.CompilerServices") { if (t != null && t.Name == "DecimalConstantAttribute" && t.Namespace == "System.Runtime.CompilerServices") {
attribute.Remove(); attribute.Remove();
if (attributeSection.Attributes.Count == 0) if (attributeSection.Attributes.Count == 0)
attributeSection.Remove(); attributeSection.Remove();
fieldDeclaration.Modifiers = (fieldDeclaration.Modifiers & ~staticReadOnly) | Modifiers.Const; fieldDeclaration.Modifiers = (fieldDeclaration.Modifiers & ~staticReadOnly) | Modifiers.Const;
return null; return;
} }
} }
} }
} }
return null;
} }
public void Run(AstNode compilationUnit) public void Run(AstNode rootNode, TransformContext context)
{ {
compilationUnit.AcceptVisitor(this, null); rootNode.AcceptVisitor(this);
} }
} }
} }

1
ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj

@ -64,6 +64,7 @@
<ItemGroup> <ItemGroup>
<Compile Include="CSharp\Annotations.cs" /> <Compile Include="CSharp\Annotations.cs" />
<Compile Include="CSharp\DecompilerSettings.cs" /> <Compile Include="CSharp\DecompilerSettings.cs" />
<Compile Include="CSharp\Transforms\DecimalConstantTransform.cs" />
<Compile Include="CSharp\Transforms\EscapeInvalidIdentifiers.cs" /> <Compile Include="CSharp\Transforms\EscapeInvalidIdentifiers.cs" />
<Compile Include="CSharp\Transforms\IntroduceUsingDeclarations.cs" /> <Compile Include="CSharp\Transforms\IntroduceUsingDeclarations.cs" />
<Compile Include="CSharp\Transforms\TransformContext.cs" /> <Compile Include="CSharp\Transforms\TransformContext.cs" />

46
ICSharpCode.Decompiler/IL/Instructions.cs

@ -113,6 +113,8 @@ namespace ICSharpCode.Decompiler.IL
LdcI8, LdcI8,
/// <summary>Loads a constant floating-point number.</summary> /// <summary>Loads a constant floating-point number.</summary>
LdcF, LdcF,
/// <summary>Loads a constant decimal.</summary>
LdcDecimal,
/// <summary>Loads the null reference.</summary> /// <summary>Loads the null reference.</summary>
LdNull, LdNull,
/// <summary>Load method pointer</summary> /// <summary>Load method pointer</summary>
@ -1539,6 +1541,31 @@ namespace ICSharpCode.Decompiler.IL
} }
} }
/// <summary>Loads a constant decimal.</summary>
public sealed partial class LdcDecimal : SimpleInstruction
{
public LdcDecimal(decimal value) : base(OpCode.LdcDecimal)
{
this.Value = value;
}
public readonly decimal Value;
public override StackType ResultType { get { return StackType.O; } }
public override void WriteTo(ITextOutput output)
{
output.Write(OpCode);
output.Write(' ');
Disassembler.DisassemblerHelpers.WriteOperand(output, Value);
}
public override void AcceptVisitor(ILVisitor visitor)
{
visitor.VisitLdcDecimal(this);
}
public override T AcceptVisitor<T>(ILVisitor<T> visitor)
{
return visitor.VisitLdcDecimal(this);
}
}
/// <summary>Loads the null reference.</summary> /// <summary>Loads the null reference.</summary>
public sealed partial class LdNull : SimpleInstruction public sealed partial class LdNull : SimpleInstruction
{ {
@ -3163,6 +3190,10 @@ namespace ICSharpCode.Decompiler.IL
{ {
Default(inst); Default(inst);
} }
protected internal virtual void VisitLdcDecimal(LdcDecimal inst)
{
Default(inst);
}
protected internal virtual void VisitLdNull(LdNull inst) protected internal virtual void VisitLdNull(LdNull inst)
{ {
Default(inst); Default(inst);
@ -3473,6 +3504,10 @@ namespace ICSharpCode.Decompiler.IL
{ {
return Default(inst); return Default(inst);
} }
protected internal virtual T VisitLdcDecimal(LdcDecimal inst)
{
return Default(inst);
}
protected internal virtual T VisitLdNull(LdNull inst) protected internal virtual T VisitLdNull(LdNull inst)
{ {
return Default(inst); return Default(inst);
@ -3704,6 +3739,7 @@ namespace ICSharpCode.Decompiler.IL
"ldc.i4", "ldc.i4",
"ldc.i8", "ldc.i8",
"ldc.f", "ldc.f",
"ldc.decimal",
"ldnull", "ldnull",
"ldftn", "ldftn",
"ldvirtftn", "ldvirtftn",
@ -4048,6 +4084,16 @@ namespace ICSharpCode.Decompiler.IL
value = default(double); value = default(double);
return false; return false;
} }
public bool MatchLdcDecimal(out decimal value)
{
var inst = this as LdcDecimal;
if (inst != null) {
value = inst.Value;
return true;
}
value = default(decimal);
return false;
}
public bool MatchLdNull() public bool MatchLdNull()
{ {
var inst = this as LdNull; var inst = this as LdNull;

2
ICSharpCode.Decompiler/IL/Instructions.tt

@ -122,6 +122,8 @@
LoadConstant("long"), ResultType("I8")), LoadConstant("long"), ResultType("I8")),
new OpCode("ldc.f", "Loads a constant floating-point number.", new OpCode("ldc.f", "Loads a constant floating-point number.",
LoadConstant("double"), ResultType("F")), LoadConstant("double"), ResultType("F")),
new OpCode("ldc.decimal", "Loads a constant decimal.",
LoadConstant("decimal"), ResultType("O")),
new OpCode("ldnull", "Loads the null reference.", new OpCode("ldnull", "Loads the null reference.",
CustomClassName("LdNull"), NoArguments, ResultType("O")), CustomClassName("LdNull"), NoArguments, ResultType("O")),
new OpCode("ldftn", "Load method pointer", new OpCode("ldftn", "Load method pointer",

45
ICSharpCode.Decompiler/IL/Transforms/ExpressionTransforms.cs

@ -74,8 +74,51 @@ namespace ICSharpCode.Decompiler.IL.Transforms
var newObj = new NewObj(inst.Method); var newObj = new NewObj(inst.Method);
newObj.ILRange = inst.ILRange; newObj.ILRange = inst.ILRange;
newObj.Arguments.AddRange(inst.Arguments.Skip(1)); newObj.Arguments.AddRange(inst.Arguments.Skip(1));
var expr = new StObj(inst.Arguments[0], newObj, inst.Method.DeclaringType); LdcDecimal decimalConstant;
ILInstruction result;
if (TransformDecimalCtorToConstant(newObj, out decimalConstant)) {
result = decimalConstant;
} else {
result = newObj;
}
var expr = new StObj(inst.Arguments[0], result, inst.Method.DeclaringType);
inst.ReplaceWith(expr); inst.ReplaceWith(expr);
} }
protected internal override void VisitNewObj(NewObj inst)
{
LdcDecimal decimalConstant;
if (TransformDecimalCtorToConstant(inst, out decimalConstant)) {
inst.ReplaceWith(decimalConstant);
return;
}
base.VisitNewObj(inst);
}
bool TransformDecimalCtorToConstant(NewObj inst, out LdcDecimal result)
{
IType t = inst.Method.DeclaringType;
result = null;
if (!t.IsKnownType(KnownTypeCode.Decimal))
return false;
var args = inst.Arguments;
if (args.Count == 1) {
int val;
if (args[0].MatchLdcI4(out val)) {
result = new LdcDecimal(val);
return true;
}
} else if (args.Count == 5) {
int lo, mid, hi, isNegative, scale;
if (args[0].MatchLdcI4(out lo) && args[1].MatchLdcI4(out mid) &&
args[2].MatchLdcI4(out hi) && args[3].MatchLdcI4(out isNegative) &&
args[4].MatchLdcI4(out scale))
{
result = new LdcDecimal(new decimal(lo, mid, hi, isNegative != 0, (byte)scale));
return true;
}
}
return false;
}
} }
} }

1
ICSharpCode.Decompiler/Tests/ICSharpCode.Decompiler.Tests.csproj

@ -104,6 +104,7 @@
<Compile Include="Loops.cs" /> <Compile Include="Loops.cs" />
<Compile Include="TestCases\CompoundAssignment.cs" /> <Compile Include="TestCases\CompoundAssignment.cs" />
<Compile Include="TestCases\ControlFlow.cs" /> <Compile Include="TestCases\ControlFlow.cs" />
<Compile Include="TestCases\DecimalFields.cs" />
<Compile Include="TestCases\Generics.cs" /> <Compile Include="TestCases\Generics.cs" />
<Compile Include="TestCases\HelloWorld.cs" /> <Compile Include="TestCases\HelloWorld.cs" />
<Compile Include="TestCases\InitializerTests.cs" /> <Compile Include="TestCases\InitializerTests.cs" />

42
ICSharpCode.Decompiler/Tests/TestCases/DecimalFields.cs

@ -0,0 +1,42 @@
// Copyright (c) 2014 AlphaSierraPapa for the SharpDevelop Team
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System;
namespace ICSharpCode.Decompiler.Tests.TestCases
{
/// <summary>
/// Description of DecimalFields.
/// </summary>
public class DecimalFields
{
public const decimal field1 = 1.5m;
public const decimal field2 = decimal.One;
public const decimal field3 = decimal.MaxValue;
public const decimal field4 = decimal.MinValue;
public static int Main()
{
Console.WriteLine(field1);
Console.WriteLine(field2);
Console.WriteLine(field3);
Console.WriteLine(field4);
return 0;
}
}
}

6
ICSharpCode.Decompiler/Tests/TestRunner.cs

@ -75,6 +75,12 @@ namespace ICSharpCode.Decompiler.Tests
{ {
TestCompileDecompileCompileOutputAll("InitializerTests.cs"); TestCompileDecompileCompileOutputAll("InitializerTests.cs");
} }
[Test]
public void DecimalFields()
{
TestCompileDecompileCompileOutputAll("DecimalFields.cs");
}
void TestCompileDecompileCompileOutputAll(string testFileName) void TestCompileDecompileCompileOutputAll(string testFileName)
{ {

Loading…
Cancel
Save