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

7
ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs

@ -177,6 +177,13 @@ namespace ICSharpCode.Decompiler.CSharp @@ -177,6 +177,13 @@ namespace ICSharpCode.Decompiler.CSharp
.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)
{
return new PrimitiveExpression(inst.Value)

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

@ -19,40 +19,39 @@ @@ -19,40 +19,39 @@
using System;
using ICSharpCode.NRefactory.CSharp;
using ICSharpCode.NRefactory.PatternMatching;
using Mono.Cecil;
using ICSharpCode.NRefactory.TypeSystem;
namespace ICSharpCode.Decompiler.CSharp.Transforms
{
/// <summary>
/// Transforms decimal constant fields.
/// </summary>
public class DecimalConstantTransform : DepthFirstAstVisitor<object, object>, IAstTransform
public class DecimalConstantTransform : DepthFirstAstVisitor, IAstTransform
{
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;
if ((fieldDeclaration.Modifiers & staticReadOnly) == staticReadOnly && decimalType.IsMatch(fieldDeclaration.ReturnType)) {
foreach (var attributeSection in fieldDeclaration.Attributes) {
foreach (var attribute in attributeSection.Attributes) {
TypeReference tr = attribute.Type.Annotation<TypeReference>();
if (tr != null && tr.Name == "DecimalConstantAttribute" && tr.Namespace == "System.Runtime.CompilerServices") {
var t = attribute.Type.GetSymbol() as IType;
if (t != null && t.Name == "DecimalConstantAttribute" && t.Namespace == "System.Runtime.CompilerServices") {
attribute.Remove();
if (attributeSection.Attributes.Count == 0)
attributeSection.Remove();
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 @@ @@ -64,6 +64,7 @@
<ItemGroup>
<Compile Include="CSharp\Annotations.cs" />
<Compile Include="CSharp\DecompilerSettings.cs" />
<Compile Include="CSharp\Transforms\DecimalConstantTransform.cs" />
<Compile Include="CSharp\Transforms\EscapeInvalidIdentifiers.cs" />
<Compile Include="CSharp\Transforms\IntroduceUsingDeclarations.cs" />
<Compile Include="CSharp\Transforms\TransformContext.cs" />

46
ICSharpCode.Decompiler/IL/Instructions.cs

@ -113,6 +113,8 @@ namespace ICSharpCode.Decompiler.IL @@ -113,6 +113,8 @@ namespace ICSharpCode.Decompiler.IL
LdcI8,
/// <summary>Loads a constant floating-point number.</summary>
LdcF,
/// <summary>Loads a constant decimal.</summary>
LdcDecimal,
/// <summary>Loads the null reference.</summary>
LdNull,
/// <summary>Load method pointer</summary>
@ -1539,6 +1541,31 @@ namespace ICSharpCode.Decompiler.IL @@ -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>
public sealed partial class LdNull : SimpleInstruction
{
@ -3163,6 +3190,10 @@ namespace ICSharpCode.Decompiler.IL @@ -3163,6 +3190,10 @@ namespace ICSharpCode.Decompiler.IL
{
Default(inst);
}
protected internal virtual void VisitLdcDecimal(LdcDecimal inst)
{
Default(inst);
}
protected internal virtual void VisitLdNull(LdNull inst)
{
Default(inst);
@ -3473,6 +3504,10 @@ namespace ICSharpCode.Decompiler.IL @@ -3473,6 +3504,10 @@ namespace ICSharpCode.Decompiler.IL
{
return Default(inst);
}
protected internal virtual T VisitLdcDecimal(LdcDecimal inst)
{
return Default(inst);
}
protected internal virtual T VisitLdNull(LdNull inst)
{
return Default(inst);
@ -3704,6 +3739,7 @@ namespace ICSharpCode.Decompiler.IL @@ -3704,6 +3739,7 @@ namespace ICSharpCode.Decompiler.IL
"ldc.i4",
"ldc.i8",
"ldc.f",
"ldc.decimal",
"ldnull",
"ldftn",
"ldvirtftn",
@ -4048,6 +4084,16 @@ namespace ICSharpCode.Decompiler.IL @@ -4048,6 +4084,16 @@ namespace ICSharpCode.Decompiler.IL
value = default(double);
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()
{
var inst = this as LdNull;

2
ICSharpCode.Decompiler/IL/Instructions.tt

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

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

@ -74,8 +74,51 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -74,8 +74,51 @@ namespace ICSharpCode.Decompiler.IL.Transforms
var newObj = new NewObj(inst.Method);
newObj.ILRange = inst.ILRange;
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);
}
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 @@ @@ -104,6 +104,7 @@
<Compile Include="Loops.cs" />
<Compile Include="TestCases\CompoundAssignment.cs" />
<Compile Include="TestCases\ControlFlow.cs" />
<Compile Include="TestCases\DecimalFields.cs" />
<Compile Include="TestCases\Generics.cs" />
<Compile Include="TestCases\HelloWorld.cs" />
<Compile Include="TestCases\InitializerTests.cs" />

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

@ -0,0 +1,42 @@ @@ -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 @@ -75,6 +75,12 @@ namespace ICSharpCode.Decompiler.Tests
{
TestCompileDecompileCompileOutputAll("InitializerTests.cs");
}
[Test]
public void DecimalFields()
{
TestCompileDecompileCompileOutputAll("DecimalFields.cs");
}
void TestCompileDecompileCompileOutputAll(string testFileName)
{

Loading…
Cancel
Save